3
0
mirror of https://github.com/larvit/adf-codec.git synced 2026-11-12 11:48:29 +01:00

Compare the package with the other ADF converters in the README

This commit is contained in:
2026-10-14 19:55:27 +02:00
committed by Lillem4n
parent 1af791ab88
commit 770cc3b938
5 changed files with 130 additions and 17 deletions
+3
View File
@@ -11,6 +11,9 @@
- `losslessMarkdownToAdf` names the CommonMark spelling to write when it refuses a directive whose
node CommonMark spells, such as `[![alt](url)](href)` for a linked `!adf:mediaSingle`.
- The README compares the package with seven other ADF converters, each checked against its
published version.
## 0.2.0
- **Breaking:** each call names the markdown it reads or writes. `adfToMarkdown` and `markdownToAdf`
+19
View File
@@ -146,6 +146,7 @@ Nothing throws. `code` is from a closed list, so a `switch` with no `default` co
- [Goals](#goals)
- [Audience](#audience)
- [Other ADF converters](#other-adf-converters)
- [The calls](#the-calls)
- [The lossless flavour](#the-lossless-flavour)
- [Portable markdown](#portable-markdown)
@@ -191,6 +192,24 @@ Behind those apps, the people who read and write the markdown, and later the HTM
managers, engineers and support agents working in Atlassian products through a plugin or another
UI. They know markdown and not ADF, and rely on every spelling saying what it means to them.
## Other ADF converters
Serves [Goals](#goals) 3. Each package at the version named, checked 2026-10-14 by running its
published code on one document holding marks, a link, a mention, a status, a panel and a list, and
on one holding a node type it cannot know:
[`converter-comparison/`](https://github.com/larvit/adf-codec/tree/main/converter-comparison).
| Package | Converts | ADF to markdown to ADF | A node type it does not know | Formats | Runtime dependencies |
| --- | --- | --- | --- | --- | --- |
| `@larvit/adf-codec` 0.2.0 | both ways | the same document | kept | markdown: lossless, portable, CommonMark | 0 |
| `@atlaskit/editor-markdown-transformer` 6.3.1 | markdown to ADF, through `@atlaskit/editor-json-transformer`; ADF to markdown throws "not implemented" | – | – | markdown | 5 |
| `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 |
| `adf2markdown` 1.2.0 | ADF to markdown | – | its text kept | markdown | 0 |
| `extended-markdown-adf-parser` 2.4.0 | both ways | a different document: the mention comes back as linked text, the status without its `localId` | written as JSON, read back as a paragraph of that JSON's text | markdown | 9 |
| `marklassian` 1.2.1 | markdown to ADF | – | – | markdown | 1 |
| `md-to-adf` 0.6.4 | markdown to ADF | – | – | markdown | 2 |
## The calls
Serves [Goals](#goals) 1, 2 and 8. Pure functions, each taking a whole document and returning a
+86
View File
@@ -0,0 +1,86 @@
import { createRequire } from "node:module";
import { readFileSync } from "node:fs";
import { isDeepStrictEqual } from "node:util";
import * as atlaskitJson from "@atlaskit/editor-json-transformer";
import * as atlaskitMarkdown from "@atlaskit/editor-markdown-transformer";
import * as adfCodec from "@larvit/adf-codec";
import * as adfToMarkdown from "adf-to-markdown";
import adfToMd from "adf-to-md";
import * as adf2markdown from "adf2markdown";
import * as extendedParser from "extended-markdown-adf-parser";
import * as marklassian from "marklassian";
import mdToAdf from "md-to-adf";
const { defaultSchema } = createRequire(import.meta.url)("@atlaskit/adf-schema/schema-default");
const roundTripDoc = {
type: "doc", version: 1, content: [
{ type: "paragraph", content: [
{ type: "text", text: "bold italic", marks: [{ type: "strong" }, { type: "em" }] },
{ type: "text", text: " and " },
{ type: "text", text: "a link", marks: [{ type: "link", attrs: { href: "https://example.com" } }] },
{ type: "text", text: " hi " },
{ type: "mention", attrs: { id: "abc", text: "@Ann" } },
{ type: "text", text: " state " },
{ type: "status", attrs: { color: "green", localId: "s1", text: "DONE" } },
] },
{ type: "panel", attrs: { panelType: "info" }, content: [{ type: "paragraph", content: [{ type: "text", text: "note" }] }] },
{ type: "bulletList", content: [
{ type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "one" }] }] },
{ type: "listItem", content: [{ type: "paragraph", content: [{ type: "text", text: "two" }] }] },
] },
],
};
const unknownNodeDoc = {
type: "doc", version: 1, content: [
{ type: "paragraph", content: [{ type: "text", text: "before" }] },
{ type: "futureThing", attrs: { x: 1 }, content: [{ type: "paragraph", content: [{ type: "text", text: "inside" }] }] },
{ type: "paragraph", content: [{ type: "text", text: "after" }] },
],
};
const markdown = "***bold italic*** and [a link](https://example.com) hi @Ann\n\n> note\n\n- one\n- two\n";
const extended = new extendedParser.Parser();
const json = new atlaskitJson.JSONTransformer();
const atlaskit = new atlaskitMarkdown.MarkdownTransformer(defaultSchema);
const converters = {
"@atlaskit/editor-markdown-transformer": {
toAdf: (md) => json.encode(atlaskit.parse(md)),
toMarkdown: (doc) => atlaskit.encode(json.parse(doc)),
},
"@larvit/adf-codec": {
toAdf: (md) => adfCodec.losslessMarkdownToAdf(md).value,
toMarkdown: (doc) => adfCodec.adfToLosslessMarkdown(doc).value,
},
"adf-to-markdown": { toMarkdown: (doc) => adfToMarkdown.convertADFToMarkdown(doc) },
"adf-to-md": { toMarkdown: (doc) => adfToMd.convert(doc).result },
adf2markdown: { toMarkdown: (doc) => adf2markdown.adf2markdown(doc) },
"extended-markdown-adf-parser": {
toAdf: (md) => extended.markdownToAdf(md),
toMarkdown: (doc) => extended.adfToMarkdown(doc),
},
marklassian: { toAdf: (md) => marklassian.markdownToAdf(md) },
"md-to-adf": { toAdf: (md) => mdToAdf(md) },
};
const show = (label, call) => {
try {
const value = call();
console.log(`${label}:`, JSON.stringify(value));
return value;
} catch (error) {
console.log(`${label} threw:`, error.message);
}
};
for (const [name, { toAdf, toMarkdown }] of Object.entries(converters)) {
const manifest = JSON.parse(readFileSync(`node_modules/${name}/package.json`, "utf8"));
console.log(`\n## ${name} ${manifest.version}`);
console.log("runtime dependencies:", Object.keys(manifest.dependencies ?? {}).length);
const written = toMarkdown && show("ADF to markdown", () => toMarkdown(roundTripDoc));
if (written !== undefined) {
if (toAdf) show("round-trip deep-equal", () => isDeepStrictEqual(toAdf(written), roundTripDoc));
const unknown = show("unknown node to markdown", () => toMarkdown(unknownNodeDoc));
if (toAdf && unknown !== undefined) show("unknown node read back", () => toAdf(unknown));
}
if (toAdf) show("markdown to ADF", () => toAdf(markdown));
}
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
# Re-checks the README's comparison table against each package's published version.
set -eu
here=$(cd "$(dirname "$0")" && pwd)
docker run --rm --ulimit core=0 -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$here:/comparison:ro" -w /tmp \
node:24.21.0-alpine3.24 sh -c '
npm install --ignore-scripts --no-audit --no-fund --silent \
@atlaskit/editor-json-transformer@10.0.0 \
@atlaskit/editor-markdown-transformer@6.3.1 \
@larvit/adf-codec@0.2.0 \
adf-to-markdown@1.0.1 \
adf-to-md@1.2.1 \
adf2markdown@1.2.0 \
extended-markdown-adf-parser@2.4.0 \
marklassian@1.2.1 \
md-to-adf@0.6.4 &&
cp /comparison/compare.mjs . && node compare.mjs'
+5 -17
View File
@@ -26,7 +26,6 @@
| ID | Release | Exempt | Item | R | S | C | A | G | Goals | Score |
|---|---|---|---|---|---|---|---|---|---|---|
| 73 | 0.3.0 | | **Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions.** | 1 | 2 | 1 | 6 | 8 | 3 | 23.0 |
| 71 | 0.3.0 | | **Add a README table comparing the package with the other ADF converters, each cell checked against that package's own docs or behaviour.** | 1 | 3 | 2 | 6 | 7 | 3 | 21.2 |
| 114 | 0.3.0 | defect | **Build code-marked text holding no mark besides `link` and `annotation`, in every reader, and have `adfToLosslessMarkdown` carry code text holding any other mark.** | 3 | 4 | 5 | 5 | 7 | 4 | 15.4 |
| 99 | 0.3.0 | defect | **Write a linked external image standing inline or in a table cell in the spelling a reader panel picks, in `adfToPortableMarkdown`.** | 3 | 3 | 5 | 6 | 7 | 7 | 12.9 |
| 100 | 0.3.0 | decision | **Put the reading of an image's title as its caption back to a reader panel, now that a writer panel reads a title as hover text.** | 3 | 3 | 3 | 4 | 5 | 4, 6 | 10.9 |
@@ -71,20 +70,9 @@
### 73. Announce the package where someone needing an ADF converter already reads: JRACLOUD-77436, the Atlassian developer community and Stack Overflow's ADF-to-markdown questions.
Lands after item 71, so each post links the GitHub repository, the README's comparison table and a
README that opens with what the package is. We draft each post for the place it goes; the maintainer
posts them once `0.3.0` is published. Found while planning discoverability, 2026-10-04.
### 71. Add a README table comparing the package with the other ADF converters, each cell checked against that package's own docs or behaviour.
Lands before items 7 and 46, which add HTML and a size column to the table. Its columns: which
directions each converts, whether the round-trip holds, what an unknown node does, the formats and
runtime dependencies. Candidates are the packages an npm search for ADF and markdown returns. Every
cell cites that package's README or a run against its published version, and the table names each
version and the date it was checked. Found while planning discoverability, 2026-10-04. Checked
2026-10-05: no other package converts HTML or holds the round-trip; the candidates are
`@atlaskit/editor-markdown-transformer`, `adf-to-markdown`, `adf-to-md`, `adf2markdown`,
`extended-markdown-adf-parser`, `marklassian` and `md-to-adf`.
Each post links the GitHub repository, the README's comparison table and a README that opens with
what the package is. We draft each post for the place it goes; the maintainer posts them once
`0.3.0` is published. Found while planning discoverability, 2026-10-04.
### 114. Build code-marked text holding no mark besides `link` and `annotation`, in every reader, and have `adfToLosslessMarkdown` carry code text holding any other mark.
@@ -185,7 +173,7 @@ on such a document. Found while shipping item 106, 2026-10-11.
Lands after items 6, 59, 60 and 62. Which flavours get a composed call is this item's to settle; the
CommonMark spec suite also runs against the one reading CommonMark. The README documents HTML as it
documents markdown, its comparison table (item 71) names HTML, and its tagline and `package.json`'s
documents markdown, its comparison table names HTML, and its tagline and `package.json`'s
description and keywords name HTML again. `htmlToAdf` refuses a value that is not a string as
`not-a-string` (`docs/decisions.md` §Which code a cause takes).
@@ -266,7 +254,7 @@ tarball `npm pack` produces, its unpacked `dist`, and the built JavaScript minif
figure the competitors advertise (marklassian's "12kb") and the only apples-to-apples one, since
ours ships tsc's unminified output and no minifier yet (decide here whether to minify for the build
or report the unminified gzip). The figure lands in README §The package beside the "no runtime
dependencies" claim, and in a size column of the comparison table (item 71). Measured today,
dependencies" claim, and in a size column of the comparison table. Measured today,
unminified: tarball 60.4 kB, unpacked 221.5 kB, JS gzipped 45.6 kB.
### 72. Re-create `gitea.larvit.se/larvit/adf-codec` as a read-only pull mirror of GitHub, its issues and Actions off and its description pointing at GitHub.