36a - review: README links the decision log, premises that can lapse, citations fixed
This commit was merged in pull request #134.
This commit is contained in:
@@ -172,16 +172,16 @@ functions, and a branch floor that only ever moves upward. It sits below 100 bec
|
||||
compared against `undefined` — have a half no valid document reaches.
|
||||
|
||||
The size ratchet is the other such number, `.oxlintrc.json`'s single rule over the files
|
||||
`tsconfig.build.json` builds — `oxlint`, since TypeScript 7 is a native compiler publishing no
|
||||
in-process parser, only the `unstable/` AST surface an out-of-process handshake reaches: a
|
||||
per-function line ceiling, set at that set's worst and moving only downward. It covers the built
|
||||
files alone, since one ceiling over the tests too would have to be their worst, loosening the guard
|
||||
over the shipped code. It guards against drift and never drives a refactor, so no cyclomatic rule
|
||||
and no second lint rule join it: neither measure picked out what nine readers found hard (the
|
||||
comprehension panel, 2026-09-20). Three switches guard a silent green: `IIFEs: true`, since oxlint
|
||||
exempts an IIFE otherwise; an explicit `-c`, so a config gone missing fails the leg instead of
|
||||
falling back to oxlint's own defaults; and `--deny-warnings`, since a rule from a category this
|
||||
config never names arrives as a warning it exits 0 on.
|
||||
`tsconfig.build.json` builds, measured by `oxlint` since TypeScript 7 is a native compiler
|
||||
publishing no in-process parser, only the `unstable/` AST surface an out-of-process handshake
|
||||
reaches. It is a per-function line ceiling, set at that set's worst and moving only downward. It
|
||||
covers the built files alone, since one ceiling over the tests too would have to be their worst,
|
||||
loosening the guard over the shipped code. It guards against drift and never drives a refactor, so
|
||||
no cyclomatic rule and no second lint rule join it: neither measure picked out what nine readers
|
||||
found hard (the comprehension panel, 2026-09-20). Three switches guard a silent green: `IIFEs:
|
||||
true`, since oxlint exempts an IIFE otherwise; an explicit `-c`, so a config gone missing fails the
|
||||
leg instead of falling back to oxlint's own defaults; and `--deny-warnings`, since a rule from a
|
||||
category this config never names arrives as a warning it exits 0 on.
|
||||
|
||||
The corpus, all checked in: hand-built fixtures per node and combination; real ADF Atlassian's
|
||||
editor wrote; the CommonMark spec suite against `markdownToAdf` and `markdownToHtml`.
|
||||
@@ -372,8 +372,9 @@ The verdict lands in the item it settles (the maintainer, 2026-09-25).
|
||||
### Rules the loop has settled (the maintainer, 2026-09-18)
|
||||
|
||||
- A finding inside the chunk's item is fixed in the chunk. Outside it, a new `todo.md` item, always
|
||||
in a release, weighed against every item on that release by the personas and Goals 1 and 2 — an
|
||||
item it outweighs moves later. A weighing no rule decides is asked as a gap.
|
||||
in a release, weighed against every item on that release by the personas and `docs/decisions.md`
|
||||
§Plain markdown is a flavour of the grammar through §Names stay text — an item it outweighs moves
|
||||
later. A weighing no rule decides is asked as a gap.
|
||||
- A stated number — 500 levels, the branch floor — is kept; a chunk that cannot keep it asks,
|
||||
naming the number it can reach. A number the code needs and no rule states is a gap.
|
||||
- An earliest release with no items left and nothing shipped toward it is planned as the chunk:
|
||||
|
||||
@@ -5,7 +5,8 @@ an HTML dialect.
|
||||
|
||||
**Status: published — the markdown round-trip (`adfToMarkdown`, `markdownToAdf`); HTML at
|
||||
`0.2.0`.**
|
||||
Plan: `todo.md`. Decisions: `AGENTS.md`. Changes:
|
||||
Plan: `todo.md`. Decisions:
|
||||
[`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md). Changes:
|
||||
[`CHANGELOG.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/CHANGELOG.md). The lossless flavour's grammar:
|
||||
[`spec/flavour.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/spec/flavour.md).
|
||||
Upgrading from `0.1.0`: [convert your markdown first](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/MIGRATION.md).
|
||||
@@ -143,7 +144,7 @@ saving what this pair read replaces mentions, attachments and macros with text.
|
||||
## The errors
|
||||
|
||||
An ADF node type this version does not know is not an error: it is carried opaquely and restores
|
||||
unchanged (`docs/decisions.md §Unknown nodes ride the carry`).
|
||||
unchanged ([`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#unknown-nodes-ride-the-carry)).
|
||||
|
||||
`ConvertError` is `{ code, message, path, position? }`. `code` is the exported `ConvertErrorCode`,
|
||||
stable across minors and safe to `switch` on exhaustively with no `default`; `message` is free text
|
||||
@@ -195,7 +196,7 @@ emit refuses:
|
||||
## The guarantees
|
||||
|
||||
- `markdownToAdf(adfToMarkdown(doc))` equals `doc` — unknown node types included, carried opaquely
|
||||
(`docs/decisions.md §Unknown nodes ride the carry`).
|
||||
([`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#unknown-nodes-ride-the-carry)).
|
||||
- Plain CommonMark is valid input to `markdownToAdf` apart from the raw HTML `unmappable-html`
|
||||
names, with three carve-outs — literal text matching directive, pipe-table or strikethrough
|
||||
syntax is claimed (escapable — `spec/flavour.md`) — and one gap: a CommonMark image fits only as
|
||||
@@ -234,4 +235,5 @@ emit refuses:
|
||||
ESM only, no runtime dependencies, public npmjs. Built JavaScript with `.d.ts` beside it.
|
||||
Pure ECMAScript at an ES2022 baseline, reaching for no host API; the test suite runs under Node,
|
||||
Deno and Bun, and a headless Firefox converts the corpus through the built entrypoint.
|
||||
Contract: `docs/decisions.md`.
|
||||
Contract: [`docs/decisions.md`](https://gitea.larvit.se/larvit/adf-codec/src/branch/main/docs/decisions.md#any-es2022-engine), §Any
|
||||
ES2022 engine to §Public on npm.
|
||||
|
||||
+8
-7
@@ -40,7 +40,7 @@ array the absent key — the only domain markdown can restore.
|
||||
## Unknown nodes ride the carry
|
||||
|
||||
2026-08-23, extended to misplaced known nodes 2026-08-26, the maintainer. Goal 1. Valid while ADF
|
||||
gains node types faster than this library spells them.
|
||||
holds nodes, or node positions, this library does not spell.
|
||||
|
||||
An unknown ADF node is carried opaquely — raw JSON rides a dedicated syntax in both formats and
|
||||
restores to a deep-equal node. The round-trip holds for documents newer than the library. So does
|
||||
@@ -76,7 +76,7 @@ opener nests by itself and leaf versus container falls out of the node's content
|
||||
|
||||
## CommonMark is a subset
|
||||
|
||||
2026-08-23, the maintainer. Goal 3. Valid while the carve-outs stay the flavour's only claims.
|
||||
2026-08-23, the maintainer. Goal 3. Valid while prose rarely writes the shapes the carve-outs claim.
|
||||
|
||||
Plain CommonMark is a subset, with carve-outs (`spec/flavour.md`): literal text shaped like a
|
||||
directive, a pipe table or a `~~` pair is claimed — plus one image gap.
|
||||
@@ -117,7 +117,8 @@ for what HTML cannot express, text always escaped. No stylesheet ships.
|
||||
|
||||
## No runtime dependencies
|
||||
|
||||
2026-08-23, the maintainer. Goal 7. Valid while Goal 7 names no runtime dependencies.
|
||||
2026-08-23, the maintainer. Goal 7. Valid while ~20 lines of own code, or a vendored table, do each
|
||||
job a dependency would.
|
||||
|
||||
`dependencies` is empty. A runtime dependency enters only through an entry here stating why ~20
|
||||
lines of own code cannot do the job, who maintains it, and what auditing it costs. So the CommonMark
|
||||
@@ -125,8 +126,8 @@ and HTML parsers are written in this repo.
|
||||
|
||||
## Standards ship as data
|
||||
|
||||
2026-08-30, the CommonMark suite 2026-09-05 and ADF's schemas 2026-09-13, the maintainer. Goals 1
|
||||
and 7. Valid while each table's upstream package is CommonJS-only or heavy.
|
||||
2026-08-30, the CommonMark suite 2026-09-05 and ADF's schemas 2026-09-13, the maintainer. Goals 1,
|
||||
3 and 7. Valid while each table is fixed data a dependency would only wrap.
|
||||
|
||||
A table a standard fixes is data rather than a dependency: HTML5's 2125 semicolon-terminated
|
||||
character references ship packed in their own module, so entity decoding is complete without one.
|
||||
@@ -163,7 +164,7 @@ never the higher one those repo-only tools want.
|
||||
|
||||
## ESM only
|
||||
|
||||
2026-08-23, the maintainer. Goal 7. Valid while every supported engine loads ES modules.
|
||||
2026-08-23, the maintainer. Goal 7. Valid while the audience's toolchains all import ES modules.
|
||||
|
||||
No CommonJS build, no dual-package hazard.
|
||||
|
||||
@@ -177,7 +178,7 @@ an npm consumer.
|
||||
|
||||
## Public on npm
|
||||
|
||||
2026-08-23, the maintainer. Goal 7 and the Audience. Valid while the audience installs from public
|
||||
2026-08-23, the maintainer. The Audience. Valid while the audience installs from public
|
||||
npm.
|
||||
|
||||
Published to public npmjs as `@larvit/adf-codec`. Public source: the Gitea repo goes public,
|
||||
|
||||
+11
-11
@@ -156,13 +156,13 @@ naming no open container or a node other than the innermost open one, a leaf giv
|
||||
unparseable or duplicate-keyed attrs, invalid JSON in an opaque carry. Never a silent literal-text
|
||||
fallback — a typo that reparses as prose is the silent loss the round-trip refuses.
|
||||
|
||||
## The opaque carry (`docs/decisions.md` §Unknown nodes ride the carry)
|
||||
## The opaque carry
|
||||
|
||||
A node no section spells where it stands — an unknown type, or a known one whose spelling belongs to
|
||||
the other position — rides as its raw JSON and restores to a deep-equal node. A carry may hold a
|
||||
node the emitter spells natively: it restores unreinterpreted, and the next emit spells it
|
||||
canonically (`docs/decisions.md` §The round-trip is the product). Block and inline positions
|
||||
canonicalize differently, each fitting where it sits:
|
||||
A node no section spells where it stands (`docs/decisions.md` §Unknown nodes ride the carry) — an
|
||||
unknown type, or a known one whose spelling belongs to the other position — rides as its raw JSON
|
||||
and restores to a deep-equal node. A carry may hold a node the emitter spells natively: it restores
|
||||
unreinterpreted, and the next emit spells it canonically (`docs/decisions.md` §The round-trip is the
|
||||
product). Block and inline positions canonicalize differently, each fitting where it sits:
|
||||
|
||||
- **Block position**: a fenced code block with info string `carry`, body = the node's JSON —
|
||||
two-space indent, object keys sorted.
|
||||
@@ -490,11 +490,11 @@ the directive form, open to no literal reading, is a named error.
|
||||
|
||||
A spelling adds its mark to every inline node it wraps, and nesting is the marks array in order,
|
||||
outermost first: `_!adf:underline[x]_` gives marks `[em, underline]`, `!adf:underline[_x_]` the
|
||||
reverse.
|
||||
`adfToMarkdown` nests in the order the array holds rather than sorting it — §2's equality
|
||||
restores the array, not a set — and opens each spelling once over the longest run of adjacent
|
||||
inline nodes carrying an identical mark, attributes included, at that depth. A run breaks at every
|
||||
node the emitter carries, so no emitted carry sits inside a mark spelling.
|
||||
reverse. `adfToMarkdown` nests in the order the array holds rather than sorting it —
|
||||
`docs/decisions.md` §Equality is editor-normal restores the array, not a set — and opens each
|
||||
spelling once over the longest run of adjacent inline nodes carrying an identical mark, attributes
|
||||
included, at that depth. A run breaks at every node the emitter carries, so no emitted carry sits
|
||||
inside a mark spelling.
|
||||
|
||||
An inline node whose marks no nesting spells — a mark type not listed here, an attrs key its
|
||||
spelling does not list, a value that is not the spelling's type, an attribute the spelling needs
|
||||
|
||||
Reference in New Issue
Block a user