13b - review nits: README code span, AGENTS.md §2 example, comments, block-directive link message
CI / gate (push) Successful in 25s
CI / publish (push) Successful in 4s

This commit was merged in pull request #93.
This commit is contained in:
2026-09-16 23:28:31 +02:00
parent b792c946c5
commit 43292555cd
7 changed files with 12 additions and 11 deletions
+1 -2
View File
@@ -41,7 +41,6 @@ export function emitInlineLine(nodes: readonly AdfNode[], container: LineContain
return success(emitted.value.line)
}
// The parser asks which form a paragraph's opening link takes rather than restating the line rule (AGENTS.md §11).
export function openingLinkTakesDirective(nodes: readonly AdfNode[], path: ConvertErrorPath): Result<boolean> {
const emitted = emitLine(nodes, 'paragraph', path)
if (!emitted.ok) return emitted
@@ -64,7 +63,7 @@ export function tryImageLine(alt: string | undefined, href: string, path: Conver
return attempt.ok ? attempt.value.line : undefined
}
// A carried node joins no run and the opening link turns directive once, so every pass carries at least one more node.
// Every pass carries at least one more node, or flips openingLinkAsDirective, which happens once — so the loop ends.
function emitLine(nodes: readonly AdfNode[], container: LineContainer, path: ConvertErrorPath): Result<EmittedLine> {
const carried = new Set<number>()
let openingLinkAsDirective = false
+1 -1
View File
@@ -35,7 +35,7 @@ export function markSpelling(type: string): MarkSpelling | undefined {
return { attributes, kind: spelling.kind }
}
// spec/flavour.md, Marks. `marksInside` counts the marks the link's nodes carry within it: the emitter's depth, the parser's none.
// spec/flavour.md, Marks. `marksInside` counts the marks the link's nodes carry within it: the emitter's depth + 1, the parser's 0.
export function commonMarkLink(attrs: AdfAttributes, href: string, nodes: readonly AdfNode[], marksInside: number, bracketed: boolean): CommonMarkLink | undefined {
if (Object.keys(attrs).some((key) => key !== 'href' && key !== 'title')) return undefined
const title = attrs['title']
+3 -1
View File
@@ -20,7 +20,9 @@ export function readDirectiveMark(name: string, attributes: DirectiveAttributes,
export function inlineMarkSpellingFault(name: string): ConvertFault | undefined {
const spelling = markSpelling(name)
if (spelling === undefined) return undefined
return { code: 'unsupported-node-shape', message: `${name} is spelled ${markdownForm(spelling) ?? `${directivePrefix}${name}[…]`}, never as a block directive` }
const directive = `${directivePrefix}${name}[…]`
const forms = spelling.kind === 'link' ? `[x](url) or ${directive}` : (markdownForm(spelling) ?? directive)
return { code: 'unsupported-node-shape', message: `${name} is spelled ${forms}, never as a block directive` }
}
function markdownForm(spelling: MarkSpelling): string | undefined {
+1 -1
View File
@@ -36,7 +36,7 @@ type Piece =
type Run = { canClose: boolean; canOpen: boolean; character: string; index: number; length: number }
// `container` is the emitter's line container, `undefined` inside a directive's content slot; `openingSpellableLink` defers a directive link at offset 0 to `assemble`.
// `container` is `undefined` inside a directive's content slot, the emitter's `bracketed`.
type Scan = {
container: LineContainer | undefined
definitions: LinkDefinitions
+1 -1
View File
@@ -333,6 +333,7 @@ test('names the leaf given a body at its opener, ahead of any refusal the leaf h
test('names the position a directive name the other one spells belongs to', () => {
assert.equal(content(markdownToAdf('!adf:em\na\n!adf:/em\n')), 'unsupported-node-shape: em is spelled _x_, never as a block directive')
assert.equal(content(markdownToAdf('!adf:underline\n')), 'unsupported-node-shape: underline is spelled !adf:underline[…], never as a block directive')
assert.equal(content(markdownToAdf('!adf:link\n')), 'unsupported-node-shape: link is spelled [x](url) or !adf:link[…], never as a block directive')
assert.equal(content(markdownToAdf('!adf:text {text=" "}\n')), 'unsupported-node-shape: text takes the inline form, !adf:text{…}, never the block form')
assert.equal(content(markdownToAdf('!adf:date {timestamp=1}\n')), 'unsupported-node-shape: date takes the inline form, !adf:date{…}, never the block form')
assert.equal(content(markdownToAdf('!adf:paragraph[a]\n')), 'unsupported-node-shape: paragraph takes the block form, !adf:paragraph, never the inline form')
@@ -968,7 +969,6 @@ test('names the mark markdown spells, never a directive', () => {
assert.equal(content(markdownToAdf('!adf:code[a]\n')), 'unsupported-node-shape: code is spelled `x`, never as a directive')
})
// spec/flavour.md, Marks: the directive link is refused wherever the emitter would pick the markdown spelling.
test('refuses the directive link CommonMark could spell, and reads the one it could not', () => {
const refused = 'unsupported-node-shape: link takes the directive form only where CommonMark cannot spell it: this one it can, as [text](url "title") or <url>'
assert.equal(content(markdownToAdf('!adf:link[a]{href="/u"}\n')), refused)