10c - adfToPlainMarkdown and plainMarkdownToAdf exported, whitespace-only leaves trimmed at a line end
CI / gate (push) Successful in 41s
CI / publish (push) Has been skipped

This commit is contained in:
2026-09-26 13:20:16 +02:00
parent 2f03e20549
commit 613dc0edbb
11 changed files with 100 additions and 12 deletions
+39
View File
@@ -86,6 +86,9 @@ adfToMarkdown(doc: AdfDocument): Result<string>
markdownToAdf(markdown: string): Result<AdfDocument, ParseError>
isAdfDocument(v: unknown): v is AdfDocument
adfToPlainMarkdown(doc: AdfDocument): Result<string>
plainMarkdownToAdf(markdown: string): Result<AdfDocument, ParseError>
adfToHtml(doc: AdfDocument): Result<string> // 0.2.0
htmlToAdf(html: string): Result<AdfDocument, ParseError> // 0.2.0
markdownToHtml(markdown: string): Result<string> // 0.2.0, via ADF
@@ -94,6 +97,42 @@ htmlToMarkdown(html: string): Result<string> // 0.2.0, via ADF
`Result<T>` is `{ ok: true; value: T } | { ok: false; error: ConvertError }` — nothing throws.
## Plain markdown
`adfToPlainMarkdown` writes markdown other tools render — GitHub, GitLab, Obsidian and the like —
keeping the content and dropping the rest: attributes, colours, layout, identity. It refuses only
`not-an-adf-document`, `unsupported-document-version` and `unsupported-nesting-depth`, and writes
no directive. `plainMarkdownToAdf` reads through `markdownToAdf`, refusing what it refuses, and
lifts the conventions below back into nodes, reading other tools' spellings too. Markdown
`adfToPlainMarkdown` wrote reads back and writes again byte for byte; the document it came from
does not come back.
| ADF | Written | Read back |
| --- | --- | --- |
| `panel` | a GitHub alert, `> [!WARNING]`: info `NOTE`, note `IMPORTANT`, tip and success `TIP`, warning `WARNING`, error `CAUTION`, custom `NOTE` | GitHub's five words, and Obsidian's: hint tip; success, check, done success; attention warning; danger, failure, fail, missing, bug, error error; any other word info — in any case |
| `expand`, `nestedExpand` | Obsidian's folded callout, `> [!NOTE]- Title` | `-` or `+` after any word; an expand inside an expand is a `nestedExpand` |
| `taskList` | `- [x] Done`, `- [ ] Todo` | a bullet list whose every item is so marked, `[X]` too |
| `backgroundColor` | `==text==` | `==text==` bounded outside by whitespace, punctuation or a line edge, in the editor's default highlight |
| `table` | a pipe table: the first row its header, a cell's blocks on one line, a span kept under its header by empty cells | — |
| `decisionList` | a bullet list | — |
| `mention`, `status`, `emoji`, `date` | their text: `@` kept, a mention with none `@` and its id, an emoji its `shortName` without, a date `2026-09-13` in UTC | — |
| `inlineCard`, `blockCard`, `embedCard` | a link to the card's URL | — |
| external `media` | `![alt](url)` in a block, `[alt](url)` inline | — |
| stored `media`, `mediaInline`, `extension`, `inlineExtension` | their `alt` or `text` | — |
| `layoutSection`, `bodiedExtension`, `bodiedSyncBlock`, `multiBodiedExtension`, `extensionFrame`, `caption`, a node this version does not know | its blocks or its text | — |
| `placeholder` | nothing | — |
- Content the document only references leaves an italic note naming it where it stood:
`_(image not included)_`, `_(jira-issues-table not included)_`, `_(synced block not included)_`,
`_(link card not included)_`, `_(extension not included)_`.
- `code`, `em`, `link`, `strike` and `strong` stay; every other mark drops, keeping its text, and
so does a mark CommonMark cannot spell where it stands.
- A newline in text is a hard break, edge whitespace is trimmed, carriage returns and null
characters are removed, and an empty paragraph drops.
- An ordered list numbered past `999999999`, or adjacent ordered lists whose numbering does not
continue, is one bullet list keeping its numbers as text.
- A node read back carries no `localId`.
## The errors
An ADF node type this version does not know is not an error: it is carried opaquely and restores