Charge a carried node against the levels its position leaves, and part the causes one guard hid
CI / gate (push) Successful in 8s

This commit is contained in:
2026-09-03 08:01:27 +02:00
parent 32706adfeb
commit 4d0ad3728c
11 changed files with 74 additions and 59 deletions
+2 -2
View File
@@ -173,7 +173,7 @@ function directivePiece(scan: Scan, span: DirectiveSpan): Result<Piece> {
const text = readTextDirective(span)
if (text?.fault !== undefined) return faulted(text.fault, scan.path)
if (text !== undefined) return success({ kind: 'nodes', nodes: [{ text: text.value, type: 'text' }] })
const slot = slotNodes(scan, span.content)
const slot = slotContent(scan, span.content)
if (!slot.ok) return slot
const mark = readDirectiveMark(span.name, span.attributes, scan.path)
if (mark !== undefined) {
@@ -189,7 +189,7 @@ function directivePiece(scan: Scan, span: DirectiveSpan): Result<Piece> {
return success({ kind: 'nodes', nodes: [node.value] })
}
function slotNodes(scan: Scan, content: string | undefined): Result<SlotContent | undefined> {
function slotContent(scan: Scan, content: string | undefined): Result<SlotContent | undefined> {
if (content === undefined) return success(undefined)
const parsed = parseInline(content, scan.definitions, scan.path, false)
if (!parsed.ok) return parsed
+13 -3
View File
@@ -312,9 +312,19 @@ test('names the shape the inline carry reads alone', () => {
assert.equal(content(markdownToAdf(':adf{json="null"}\n')), 'unsupported-node-shape: adf spells its json attribute as json=null')
})
test('holds a carried JSON value to the nesting the parser carries', () => {
const deep = `:adf{json="${'['.repeat(largestNesting + 2)}${']'.repeat(largestNesting + 2)}"}\n`
assert.equal(content(markdownToAdf(deep)), `unsupported-nesting-depth: a carried node's JSON nests deeper than the ${largestNesting} levels the parser carries`)
test('holds a carried JSON value to the nesting its position leaves', () => {
const nested = (levels: number): string => `${'['.repeat(levels)}${']'.repeat(levels)}`
const fence = (prefix: string, levels: number): string => `${prefix}\`\`\`adf\n${prefix}${nested(levels)}\n${prefix}\`\`\`\n`
const deeper = `unsupported-nesting-depth: a carried node's JSON nests the input deeper than the ${largestNesting} levels the parser carries`
assert.equal(content(markdownToAdf(`:adf{json="${nested(largestNesting + 2)}"}\n`)), deeper)
assert.equal(code(markdownToAdf(fence('', largestNesting + 1))), 'unsupported-node-shape')
assert.equal(content(markdownToAdf(fence('> ', largestNesting + 1))), deeper)
})
test('names the number no JSON spelling carries in an opaque carry', () => {
const named = 'unsupported-node-shape: the opaque carry holds a number JSON cannot spell'
assert.equal(content(markdownToAdf(':adf{json="{\\"attrs\\":{\\"width\\":1e999},\\"type\\":\\"blockCard\\"}"}\n')), named)
assert.equal(content(markdownToAdf('```adf\n1e999\n```\n')), named)
})
test('names the mark spelling no opaque carry sits inside', () => {
+3 -3
View File
@@ -36,7 +36,7 @@ function blockNode(block: Block, definitions: LinkDefinitions, path: ConvertErro
case 'bulletList':
return listNode({ type: 'bulletList' }, block.items, definitions, path, depth)
case 'code':
return codeBlockNode(block.language, block.text, path)
return codeBlockNode(block.language, block.text, path, depth)
case 'directive':
return directiveNode(block, definitions, path, depth)
case 'fault':
@@ -134,9 +134,9 @@ function listNode(node: AdfNode, items: readonly Block[][], definitions: LinkDef
return success({ ...node, content })
}
function codeBlockNode(language: string, text: string, path: ConvertErrorPath): Result<AdfNode> {
function codeBlockNode(language: string, text: string, path: ConvertErrorPath, depth: number): Result<AdfNode> {
if (language === carryName) {
const carried = readCarriedBlock(text)
const carried = readCarriedBlock(text, depth)
if (carried.fault !== undefined) return faulted(carried.fault, path)
return success(carried.value)
}