27 - a placed block carries no headroom, so the list's directive items write none #126
@@ -296,11 +296,10 @@ someone spells it or pins it.
|
|||||||
attribute's and a carried node's alike — are all held to 500 levels (`largestNesting`), so a
|
attribute's and a carried node's alike — are all held to 500 levels (`largestNesting`), so a
|
||||||
deep document is a `Result` rather than the stack overflow that waits near 2000. An attribute
|
deep document is a `Result` rather than the stack overflow that waits near 2000. An attribute
|
||||||
is counted from its value; a spelling that nests it deeper — the block directive's `marks`, the
|
is counted from its value; a spelling that nests it deeper — the block directive's `marks`, the
|
||||||
carry — refuses in its own format, as its parser does. A list giving way after its walk owes
|
carry — refuses in its own format, as its parser does. A list giving way to the directive form
|
||||||
the directive form a level the walk did not count, and the walk reports its headroom — the
|
refuses at zero headroom rather than walking again; counting every list twice halved the list
|
||||||
least slack any depth guard below it has — for the fallback to refuse at zero rather than walk
|
limit, counting the directive form once doubled the parser's frames per level (the maintainer,
|
||||||
again; counting every list twice halved the list limit, counting the directive form once
|
2026-09-18).
|
||||||
doubled the parser's frames per level (the maintainer, 2026-09-18).
|
|
||||||
- Nothing spreads an unbounded array into a call — a node's siblings, a code block's held lines, a
|
- Nothing spreads an unbounded array into a call — a node's siblings, a code block's held lines, a
|
||||||
mark run's segments: the argument list caps near 125k and throws a `RangeError` where a `Result`
|
mark run's segments: the argument list caps near 125k and throws a `RangeError` where a `Result`
|
||||||
is owed. A walk pushes one at a time. A literal spread (`[...value]`) is not the same thing and
|
is owed. A walk pushes one at a time. A literal spread (`[...value]`) is not the same thing and
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ type BlockContainer = 'directive' | 'document' | 'list-item'
|
|||||||
type BlockSpelling = 'commonmark' | 'directive' | 'list'
|
type BlockSpelling = 'commonmark' | 'directive' | 'list'
|
||||||
type EmittedBlock = { headroom: number; spelling: BlockSpelling; text: string }
|
type EmittedBlock = { headroom: number; spelling: BlockSpelling; text: string }
|
||||||
type KeptSpelling = { block: EmittedBlock | undefined; depth: number }
|
type KeptSpelling = { block: EmittedBlock | undefined; depth: number }
|
||||||
type PlacedBlock = EmittedBlock & { node: AdfNode }
|
type PlacedBlock = Omit<EmittedBlock, 'headroom'> & { node: AdfNode }
|
||||||
export type SpellingMemo = Map<AdfNode, KeptSpelling>
|
export type SpellingMemo = Map<AdfNode, KeptSpelling>
|
||||||
type Walk = { blocks: readonly PlacedBlock[]; headroom: number }
|
type Walk = { blocks: readonly PlacedBlock[]; headroom: number }
|
||||||
type WalkedItem = { node: AdfNode; walk: Walk }
|
type WalkedItem = { node: AdfNode; walk: Walk }
|
||||||
@@ -246,6 +246,7 @@ function tryList(node: AdfNode, path: ConvertErrorPath, depth: number, memo: Spe
|
|||||||
for (const [offset, item] of walked.entries()) {
|
for (const [offset, item] of walked.entries()) {
|
||||||
const line = tryListItemLines(item.walk.blocks, ordered ? `${start + offset}. ` : '- ')
|
const line = tryListItemLines(item.walk.blocks, ordered ? `${start + offset}. ` : '- ')
|
||||||
if (line === undefined) {
|
if (line === undefined) {
|
||||||
|
// The directive form spends a level the walk did not count.
|
||||||
if (headroom < 1) return tooDeep(path)
|
if (headroom < 1) return tooDeep(path)
|
||||||
return emitDirectiveBlock(node, ordered ? blockNodes.orderedList : blockNodes.bulletList, path, depth, () => success({ blocks: directiveItems(walked), headroom: headroom - 1 }))
|
return emitDirectiveBlock(node, ordered ? blockNodes.orderedList : blockNodes.bulletList, path, depth, () => success({ blocks: directiveItems(walked), headroom: headroom - 1 }))
|
||||||
}
|
}
|
||||||
@@ -254,9 +255,8 @@ function tryList(node: AdfNode, path: ConvertErrorPath, depth: number, memo: Spe
|
|||||||
return success({ headroom, spelling: 'list', text: lines.join('\n') })
|
return success({ headroom, spelling: 'list', text: lines.join('\n') })
|
||||||
}
|
}
|
||||||
|
|
||||||
// The directive form sinks each item's blocks a level below where the walk read them.
|
|
||||||
function directiveItems(items: readonly WalkedItem[]): PlacedBlock[] {
|
function directiveItems(items: readonly WalkedItem[]): PlacedBlock[] {
|
||||||
return items.map((item) => ({ ...directivePair(item.node, listItemOpener, joinBlocks(item.walk.blocks, 'directive'), item.walk.headroom - 1), node: item.node }))
|
return items.map((item) => ({ ...directivePair(item.node, listItemOpener, joinBlocks(item.walk.blocks, 'directive')), node: item.node }))
|
||||||
}
|
}
|
||||||
|
|
||||||
function listStart(node: AdfNode, items: number): number | undefined {
|
function listStart(node: AdfNode, items: number): number | undefined {
|
||||||
|
|||||||
@@ -1066,6 +1066,11 @@ The done `todo.md` items in full, as they were written. `todo.md` keeps a one-li
|
|||||||
pass's set read-only and returns the whole. `containerStack` is the one writer of the stack,
|
pass's set read-only and returns the whole. `containerStack` is the one writer of the stack,
|
||||||
`edges` and the open directives' depths by name, all read-only elsewhere; deriving `edges` from the
|
`edges` and the open directives' depths by name, all read-only elsewhere; deriving `edges` from the
|
||||||
stack instead makes every line walk the open directives, quadratic in their nesting.
|
stack instead makes every line walk the open directives, quadratic in their nesting.
|
||||||
|
- [x] **27 — The dead `headroom` write goes (`0.2.0`).** `directiveItems`
|
||||||
|
(`emit/adf-to-markdown.ts:258`) writes `item.walk.headroom - 1` onto each `PlacedBlock`, and
|
||||||
|
nothing on that path reads a block's `headroom`: `joinBlocks` and `separationBetween` read
|
||||||
|
`text` and `spelling`, and `emitDirectiveBlock` takes the level from the `Walk`. Of the two
|
||||||
|
subtractions three readers flagged as double-counting, this is the one that is dead.
|
||||||
|
|
||||||
## 5 — Ship `0.1.0`
|
## 5 — Ship `0.1.0`
|
||||||
|
|
||||||
|
|||||||
@@ -59,11 +59,7 @@ chunk clearing a §11 seam.
|
|||||||
- [x] **24 — The conformance gates have a directory (`0.2.0`).**
|
- [x] **24 — The conformance gates have a directory (`0.2.0`).**
|
||||||
- [x] **25 — AGENTS.md §8 and §11 are findable (`0.2.0`).**
|
- [x] **25 — AGENTS.md §8 and §11 are findable (`0.2.0`).**
|
||||||
- [x] **26 — The two mutable structures say what they guarantee (`0.2.0`).**
|
- [x] **26 — The two mutable structures say what they guarantee (`0.2.0`).**
|
||||||
- [ ] **27 — The dead `headroom` write goes (`0.2.0`).** `directiveItems`
|
- [x] **27 — The dead `headroom` write goes (`0.2.0`).**
|
||||||
(`emit/adf-to-markdown.ts:258`) writes `item.walk.headroom - 1` onto each `PlacedBlock`, and
|
|
||||||
nothing on that path reads a block's `headroom`: `joinBlocks` and `separationBetween` read
|
|
||||||
`text` and `spelling`, and `emitDirectiveBlock` takes the level from the `Walk`. Of the two
|
|
||||||
subtractions three readers flagged as double-counting, this is the one that is dead.
|
|
||||||
- [x] **0 — Scaffold.**
|
- [x] **0 — Scaffold.**
|
||||||
- [x] **1a — The directive grammar.**
|
- [x] **1a — The directive grammar.**
|
||||||
- [x] **1b — Block node syntaxes.**
|
- [x] **1b — Block node syntaxes.**
|
||||||
|
|||||||
Reference in New Issue
Block a user