diff --git a/MIGRATION.md b/MIGRATION.md index 975d1e3..66e2c03 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -71,7 +71,7 @@ markdown it named on parse refuses with the code the table gives. | a link whose `href` or `title` no CommonMark escape spells, on emit | `unspellable-link` | spells `!adf:link[text]{attrs}` | | a carriage return in text, on emit | `unspellable-character` | spells ` ` | | a null character in text, on emit | `unspellable-character` | spells `!adf:text{text="\u0000"}` | -| a carriage return or null character in a code block or code span, on emit | `unspellable-character` | rides the carry | +| a carriage return or null character in a code block, or a null character in a code span, on emit | `unspellable-character` | rides the carry | | a paragraph line opening with a code span of three or more backticks, on emit | `unspellable-line-start` | spells the code span | | a block directive whose CommonMark spelling holds one of the above, on parse | `unspellable-character`, `unspellable-line-start` | `unsupported-node-shape`; write the CommonMark spelling | | an `emoji`, `mention` or `status` whose `text` holds a line ending or a null character, on emit | `unspellable-whitespace`, `unspellable-character` | rides the inline carry | diff --git a/README.md b/README.md index 271e3c6..59cb408 100644 --- a/README.md +++ b/README.md @@ -196,7 +196,7 @@ emit refuses: | Code | Fires when | What you can do | | --- | --- | --- | | `unsupported-nesting-depth` | blocks, marks, an attribute's JSON or a carried node's JSON nest past 500 levels | keep the ADF and pass the document over, or show it read-only; flatten the input where you are the one who wrote it | -| `unsupported-node-shape` | parsing: markdown spells a node with an attribute, value, argument or body its type does not take, or without one it needs, writes as a directive a node or mark the lossless flavour spells as CommonMark, or puts a reserved directive out of place: `!adf:textBreak{}` or `!adf:listBreak` parting nothing, `!adf:doc` anywhere but as the whole document. Emitting: a node "Not every document converts back" below names | fix what the message names; `spec/flavour.md` lists every type's attributes and body | +| `unsupported-node-shape` | parsing: markdown spells a node with an attribute, value, argument or body its type does not take, or without one it needs, writes as a directive a node or mark the lossless flavour spells as CommonMark, or puts a reserved directive out of place: `!adf:textBreak{}` or `!adf:listBreak` parting nothing, `!adf:doc` anywhere but as the whole document. Emitting: a node listed under "Not every document converts back" below | fix what the message names; `spec/flavour.md` lists every type's attributes and body | ## The guarantees diff --git a/todo.md b/todo.md index e6ca6d9..4b5e86e 100644 --- a/todo.md +++ b/todo.md @@ -6,7 +6,7 @@ `Bar = 9` -`Next ID = 69` +`Next ID = 70` | Goal | W | |---|---| @@ -51,6 +51,7 @@ | 33 | 0.3.0 | | **Emit a line in time linear in its mark runs, in `adfToMarkdown` and `adfToPlainMarkdown`.** | 4 | 5 | 6 | 9 | 8 | 10.7 | | 46 | 0.3.0 | | **Publish the bundle size in the README, failing the release pipeline when it drifts.** | 2 | 4 | 5 | 5 | 7, 9 | 10.3 | | 9 | 0.3.0 | | **Ship an online sandbox: a web page with two textboxes converting between ADF and markdown on the library's browser build.** | 2 | 6 | 6 | 8 | 9 | 10.3 | +| 69 | 0.3.0 | question | **Decide whether a text node's `content` is content `adfToPlainMarkdown` keeps, and keep or document it.** | 2 | 2 | 3 | 5 | 6 | 7.9 | | 56 | 0.3.0 | principle | **Give each piece of `blocks.ts`'s block-walk state and `inline-content.ts`'s `Scan` one owner that returns what it changes.** | 4 | 5 | 2 | 4 | 1 | 6.8 | | 57 | 0.3.0 | principle | **Make each `ci.sh` leg build what it reads, so one leg run alone tests the current tree.** | 2 | 3 | 1 | 3 | 7 | 1.2 | | 58 | 0.3.0 | principle | **Port `ci.sh`, `publish.sh` and `docker-runner.sh` to standalone Python scripts.** | 4 | 6 | 1 | 2 | 7 | -2.2 | @@ -249,7 +250,9 @@ measured one. `adfToMarkdown` spends 23 s on one paragraph of 2000 × `un` plus `**-r**`: each run its flanking cannot spell re-emits the whole line before riding the carry, quadratic in the runs, and the plain -reduction's `spellableLine` drops one mark per re-emit the same way. Make both linear. +reduction's `spellableLine` drops one mark per re-emit the same way. An inline node whose +attributes no spelling writes re-emits the line the same way before riding the carry. Make all +three linear. ### 46. Publish the bundle size in the README, failing the release pipeline when it drifts. @@ -261,6 +264,16 @@ or report the unminified gzip). The figure lands in README §The package beside dependencies" claim. Measured today, unminified: tarball 60.4 kB, unpacked 221.5 kB, JS gzipped 45.6 kB. +### 69. Decide whether a text node's `content` is content `adfToPlainMarkdown` keeps, and keep or document it. + +`nodeLeaves` (`plain/inline-reduction.ts`) keeps only a text node's `text`, so +`{ text: 'a', content: [{ text: 'kept', type: 'text' }] }` writes `a`, though `toEditorNormal` +keeps that content (`plain/editor-normal.ts`) and an unknown node's children keep their text. +Atlassian's schema allows no `content` on a text node, so no Atlassian reader saw it; an +export/indexing tool fed a looser producer loses searchable text. Goal 6 reads two ways here: keep +the children's text as an unknown node's, or name the drop in the README's plain section. Found by +the product-owner review of item 55, 2026-10-04. + ### 56. Give each piece of `blocks.ts`'s block-walk state and `inline-content.ts`'s `Scan` one owner that returns what it changes. Technical principle "One owner per value": the `Walk` record passes through twelve functions that