diff --git a/README.md b/README.md index 8d56d6c..dafa6fa 100644 --- a/README.md +++ b/README.md @@ -174,8 +174,7 @@ and may change in any release. A parse always names a position, so the three mar alone; one handler typed on `ConvertError` takes both, which is what the calls between markdown and HTML hand back. `path` is the node's place from the document root, alternating `'content'` and an index, so `path.map((step) => '/' + step).join('')` is a JSON Pointer at the node — the empty path -being the document itself. A parse's path points into the document the call returns once the -refusal is fixed. +being the document itself. A call reports the first refusal in document order and stops, so a document with several surfaces them one per call. Every refusal is deterministic — there is no I/O anywhere — so a retry returns diff --git a/src/markdown/parse/markdown-to-adf.ts b/src/markdown/parse/markdown-to-adf.ts index 55d5ee3..b66b796 100644 --- a/src/markdown/parse/markdown-to-adf.ts +++ b/src/markdown/parse/markdown-to-adf.ts @@ -225,12 +225,12 @@ function bulletBlocks(items: readonly Block[][], reading: Reading, path: Convert type Refusal = { block: ReadBlock; next: ReadBlock | undefined; path: ConvertErrorPath; reading: Reading; task: AdfNode; tasks: readonly AdfNode[] } -// splitTaskList moves a task's children, so a refusal in `block` names where its node would stand: in place of the node, the split places a stand-in of its type. +// splitTaskList moves a task's children, so the path names where the refused block's node will stand: the split runs with a stand-in of that node's type. function splitPath(refused: ConvertErrorPath, { block, next, path, reading, task, tasks }: Refusal): ConvertErrorPath { const [, offset, ...within] = refused.slice(path.length + 2) const listIndex = path.at(-1) if (typeof offset !== 'number' || typeof listIndex !== 'number') return refused - // A nested task list reads as a task list, then a block the split moves out, so a node past its first stands outside the task. + // A nested task list reads as a task list, then the blocks its own split moved out; a bulletList stands in for each of those, since the split moves it out too. const before = Array.from({ length: offset }, (_, at): AdfNode => ({ type: at === 0 ? 'taskList' : 'bulletList' })) const node: AdfNode & { content: [AdfNode] } = { content: [{ text: '', type: 'text' }], type: offset === 0 ? childType(block, reading) : 'bulletList' } const after = next === undefined ? [] : [{ type: childType(next, reading) }] @@ -241,7 +241,7 @@ function splitPath(refused: ConvertErrorPath, { block, next, path, reading, task return [...path.slice(0, -1), listIndex + blockIndex, ...steps, ...within] } -// A task keeps only paragraphs and task lists, so another block's kind stands in for its node's type. +// The split tells only paragraphs and task lists from other blocks, so any other block's kind serves as its type; a paragraph may read as another node. function childType(block: ReadBlock, reading: Reading): string { if (block.kind === 'bulletList') return taskItems(block.items) === undefined ? 'bulletList' : 'taskList' if (block.kind !== 'paragraph') return block.kind === 'taskParagraph' ? 'paragraph' : block.kind diff --git a/src/markdown/parse/portable-markdown-to-adf.test.ts b/src/markdown/parse/portable-markdown-to-adf.test.ts index 6738b6b..8242efc 100644 --- a/src/markdown/parse/portable-markdown-to-adf.test.ts +++ b/src/markdown/parse/portable-markdown-to-adf.test.ts @@ -180,7 +180,7 @@ test('stands a block a task item cannot hold, and what follows it in the item, a ]) }) -test('names the place a refused block would stand once the task list moves it', () => { +test('names where a refused block stands after the task list splits', () => { const refused = (markdown: string): string => { const parsed = portableMarkdownToAdf(markdown) return parsed.ok ? 'read' : parsed.error.path.map((step) => '/' + step).join('') diff --git a/src/markdown/portable/task-list.ts b/src/markdown/portable/task-list.ts index dc61b5f..e54682d 100644 --- a/src/markdown/portable/task-list.ts +++ b/src/markdown/portable/task-list.ts @@ -19,7 +19,7 @@ export function splitTaskList(list: AdfNode): AdfNode[] { return blocks } -// Where `node`, a child of one of the list's tasks, stands among the blocks splitTaskList returns; a lone paragraph, holding its inline node, stands as its taskItem. +// Where `node`, a child of one of the list's tasks, stands among the blocks splitTaskList returns; a task's lone paragraph becomes a taskItem, found by the paragraph's first inline node. export function splitPlace(list: AdfNode, node: AdfNode & { content: [AdfNode] }): [number, ...ConvertErrorPath] | undefined { const [inline] = node.content const places = splitTaskList(list).flatMap((block, index): [number, ...ConvertErrorPath][] => { diff --git a/todo.md b/todo.md index 37647cb..edcb916 100644 --- a/todo.md +++ b/todo.md @@ -122,7 +122,7 @@ commonmark.js avoids the backtick cost by caching backtick runs by length. ### 92. Lower the reading cost of the files a chunk reads most before its first commit. The last five chunks' median is 168135 new input tokens before their first commit, the five before -them 97329. Read most over the last five, opens and searches: `docs/decisions.md` 28, `README.md` +them 97329. Files read most over the last five chunks, counting opens and searches: `docs/decisions.md` 28, `README.md` 23, `todo.md` 23, `CHANGELOG.md` 19, `src/markdown/parse/blocks.ts` 15, `src/markdown/portable/adf-to-portable-markdown.ts` 12, `spec/flavour.md` 10, `src/markdown/emit/line-escaping.ts` 9, `src/markdown/parse/markdown-to-adf.test.ts` 8,