3
0
mirror of https://github.com/larvit/adf-codec.git synced 2026-11-15 21:10:25 +01:00

Answer stability round 1: 0 🔴, 2 🟡; a mark's malformed attrs name their cause, the docs name a value of the wrong type as a fallback

This commit is contained in:
2026-10-14 10:23:56 +02:00
committed by Lillem4n
parent 8188bc5e16
commit 168ca1cea2
9 changed files with 24 additions and 22 deletions
+7 -3
View File
@@ -4,7 +4,7 @@ import type { ConvertFault } from '../../result.ts'
import type { DirectiveAttributes, DirectiveValue } from '../directive-syntax.ts'
import type { Elsewhere } from './directive-attributes.ts'
import { attributeNestingMessage, isUnmarkedSpellableText } from '../../adf/document.ts'
import { attributeValue, directivePrefix, readAttributes, readDirectiveName, unknownDirectiveFault } from '../directive-syntax.ts'
import { attributeValue, directiveEscape, directivePrefix, readAttributes, readDirectiveName, unknownDirectiveFault } from '../directive-syntax.ts'
import { blockArgument, blockDirectiveForm, marksAttribute, readMarkValues, spellBlockMarks } from '../block-directive.ts'
import { blockNodeModel } from '../../adf/block-nodes.ts'
import { carryFencePrefix, carryName } from '../opaque-carry.ts'
@@ -132,10 +132,14 @@ function readNamedMark(type: string, text: string, index: number, path: ConvertE
const name = readDirectiveName(text, index)
if (name === undefined) return failure('unsupported-node-shape', unnamedMarks(type), path)
const vocabulary = markVocabularies.get(name)
if (vocabulary === undefined) return failure('unsupported-node-shape', `the ${marksAttribute} attribute of ${type} names ${name}, a mark it spells only in its JSON array`, path)
if (vocabulary === undefined) return failure('unsupported-node-shape', `the ${marksAttribute} attribute of ${type} names ${name}, no mark the flavour lists: spell an unlisted mark in the JSON array`, path)
const start = index + name.length
const attributes = text.charAt(start) === '{' ? readAttributes(text, start) : { value: { attributes: new Map<string, DirectiveValue>(), end: start } }
if (attributes.fault !== undefined) return failure('unsupported-node-shape', unnamedMarks(type), path)
if (attributes.fault !== undefined) {
// A quoted value holds no directive, so the fault's escape hint does not apply.
const cause = attributes.fault.message.replace(`; ${directiveEscape}`, '')
return failure('unsupported-node-shape', `the ${name} mark in the ${marksAttribute} attribute of ${type}: ${cause}`, path)
}
const mark = readMarkAttributes(name, attributes.value.attributes, vocabulary, path)
return mark.ok ? success({ end: attributes.value.end, mark: mark.value }) : mark
}
+5 -5
View File
@@ -556,12 +556,13 @@ test('names the marks key no marks read back from', () => {
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="{}"}\n')), named)
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="em strong"}\n')), named)
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="em "}\n')), named)
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{width=1 mode=wide}"}\n')), named)
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{mode}"}\n')), named)
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{mode=wide"}\n')), named)
const inBreakout = (cause: string): string => `unsupported-node-shape: the breakout mark in the marks attribute of rule: ${cause}`
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{width=1 mode=wide}"}\n')), inBreakout('the {attrs} keys read in alphabetical order: mode before width'))
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{mode}"}\n')), inBreakout('an attribute reads key=value, the value bare or double-quoted: this one does not'))
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{mode=wide"}\n')), inBreakout('the {attrs} closing brace is missing'))
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="em{attrs=empty}strong"}\n')), named)
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="em{attrs=x}"}\n')), 'unsupported-node-shape: the reserved key attrs takes only the value empty: this one spells attrs=x')
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks=x}\n')), 'unsupported-node-shape: the marks attribute of rule names x, a mark it spells only in its JSON array')
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks=x}\n')), 'unsupported-node-shape: the marks attribute of rule names x, no mark the flavour lists: spell an unlisted mark in the JSON array')
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{width=wide}"}\n')), 'unsupported-node-shape: the width attribute of breakout is no number')
assert.equal(content(losslessMarkdownToAdf('!adf:rule {marks="breakout{bogus=1}"}\n')), 'unsupported-node-shape: breakout holds no bogus attribute: this one spells it')
})
@@ -596,7 +597,6 @@ test('names the depth an attribute value nests past, never the kind the JSON rea
assert.equal(content(losslessMarkdownToAdf(`!adf:extension {parameters="${nested(largestNesting + 1)}"}\n`)), deeper('parameters', 'extension'))
assert.equal(content(losslessMarkdownToAdf(`!adf:rule {marks="${nested(largestNesting + 1)}"}\n`)), deeper('marks', 'rule'))
assert.equal(content(losslessMarkdownToAdf(`!adf:rule {marks="[{\\"attrs\\":{\\"deep\\":${nested(largestNesting - 2)}},\\"type\\":\\"em\\"}]"}\n`)), deeper('marks', 'rule'))
assert.equal(content(losslessMarkdownToAdf(`!adf:rule {marks="dataConsumer{sources=\\"${nested(largestNesting + 1)}\\"}"}\n`)), deeper('sources', 'dataConsumer'))
assert.equal(content(losslessMarkdownToAdf(`!adf:media {width="${nested(largestNesting + 1)}"}\n`)), 'unsupported-node-shape: the width attribute of media is no number')
})