12b - The inline directive forms read and spell the !adf: prefix #84
@@ -12,7 +12,7 @@ import { adfToMarkdown } from './markdown/emit/adf-to-markdown.ts'
|
|||||||
import { blockArgument } from './markdown/block-directive-arguments.ts'
|
import { blockArgument } from './markdown/block-directive-arguments.ts'
|
||||||
import { blockDirectives } from './adf/block-directives.ts'
|
import { blockDirectives } from './adf/block-directives.ts'
|
||||||
import { carryFence, carryName } from './markdown/opaque-carry.ts'
|
import { carryFence, carryName } from './markdown/opaque-carry.ts'
|
||||||
import { directivePrefix, spellAttributes, spellDirectiveOpener, spellJsonAttribute, spellLeafDirective, spellStringAttribute, spellVocabulary } from './markdown/directive-syntax.ts'
|
import { directivePrefix, spellAttributes, spellInlineDirectiveOpener, spellJsonAttribute, spellLeafDirective, spellStringAttribute, spellVocabulary } from './markdown/directive-syntax.ts'
|
||||||
import { fencedCodeBlock } from './markdown/backtick-runs.ts'
|
import { fencedCodeBlock } from './markdown/backtick-runs.ts'
|
||||||
import { inlineDirectives } from './adf/inline-directives.ts'
|
import { inlineDirectives } from './adf/inline-directives.ts'
|
||||||
import { listBreakName } from './markdown/list-break.ts'
|
import { listBreakName } from './markdown/list-break.ts'
|
||||||
@@ -227,11 +227,11 @@ function inlineMarkdown(hostile: boolean): InlineMarkdown {
|
|||||||
...Object.entries(inlineDirectives).map(([name, directive]) =>
|
...Object.entries(inlineDirectives).map(([name, directive]) =>
|
||||||
fc
|
fc
|
||||||
.tuple(directive.textAttribute === undefined ? fc.constant(null) : fc.option(hostile ? word : prose), tableAttributes(directive.attributes, directive.textAttribute))
|
.tuple(directive.textAttribute === undefined ? fc.constant(null) : fc.option(hostile ? word : prose), tableAttributes(directive.attributes, directive.textAttribute))
|
||||||
.map(([slot, attrs]) => (slot === null ? spellLeafDirective(name, attrs) : `${spellDirectiveOpener(name)}${slot}]${attrs}`)),
|
.map(([slot, attrs]) => (slot === null ? spellLeafDirective(name, attrs) : `${spellInlineDirectiveOpener(name)}${slot}]${attrs}`)),
|
||||||
),
|
),
|
||||||
...Object.entries(markAttributes)
|
...Object.entries(markAttributes)
|
||||||
.filter(([name]) => hostile || markSpelling(name)?.kind === 'directive')
|
.filter(([name]) => hostile || markSpelling(name)?.kind === 'directive')
|
||||||
.map(([name, vocabulary]) => fc.tuple(tie('inlines'), tableAttributes(vocabulary)).map(([content, attrs]) => `${spellDirectiveOpener(name)}${content}]${attrs}`)),
|
.map(([name, vocabulary]) => fc.tuple(tie('inlines'), tableAttributes(vocabulary)).map(([content, attrs]) => `${spellInlineDirectiveOpener(name)}${content}]${attrs}`)),
|
||||||
),
|
),
|
||||||
weight: 2,
|
weight: 2,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export function spellJsonAttribute(value: JsonValue): string {
|
|||||||
return quote(serializeCanonicalJson(value, 'compact'))
|
return quote(serializeCanonicalJson(value, 'compact'))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function spellDirectiveOpener(name: string): string {
|
export function spellInlineDirectiveOpener(name: string): string {
|
||||||
return `${directivePrefix}${name}[`
|
return `${directivePrefix}${name}[`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { carriedInline } from '../opaque-carry.ts'
|
|||||||
import { claimsLine, holdsNullCharacter, isAutolink } from '../commonmark-grammar.ts'
|
import { claimsLine, holdsNullCharacter, isAutolink } from '../commonmark-grammar.ts'
|
||||||
import { escapeUnbalanced, spellDestination, spellLinkTarget } from '../link-syntax.ts'
|
import { escapeUnbalanced, spellDestination, spellLinkTarget } from '../link-syntax.ts'
|
||||||
import { failure, faulted, success, type ConvertErrorPath, type Result } from '../../result.ts'
|
import { failure, faulted, success, type ConvertErrorPath, type Result } from '../../result.ts'
|
||||||
import { holdsDirectivePrefix, slotLineEndingFault, spellDirectiveOpener, spellLeafDirective } from '../directive-syntax.ts'
|
import { holdsDirectivePrefix, slotLineEndingFault, spellInlineDirectiveOpener, spellLeafDirective } from '../directive-syntax.ts'
|
||||||
import { holdsEntityReference } from '../entity-references.ts'
|
import { holdsEntityReference } from '../entity-references.ts'
|
||||||
import { inlineDirective } from '../../adf/inline-directives.ts'
|
import { inlineDirective } from '../../adf/inline-directives.ts'
|
||||||
import { largestNesting } from '../../nesting.ts'
|
import { largestNesting } from '../../nesting.ts'
|
||||||
@@ -214,7 +214,7 @@ function emitInlineDirective(node: AdfNode, directive: InlineDirective, index: n
|
|||||||
if (spans !== undefined) return faulted(spans, path)
|
if (spans !== undefined) return faulted(spans, path)
|
||||||
if (holdsNullCharacter(slot)) return failure('unspellable-character', `a ${node.type} content slot holds a null character CommonMark replaces`, path)
|
if (holdsNullCharacter(slot)) return failure('unspellable-character', `a ${node.type} content slot holds a null character CommonMark replaces`, path)
|
||||||
const content: InlineSegment[] = slot === '' ? [] : [{ escaping: 'bracketed', text: slot }]
|
const content: InlineSegment[] = slot === '' ? [] : [{ escaping: 'bracketed', text: slot }]
|
||||||
return success({ segments: [syntax(spellDirectiveOpener(node.type)), ...content, syntax(`]${attributes}`)] })
|
return success({ segments: [syntax(spellInlineDirectiveOpener(node.type)), ...content, syntax(`]${attributes}`)] })
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitText(node: AdfNode, context: InlineContext, index: number, path: ConvertErrorPath): Result<Emission> {
|
function emitText(node: AdfNode, context: InlineContext, index: number, path: ConvertErrorPath): Result<Emission> {
|
||||||
@@ -241,7 +241,7 @@ function emitMarkedRun(nodes: readonly AdfNode[], mark: AdfMark, depth: number,
|
|||||||
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
|
||||||
if (inner.value.carry !== undefined) return inner
|
if (inner.value.carry !== undefined) return inner
|
||||||
return success({ segments: [syntax(spellDirectiveOpener(mark.type)), ...inner.value.segments, syntax(`]${attributes}`)] })
|
return success({ segments: [syntax(spellInlineDirectiveOpener(mark.type)), ...inner.value.segments, syntax(`]${attributes}`)] })
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitEmphasis(nodes: readonly AdfNode[], spelling: string, depth: number, range: NodeRange, context: InlineContext): Result<Emission> {
|
function emitEmphasis(nodes: readonly AdfNode[], spelling: string, depth: number, range: NodeRange, context: InlineContext): Result<Emission> {
|
||||||
|
|||||||
@@ -247,6 +247,9 @@ proves 12, 13 spells 11's gaps in 12's grammar, and 12 rewrites code 4b and 4c c
|
|||||||
container parses.
|
container parses.
|
||||||
- Split by construct, each sub-item both directions: 55 of 78 round-trip fixtures feed both
|
- Split by construct, each sub-item both directions: 55 of 78 round-trip fixtures feed both
|
||||||
the emit and the read-back test, so an emit-only chunk cannot land green.
|
the emit and the read-back test, so an emit-only chunk cannot land green.
|
||||||
|
- The spec leads the code from 12a to 12d: `spec/flavour.md` and `AGENTS.md` §4 spell the
|
||||||
|
`!adf:` grammar whole, while code and fixtures reach it one form at a time. A reader landing
|
||||||
|
in either without `todo.md` sees a gap that is the plan, not a defect.
|
||||||
- [x] **12a — The spec and the decision.**
|
- [x] **12a — The spec and the decision.**
|
||||||
- [ ] **12b — The inline form.** Inline nodes, directive marks, `text` and the inline carry
|
- [ ] **12b — The inline form.** Inline nodes, directive marks, `text` and the inline carry
|
||||||
`!adf:carry{json=…}` spelled and read as `!adf:name[content]{attrs}`, with the prefix claim
|
`!adf:carry{json=…}` spelled and read as `!adf:name[content]{attrs}`, with the prefix claim
|
||||||
@@ -258,6 +261,14 @@ proves 12, 13 spells 11's gaps in 12's grammar, and 12 rewrites code 4b and 4c c
|
|||||||
model, empty pairs, `listBreak` and the `carry` fence, spelled and read; the fence-length
|
model, empty pairs, `listBreak` and the `carry` fence, spelled and read; the fence-length
|
||||||
rule and the corpus test's fence nesting check deleted; the remaining fixtures re-spelled
|
rule and the corpus test's fence nesting check deleted; the remaining fixtures re-spelled
|
||||||
and `errors/` re-derived under the shifted codes, and the gate green.
|
and `errors/` re-derived under the shifted codes, and the gate green.
|
||||||
|
12b's two temporary seams expire here: `carryFence` folds back into `carryName` once the
|
||||||
|
fence reads `carry`, and `directiveLineEscape` into `inlineDirectiveEscape` once one escape
|
||||||
|
serves both forms. `spellLeafDirective` takes the `Inline` its reader-side regex already
|
||||||
|
carries, and `header` versus `opener` settles as one word in spec and code. While
|
||||||
|
`readNestedDirective` is open, its `[content]` and `{attrs}` reads lift out as named steps,
|
||||||
|
and the two `charAt`-against-`!` fast paths ahead of `claimsDirectivePrefix` — in
|
||||||
|
`readDirectiveContent` and `line-escaping`'s `bracketed-link-target` arm — either earn a
|
||||||
|
reason or go (the systems-architect, 2026-09-16).
|
||||||
- [ ] **12d — The README, `MIGRATION.md` and the sweep.** The README's examples and error tables
|
- [ ] **12d — The README, `MIGRATION.md` and the sweep.** The README's examples and error tables
|
||||||
follow, `MIGRATION.md` linked from one README line; docs and fixtures swept for any stale
|
follow, `MIGRATION.md` linked from one README line; docs and fixtures swept for any stale
|
||||||
`::`/`:name` spelling.
|
`::`/`:name` spelling.
|
||||||
|
|||||||
Reference in New Issue
Block a user