Fold the per-node ambiguity codes into one, and sharpen the container fence rule
CI / gate (push) Successful in 5s

This commit is contained in:
2026-08-25 15:38:16 +02:00
parent f065783f8f
commit 9ce5946173
9 changed files with 16 additions and 17 deletions
+4 -4
View File
@@ -53,13 +53,13 @@ test('refuses marks on a block node', () => {
test('refuses an ordered list whose markdown start is ambiguous', () => {
const items: AdfNode[] = [{ content: [paragraph({ text: 'x', type: 'text' })], type: 'listItem' }]
assert.equal(code(adfToMarkdown(document({ content: items, type: 'orderedList' }))), 'ambiguous-ordered-list-start')
assert.equal(code(adfToMarkdown(document({ attrs: { order: 1 }, content: items, type: 'orderedList' }))), 'ambiguous-ordered-list-start')
assert.equal(code(adfToMarkdown(document({ content: items, type: 'orderedList' }))), 'ambiguous-attribute-spelling')
assert.equal(code(adfToMarkdown(document({ attrs: { order: 1 }, content: items, type: 'orderedList' }))), 'ambiguous-attribute-spelling')
assert.equal(markdown(adfToMarkdown(document({ attrs: { order: 2 }, content: items, type: 'orderedList' }))), '2. x\n')
})
test('refuses the code block info strings the fence cannot hold', () => {
assert.equal(code(adfToMarkdown(document({ attrs: { language: '' }, type: 'codeBlock' }))), 'ambiguous-empty-code-block-language')
assert.equal(code(adfToMarkdown(document({ attrs: { language: '' }, type: 'codeBlock' }))), 'ambiguous-attribute-spelling')
assert.equal(code(adfToMarkdown(document({ attrs: { language: 'adf' }, type: 'codeBlock' }))), 'reserved-adf-language')
assert.equal(code(adfToMarkdown(document({ attrs: { language: 'a`b' }, type: 'codeBlock' }))), 'unspellable-code-block-language')
assert.equal(code(adfToMarkdown(document({ attrs: { language: ' sql' }, type: 'codeBlock' }))), 'unspellable-code-block-language')
@@ -334,7 +334,7 @@ test('spells the image form for exactly the centered external media shape', () =
assert.equal(markdown(adfToMarkdown(single({ alt: 'The moon', type: 'external', url }))), `![The moon](${url})\n`)
assert.equal(markdown(adfToMarkdown(single({ type: 'external', url }))), `![](${url})\n`)
assert.equal(markdown(adfToMarkdown(single({ alt: 'a [b] c', type: 'external', url }))), `![a \\[b\\] c](${url})\n`)
assert.equal(code(adfToMarkdown(single({ alt: '', type: 'external', url }))), 'ambiguous-empty-media-alt')
assert.equal(code(adfToMarkdown(single({ alt: '', type: 'external', url }))), 'ambiguous-attribute-spelling')
assert.equal(code(adfToMarkdown(single({ alt: 'a\nb', type: 'external', url }))), 'unspellable-whitespace')
assert.equal(code(adfToMarkdown(single({ alt: 'a\u0000b', type: 'external', url }))), 'unspellable-character')
assert.equal(code(adfToMarkdown(single({ type: 'external', url: 'https://example.com/a b>c' }))), 'unspellable-link-destination')
+2 -2
View File
@@ -178,7 +178,7 @@ function spellCodeFenceInfo(language: JsonValue | undefined, path: ConvertErrorP
if (language === undefined) return success('')
if (typeof language !== 'string') return failure('unsupported-node-shape', 'a codeBlock language is no string', path)
if (language === '') {
return failure('ambiguous-empty-code-block-language', 'an empty codeBlock language and an absent one share one markdown spelling', path)
return failure('ambiguous-attribute-spelling', 'an empty codeBlock language and an absent one share one markdown spelling', path)
}
if (language === 'adf') return failure('reserved-adf-language', 'the adf info string is reserved for the opaque carry', path)
if (/[`\n\r]/.test(language) || language !== language.trim()) {
@@ -227,7 +227,7 @@ function listStart(node: AdfNode, items: number, path: ConvertErrorPath): Result
if (node.type !== 'orderedList') return success(0)
const start = node.attrs?.['order']
if (start === undefined || start === 1) {
return failure('ambiguous-ordered-list-start', 'an orderedList starting at 1 and one with no order share one markdown spelling', path)
return failure('ambiguous-attribute-spelling', 'an orderedList starting at 1 and one with no order share one markdown spelling', path)
}
if (typeof start !== 'number' || !Number.isInteger(start) || start < 0 || start > largestListMarker) {
return failure('unsupported-node-shape', `no list marker spells the order ${JSON.stringify(start)}`, path)
+1 -1
View File
@@ -10,7 +10,7 @@ export function emitImage(node: AdfNode, path: ConvertErrorPath): Result<string>
const image = imageShape(node)
if (image === undefined) return undefined
const mediaPath = [...path, 'content', 0]
if (image.alt === '') return failure('ambiguous-empty-media-alt', 'an empty media alt and an absent one share one image spelling', mediaPath)
if (image.alt === '') return failure('ambiguous-attribute-spelling', 'an empty media alt and an absent one share one image spelling', mediaPath)
return emitImageLine(image.alt, image.url, mediaPath)
}
+1 -3
View File
@@ -1,7 +1,5 @@
export type ConvertErrorCode =
| 'ambiguous-empty-code-block-language'
| 'ambiguous-empty-media-alt'
| 'ambiguous-ordered-list-start'
| 'ambiguous-attribute-spelling'
| 'not-an-adf-document'
| 'reserved-adf-language'
| 'unspellable-adjacent-lists'