From 9192f97f99e6719ed7bb5d191fdcea9a3a32595e Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Wed, 28 Oct 2026 21:15:43 +0100 Subject: [PATCH] Answer round 1: the bar says every package runs in Node whatever it gets wrong, the HTML row names the marks it writes, the table drops a fork, md-adf's warnings show --- CHANGELOG.md | 2 +- README.md | 16 ++++++++-------- converter-comparison/compare.mjs | 10 ++++++---- converter-comparison/run.sh | 1 - 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18567a4..8194023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - The package's description and keywords say it needs no React, Atlaskit or runtime dependency and runs in Node, Forge, Deno, Bun and browsers, and the README opens with the call to take for each need. Its comparison table lists every npm package - converting ADF to or from markdown, and other ecosystems' libraries and Atlassian's own paths. + running in Node that converts ADF to or from markdown, and other ecosystems' libraries and Atlassian's own paths. - `adfToHtml` writes ADF as HTML: paragraphs, headings, lists, quotes, code blocks, rules, hard breaks, a centered, uncaptioned external image holding no attribute but its URL and alt, and `em`, `strong`, `code` and links as their elements. A paragraph, heading, quote, list, list item, code block or diff --git a/README.md b/README.md index 31cbf8e..cf1b974 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ shows, edits, exports or generates the rich text Atlassian products store as ADF | Markdown from a bot, a model or a person | ADF | `portableMarkdownToAdf` | reads CommonMark plus GFM's tables, task lists and alerts, `~~`, and Obsidian's callouts and `==`; `commonMarkToAdf` reads strict CommonMark alone | | ADF | markdown to edit, then ADF again | `adfToLosslessMarkdown`, then `losslessMarkdownToAdf` | gives back the document it started from, panels, mentions, statuses and node types this version does not know included | | ADF | markdown that GitHub, GitLab and Obsidian render | `adfToPortableMarkdown` | keeps the text, images by URL and link targets and drops the rest | -| ADF | HTML | `adfToHtml` | writes paragraphs, headings, lists, quotes, code blocks, links and marks as HTML elements, and every other node as an element holding its JSON; `htmlToAdf` reads that HTML back to the same document, and refuses any other HTML | +| ADF | HTML | `adfToHtml` | writes paragraphs, headings, lists, quotes, code blocks, rules, breaks, links, and code, emphasis and strong text as HTML elements, and every other node as an element holding its JSON; `htmlToAdf` reads that HTML back to the same document, and refuses any other HTML | Every call returns a result, never a throw. A refusal carries a code from a closed list, and every refusal but `engine-limit` repeats on the same input ([The guarantees](#the-guarantees)). @@ -245,8 +245,9 @@ place, and on CI failing a change that breaks a guarantee. ## Other ADF converters Serves [Goals](#goals) 3. The first table lists every npm package that runs in Node and converts -ADF to or from markdown, whatever its downloads; a package that fails ordinary nodes stays, with how -it fails. A wrapper or fork of a listed package is left out. On 2026-10-28, [`converter-comparison/`](https://github.com/larvit/adf-codec/tree/main/converter-comparison) +ADF to or from markdown, whatever its downloads and +whatever it gets wrong, which its row says. A wrapper or fork of a listed package is left out. The +searches are recorded in `run.sh`. On 2026-10-28, [`converter-comparison/`](https://github.com/larvit/adf-codec/tree/main/converter-comparison) ran each package's published code, at the version the table names, with its default options. A package writing markdown got a document holding marks, a link, a mention, a status, a panel and a list, and a document holding a node type it cannot know. A package reading markdown got markdown @@ -256,11 +257,10 @@ holding the same marks and link. | --- | --- | --- | --- | --- | --- | | `@larvit/adf-codec` | both ways | the same document | kept | markdown: lossless, portable; CommonMark in; HTML out; its own HTML in | 0 | | `@atlaskit/editor-markdown-transformer` 6.3.1 | markdown to ADF, through `@atlaskit/editor-json-transformer` 10.0.0; ADF to markdown throws "This is not implemented yet" | – | – | markdown | 5 | -| `@complexthings/md-to-adf` 1.0.0 | markdown to ADF; writes each list item as a list of its own | – | – | markdown | 1 | | `@faulander/md2adf` 1.0.0 | both ways | a different document: the status is gone, the mention's `id` becomes its text and the panel a quote | dropped with its text | markdown | 2 | | `@nthings.dev/adf4j-wasm` 1.0.2 | ADF to markdown | – | replaced by the text `[Unsupported: futureThing]` | GitHub Flavored Markdown, from WebAssembly | 0 | -| `@wrtnlabs/markdown-to-adf` 1.0.2 | markdown to a list of blocks, not a document; `***bold italic***` comes out as italic text holding asterisks | – | – | markdown | 2 | -| `adf-converter` 0.1.0 | ADF to markdown | – | its text kept, with a console message | markdown | 0 | +| `@wrtnlabs/markdown-to-adf` 1.0.2 | markdown to a list of blocks, not a document; `***bold italic***` comes out as italic text holding asterisks, and a paragraph holding a hard break stands between blocks | – | – | markdown | 2 | +| `adf-converter` 0.1.0 | ADF to markdown; writes a mention as `@@Ann` | – | its text kept, with a console message | markdown | 0 | | `adf-md` 0.2.0 | both ways | a different document: the status without its `localId`, the marks in the other order | dropped with its text | markdown with MDX tags for panels, mentions and statuses | 6 | | `adf-to-markdown` 1.0.1 | ADF to markdown | – | dropped with its text | markdown | 0 | | `adf-to-md` 1.2.1 | ADF to markdown | – | dropped with its text, as are mentions, statuses and panels | markdown | 1 | @@ -269,8 +269,8 @@ holding the same marks and link. | `github-markdown-adf` 1.3.0 | both ways | a different document: the mention comes back as text, the status as inline code, the marks in the other order | dropped with its text | markdown | 3 | | `markdown-to-adf` 0.2.20 | markdown to ADF; writes a quote as the node type `blockQuote`, which ADF spells `blockquote` | – | – | markdown | 3 | | `marklassian` 1.2.1 | markdown to ADF | – | – | markdown | 1 | -| `md-adf` 0.2.2 | both ways | a different document: the mention and the status come back as text, the marks in the other order, the panel as a quote | dropped with its text | markdown | 5 | -| `md-to-adf` 0.6.4 | markdown to ADF | – | – | markdown | 2 | +| `md-adf` 0.2.2 | both ways, with a warning for each fallback | a different document: the mention and the status come back as text, the marks in the other order, the panel as a quote | dropped with its text, with a warning | markdown | 5 | +| `md-to-adf` 0.6.4 | markdown to ADF; writes each list item as a list of its own | – | – | markdown | 2 | | `mdast-util-from-adf` 2.3.0 | ADF to an mdast tree, which `mdast-util-to-markdown` 2.2.1 writes as markdown; throws on a status | – | throws | markdown | 3 | The next table lists converters this comparison does not run: other ecosystems' libraries, diff --git a/converter-comparison/compare.mjs b/converter-comparison/compare.mjs index 4d255ad..802f77e 100644 --- a/converter-comparison/compare.mjs +++ b/converter-comparison/compare.mjs @@ -20,7 +20,6 @@ import * as mdAdf from "md-adf"; import mdToAdf from "md-to-adf"; import { toMarkdown as mdastToMarkdown } from "mdast-util-to-markdown"; import { readFileSync } from "node:fs"; -import translateGithubMarkdown from "@complexthings/md-to-adf"; const { defaultSchema } = createRequire(import.meta.url)("@atlaskit/adf-schema/schema-default"); @@ -55,6 +54,10 @@ const extended = new extendedParser.Parser(); const json = new atlaskitJson.JSONTransformer(); const atlaskit = new atlaskitMarkdown.MarkdownTransformer(defaultSchema); const adf4j = await loadAdf4j(); +const reported = (result) => { + for (const diagnostic of result.diagnostics) console.log("diagnostic:", JSON.stringify(diagnostic)); + return result.value; +}; const succeeded = (result) => { if (result.type !== "Success") throw new Error(JSON.stringify(result)); return result.value; @@ -64,7 +67,6 @@ const converters = { toAdf: (md) => json.encode(atlaskit.parse(md)), toMarkdown: (doc) => atlaskit.encode(json.parse(doc)), }, - "@complexthings/md-to-adf": { toAdf: (md) => translateGithubMarkdown(md) }, "@faulander/md2adf": { toAdf: (md) => faulander.markdownToAdf(md), toMarkdown: (doc) => faulander.adfToMarkdown(doc), @@ -94,8 +96,8 @@ const converters = { "markdown-to-adf": { toAdf: (md) => markdownToAdf.markdownToAdf(md) }, marklassian: { toAdf: (md) => marklassian.markdownToAdf(md) }, "md-adf": { - toAdf: (md) => mdAdf.markdownToAdf(md).value, - toMarkdown: (doc) => mdAdf.adfToMarkdown(doc).value, + toAdf: (md) => reported(mdAdf.markdownToAdf(md)), + toMarkdown: (doc) => reported(mdAdf.adfToMarkdown(doc)), }, "md-to-adf": { toAdf: (md) => mdToAdf(md) }, "mdast-util-from-adf": { toMarkdown: (doc) => mdastToMarkdown(fromADF(doc)) }, diff --git a/converter-comparison/run.sh b/converter-comparison/run.sh index fc50d4f..f8f24ca 100755 --- a/converter-comparison/run.sh +++ b/converter-comparison/run.sh @@ -9,7 +9,6 @@ docker run --rm --memory 2g --memory-swap 2g --ulimit core=0 -u "$(id -u):$(id - npm install --before=2026-10-29 --ignore-scripts --no-audit --no-fund --silent \ @atlaskit/editor-json-transformer@10.0.0 \ @atlaskit/editor-markdown-transformer@6.3.1 \ - @complexthings/md-to-adf@1.0.0 \ @faulander/md2adf@1.0.0 \ @larvit/adf-codec@0.2.0 \ @nthings.dev/adf4j-wasm@1.0.2 \