A read below the depth that filled the memo re-spells, so the depth guards still run
CI / gate (push) Successful in 28s
CI / publish (push) Has been skipped

This commit is contained in:
2026-09-19 13:37:58 +02:00
parent 3f8afcb9d7
commit d6756ea5e6
4 changed files with 33 additions and 12 deletions
+5 -2
View File
@@ -103,8 +103,11 @@ export function commonMarkSpelling(node: AdfNode, path: ConvertErrorPath, depth:
function readableBlock(node: AdfNode, path: ConvertErrorPath, depth: number, memo: SpellingMemo | undefined): Result<EmittedBlock> | undefined {
const kept = memo?.get(node)
// A reuse sits no deeper than the fill it reads, so the kept headroom only ever grows (AGENTS.md §11).
if (kept !== undefined) return kept.block === undefined ? undefined : success({ ...kept.block, headroom: kept.block.headroom + kept.depth - depth })
if (kept !== undefined) {
if (kept.block === undefined) return undefined
// A read below the fill would skip the depth guards the walk it replaces runs (AGENTS.md §11).
if (depth <= kept.depth) return success({ ...kept.block, headroom: kept.block.headroom + kept.depth - depth })
}
const spelled = spellReadableBlock(node, path, depth, memo)
if (spelled === undefined) memo?.set(node, { block: undefined, depth })
else if (spelled.ok) memo?.set(node, { block: spelled.value, depth })
+11 -1
View File
@@ -672,7 +672,7 @@ test('refuses input nested deeper than the parser carries', () => {
assert.equal(code(markdownToAdf(marks(largestNesting + 1))), 'unsupported-nesting-depth')
assert.deepEqual(content(markdownToAdf(marks(largestNesting))), [{ content: [marked('a', underline)], type: 'paragraph' }])
const nest = (names: readonly string[], body: string): string => [...names.map((name) => `!adf:${name}\n`), body, ...names.map((name) => `!adf:/${name}\n`).reverse()].join('')
const repeated = (name: string): string[] => Array.from({ length: largestNesting }, () => name)
const repeated = (name: string, levels: number = largestNesting): string[] => Array.from({ length: levels }, () => name)
assert.ok(markdownToAdf(nest(repeated('panel'), '!adf:paragraph {localId=a-1}\nPart.\n!adf:/paragraph\n')).ok)
assert.deepEqual(position(markdownToAdf(nest(['expand', ...repeated('panel'), 'expand'], 'Part.\n'))), { line: 501, offset: 5501 })
assert.equal(code(markdownToAdf(nest(['panel', ...repeated('expand'), 'panel'], 'Part.\n'))), 'unsupported-nesting-depth')
@@ -680,6 +680,16 @@ test('refuses input nested deeper than the parser carries', () => {
const directiveLists = largestNesting / 2
assert.ok(markdownToAdf(listed(directiveLists)).ok)
assert.equal(code(markdownToAdf(listed(directiveLists + 1))), 'unsupported-nesting-depth')
const asking = (body: string): string => `!adf:bulletList\n!adf:listItem\n${body}!adf:/listItem\n!adf:/bulletList\n`
// Two items past the largest list marker leave the list no readable spelling, so the emitter
// walks it as list plus item where the parser counted one level.
const overflowing = (body: string): string => {
const marker = '999999999. '
return `${marker}${body.replace(/^(?!$)/gm, ' '.repeat(marker.length)).slice(marker.length)}\n${marker}z\n`
}
const overflowed = (panels: number): string => asking(overflowing(overflowing(asking(`---\n${nest(repeated('panel', panels), 'Part.\n')}`))))
assert.equal(code(markdownToAdf(overflowed(493))), 'unsupported-node-shape')
assert.equal(code(markdownToAdf(overflowed(494))), 'unsupported-nesting-depth')
assert.ok(markdownToAdf(`${'- '.repeat(largestNesting)}a\n`).ok)
assert.equal(code(markdownToAdf(`${'- '.repeat(largestNesting + 1)}a\n`)), 'unsupported-nesting-depth')
})