Emitter 2b: the block-node directives, the pipe table and the refusal corpus #11
@@ -75,7 +75,8 @@ Pre-1.0, normal 0.x rules.
|
|||||||
The error surface is a contract too. `ConvertError` is `{ code, message, path }` — the code from a
|
The error surface is a contract too. `ConvertError` is `{ code, message, path }` — the code from a
|
||||||
closed list a consumer may switch exhaustively, the message free text, the path the node's position
|
closed list a consumer may switch exhaustively, the message free text, the path the node's position
|
||||||
from the document root. Adding, removing or renaming a code is breaking, so a milestone meeting a
|
from the document root. Adding, removing or renaming a code is breaking, so a milestone meeting a
|
||||||
new failure cause reuses a code where one fits; the list is complete at `0.1.0`.
|
new failure cause reuses a code where one fits; the list is complete at `0.1.0`. A code names the
|
||||||
|
cause, never the node — `path` and `message` carry that.
|
||||||
|
|
||||||
## 9. Release automation
|
## 9. Release automation
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
ambiguous-empty-code-block-language
|
ambiguous-attribute-spelling
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
ambiguous-empty-media-alt
|
ambiguous-attribute-spelling
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
ambiguous-ordered-list-start
|
ambiguous-attribute-spelling
|
||||||
|
|||||||
+3
-3
@@ -74,9 +74,9 @@ block content
|
|||||||
|
|
||||||
The fence is three or more colons. `arg` is one optional bare token whose meaning each node
|
The fence is three or more colons. `arg` is one optional bare token whose meaning each node
|
||||||
defines (e.g. the panel type). The body is block markdown. The closing fence is a line of at
|
defines (e.g. the panel type). The body is block markdown. The closing fence is a line of at
|
||||||
least the opening's length, and a container's fence is longer than every directive fence line in
|
least the opening's length, and a container's fence is longer than every directive fence line
|
||||||
its body — counting only lines that parse as directive fences in the body's block structure; a
|
anywhere in its body, however deeply a list item or blockquote nests it; a colon run inside a code
|
||||||
colon run inside a code fence or opaque carry is content. Canonical form uses minimal lengths.
|
fence or opaque carry is content. Canonical form uses minimal lengths.
|
||||||
Directive fence lines follow code-fence indentation (up to three spaces relative to their
|
Directive fence lines follow code-fence indentation (up to three spaces relative to their
|
||||||
container); trailing whitespace on a fence line is tolerated in input, never emitted.
|
container); trailing whitespace on a fence line is tolerated in input, never emitted.
|
||||||
|
|
||||||
|
|||||||
@@ -53,13 +53,13 @@ test('refuses marks on a block node', () => {
|
|||||||
|
|
||||||
test('refuses an ordered list whose markdown start is ambiguous', () => {
|
test('refuses an ordered list whose markdown start is ambiguous', () => {
|
||||||
const items: AdfNode[] = [{ content: [paragraph({ text: 'x', type: 'text' })], type: 'listItem' }]
|
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({ content: items, type: 'orderedList' }))), 'ambiguous-attribute-spelling')
|
||||||
assert.equal(code(adfToMarkdown(document({ attrs: { order: 1 }, content: items, type: 'orderedList' }))), 'ambiguous-ordered-list-start')
|
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')
|
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', () => {
|
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: '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: 'a`b' }, type: 'codeBlock' }))), 'unspellable-code-block-language')
|
||||||
assert.equal(code(adfToMarkdown(document({ attrs: { language: ' sql' }, 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 }))), `\n`)
|
assert.equal(markdown(adfToMarkdown(single({ alt: 'The moon', type: 'external', url }))), `\n`)
|
||||||
assert.equal(markdown(adfToMarkdown(single({ type: 'external', url }))), `\n`)
|
assert.equal(markdown(adfToMarkdown(single({ type: 'external', url }))), `\n`)
|
||||||
assert.equal(markdown(adfToMarkdown(single({ alt: 'a [b] c', type: 'external', url }))), `![a \\[b\\] c](${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\nb', type: 'external', url }))), 'unspellable-whitespace')
|
||||||
assert.equal(code(adfToMarkdown(single({ alt: 'a\u0000b', type: 'external', url }))), 'unspellable-character')
|
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')
|
assert.equal(code(adfToMarkdown(single({ type: 'external', url: 'https://example.com/a b>c' }))), 'unspellable-link-destination')
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ function spellCodeFenceInfo(language: JsonValue | undefined, path: ConvertErrorP
|
|||||||
if (language === undefined) return success('')
|
if (language === undefined) return success('')
|
||||||
if (typeof language !== 'string') return failure('unsupported-node-shape', 'a codeBlock language is no string', path)
|
if (typeof language !== 'string') return failure('unsupported-node-shape', 'a codeBlock language is no string', path)
|
||||||
if (language === '') {
|
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 (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()) {
|
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)
|
if (node.type !== 'orderedList') return success(0)
|
||||||
const start = node.attrs?.['order']
|
const start = node.attrs?.['order']
|
||||||
if (start === undefined || start === 1) {
|
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) {
|
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)
|
return failure('unsupported-node-shape', `no list marker spells the order ${JSON.stringify(start)}`, path)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export function emitImage(node: AdfNode, path: ConvertErrorPath): Result<string>
|
|||||||
const image = imageShape(node)
|
const image = imageShape(node)
|
||||||
if (image === undefined) return undefined
|
if (image === undefined) return undefined
|
||||||
const mediaPath = [...path, 'content', 0]
|
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)
|
return emitImageLine(image.alt, image.url, mediaPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -1,7 +1,5 @@
|
|||||||
export type ConvertErrorCode =
|
export type ConvertErrorCode =
|
||||||
| 'ambiguous-empty-code-block-language'
|
| 'ambiguous-attribute-spelling'
|
||||||
| 'ambiguous-empty-media-alt'
|
|
||||||
| 'ambiguous-ordered-list-start'
|
|
||||||
| 'not-an-adf-document'
|
| 'not-an-adf-document'
|
||||||
| 'reserved-adf-language'
|
| 'reserved-adf-language'
|
||||||
| 'unspellable-adjacent-lists'
|
| 'unspellable-adjacent-lists'
|
||||||
|
|||||||
Reference in New Issue
Block a user