Extend prose-minimum rule to all markdown files and apply it to the docs

This commit is contained in:
2026-08-23 23:20:46 +02:00
parent 359c9a0083
commit 61d6fca105
3 changed files with 122 additions and 173 deletions
+25 -38
View File
@@ -3,25 +3,21 @@
Lossless conversion between **Atlassian Document Format** (ADF), an extended markdown flavour, and
an HTML dialect.
**Status: specification only. No code is implemented yet.** `todo.md` holds the plan; `AGENTS.md`
holds the decisions already made.
**Status: specification only, no code yet.** Plan: `todo.md`. Decisions: `AGENTS.md`.
## What it is for
Atlassian Cloud REST APIs (Jira v3, Confluence) hand out rich text — issue descriptions, comments,
pages — as ADF, a JSON node tree, ProseMirror-shaped, and take it back the same way. There is no
Atlassian endpoint that converts it: `pf-editor-service/convert` was decommissioned and
[JRACLOUD-77436](https://jira.atlassian.com/browse/JRACLOUD-77436) is still an open request. The npm
ecosystem covers one direction each, drops what markdown cannot express, and none of it round-trips.
A consumer that shows a document and lets someone edit it needs both directions, and needs them
lossless — otherwise saving an edit silently destroys the panels, mentions and attachments that were
in someone else's document. That is what this library is.
Atlassian Cloud REST APIs hand out rich text — issue descriptions, comments, pages — as ADF, a
ProseMirror-shaped JSON tree, and take it back the same way. No Atlassian endpoint converts it
(`pf-editor-service/convert` is decommissioned,
[JRACLOUD-77436](https://jira.atlassian.com/browse/JRACLOUD-77436) open), and the npm ecosystem is
one-directional and lossy. A consumer that shows a document and lets someone edit it needs both
directions lossless — otherwise saving destroys the panels, mentions and attachments it could not
represent.
## The shape
Pure functions and their types. No I/O, no network, no configuration. ADF is the hub: the
markdown↔HTML directions compose through it.
Pure functions, no I/O, no configuration. ADF is the hub: markdown↔HTML compose through it.
```ts
adfToMarkdown(doc: AdfDocument): Result<string>
@@ -37,36 +33,27 @@ isAdfDocument(v: unknown): v is AdfDocument
## The guarantees
- **`markdownToAdf(adfToMarkdown(doc))` equals `doc`**including node types the library has never
seen, which are carried opaquely (AGENTS.md §3).
- **`htmlToAdf(adfToHtml(doc))` equals `doc`** — fidelity HTML cannot express rides `data-*`
- `markdownToAdf(adfToMarkdown(doc))` equals `doc`unknown node types included, carried opaquely
(AGENTS.md §3).
- `htmlToAdf(adfToHtml(doc))` equals `doc` — fidelity HTML cannot express rides `data-*`
attributes.
- **Plain CommonMark is valid input** to `markdownToAdf`: any ordinary markdown a human types
converts per the CommonMark spec. Converting back yields the library's canonical spelling, which
then round-trips byte-identically.
- **Foreign HTML** (not emitted by this library) maps a documented element set; an unmappable
element is an error result, never a silent drop. The parser takes well-formed HTML, not
WHATWG tag-soup recovery.
- **The emitted formats are semver surface** (AGENTS.md §8): after 1.0, output an old version
emitted always parses under a newer one within the same major.
- Plain CommonMark is valid input to `markdownToAdf`; converting back yields the library's
canonical spelling, which round-trips byte-identically.
- Foreign HTML maps a documented element set; an unmappable element is an error, never a silent
drop. Well-formed HTML only — no tag-soup recovery.
- The emitted formats are semver surface (AGENTS.md §8).
## Who it is for
No actual consumer is named here or anywhere in this repo (AGENTS.md §7). The personas the design
serves:
Personas, never named consumers (AGENTS.md §7):
- **A viewer/editor app** — shows a document as markdown or HTML, lets a human edit, posts the
result back. Needs losslessness above all.
- **A bot posting content** — generates ordinary markdown (templates, LLM output) and converts it
to ADF. Needs the CommonMark input promise; never reads ADF back.
- **An export/indexing tool** — bulk-converts ADF to markdown or HTML for archives, search, static
sites. Read-only; needs readable output.
- **An LLM/agent pipeline** — feeds documents to a model as markdown, converts the model's edits
back. Needs the round-trip plus markdown that stays legible to a reader that half-knows the
flavour.
- **Viewer/editor app** — shows a document, lets a human edit, posts back. Losslessness above all.
- **Bot posting content** — converts generated markdown to ADF; needs the CommonMark promise.
- **Export/indexing tool** — bulk ADF→markdown/HTML; needs readable output.
- **LLM/agent pipeline** — documents to a model as markdown, edits back; needs the round-trip and
markdown legible to a reader that half-knows the flavour.
## The package
ESM only, **no runtime dependencies**, published to public npmjs. Two entrypoints — built
JavaScript for ordinary consumers, TypeScript source for consumers running Node's type stripping —
with exported types either way. `AGENTS.md` §56 have the contract.
ESM only, no runtime dependencies, public npmjs. Two entrypoints — built JavaScript, and
TypeScript source for Node's type stripping — with types either way. Contract: `AGENTS.md` §56.