7.2 KiB
Todo
The plan, in order. Nothing is built. Design questions are settled in AGENTS.md; remaining spec
detail is settled at its own milestone.
Milestones
- 0 — Scaffold.
package.jsonper §6,tsconfig.json,.npmrc(save-exact=true), the Docker tooling,renovate.json(§9), and.gitea/workflows/ci.ymlgating branches:runs-on: docker-host, actions pinned to semver tags. - 1a — The directive grammar (
spec/flavour.md): inline/block/leaf directive forms, attributes, escaping, nesting, canonical form, the opaque-carry spelling, the raw-HTML input policy. - 1b — Block node syntaxes in
spec/flavour.md: panel, expand/nestedExpand, the media family, the pipe-vs-directive table rule and the directive table form, task and decision lists, layout, extensions, syncBlock. - 1c — Inline node syntaxes and marks in
spec/flavour.md: mention, emoji, status, date, inlineCard, mediaInline; underline, subsup, textColor, border; the spelling for text nodes whose whitespace CommonMark cannot hold (literal newlines, leading or trailing spaces) — escape-based, never literal, since pipe cells trim and pad. AtmediaInline, check real payloads for external-URL support — if it exists, revisit the media section's mid-text-image error and its "no slot" ground. - 1d — Corpus start (§10): checked-in fixtures per spec'd node, in
corpus/, one directory per contract kind (corpus/README.md). Blocked on the maintainer (§15), not to be guessed: Canonical form has no totality guard — aparagraph,heading,blockquoteorcodeBlockcarrying alocalId, or ablockquotecarrying marks, has no spelling that keeps it, and picking one (directive sections for the six CommonMark block nodes, or the opaque carry) is a permanent format decision (§8). Its three collision sites stay out of the corpus until then: anorderedListstarting at 1, acodeBlockwhose info string is empty, andmediawith an emptyalt— each a choice between the absent attribute and the empty value.- 1d1 — The CommonMark subset: blockquote, bulletList, codeBlock, heading, orderedList,
paragraph, rule, listItem, hardBreak, text, code spans, and the
code,em,link,strikeandstrongmarks — one mark per text node; nesting is 1d5's. - 1d2 — Block nodes: panel, expand/nestedExpand, the media family and the CommonMark
image shape, both table forms, task and decision lists, layout, extensions, syncBlock —
with the reserved
marksattribute and the fence lengths nesting forces. - 1d3 — Inline nodes and marks: date, emoji, inlineCard, mediaInline, mention, status;
border, subsup, textColor, underline; the content slot's
textattribute and the:text{text="…"}whitespace spelling. - 1d4 — Opaque carry (§3): an unknown node in both positions, the reserved
adfinfo string, and thecodeBlockwhose language isadf. - 1d5 — Carve-outs and combinations: the three carve-outs and their escapes, mark nesting order and the runs a carry breaks, attribute canonicalization, and documents combining nodes rather than isolating one.
- 1d6 — Input normalization: one-way markdown→ADF fixtures, not pairs — setext
headings, indented code, loose lists,
*/+bullets, entity references, soft wraps. - 1d7 — Error input: also one-way, a markdown input per named error, asserting only that conversion fails — malformed directives, the image gap, a claimed pipe-table line that does not parse, the content slot, raw HTML with no mapping. Which error each returns is pinned at milestone 3, where they are named.
- 1d1 — The CommonMark subset: blockquote, bulletList, codeBlock, heading, orderedList,
paragraph, rule, listItem, hardBreak, text, code spans, and the
- 2 —
adfToMarkdown. First real code — decide here where §10's coverage check lives, and gate that everycorpus/**/*.jsonre-serializes to itself under the library's own canonical serializer: one implementation, keys sorted, two spellings — two-space indent for the corpus files and the block carry's body, compact for the inline carry. - 3 —
markdownToAdf. The CommonMark parser is the largest single component. The raw-HTML element mapping is empty until milestone 6, so at0.1.0every raw-HTML construct in input is an error result. The CommonMark spec suite runs against it from here (§10), andcorpus/errors/gains the error each fixture must return (1d7). - 4 — Round-trip property tests over the corpus, both ways — the thing that proves 2 and
3. Generators emit editor-normal ADF (§2). Real sanitized ADF from live Atlassian APIs lands
here too (§10), in
corpus/real-payloads/: an ADF→markdown→ADF check with no expected markdown, the payloads supplied by the maintainer. - 5 — Release pipeline, ship
0.1.0. Publish-on-version-change (§9),NPM_TOKENsecret, the repo made public first (§6).0.1.0is the markdown round-trip: both markdown directions, the types,isAdfDocument. The build lands here: a build tsconfig emitting JS and.d.tstodist/(the dev config'sallowImportingTsExtensionsforcesnoEmit, so the build config needsrewriteRelativeImportExtensions), plusexports/filesinpackage.json. The maintainer's bump PR also removesprivate: true, the guard against any earlier publish. - 6 — The HTML dialect spec. Element-by-element mapping, the
data-*fidelity scheme, the opaque-carry form, and the documented foreign-element sethtmlToAdfaccepts. - 7 — HTML, ship
0.2.0.adfToHtml,htmlToAdf, the composedmarkdownToHtml/htmlToMarkdown. CommonMark spec suite runs againstmarkdownToHtmlfrom here (§10). - 8 — CLI. A later goal, shaped around the personas once the library exists.
The ADF inventory to cover
From Atlassian's structure
reference — not the
whole schema: real payloads also carry taskList/taskItem, decisionList/decisionItem,
layoutSection/layoutColumn, blockCard/embedCard, extension/bodiedExtension/inlineExtension
and placeholder, none documented there. The documented set is the floor: the floor gets designed
syntax, the rest rides the opaque carry (§3) until it does too.
| Top-level block | blockquote bodiedSyncBlock bulletList codeBlock expand heading mediaGroup mediaSingle multiBodiedExtension orderedList panel paragraph rule syncBlock table |
| Child block | blockTaskItem extensionFrame listItem media nestedExpand tableCell tableHeader tableRow |
| Inline | date emoji hardBreak inlineCard mediaInline mention status text |
| Marks | border code em link strike strong subsup textColor underline |
Plain markdown covers blockquote, bulletList, codeBlock, heading, orderedList,
paragraph, rule, listItem, hardBreak, text, and the code, em, link and strong
marks; strike is the flavour's ~~ carve-out. Everything else is what the flavour is for.