mirror of
https://github.com/larvit/adf-codec.git
synced 2026-11-12 11:48:29 +01:00
Answer principles round 1: 0 🔴, 2 🟡; drop the unreachable guards and pass the list index in
This commit is contained in:
@@ -17,10 +17,10 @@ import { leadingMarker, readAlertMarker, readTaskMarker } from '../portable/conv
|
||||
import { mintTaskIds } from '../portable/task-ids.ts'
|
||||
import { parseBlocks } from './blocks.ts'
|
||||
import { parseInlineContent } from './inline-content.ts'
|
||||
import { pathTo, splitTaskList } from '../portable/task-list.ts'
|
||||
import { readBlockDirectiveNode } from '../directive/node-reading.ts'
|
||||
import { spellStringAttribute, unsupportedNodeShape } from '../directive/syntax.ts'
|
||||
import { spellsEmpty } from '../directive/empty-keys.ts'
|
||||
import { pathTo, splitTaskList } from '../portable/task-list.ts'
|
||||
import { withinEngineLimits } from '../length-bound.ts'
|
||||
|
||||
type Paragraph = Extract<Block, { kind: 'paragraph' }>
|
||||
@@ -86,7 +86,7 @@ function readBlocks(blocks: readonly ReadBlock[], reading: Reading, path: Conver
|
||||
return positioned(faulted(fault, nodePath), block.position)
|
||||
}
|
||||
if (block.kind === 'bulletList' && flavourClaims[reading.flavour].taskMarkers) {
|
||||
const listed = positioned(bulletBlocks(block.items, reading, nodePath, depth), block.position)
|
||||
const listed = positioned(bulletBlocks(block.items, reading, nodePath, depth, content.length), block.position)
|
||||
if (!listed.ok) return listed
|
||||
for (const node of listed.value) content.push(node)
|
||||
continue
|
||||
@@ -209,7 +209,7 @@ function taskItems(items: readonly Block[][]) {
|
||||
return led
|
||||
}
|
||||
|
||||
function bulletBlocks(items: readonly Block[][], reading: Reading, path: ConvertErrorPath, depth: number): Result<AdfNode[]> {
|
||||
function bulletBlocks(items: readonly Block[][], reading: Reading, path: ConvertErrorPath, depth: number, listIndex: number): Result<AdfNode[]> {
|
||||
const tasks = taskBlocks(items, reading, path, depth)
|
||||
if (tasks === undefined) {
|
||||
const list = listNode({ type: 'bulletList' }, items, reading, path, depth)
|
||||
@@ -218,14 +218,14 @@ function bulletBlocks(items: readonly Block[][], reading: Reading, path: Convert
|
||||
if (!tasks.ok) return tasks
|
||||
const { nodes: blocks, refusal } = tasks.value
|
||||
if (refusal === undefined) return success(blocks)
|
||||
const listIndex = path.at(-1)
|
||||
const place = pathTo(blocks, refusal.marker)
|
||||
if (place === undefined || typeof listIndex !== 'number') return { error: refusal.error, ok: false }
|
||||
// Failures are values, so a marker the split ever copied out of sight leaves the error unplaced rather than asserting; task-list.test.ts pins that the split keeps it.
|
||||
if (place === undefined) return { error: refusal.error, ok: false }
|
||||
const [blockIndex, ...steps] = place
|
||||
return { error: { ...refusal.error, path: [...path.slice(0, -1), listIndex + blockIndex, ...steps.slice(0, -2), ...refusal.within] }, ok: false }
|
||||
}
|
||||
|
||||
// A block a task list refused. A placeholder holding `marker` stands where the block's node would, so the split that builds the list places the refusal too, and `within` is the error's path below that node.
|
||||
// A block a task list refused. A placeholder holding `marker` as its one child stands where the block's node would, so the split that builds the list places the refusal too, and `within` is the error's path below that node.
|
||||
type Refusal = { error: ConvertError; marker: AdfNode; within: ConvertErrorPath }
|
||||
|
||||
// Nodes read from task blocks and the first refusal among them; a list is read up to the task holding its refusal.
|
||||
@@ -255,12 +255,12 @@ function taskBlocks(items: readonly Block[][], reading: Reading, path: ConvertEr
|
||||
// The nodes a block of a task reads to. A refused one is a placeholder, typed as the split tells paragraphs and task lists from other blocks, so a paragraph that failed to read stays a paragraph.
|
||||
function readTaskBlock(block: ReadBlock, reading: Reading, path: ConvertErrorPath, depth: number): TaskNodes {
|
||||
const nodePath = [...path, 'content', 0]
|
||||
const nested = block.kind === 'bulletList' && depth <= largestNesting ? taskBlocks(block.items, reading, nodePath, depth) : undefined
|
||||
const nested = block.kind === 'bulletList' ? taskBlocks(block.items, reading, nodePath, depth) : undefined
|
||||
if (nested?.ok) return nested.value
|
||||
const read = positioned(nested ?? readBlocks([block], reading, path, depth), block.position)
|
||||
if (read.ok) return { nodes: read.value, refusal: undefined }
|
||||
const marker: AdfNode = { text: '', type: 'text' }
|
||||
const type = block.kind === 'taskParagraph' ? 'paragraph' : block.kind === 'bulletList' && taskItems(block.items) !== undefined ? 'taskList' : block.kind
|
||||
const type = block.kind === 'taskParagraph' ? 'paragraph' : nested === undefined ? block.kind : 'taskList'
|
||||
return { nodes: [{ content: [marker], type }], refusal: { error: read.error, marker, within: read.error.path.slice(nodePath.length) } }
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,15 @@ import test from 'node:test'
|
||||
import type { AdfNode } from '../../adf/document.ts'
|
||||
import { pathTo, splitTaskList } from './task-list.ts'
|
||||
|
||||
test('names the steps from a block to a node deep in it, and none for a node it does not hold', () => {
|
||||
test('names the steps from a block to a node deep in it', () => {
|
||||
const target: AdfNode = { text: 'x', type: 'text' }
|
||||
const blocks: AdfNode[] = [{ type: 'rule' }, { content: [{ content: [{ type: 'paragraph' }, { content: [target], type: 'paragraph' }], type: 'blockquote' }], type: 'panel' }]
|
||||
assert.deepEqual(pathTo(blocks, target), [1, 'content', 0, 'content', 1, 'content', 0])
|
||||
assert.deepEqual(pathTo(blocks, blocks[0] ?? target), [0])
|
||||
assert.equal(pathTo(blocks, { text: 'x', type: 'text' }), undefined)
|
||||
})
|
||||
|
||||
test('names no steps to a node the blocks do not hold', () => {
|
||||
assert.equal(pathTo([{ content: [{ text: 'x', type: 'text' }], type: 'paragraph' }], { text: 'x', type: 'text' }), undefined)
|
||||
})
|
||||
|
||||
test('keeps the inline nodes of a lone paragraph in the taskItem it becomes, so pathTo still finds them', () => {
|
||||
|
||||
Reference in New Issue
Block a user