3
0
mirror of https://github.com/larvit/adf-codec.git synced 2026-11-13 04:08:29 +01:00

Answer architecture round 2: a list definitions end joins a set of ended lists, which a named endList fills and openedList reads

This commit is contained in:
2026-10-10 11:17:59 +02:00
committed by Lillem4n
parent 7d00b11b2c
commit fcc6640f6e
3 changed files with 47 additions and 7 deletions
+31
View File
@@ -384,3 +384,34 @@ Inherited architect, decided by:
- Shape, Locality: `src/markdown/parse/inline-content.ts:121` `readToken`: one pure tokenizer and one switch that applies tokens
- Shape: `src/markdown/directive-syntax.ts:14` `ClaimedPrefix`: the directive read needs proof of its prefix, and the misnamed `opensConstruct` is gone
- Locality: `src/markdown/emit/line-escaping.ts:112` `escapeClaims`: the escaper steps one character at a time while the reader steps by token, which only the `==` comment explains
## 2026-10-10T09:16:56Z, PR #30 at 6182ba6, against c11aa91
Ruling: worse
Fell: Locality. Under the floor of 7.0: Locality 5.63, so the same ruling counts as worse.
| Seat | Navigation | Locality | Shape | Self-sufficiency | Overall |
|---|---|---|---|---|---|
| Mid A | same | worse | same | same | same |
| Inherited architect | better | worse | same | same | same |
| Seat | Navigation | Locality | Shape | Self-sufficiency | Overall |
|---|---|---|---|---|---|
| Junior A | 7 | 5.5 | 6.5 | 5.5 | 6 |
| Mid A | 7 | 5.5 | 6.5 | 5.5 | 6 |
| Maintainability senior | 7 | 6 | 6.5 | 6 | 6 |
| Inherited architect | 6.5 | 5.5 | 6 | 6 | 6 |
| Mean | 6.88 | 5.63 | 6.38 | 5.75 | 6.00 |
Mid A, decided by:
- Locality: `src/markdown/parse/blocks.ts:79` `Walk.endedByDefinitions`: written in `closeLeaf` at `:469` and read in `openedList` at `:257`, never cleared, correct only by identity with `blocks.at(-1)`; `closeLeaf` takes on recording where definitions ended a list
Inherited architect, decided by:
- Locality: `src/markdown/parse/blocks.ts:79` `Walk.endedByDefinitions`: a never-reset field `closeLeaf` writes and `openedList` reads, right only by identity and by `openContainers` closing before it opens; reordering those steps breaks the split silently
- Locality: `src/markdown/parse/blocks.ts:432` `readLineBlock`: a second path that can find a paragraph emptied by definitions records nothing, which a reader must prove harmless by hand
- Navigation: `src/markdown/parse/blocks.ts:252` `openedList`: the comment names the exception, so a reader of two lists merged or not lands on the right unit
- Navigation: `README.md:242` the CommonMark exceptions bullet: each exception is named rather than counted by position
- Navigation: `CHANGELOG.md:5` `## Unreleased`: breaking entries come first, other changes last
+15 -6
View File
@@ -75,8 +75,7 @@ type ContainerStack = {
type Walk = ParsedBlocks & {
claims: Claims
// The last block before a paragraph of link reference definitions alone, which ends a list as any block does.
endedByDefinitions: Block | undefined
endedLists: Set<ListBlock>
leaf: OpenLeaf | undefined
leafOpeners: Map<Block[], Map<string, LeafOpener>>
position: SourcePosition
@@ -92,7 +91,7 @@ export function parseBlocks(markdown: string, claims: Claims): ParsedBlocks {
blocks: [],
claims,
definitions: new Map(),
endedByDefinitions: undefined,
endedLists: new Set(),
leaf: undefined,
leafOpeners: new Map(),
position: { line: 1, offset: 0 },
@@ -249,16 +248,26 @@ function openContainer(walk: Walk, start: ContainerStart): void {
walk.stack.push({ blocks, indentation: start.indentation, kind: 'item', list })
}
// An item opening after its list's last item closed, as an empty item a blank line ends does, continues that list, unless definitions ended it.
// An item opening after its list's last item closed, as an empty item a blank line ends does, continues that list.
function openedList(walk: Walk, start: Extract<ContainerStart, { kind: 'item' }>): ListBlock {
if (!start.fresh) return start.list
const blocks = currentBlocks(walk)
const previous = blocks.at(-1)
if ((previous?.kind === 'bulletList' || previous?.kind === 'orderedList') && previous !== walk.endedByDefinitions && continuesList(previous, start.list)) return previous
if (isList(previous) && !walk.endedLists.has(previous) && continuesList(previous, start.list)) return previous
blocks.push(start.list)
return start.list
}
// A paragraph of link reference definitions alone leaves no block, yet ends the list before it as any block does.
function endList(walk: Walk): void {
const previous = currentBlocks(walk).at(-1)
if (isList(previous)) walk.endedLists.add(previous)
}
function isList(block: Block | undefined): block is ListBlock {
return block?.kind === 'bulletList' || block?.kind === 'orderedList'
}
function closeContainers(walk: Walk, depth: number): void {
closeLeaf(walk)
for (const container of walk.stack.drop(depth)) {
@@ -466,7 +475,7 @@ function closeLeaf(walk: Walk): void {
if (leaf === undefined) return
if (leaf.kind === 'paragraph') {
const paragraph = takeParagraph(walk)
if (paragraph === undefined) walk.endedByDefinitions = currentBlocks(walk).at(-1)
if (paragraph === undefined) endList(walk)
else currentBlocks(walk).push(bareTableFault(paragraph, walk.claims) ?? paragraph)
return
}
+1 -1
View File
@@ -355,7 +355,7 @@ quadratic in a run of blanks inside one leaf: a paragraph of `a`, 80 000 spaces,
Technical principle "One owner per value": the `Walk` record passes through twelve functions that
mutate it and return `void`; `walk.leaf` alone is written in seven places, and `openedList` reads
the `endedByDefinitions` that `closeLeaf` leaves. `ContainerStack` in the
the `endedLists` that `closeLeaf` fills. `ContainerStack` in the
same file shows the shape to follow. `inline-content.ts`'s `Scan` has the same shape: about fifteen
functions write `pending`, `pieces`, `deactivatedBefore` and `openingSpellableLink` and return
`void`, and `parseInlineContent` reads a flag `scanInline` leaves on it. The same shape recurs in