35b - review: runs as a non-empty tuple, no item for a stray child reducing to nothing, 42 filed

This commit is contained in:
2026-09-29 12:13:11 +02:00
parent 6c8ed03d36
commit 6681bec391
3 changed files with 9 additions and 5 deletions
+4 -4
View File
@@ -38,7 +38,7 @@ type LineAttempt = { fallback: NodeRange | 'opening-link'; line?: undefined } |
type LineFallbacks = { carried: Set<number>; flavour: Flavour; openingLinkAsDirective: boolean }
export type PlainLineFallback = { kind: 'claimed-line'; line: number; text: string } | { kind: 'opening-link' } | { kind: 'unspellable-run'; run: MarkRun; runs: MarkRun[] }
export type PlainLineFallback = { kind: 'claimed-line'; line: number; text: string } | { kind: 'opening-link' } | { kind: 'unspellable-run'; runs: [MarkRun, ...MarkRun[]] }
export function emitInlineLine(nodes: readonly AdfNode[], container: LineContainer, path: ConvertErrorPath, flavour: Flavour): Result<string> {
const emitted = emitLine(nodes, container, path, flavour)
@@ -120,7 +120,7 @@ function lineSegments(nodes: readonly AdfNode[], container: LineContainer, path:
function attemptLine(segments: readonly InlineSegment[], container: LineContainer, path: ConvertErrorPath, flavour: Flavour): Result<LineAttempt> {
const verdict = lineVerdict(segments, container, flavour)
if (verdict.kind === 'opening-link') return success({ fallback: 'opening-link' })
if (verdict.kind === 'unspellable-run') return success({ fallback: verdict.run })
if (verdict.kind === 'unspellable-run') return success({ fallback: verdict.runs[0] })
if (verdict.kind === 'claimed-line') return failure('unspellable-line-start', `block parsing would claim the emitted line ${JSON.stringify(verdict.text)}`, path)
return success({ line: verdict.text })
}
@@ -129,8 +129,8 @@ function attemptLine(segments: readonly InlineSegment[], container: LineContaine
function lineVerdict(segments: readonly InlineSegment[], container: LineContainer, flavour: Flavour): PlainLineFallback | { kind: 'line'; text: string } {
const assembled = assembleInlineLine(segments, container, flavour)
if (assembled.openingLinkAsDirective) return { kind: 'opening-link' }
const [run] = assembled.unspellableRuns
if (run !== undefined) return { kind: 'unspellable-run', run, runs: assembled.unspellableRuns }
const [run, ...others] = assembled.unspellableRuns
if (run !== undefined) return { kind: 'unspellable-run', runs: [run, ...others] }
const lines = assembled.line.split('\n')
const claimed = container === 'paragraph' ? lines.findIndex((single, index) => claimsLine(single, index === 0 ? 'first' : 'later')) : -1
return claimed === -1 ? { kind: 'line', text: assembled.line } : { kind: 'claimed-line', line: claimed, text: lines[claimed] ?? '' }
+1 -1
View File
@@ -285,7 +285,7 @@ function reduceTaskList(node: AdfNode, reduction: Reduction): Result<AdfNode[]>
const reduced = isTask(child) ? reduceTask(child, at) : reduceStanding(child, at)
if (!reduced.ok) return reduced
if (!regular) {
const standsAlone = !isTask(child) && child.type !== 'taskList'
const standsAlone = !isTask(child) && child.type !== 'taskList' && reduced.value.length > 0
for (const block of standsAlone ? [{ content: reduced.value, type: 'listItem' }] : reduced.value) tasks.push(block)
continue
}
+4
View File
@@ -34,6 +34,10 @@
paragraph of 2000 × `un` plus `**-r**`: each run its flanking cannot spell re-emits the whole line
before riding the carry, quadratic in the runs (Goal 9), and the plain reduction's
`spellableLine` drops one mark per re-emit the same way. Make both linear.
- **42 — Trim a text leaf's trailing blanks in linear time.** `plain-inline.ts`'s `leafEdges` finds
the trail with an unanchored `/[ \t]*$/`, quadratic in a run of blanks inside one leaf: a
paragraph of `a`, 80 000 spaces, `b` takes 6.5 s in `adfToPlainMarkdown` (Goal 9). Scan backward,
as the expand title's trim does.
- **34 — Read emphasis flanking by the whole character beside an astral symbol.** Check whether
`line-escaping.ts`'s `charAt` and the parser's flanking read one UTF-16 unit beside an astral
symbol — a lone surrogate is neither punctuation nor symbol, where CommonMark reads `😀` as