12c: one block opener speller beside its reader, the line readers split along the union, and AGENTS.md records the leaf body
CI / gate (push) Successful in 26s
CI / publish (push) Has been skipped

This commit is contained in:
2026-09-16 19:21:06 +02:00
parent 4aa9e88238
commit ba91900b89
7 changed files with 69 additions and 54 deletions
@@ -1,28 +1,27 @@
import type { AdfNode } from '../../adf/document.ts'
import type { BlockDirective } from '../../adf/block-directives.ts'
import { blockArgument } from '../block-directive-arguments.ts'
import { directivePrefix, isBareToken, spellAttributes, spellJsonAttribute, spellVocabulary } from '../directive-syntax.ts'
import { isBareToken, spellAttributes, spellDirectiveOpener, spellJsonAttribute, spellVocabulary } from '../directive-syntax.ts'
import { markValues, marksAttribute } from '../block-directive-marks.ts'
import { nodeAttrs, nodeMarks } from '../../adf/document.ts'
import { vocabularyPairs } from '../../adf/attribute-vocabulary.ts'
export function spellBlockDirectiveOpener(node: AdfNode, directive: BlockDirective, spelledByBody: readonly string[] = []): string | undefined {
const argumentAttribute = blockArgument(node.type)
const argument = spellArgument(node, argumentAttribute)
if (argument === undefined) return undefined
const slot = bareArgument(node, argumentAttribute)
if (slot === undefined) return undefined
const spelled = argumentAttribute === undefined ? spelledByBody : [argumentAttribute, ...spelledByBody]
const pairs = vocabularyPairs(nodeAttrs(node), directive.attributes, spelled)
if (pairs === undefined) return undefined
const spelledPairs = spellVocabulary(pairs)
const marks = nodeMarks(node)
if (marks.length > 0) spelledPairs.push([marksAttribute, spellJsonAttribute(markValues(marks))])
const attributes = spellAttributes(spelledPairs)
return `${directivePrefix}${node.type}${argument}${attributes === '' ? '' : ` ${attributes}`}`
return spellDirectiveOpener(node.type, slot.argument, spellAttributes(spelledPairs))
}
function spellArgument(node: AdfNode, argumentAttribute: string | undefined): string | undefined {
// `undefined` where the argument slot holds a value no bare token spells.
function bareArgument(node: AdfNode, argumentAttribute: string | undefined): { argument: string | undefined } | undefined {
const value = argumentAttribute === undefined ? undefined : nodeAttrs(node)[argumentAttribute]
if (value === undefined) return ''
if (typeof value !== 'string' || !isBareToken(value)) return undefined
return ` ${value}`
if (value === undefined) return { argument: undefined }
return typeof value === 'string' && isBareToken(value) ? { argument: value } : undefined
}