20 - the give-way emitters take the try prefix, and tryRule the narrower type
This commit is contained in:
@@ -308,10 +308,10 @@ someone spells it or pins it.
|
|||||||
the whole point of.
|
the whole point of.
|
||||||
- A readable spelling tried ahead of a general one — a CommonMark block, the image, the pipe
|
- A readable spelling tried ahead of a general one — a CommonMark block, the image, the pipe
|
||||||
table, a pipe cell — gives way with `undefined` for every shape it cannot spell, and fails only
|
table, a pipe cell — gives way with `undefined` for every shape it cannot spell, and fails only
|
||||||
where the general form fails on the same node. Refusing there refuses a document the general
|
where the general form fails on the same node; it takes the `try` prefix, so both arms read at
|
||||||
form spells, so a refusal the general form does not share belongs in the general form or
|
the call site (20). Refusing there refuses a document the general form spells, so a refusal the
|
||||||
nowhere — save the nested list a tight spelling would swallow, whose refusal the
|
general form does not share belongs in the general form or nowhere — save the nested list a
|
||||||
tight-versus-blank answer owns (`todo.md` 2b). A readable spelling that must spell its subtree
|
tight spelling would swallow, whose refusal the tight-versus-blank answer owns (`todo.md` 2b). A readable spelling that must spell its subtree
|
||||||
before it can give way — the list, whose thematic-break first line and blank lines exist only
|
before it can give way — the list, whose thematic-break first line and blank lines exist only
|
||||||
spelled — hands that one walk to the general form instead: giving way after the walk walks
|
spelled — hands that one walk to the general form instead: giving way after the walk walks
|
||||||
again at every level, doubling per level (4b).
|
again at every level, doubling per level (4b).
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type Walk = { blocks: readonly PlacedBlock[]; headroom: number }
|
|||||||
type WalkedItem = { node: AdfNode; walk: Walk }
|
type WalkedItem = { node: AdfNode; walk: Walk }
|
||||||
|
|
||||||
const largestListMarker = 999999999
|
const largestListMarker = 999999999
|
||||||
// Bare because emitList admits no item carrying attributes, marks or text.
|
// Bare because tryList admits no item carrying attributes, marks or text.
|
||||||
const listItemOpener = spellDirectiveOpener('listItem', undefined, '')
|
const listItemOpener = spellDirectiveOpener('listItem', undefined, '')
|
||||||
|
|
||||||
export function adfToMarkdown(document: AdfDocument): Result<string> {
|
export function adfToMarkdown(document: AdfDocument): Result<string> {
|
||||||
@@ -115,13 +115,13 @@ function readableBlock(node: AdfNode, path: ConvertErrorPath, depth: number, mem
|
|||||||
}
|
}
|
||||||
|
|
||||||
function spellReadableBlock(node: AdfNode, path: ConvertErrorPath, depth: number, memo: SpellingMemo | undefined): Result<EmittedBlock> | undefined {
|
function spellReadableBlock(node: AdfNode, path: ConvertErrorPath, depth: number, memo: SpellingMemo | undefined): Result<EmittedBlock> | undefined {
|
||||||
if (node.type === 'blockquote') return emitBlockquote(node, path, depth, memo)
|
if (node.type === 'blockquote') return tryBlockquote(node, path, depth, memo)
|
||||||
if (node.type === 'bulletList' || node.type === 'orderedList') return emitList(node, path, depth, memo)
|
if (node.type === 'bulletList' || node.type === 'orderedList') return tryList(node, path, depth, memo)
|
||||||
if (node.type === 'codeBlock') return emitCodeBlock(node, path)
|
if (node.type === 'codeBlock') return tryCodeBlock(node, path)
|
||||||
if (node.type === 'heading') return emitHeading(node, path)
|
if (node.type === 'heading') return tryHeading(node, path)
|
||||||
if (node.type === 'mediaSingle') return readableText(tryImage(node, path))
|
if (node.type === 'mediaSingle') return readableText(tryImage(node, path))
|
||||||
if (node.type === 'paragraph') return emitParagraph(node, path)
|
if (node.type === 'paragraph') return tryParagraph(node, path)
|
||||||
if (node.type === 'rule') return emitRule(node)
|
if (node.type === 'rule') return readableText(tryRule(node))
|
||||||
if (node.type === 'table') return readableText(tryPipeTable(node, path))
|
if (node.type === 'table') return readableText(tryPipeTable(node, path))
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ function emitDirectiveBody(node: AdfNode, directive: BlockDirective, opener: str
|
|||||||
return success(directivePair(node, opener, joinBlocks(walk.value.blocks, 'directive'), walk.value.headroom))
|
return success(directivePair(node, opener, joinBlocks(walk.value.blocks, 'directive'), walk.value.headroom))
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitBlockquote(node: AdfNode, path: ConvertErrorPath, depth: number, memo: SpellingMemo | undefined): Result<EmittedBlock> | undefined {
|
function tryBlockquote(node: AdfNode, path: ConvertErrorPath, depth: number, memo: SpellingMemo | undefined): Result<EmittedBlock> | undefined {
|
||||||
if (!carriesOnly(node, [])) return undefined
|
if (!carriesOnly(node, [])) return undefined
|
||||||
const inner = walkBlocks(nodeContent(node), path, depth + 1, memo)
|
const inner = walkBlocks(nodeContent(node), path, depth + 1, memo)
|
||||||
if (!inner.ok) return inner
|
if (!inner.ok) return inner
|
||||||
@@ -175,7 +175,7 @@ function emitBlockquote(node: AdfNode, path: ConvertErrorPath, depth: number, me
|
|||||||
return success(commonMarkText(text, inner.value.headroom))
|
return success(commonMarkText(text, inner.value.headroom))
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitCodeBlock(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlock> | undefined {
|
function tryCodeBlock(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlock> | undefined {
|
||||||
if (!carriesOnly(node, ['language'])) return undefined
|
if (!carriesOnly(node, ['language'])) return undefined
|
||||||
const slot = languageSlot(nodeAttrs(node)['language'])
|
const slot = languageSlot(nodeAttrs(node)['language'])
|
||||||
if (slot.kind === 'attribute') return undefined
|
if (slot.kind === 'attribute') return undefined
|
||||||
@@ -214,7 +214,7 @@ function codeBlockText(node: AdfNode, path: ConvertErrorPath): Result<string> {
|
|||||||
return success(text)
|
return success(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitHeading(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlock> | undefined {
|
function tryHeading(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlock> | undefined {
|
||||||
if (!carriesOnly(node, ['level'])) return undefined
|
if (!carriesOnly(node, ['level'])) return undefined
|
||||||
const level = nodeAttrs(node)['level']
|
const level = nodeAttrs(node)['level']
|
||||||
if (typeof level !== 'number' || !Number.isInteger(level) || level < 1 || level > 6) return undefined
|
if (typeof level !== 'number' || !Number.isInteger(level) || level < 1 || level > 6) return undefined
|
||||||
@@ -226,7 +226,7 @@ function emitHeading(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlock
|
|||||||
return success(commonMarkText(`${hashes} ${line.value}`))
|
return success(commonMarkText(`${hashes} ${line.value}`))
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitList(node: AdfNode, path: ConvertErrorPath, depth: number, memo: SpellingMemo | undefined): Result<EmittedBlock> | undefined {
|
function tryList(node: AdfNode, path: ConvertErrorPath, depth: number, memo: SpellingMemo | undefined): Result<EmittedBlock> | undefined {
|
||||||
const ordered = node.type === 'orderedList'
|
const ordered = node.type === 'orderedList'
|
||||||
if (!carriesOnly(node, ordered ? ['order'] : [])) return undefined
|
if (!carriesOnly(node, ordered ? ['order'] : [])) return undefined
|
||||||
const items = nodeContent(node)
|
const items = nodeContent(node)
|
||||||
@@ -276,7 +276,7 @@ function listItemLines(blocks: readonly PlacedBlock[], marker: string): string |
|
|||||||
return lines.join('\n')
|
return lines.join('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitParagraph(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlock> | undefined {
|
function tryParagraph(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlock> | undefined {
|
||||||
const content = nodeContent(node)
|
const content = nodeContent(node)
|
||||||
if (content.length === 0 || !carriesOnly(node, [])) return undefined
|
if (content.length === 0 || !carriesOnly(node, [])) return undefined
|
||||||
const line = emitInlineLine(content, 'paragraph', path)
|
const line = emitInlineLine(content, 'paragraph', path)
|
||||||
@@ -284,7 +284,7 @@ function emitParagraph(node: AdfNode, path: ConvertErrorPath): Result<EmittedBlo
|
|||||||
return success(commonMarkText(line.value))
|
return success(commonMarkText(line.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
function emitRule(node: AdfNode): Result<EmittedBlock> | undefined {
|
function tryRule(node: AdfNode): string | undefined {
|
||||||
if (!carriesOnly(node, []) || nodeContent(node).length > 0) return undefined
|
if (!carriesOnly(node, []) || nodeContent(node).length > 0) return undefined
|
||||||
return success(commonMarkText('---'))
|
return '---'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -922,6 +922,19 @@ The done `todo.md` items in full, as they were written. `todo.md` keeps a one-li
|
|||||||
moved: a construct rises on its second consumer, so `linkHref` (`markdown/mark-spellings.ts`)
|
moved: a construct rises on its second consumer, so `linkHref` (`markdown/mark-spellings.ts`)
|
||||||
and the external-image read (`markdown/emit/image.ts`), both pure ADF attribute reads, move
|
and the external-image read (`markdown/emit/image.ts`), both pure ADF attribute reads, move
|
||||||
when `html/` reads them (7).
|
when `html/` reads them (7).
|
||||||
|
- [x] **20 — The give-way channel is unmistakable (`0.2.0`).** `emitBlockquote`, `emitCodeBlock`,
|
||||||
|
`emitHeading`, `emitList`, `emitParagraph` and `emitRule` return
|
||||||
|
`Result<EmittedBlock> | undefined`, where `undefined` gives way to the directive form and an
|
||||||
|
error refuses the document. Give the six the `try` prefix the repo already uses for
|
||||||
|
`tryImage`, `tryPipeTable` and `tryPipeCell`, or a return type that cannot hold both, so a
|
||||||
|
newcomer meeting an unspellable shape cannot reach for `failure` and silently narrow what
|
||||||
|
converts. Named as the first thing a new senior would break, and it lands on §1.
|
||||||
|
**Done** (2026-09-21): both answers, each where it fits. Five of the six reach a refusal the
|
||||||
|
directive form shares — a walk, `codeBlockText`, `emitInlineLine` — so moving it out is the
|
||||||
|
second walk 4b removed, and they take the prefix alone. `tryRule` refuses nothing, so it
|
||||||
|
takes the narrower type as well, `string | undefined` through `readableText`, which is what
|
||||||
|
`tryImage` and `tryPipeTable` already return. §11's readable-spelling rule carries the
|
||||||
|
prefix, so the next spelling is named by the rule rather than by the six beside it.
|
||||||
- [x] **28 — `emitLine`'s retry loop cannot spin (`0.2.0`).** `emit/inline-line.ts:67` is a
|
- [x] **28 — `emitLine`'s retry loop cannot spin (`0.2.0`).** `emit/inline-line.ts:67` is a
|
||||||
`for (;;)` that re-emits the line until every unspellable node has been carried, and its
|
`for (;;)` that re-emits the line until every unspellable node has been carried, and its
|
||||||
termination rests on a comment: each pass carries at least one more node, or flips
|
termination rests on a comment: each pass carries at least one more node, or flips
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ Start a session with: `Read AGENTS.md and todo.md, then do what todo.md's "Next
|
|||||||
## Milestones
|
## Milestones
|
||||||
|
|
||||||
Shipping order: 3h, 3i, 3j, 5a, 5b, 5c, 5d, 5 → `0.1.0` (shipped 2026-09-05); 3k, 11, 4, 12, 13, 4b,
|
Shipping order: 3h, 3i, 3j, 5a, 5b, 5c, 5d, 5 → `0.1.0` (shipped 2026-09-05); 3k, 11, 4, 12, 13, 4b,
|
||||||
4c, 14, 15, 16, 18, 4d, 28, 17, 29, 19, 20, 21, 22, 23, 24, 25, 30, 26, 27, 10, 6, 7, 5f, 5g →
|
4c, 14, 15, 16, 18, 4d, 28, 17, 29, 19, 20, 21, 22, 23, 24, 25, 30, 26, 27, 10, 6, 7, 31, 5f, 5g →
|
||||||
`0.2.0`;
|
`0.2.0`;
|
||||||
8, 9 → TBD; 5e last.
|
8, 9 → TBD; 5e last.
|
||||||
The numbering is the order the work was planned in, not the order it ships. Everything known and
|
The numbering is the order the work was planned in, not the order it ships. Everything known and
|
||||||
@@ -41,14 +41,18 @@ HTML doubles the importers and the file count they touch, and 25 to 27 because t
|
|||||||
panel says the next reader pays for.
|
panel says the next reader pays for.
|
||||||
29 and 30 come from 17's prose pass (2026-09-20). 29 reads first because every goal is what a later
|
29 and 30 come from 17's prose pass (2026-09-20). 29 reads first because every goal is what a later
|
||||||
ask is settled against, 19's included; 30 sits beside 25, the other chunk rereading AGENTS.md.
|
ask is settled against, 19's included; 30 sits beside 25, the other chunk rereading AGENTS.md.
|
||||||
|
31 comes from 20's gate runs (2026-09-21) and reads beside 5f, the other chunk putting a measured
|
||||||
|
number under the pipeline.
|
||||||
|
|
||||||
- [ ] **20 — The give-way channel is unmistakable (`0.2.0`).** `emitBlockquote`, `emitCodeBlock`,
|
- [ ] **31 — The branch figure the floor is read against is stable (`0.2.0`).** Three Node test
|
||||||
`emitHeading`, `emitList`, `emitParagraph` and `emitRule` return
|
legs over one unchanged tree reported `emit/inline-line.ts` at 95.83%, 96.23% and 96.23%,
|
||||||
`Result<EmittedBlock> | undefined`, where `undefined` gives way to the directive form and an
|
and the total at 98.80%, 98.84% and 98.84% (2026-09-21). `--experimental-test-coverage`
|
||||||
error refuses the document. Give the six the `try` prefix the repo already uses for
|
counts branches off V8's own coverage, which the runner's parallel files and V8's
|
||||||
`tryImage`, `tryPipeTable` and `tryPipeCell`, or a return type that cannot hold both, so a
|
optimization make run-dependent, so the number the floor is read against is not the code's
|
||||||
newcomer meeting an unspellable shape cannot reach for `failure` and silently narrow what
|
alone. The floor of 98 holds today on 0.8 points of slack and §10 says it only ever moves
|
||||||
converts. Named as the first thing a new senior would break, and it lands on §1.
|
upward, so the first raise to the measured figure reddens a run that changed nothing. Make
|
||||||
|
the measurement repeatable, or state the number the floor may be raised to and why it is not
|
||||||
|
the measured one.
|
||||||
- [ ] **21 — The ADF tables carry ADF's nouns (`0.2.0`).** `adf/block-directives.ts` and
|
- [ ] **21 — The ADF tables carry ADF's nouns (`0.2.0`).** `adf/block-directives.ts` and
|
||||||
`adf/inline-directives.ts` hold the ADF node tables — `paragraph`, `heading`, `blockquote`
|
`adf/inline-directives.ts` hold the ADF node tables — `paragraph`, `heading`, `blockquote`
|
||||||
and `rule` among them — under the markdown flavour's word, inside the directory §11 forbids
|
and `rule` among them — under the markdown flavour's word, inside the directory §11 forbids
|
||||||
@@ -280,6 +284,7 @@ ask is settled against, 19's included; 30 sits beside 25, the other chunk reread
|
|||||||
- [x] **17 — A machine-enforced size ratchet (`0.2.0`).**
|
- [x] **17 — A machine-enforced size ratchet (`0.2.0`).**
|
||||||
- [x] **18 — The subtree the directive spelling asks about (`0.2.0`).**
|
- [x] **18 — The subtree the directive spelling asks about (`0.2.0`).**
|
||||||
- [x] **19 — A home for what both formats read (`0.2.0`).**
|
- [x] **19 — A home for what both formats read (`0.2.0`).**
|
||||||
|
- [x] **20 — The give-way channel is unmistakable (`0.2.0`).**
|
||||||
- [x] **28 — `emitLine`'s retry loop cannot spin (`0.2.0`).**
|
- [x] **28 — `emitLine`'s retry loop cannot spin (`0.2.0`).**
|
||||||
- [x] **29 — The README reads raw HTML as refused for good (`0.2.0`).**
|
- [x] **29 — The README reads raw HTML as refused for good (`0.2.0`).**
|
||||||
- [x] **30 — AGENTS.md says each thing once (`0.2.0`).**
|
- [x] **30 — AGENTS.md says each thing once (`0.2.0`).**
|
||||||
|
|||||||
Reference in New Issue
Block a user