19 - adf/ is what both formats read, and a construct rises on its second consumer
This commit was merged in pull request #117.
This commit is contained in:
@@ -349,19 +349,26 @@ someone spells it or pins it.
|
|||||||
- No casts: `as`, `as unknown as`, non-null `!`. A boundary owes a type guard validating the
|
- No casts: `as`, `as unknown as`, non-null `!`. A boundary owes a type guard validating the
|
||||||
fields it claims (`isAdfDocument`); past it everything is typed. Make invalid states
|
fields it claims (`isAdfDocument`); past it everything is typed. Make invalid states
|
||||||
unrepresentable.
|
unrepresentable.
|
||||||
- `src/adf/` holds ADF's own knowledge and imports no format. Each format directory (`markdown/`,
|
- `src/adf/` holds ADF's own knowledge, imports no format, and is where a construct both formats
|
||||||
`html/`) parts into `emit/` (ADF→format) and `parse/` (format→ADF), the rest of it holding what
|
read lives: the question is answered in ADF's vocabulary — a node type, an attribute kind, a
|
||||||
both directions read. A construct's reader lives there beside the regex the emitter escapes
|
content model — and no delimiter, element name or escape reaches it. A helper that cannot answer
|
||||||
against, so the two cannot drift; a reader with no emit counterpart goes in `parse/`, unless it is
|
that way is two constructs, the ADF question there and the spelling in each format, the seam
|
||||||
part of a construct that side already holds — a grammar stays in one file rather than splitting
|
`markAttributes` and `markSpellings` already draw; one that cannot be split is a gap to ask (§15).
|
||||||
across the seam. A rule both
|
`markdown/` and `html/` are peers: neither imports the other, and no third directory sits between
|
||||||
directions must answer alike — whether a list marker interrupts a paragraph — is one function
|
them. A primitive knowing neither ADF nor a format — `result.ts`, `json-value.ts`, `nesting.ts`,
|
||||||
there too, never a copy per direction, however conservative the copy would be. Where the rule is
|
`canonical-json.ts` — stays at `src/` root. A construct rises to `adf/` on its second consumer,
|
||||||
the emitter's own choice, input consults it rather than restating it: the parser asks
|
not in anticipation of one (the maintainer, 2026-09-21).
|
||||||
`commonMarkSpelling` which form the emitter picks, and `openingLinkTakesDirective` whether the
|
- Each format directory (`markdown/`, `html/`) parts into `emit/` (ADF→format) and `parse/`
|
||||||
line a paragraph's opening link starts forces the directive link, so no fixture the emitter
|
(format→ADF), the rest of it holding what both directions read. A construct's reader lives there
|
||||||
writes can be refused, and a spelling the emitter refuses gives its own error rather than a
|
beside the regex the emitter escapes against, so the two cannot drift; a reader with no emit
|
||||||
second name for it.
|
counterpart goes in `parse/`, unless it is part of a construct that side already holds — a grammar
|
||||||
|
stays in one file rather than splitting across the seam. A rule both directions must answer
|
||||||
|
alike — whether a list marker interrupts a paragraph — is one function there too, never a copy
|
||||||
|
per direction, however conservative the copy would be. Where the rule is the emitter's own
|
||||||
|
choice, input consults it rather than restating it: the parser asks `commonMarkSpelling` which
|
||||||
|
form the emitter picks, and `openingLinkTakesDirective` whether the line a paragraph's opening
|
||||||
|
link starts forces the directive link, so no fixture the emitter writes can be refused, and a
|
||||||
|
spelling the emitter refuses gives its own error rather than a second name for it.
|
||||||
- The attribute vocabulary is ADF's: `adf/` walks it and narrows each value to its kind, and a
|
- The attribute vocabulary is ADF's: `adf/` walks it and narrows each value to its kind, and a
|
||||||
format spells the narrowed value. A spelling that re-checks the type is the check's second copy.
|
format spells the narrowed value. A spelling that re-checks the type is the check's second copy.
|
||||||
Reading a spelling back is the format's own: the reader sits beside the spelling it inverts, so
|
Reading a spelling back is the format's own: the reader sits beside the spelling it inverts, so
|
||||||
|
|||||||
@@ -907,6 +907,21 @@ The done `todo.md` items in full, as they were written. `todo.md` keeps a one-li
|
|||||||
(the stability-reviewer, 2026-09-19). The one list accounting was not
|
(the stability-reviewer, 2026-09-19). The one list accounting was not
|
||||||
taken: 4b settled that accounting the day this was filed, and reopening it is an ask rather
|
taken: 4b settled that accounting the day this was filed, and reopening it is an ask rather
|
||||||
than a chunk.
|
than a chunk.
|
||||||
|
- [x] **19 — A home for what both formats read (`0.2.0`).** Settle where a construct both formats
|
||||||
|
need lives, and say so in AGENTS.md §11. Today `adf/` may hold no format knowledge and each
|
||||||
|
format directory holds its own shared layer, so there is no third place; the first ADF-shaped
|
||||||
|
but format-touching helper either breaks the layering or becomes a second spelling of one
|
||||||
|
rule, which is the loss §2 exists to stop. Both architects ranked this first and the only
|
||||||
|
item cheaper before the feature than after.
|
||||||
|
**Settled** (the maintainer, 2026-09-21): `adf/` is that place, and the test is the vocabulary
|
||||||
|
the answer is in — a node type, an attribute kind, a content model, never a delimiter, an
|
||||||
|
element name or an escape. A helper that cannot answer that way is the ADF question there and
|
||||||
|
a spelling per format, the seam `markAttributes` and `markSpellings` already draw; one that
|
||||||
|
cannot be split is a gap to ask. `markdown/` and `html/` are peers with no third directory
|
||||||
|
between them, and `src/` root keeps the primitives knowing neither ADF nor a format. No code
|
||||||
|
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
|
||||||
|
when `html/` reads them (7).
|
||||||
- [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
|
||||||
|
|||||||
@@ -42,12 +42,6 @@ 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.
|
||||||
|
|
||||||
- [ ] **19 — A home for what both formats read (`0.2.0`).** Settle where a construct both formats
|
|
||||||
need lives, and say so in AGENTS.md §11. Today `adf/` may hold no format knowledge and each
|
|
||||||
format directory holds its own shared layer, so there is no third place; the first ADF-shaped
|
|
||||||
but format-touching helper either breaks the layering or becomes a second spelling of one
|
|
||||||
rule, which is the loss §2 exists to stop. Both architects ranked this first and the only
|
|
||||||
item cheaper before the feature than after.
|
|
||||||
- [ ] **20 — The give-way channel is unmistakable (`0.2.0`).** `emitBlockquote`, `emitCodeBlock`,
|
- [ ] **20 — The give-way channel is unmistakable (`0.2.0`).** `emitBlockquote`, `emitCodeBlock`,
|
||||||
`emitHeading`, `emitList`, `emitParagraph` and `emitRule` return
|
`emitHeading`, `emitList`, `emitParagraph` and `emitRule` return
|
||||||
`Result<EmittedBlock> | undefined`, where `undefined` gives way to the directive form and an
|
`Result<EmittedBlock> | undefined`, where `undefined` gives way to the directive form and an
|
||||||
@@ -285,6 +279,7 @@ ask is settled against, 19's included; 30 sits beside 25, the other chunk reread
|
|||||||
- [x] **16 — The link wrapping a link (`0.2.0`).**
|
- [x] **16 — The link wrapping a link (`0.2.0`).**
|
||||||
- [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] **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