Corpus 2e2: the mark runs, the run a carry breaks, and one mark vocabulary #21
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "em"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "strong"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "Ready",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"extensionKey": "status-lozenge",
|
||||||
|
"extensionType": "com.atlassian.confluence.macro.core"
|
||||||
|
},
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "em"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "strong"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "inlineExtension"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "em"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "strong"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "to ship",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "paragraph"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "doc",
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
_**Ready**_:adf{json="{\"attrs\":{\"extensionKey\":\"status-lozenge\",\"extensionType\":\"com.atlassian.confluence.macro.core\"},\"marks\":[{\"type\":\"em\"},{\"type\":\"strong\"}],\"type\":\"inlineExtension\"}"}_**to ship**_
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"color": "#ae2e24"
|
||||||
|
},
|
||||||
|
"type": "textColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "Overdue since ",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"color": "red",
|
||||||
|
"text": "Blocked"
|
||||||
|
},
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"color": "#ae2e24"
|
||||||
|
},
|
||||||
|
"type": "textColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "status"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"color": "#ae2e24"
|
||||||
|
},
|
||||||
|
"type": "textColor"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": " on Tuesday",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "paragraph"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "em"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "Torque the ",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "em"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "strong"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "M8 bolt",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "em"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": " to ",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "em"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "strong"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "25 Nm",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "paragraph"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"href": "https://example.com/release"
|
||||||
|
},
|
||||||
|
"type": "link"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "Release notes ",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"shortName": ":rocket:",
|
||||||
|
"text": "🚀"
|
||||||
|
},
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"attrs": {
|
||||||
|
"href": "https://example.com/release"
|
||||||
|
},
|
||||||
|
"type": "link"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "emoji"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "paragraph"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "doc",
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
:textColor[Overdue since :status[Blocked]{color=red} on Tuesday]{color="#ae2e24"}
|
||||||
|
|
||||||
|
_Torque the **M8 bolt** to **25 Nm**_
|
||||||
|
|
||||||
|
[Release notes :emoji[🚀]{shortName=":rocket:"}](https://example.com/release)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
unspellable-mark
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"text": "un",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"marks": [
|
||||||
|
{
|
||||||
|
"type": "strong"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "-real",
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "istic",
|
||||||
|
"type": "text"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "paragraph"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"type": "doc",
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
+4
-3
@@ -386,9 +386,10 @@ inline nodes carrying an identical mark, attributes included, at that depth. A r
|
|||||||
node the emitter carries, so no emitted carry sits inside a mark spelling.
|
node the emitter carries, so no emitted carry sits inside a mark spelling.
|
||||||
|
|
||||||
An inline node whose marks no nesting spells — a mark type not listed here, an attribute no
|
An inline node whose marks no nesting spells — a mark type not listed here, an attribute no
|
||||||
spelling holds, an order putting a code span outside another mark, or `code` on text holding a
|
spelling holds, an order putting a code span outside another mark, `code` on text holding a
|
||||||
newline — rides the inline carry whole. An opaque carry inside a mark spelling is a named error
|
newline, or a spelling CommonMark's flanking rules cannot open or close where the run sits
|
||||||
in input: the carry restores its node exactly, marks included (AGENTS.md §3).
|
(`un**-real**istic`) — rides the inline carry whole. An opaque carry inside a mark spelling is a
|
||||||
|
named error in input: the carry restores its node exactly, marks included (AGENTS.md §3).
|
||||||
|
|
||||||
```
|
```
|
||||||
:textColor[**Overdue**]{color="#ae2e24"}, H:subsup[2]{type=sub}O, :underline[signed].
|
:textColor[**Overdue**]{color="#ae2e24"}, H:subsup[2]{type=sub}O, :underline[signed].
|
||||||
|
|||||||
@@ -90,12 +90,15 @@ test('refuses a link attribute no markdown spelling holds', () => {
|
|||||||
code(adfToMarkdown(document(paragraph({ marks: [{ attrs: { href: 'https://example.com/', id: 'x' }, type: 'link' }], text: 't', type: 'text' })))),
|
code(adfToMarkdown(document(paragraph({ marks: [{ attrs: { href: 'https://example.com/', id: 'x' }, type: 'link' }], text: 't', type: 'text' })))),
|
||||||
'unspellable-mark',
|
'unspellable-mark',
|
||||||
)
|
)
|
||||||
|
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ attrs: { href: 4 }, type: 'link' }], text: 't', type: 'text' })))), 'unspellable-mark')
|
||||||
|
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ type: 'link' }], text: 't', type: 'text' })))), 'unsupported-node-shape')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('refuses a mark the canonical spellings cannot nest', () => {
|
test('refuses a mark the canonical spellings cannot nest', () => {
|
||||||
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ type: 'annotation' }], text: 'x', type: 'text' })))), 'unspellable-mark')
|
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ type: 'annotation' }], text: 'x', type: 'text' })))), 'unspellable-mark')
|
||||||
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ type: 'code' }, { type: 'strong' }], text: 'x', type: 'text' })))), 'unspellable-mark')
|
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ type: 'code' }, { type: 'strong' }], text: 'x', type: 'text' })))), 'unspellable-mark')
|
||||||
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ attrs: { colour: 'red' }, type: 'em' }], text: 'x', type: 'text' })))), 'unspellable-mark')
|
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ attrs: { colour: 'red' }, type: 'em' }], text: 'x', type: 'text' })))), 'unspellable-mark')
|
||||||
|
assert.equal(code(adfToMarkdown(document(paragraph({ marks: [{ attrs: { localId: 'x' }, type: 'code' }], text: 'x', type: 'text' })))), 'unspellable-mark')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('refuses whitespace CommonMark cannot hold', () => {
|
test('refuses whitespace CommonMark cannot hold', () => {
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ export type InlineDirective = {
|
|||||||
slot?: string
|
slot?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MarkSpelling =
|
||||||
|
| { attributes: AttributeVocabulary; kind: 'code' | 'directive' | 'link'; spelling?: undefined }
|
||||||
|
| { attributes: AttributeVocabulary; kind: 'emphasis'; spelling: string }
|
||||||
|
|
||||||
const inlineDirectives: Readonly<Record<string, InlineDirective>> = {
|
const inlineDirectives: Readonly<Record<string, InlineDirective>> = {
|
||||||
date: { attributes: { localId: 'string', timestamp: 'string' } },
|
date: { attributes: { localId: 'string', timestamp: 'string' } },
|
||||||
emoji: { attributes: { id: 'string', localId: 'string', shortName: 'string' }, slot: 'text' },
|
emoji: { attributes: { id: 'string', localId: 'string', shortName: 'string' }, slot: 'text' },
|
||||||
@@ -29,19 +33,24 @@ const inlineDirectives: Readonly<Record<string, InlineDirective>> = {
|
|||||||
status: { attributes: { color: 'string', localId: 'string', style: 'string' }, slot: 'text' },
|
status: { attributes: { color: 'string', localId: 'string', style: 'string' }, slot: 'text' },
|
||||||
}
|
}
|
||||||
|
|
||||||
const markDirectives: Readonly<Record<string, AttributeVocabulary>> = {
|
const markSpellings: Readonly<Record<string, MarkSpelling>> = {
|
||||||
border: { color: 'string', size: 'number' },
|
border: { attributes: { color: 'string', size: 'number' }, kind: 'directive' },
|
||||||
subsup: { type: 'string' },
|
code: { attributes: {}, kind: 'code' },
|
||||||
textColor: { color: 'string' },
|
em: { attributes: {}, kind: 'emphasis', spelling: '_' },
|
||||||
underline: {},
|
link: { attributes: { href: 'string', title: 'string' }, kind: 'link' },
|
||||||
|
strike: { attributes: {}, kind: 'emphasis', spelling: '~~' },
|
||||||
|
strong: { attributes: {}, kind: 'emphasis', spelling: '**' },
|
||||||
|
subsup: { attributes: { type: 'string' }, kind: 'directive' },
|
||||||
|
textColor: { attributes: { color: 'string' }, kind: 'directive' },
|
||||||
|
underline: { attributes: {}, kind: 'directive' },
|
||||||
}
|
}
|
||||||
|
|
||||||
export function inlineDirective(type: string): InlineDirective | undefined {
|
export function inlineDirective(type: string): InlineDirective | undefined {
|
||||||
return Object.hasOwn(inlineDirectives, type) ? inlineDirectives[type] : undefined
|
return Object.hasOwn(inlineDirectives, type) ? inlineDirectives[type] : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function markDirective(type: string): AttributeVocabulary | undefined {
|
export function markSpelling(type: string): MarkSpelling | undefined {
|
||||||
return Object.hasOwn(markDirectives, type) ? markDirectives[type] : undefined
|
return Object.hasOwn(markSpellings, type) ? markSpellings[type] : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spellInlineNodeAttributes(node: AdfNode, directive: InlineDirective, path: ConvertErrorPath): Result<string> {
|
export function spellInlineNodeAttributes(node: AdfNode, directive: InlineDirective, path: ConvertErrorPath): Result<string> {
|
||||||
|
|||||||
+9
-18
@@ -1,7 +1,7 @@
|
|||||||
import type { AdfMark, AdfNode } from './adf-document.ts'
|
import type { AdfMark, AdfNode } from './adf-document.ts'
|
||||||
import type { InlineDirective } from './inline-directives.ts'
|
import type { InlineDirective } from './inline-directives.ts'
|
||||||
import { assembleInlineLine, type InlineEscaping, type InlineSegment, type LineContainer } from './markdown-escaping.ts'
|
import { assembleInlineLine, type InlineEscaping, type InlineSegment, type LineContainer } from './markdown-escaping.ts'
|
||||||
import { inlineDirective, markDirective, spellInlineNodeAttributes, spellMarkAttributes } from './inline-directives.ts'
|
import { inlineDirective, markSpelling, spellInlineNodeAttributes, spellMarkAttributes } from './inline-directives.ts'
|
||||||
import { largestNesting } from './nesting.ts'
|
import { largestNesting } from './nesting.ts'
|
||||||
import { claimsLine, holdsControlCharacter, holdsEntityReference, holdsNullCharacter, isAutolink, isUnicodeWhitespace } from './commonmark-grammar.ts'
|
import { claimsLine, holdsControlCharacter, holdsEntityReference, holdsNullCharacter, isAutolink, isUnicodeWhitespace } from './commonmark-grammar.ts'
|
||||||
import { carriedInline } from './opaque-carry.ts'
|
import { carriedInline } from './opaque-carry.ts'
|
||||||
@@ -19,9 +19,6 @@ type InlineContext = {
|
|||||||
|
|
||||||
type InlineRun = { index: number; kind: 'marked'; mark: AdfMark; nodes: AdfNode[] } | { index: number; kind: 'plain'; node: AdfNode }
|
type InlineRun = { index: number; kind: 'marked'; mark: AdfMark; nodes: AdfNode[] } | { index: number; kind: 'plain'; node: AdfNode }
|
||||||
|
|
||||||
const emphasisSpellings: Readonly<Record<string, string>> = { em: '_', strike: '~~', strong: '**' }
|
|
||||||
const linkAttributes = ['href', 'title']
|
|
||||||
|
|
||||||
export function emitInlineLine(nodes: readonly AdfNode[], container: LineContainer, path: ConvertErrorPath): Result<string> {
|
export function emitInlineLine(nodes: readonly AdfNode[], container: LineContainer, path: ConvertErrorPath): Result<string> {
|
||||||
const segments = lineSegments(nodes, container, path)
|
const segments = lineSegments(nodes, container, path)
|
||||||
if (!segments.ok) return segments
|
if (!segments.ok) return segments
|
||||||
@@ -204,15 +201,14 @@ function emitText(node: AdfNode, context: InlineContext, path: ConvertErrorPath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
function emitMarkedRun(nodes: readonly AdfNode[], mark: AdfMark, depth: number, index: number, context: InlineContext): Result<InlineSegment[]> {
|
function emitMarkedRun(nodes: readonly AdfNode[], mark: AdfMark, depth: number, index: number, context: InlineContext): Result<InlineSegment[]> {
|
||||||
if (mark.type === 'code') return emitCodeSpan(nodes, depth, nodePath(context, index))
|
|
||||||
if (mark.type === 'link') return emitLink(nodes, mark, depth, index, context)
|
|
||||||
const path = nodePath(context, index)
|
const path = nodePath(context, index)
|
||||||
const spelling = Object.hasOwn(emphasisSpellings, mark.type) ? emphasisSpellings[mark.type] : undefined
|
const spelling = markSpelling(mark.type)
|
||||||
if (spelling !== undefined) return emitEmphasis(nodes, mark, spelling, depth, index, context, path)
|
if (spelling === undefined) return failure('unspellable-mark', `no markdown spelling holds the ${mark.type} mark`, path)
|
||||||
const vocabulary = markDirective(mark.type)
|
const attributes = spellMarkAttributes(mark, spelling.attributes, path)
|
||||||
if (vocabulary === undefined) return failure('unspellable-mark', `no markdown spelling holds the ${mark.type} mark`, path)
|
|
||||||
const attributes = spellMarkAttributes(mark, vocabulary, path)
|
|
||||||
if (!attributes.ok) return attributes
|
if (!attributes.ok) return attributes
|
||||||
|
if (spelling.kind === 'code') return emitCodeSpan(nodes, depth, path)
|
||||||
|
if (spelling.kind === 'emphasis') return emitEmphasis(nodes, mark, spelling.spelling, depth, index, context, path)
|
||||||
|
if (spelling.kind === 'link') return emitLink(nodes, mark, depth, index, context, path)
|
||||||
const inner = emitRun(nodes, depth + 1, index, { ...context, bracketed: true, spansLines: false })
|
const inner = emitRun(nodes, depth + 1, index, { ...context, bracketed: true, spansLines: false })
|
||||||
if (!inner.ok) return inner
|
if (!inner.ok) return inner
|
||||||
return success([syntax(`:${mark.type}[`), ...inner.value, syntax(`]${attributes.value}`)])
|
return success([syntax(`:${mark.type}[`), ...inner.value, syntax(`]${attributes.value}`)])
|
||||||
@@ -227,7 +223,6 @@ function emitEmphasis(
|
|||||||
context: InlineContext,
|
context: InlineContext,
|
||||||
path: ConvertErrorPath,
|
path: ConvertErrorPath,
|
||||||
): Result<InlineSegment[]> {
|
): Result<InlineSegment[]> {
|
||||||
if (Object.keys(mark.attrs ?? {}).length > 0) return failure('unspellable-mark', `the ${mark.type} spelling holds no attributes`, path)
|
|
||||||
const inner = emitRun(nodes, depth + 1, index, context)
|
const inner = emitRun(nodes, depth + 1, index, context)
|
||||||
if (!inner.ok) return inner
|
if (!inner.ok) return inner
|
||||||
const carried = carryStrippedWhitespace(inner.value)
|
const carried = carryStrippedWhitespace(inner.value)
|
||||||
@@ -263,20 +258,16 @@ function needsPadding(text: string): boolean {
|
|||||||
return text.startsWith(' ') && text.endsWith(' ') && /[^ ]/.test(text)
|
return text.startsWith(' ') && text.endsWith(' ') && /[^ ]/.test(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitLink(nodes: readonly AdfNode[], mark: AdfMark, depth: number, index: number, context: InlineContext): Result<InlineSegment[]> {
|
function emitLink(nodes: readonly AdfNode[], mark: AdfMark, depth: number, index: number, context: InlineContext, path: ConvertErrorPath): Result<InlineSegment[]> {
|
||||||
const path = nodePath(context, index)
|
|
||||||
const unspelled = Object.keys(mark.attrs ?? {}).find((key) => !linkAttributes.includes(key))
|
|
||||||
if (unspelled !== undefined) return failure('unspellable-mark', `the link spelling holds no ${unspelled} attribute`, path)
|
|
||||||
const href = mark.attrs?.['href']
|
const href = mark.attrs?.['href']
|
||||||
const title = mark.attrs?.['title']
|
const title = mark.attrs?.['title']
|
||||||
if (typeof href !== 'string') return failure('unsupported-node-shape', 'a link mark carries no href', path)
|
if (typeof href !== 'string') return failure('unsupported-node-shape', 'a link mark carries no href', path)
|
||||||
if (title !== undefined && typeof title !== 'string') return failure('unsupported-node-shape', 'a link title is no string', path)
|
|
||||||
const node = nodes[0]
|
const node = nodes[0]
|
||||||
const bare = nodes.length === 1 && node !== undefined && node.type === 'text' && node.text === href && (node.marks ?? []).length === depth + 1
|
const bare = nodes.length === 1 && node !== undefined && node.type === 'text' && node.text === href && (node.marks ?? []).length === depth + 1
|
||||||
if (bare && title === undefined && isAutolink(href) && !holdsEntityReference(href)) return success([syntax(`<${href}>`)])
|
if (bare && title === undefined && isAutolink(href) && !holdsEntityReference(href)) return success([syntax(`<${href}>`)])
|
||||||
const destination = spellDestination(href, path)
|
const destination = spellDestination(href, path)
|
||||||
if (!destination.ok) return destination
|
if (!destination.ok) return destination
|
||||||
const spelledTitle = title === undefined ? success('') : spellTitle(title, path)
|
const spelledTitle = typeof title === 'string' ? spellTitle(title, path) : success('')
|
||||||
if (!spelledTitle.ok) return spelledTitle
|
if (!spelledTitle.ok) return spelledTitle
|
||||||
const inner = emitRun(nodes, depth + 1, index, { ...context, bracketed: true })
|
const inner = emitRun(nodes, depth + 1, index, { ...context, bracketed: true })
|
||||||
if (!inner.ok) return inner
|
if (!inner.ok) return inner
|
||||||
|
|||||||
@@ -110,7 +110,10 @@ detail is settled at its own milestone.
|
|||||||
arg slot holding no bare token, marks no nesting spells — where the emitter still refuses,
|
arg slot holding no bare token, marks no nesting spells — where the emitter still refuses,
|
||||||
which leaves the refusals a container's own spelling owns. The carry spells
|
which leaves the refusals a container's own spelling owns. The carry spells
|
||||||
`escaping: 'none'`, which is what makes `tryPipeCell` refuse the pipe form for a carry
|
`escaping: 'none'`, which is what makes `tryPipeCell` refuse the pipe form for a carry
|
||||||
whose JSON holds a pipe.
|
whose JSON holds a pipe. The flanking trigger 2e2 added to that list is the odd one out:
|
||||||
|
`unspellableMark` finds it after assembly and names a mark type against the line's path,
|
||||||
|
so the failing run needs identifying before the carry can replace the refusal
|
||||||
|
`corpus/unspellable/mark-inside-word` pins.
|
||||||
- [ ] **2e5 — Combined documents and the collision property.** Documents combining nodes rather
|
- [ ] **2e5 — Combined documents and the collision property.** Documents combining nodes rather
|
||||||
than isolating one, and the gate's collision property: no two corpus documents may emit
|
than isolating one, and the gate's collision property: no two corpus documents may emit
|
||||||
the same bytes — one spelling for two documents is a round-trip break no parser can undo,
|
the same bytes — one spelling for two documents is a round-trip break no parser can undo,
|
||||||
@@ -169,8 +172,8 @@ detail is settled at its own milestone.
|
|||||||
markdown, the payloads supplied by the maintainer.
|
markdown, the payloads supplied by the maintainer.
|
||||||
- [ ] **5 — Release pipeline, ship `0.1.0`.** Publish-on-version-change (§9), `NPM_TOKEN` secret,
|
- [ ] **5 — Release pipeline, ship `0.1.0`.** Publish-on-version-change (§9), `NPM_TOKEN` secret,
|
||||||
the repo made public first (§6). The `ConvertErrorCode` freeze (§8) is checkable here: every
|
the repo made public first (§6). The `ConvertErrorCode` freeze (§8) is checkable here: every
|
||||||
`corpus/unspellable/` document is one of 1d's decisions, so the directory empties as they land
|
`corpus/unspellable/` document is a decision or a deferred trigger this file names, so the
|
||||||
and whatever survives is permanent. `0.1.0` is the markdown round-trip: both markdown
|
directory empties as they land and whatever survives is permanent. `0.1.0` is the markdown round-trip: both markdown
|
||||||
directions, the types, `isAdfDocument`. The build lands here: a build tsconfig emitting JS
|
directions, the types, `isAdfDocument`. The build lands here: a build tsconfig emitting JS
|
||||||
and `.d.ts` to `dist/` (the dev config's `allowImportingTsExtensions` forces `noEmit`, so
|
and `.d.ts` to `dist/` (the dev config's `allowImportingTsExtensions` forces `noEmit`, so
|
||||||
the build config needs `rewriteRelativeImportExtensions`), plus `exports`/`files` in
|
the build config needs `rewriteRelativeImportExtensions`), plus `exports`/`files` in
|
||||||
|
|||||||
Reference in New Issue
Block a user