12c: one block opener speller beside its reader, the line readers split along the union, and AGENTS.md records the leaf body
This commit is contained in:
@@ -113,13 +113,16 @@ function directivePair(node: AdfNode, opener: string, body: string): EmittedBloc
|
||||
|
||||
function emitDirectiveBlock(node: AdfNode, directive: BlockDirective, path: ConvertErrorPath, depth: number): Result<EmittedBlock> {
|
||||
if (node.text !== undefined) return failure('unsupported-node-shape', `a ${node.type} carries no text: this one holds text`, path)
|
||||
const content = nodeContent(node)
|
||||
const leaf = blockDirectiveForm(node.type) === 'leaf'
|
||||
if (leaf && content.length > 0) return failure('unsupported-node-shape', `a ${node.type} holds no content: this one holds some`, path)
|
||||
if (blockDirectiveForm(node.type) === 'leaf' && nodeContent(node).length > 0) return failure('unsupported-node-shape', `a ${node.type} holds no content: this one holds some`, path)
|
||||
if (directive.contentModel === 'code') return emitCodeDirective(node, directive, path, depth)
|
||||
const opener = spellBlockDirectiveOpener(node, directive)
|
||||
if (opener === undefined) return commonMarkLine(carriedBlock(node, path, depth))
|
||||
if (leaf) return success({ spelling: 'directive', text: opener })
|
||||
return emitDirectiveBody(node, directive, opener, path, depth)
|
||||
}
|
||||
|
||||
function emitDirectiveBody(node: AdfNode, directive: BlockDirective, opener: string, path: ConvertErrorPath, depth: number): Result<EmittedBlock> {
|
||||
if (blockDirectiveForm(node.type) === 'leaf') return success({ spelling: 'directive', text: opener })
|
||||
const content = nodeContent(node)
|
||||
const body = directive.contentModel === 'inline' ? emitInlineLine(content, 'paragraph', path) : emitBlocks(content, 'directive', path, depth + 1)
|
||||
if (!body.ok) return body
|
||||
return success(directivePair(node, opener, body.value))
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user