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

Open the README with what the package does and for whom, and give npm search keywords

This commit is contained in:
2026-10-05 00:24:20 +02:00
committed by Lillem4n
parent 7bd37deb65
commit 3fb21b9766
4 changed files with 67 additions and 51 deletions
+2
View File
@@ -2,6 +2,8 @@
## Unreleased
- The README opens with what the package does and for whom, and compares it with the other ADF
converters on npm; `package.json` carries search keywords.
- The source moves to [github.com/larvit/adf-codec](https://github.com/larvit/adf-codec), where
issues and pull requests go.
- **Breaking:** directives, the inline opaque carry among them (now `!adf:carry{json="…"}`), are
+40 -18
View File
@@ -1,26 +1,31 @@
# @larvit/adf-codec
Lossless conversion between **Atlassian Document Format** (ADF), an extended markdown flavour, and
an HTML dialect.
[![npm](https://img.shields.io/npm/v/@larvit/adf-codec)](https://www.npmjs.com/package/@larvit/adf-codec)
[![CI](https://github.com/larvit/adf-codec/actions/workflows/ci.yml/badge.svg)](https://github.com/larvit/adf-codec/actions/workflows/ci.yml)
**Status: published — the markdown round-trip (`adfToMarkdown`, `markdownToAdf`); HTML at
`0.2.0`.**
Plan:
[`todo.md`](https://github.com/larvit/adf-codec/blob/main/todo.md). Decisions:
[`docs/decisions.md`](https://github.com/larvit/adf-codec/blob/main/docs/decisions.md). Changes:
[`CHANGELOG.md`](https://github.com/larvit/adf-codec/blob/main/CHANGELOG.md). The lossless flavour's grammar:
[`spec/flavour.md`](https://github.com/larvit/adf-codec/blob/main/spec/flavour.md).
Upgrading from `0.1.0`: [convert your markdown first](https://github.com/larvit/adf-codec/blob/main/MIGRATION.md).
Convert Atlassian Document Format (ADF) to and from markdown and HTML, with a lossless round-trip.
## What it is for
For application developers whose app shows, edits, exports or generates the rich text Atlassian
products store as ADF.
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.
- **Lossless:** `adfToMarkdown` and `markdownToAdf` give back the document they started from —
panels, mentions, statuses and node types this version does not know included.
- **Plain CommonMark in:** a bot's or a model's markdown is valid input, nothing to learn first.
- **Plain markdown out:** `adfToPlainMarkdown` and `plainMarkdownToAdf` convert to and from what
GitHub, GitLab and Obsidian render — GitHub Flavored Markdown's alerts and task lists, Obsidian
Flavored Markdown's callouts, highlights and pipe tables — keeping the content.
- **No throws:** every call returns a result; a refusal carries a code from a closed list.
- **Runs anywhere:** pure functions with no runtime dependencies, in Node, Deno, Bun and browsers.
- **HTML** at `0.2.0`: `adfToHtml`, `htmlToAdf`, `markdownToHtml`, `htmlToMarkdown`.
[Goals](#goals) · [Audience](#audience) · [The shape](#the-shape) ·
[Other ADF converters](#other-adf-converters) · [Plain markdown](#plain-markdown) ·
[The errors](#the-errors) · [The guarantees](#the-guarantees) · [The package](#the-package) ·
[Grammar](https://github.com/larvit/adf-codec/blob/main/spec/flavour.md) ·
[Changes](https://github.com/larvit/adf-codec/blob/main/CHANGELOG.md) ·
[Upgrading from `0.1.0`](https://github.com/larvit/adf-codec/blob/main/MIGRATION.md) ·
[Plan](https://github.com/larvit/adf-codec/blob/main/todo.md) ·
[Decisions](https://github.com/larvit/adf-codec/blob/main/docs/decisions.md)
## Goals
@@ -94,6 +99,23 @@ htmlToMarkdown(html: string): Result<string> // 0.2.0
`Result<T>` is `{ ok: true; value: T } | { ok: false; error: ConvertError }` — nothing throws.
## Other ADF converters
Serves Goal 3. Each package's latest version on npm, checked 2026-10-05 against its docs and by
converting a document holding a paragraph, a mention, a status, an info panel and an unknown node
type to markdown and back.
| Package | ADF to markdown | Markdown to ADF | Round-trip | Invalid ADF | Runtime dependencies |
| --- | --- | --- | --- | --- | --- |
| `@larvit/adf-codec` | yes | yes | deep-equal | returns `not-an-adf-document` | 0 |
| `@atlaskit/editor-markdown-transformer` 6.3.1 | no: `encode` throws | yes, through `@atlaskit/editor-json-transformer` | — | — | 5 |
| `marklassian` 1.2.1 | no | yes | — | — | 1 |
| `adf-to-md` 1.2.1 | yes | no | — | throws | 1 |
| `extended-markdown-adf-parser` 2.4.0 | yes | yes | lossy: the mention reads back as a link, the status loses its `localId`, the unknown node as its JSON in a paragraph | writes empty markdown | 9 |
| `md-to-adf` 0.6.4 | no | yes | — | — | 2 |
| `adf-to-markdown` 1.0.1 | yes | no | — | throws on `null`, writes empty markdown for a `doc` without `content` | 0 |
| `adf2markdown` 1.2.0 | yes | no | — | throws on `null`, writes a newline for a `doc` without `content` | 0 |
## Plain markdown
Serves Goal 7. Plain markdown is a second flavour of the same grammar. `adfToPlainMarkdown` writes
+13 -1
View File
@@ -1,7 +1,19 @@
{
"name": "@larvit/adf-codec",
"version": "0.1.0",
"description": "Lossless conversion between Atlassian Document Format, extended markdown and HTML",
"description": "Convert Atlassian Document Format (ADF) to and from markdown and HTML, with a lossless round-trip.",
"keywords": [
"adf",
"atlassian",
"atlassian-document-format",
"commonmark",
"confluence",
"converter",
"html",
"jira",
"markdown",
"prosemirror"
],
"license": "MIT",
"repository": {
"type": "git",
+12 -32
View File
@@ -6,7 +6,7 @@
`Bar = 9`
`Next ID = 78`
`Next ID = 79`
| Goal | W |
|---|---|
@@ -24,20 +24,18 @@
| ID | Release | Exempt | Item | R | S | A | G | Goals | Score |
|---|---|---|---|---|---|---|---|---|---|
| 47 | 0.2.0 | | **Open the README with what the package is, what it does and for whom.** | 1 | 4 | 7 | 9 | 3 | 26.0 |
| 7 | 0.2.0 | | **Ship HTML: `adfToHtml`, `htmlToAdf`, and `markdownToHtml` / `htmlToMarkdown` composed through ADF.** | 6 | 9 | 9 | 9 | 2, 4 | 25.8 |
| 78 | 0.2.0 | defect | **Return a result when `markdownToAdf` or `plainMarkdownToAdf` is handed a value that is not a string.** | 2 | 2 | 5 | 9 | 1 | 25.5 |
| 45 | 0.2.0 | | **Replace `isAdfDocument` with a reader returning `Result<AdfDocument>`.** | 2 | 3 | 6 | 8 | 1 | 25.2 |
| 67 | 0.2.0 | defect | **Push an expand title's leaves one at a time, so a title carrying many text nodes returns a result.** | 1 | 1 | 4 | 9 | 1 | 24.8 |
| 6 | 0.2.0 | decision | **Specify the HTML dialect.** | 2 | 6 | 7 | 8 | 2, 4 | 24.7 |
| 64 | 0.2.0 | defect | **Read back unchanged on V8 every JSON key the emitter writes, with a fixture whose key holds `\`, `"` or a control character.** | 4 | 4 | 6 | 8 | 1, 8 | 23.0 |
| 77 | 0.2.0 | decision | **Read the input once into a plain copy, so an accessor property or a throwing Proxy yields `not-an-adf-document` and every call returns a result.** | 4 | 4 | 5 | 9 | 1 | 23.0 |
| 66 | 0.2.0 | defect | **Refuse an attribute value that is not a plain object, array or JSON primitive.** | 3 | 2 | 5 | 8 | 1 | 22.5 |
| 71 | 0.2.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 | 6 | 7 | 3 | 21.2 |
| 43 | 0.2.0 | decision | **Give each markdown input its own reader, strict to its own standard.** | 6 | 7 | 8 | 9 | 4, 5 | 20.3 |
| 68 | 0.2.0 | | **Carry a non-text inline node holding `content` or `text`, a block holding `text`, and a leaf block holding `content`.** | 3 | 3 | 4 | 7 | 1 | 18.2 |
| 75 | 0.2.0 | | **Make the generated-markdown property write block carries as `adf:` fences, canonical and hostile.** | 2 | 2 | 3 | 7 | 1 | 17.5 |
| 65 | 0.2.0 | defect | **Read an image not alone in its paragraph as its alt text linked to its URL, and a titled image alone in its paragraph as the image captioned with its title.** | 5 | 5 | 7 | 7 | 4, 5, 7 | 17.1 |
| 70 | 0.2.0 | | **Give `package.json` the `keywords` someone searching npm for an ADF converter types.** | 1 | 1 | 4 | 6 | 3 | 16.1 |
| 49 | 0.2.0 | | **Read a list whose bullet or ordered delimiter changes as two lists, in both readers, and retire `!adf:listBreak`.** | 4 | 5 | 5 | 8 | 4, 5 | 15.5 |
| 46 | 0.2.0 | | **Publish the bundle size in the README, failing the release pipeline when it drifts.** | 2 | 4 | 5 | 5 | 3, 8 | 14.8 |
| 61 | 0.2.0 | decision | **Have the emitter ask the inline reader how a line reads back, in place of `line-escaping.ts` predicting it.** | 6 | 8 | 3 | 8 | 1 | 14.0 |
@@ -65,20 +63,18 @@
## Details
### 47. Open the README with what the package is, what it does and for whom.
Add badges for npm's version and the GitHub Actions status. Today the README opens with the
pre-launch rationale — Atlassian's REST APIs, `pf-editor-service/convert` being decommissioned, a
link to JRACLOUD-77436. The background goes entirely, no endpoint, ticket or "why" note left. The
README names the lossy pair, `adfToPlainMarkdown` and `plainMarkdownToAdf`, and the flavours it
writes and reads — GitHub Flavored Markdown's alerts and task lists, Obsidian Flavored Markdown's
callouts — so a search for any of these names finds the package.
### 7. Ship HTML: `adfToHtml`, `htmlToAdf`, and `markdownToHtml` / `htmlToMarkdown` composed through ADF.
Lands after items 6, 59, 60, 61 and 62. The CommonMark spec suite also runs against
`markdownToHtml`. The README documents HTML as it documents markdown.
### 78. Return a result when `markdownToAdf` or `plainMarkdownToAdf` is handed a value that is not a string.
Today `null` and `undefined` throw a `TypeError` reading `length`, and `42` reads as an empty
document. A JavaScript caller, or a TypeScript one past an untyped boundary, reaches both. The code
it returns follows `docs/decisions.md` §Which code a cause takes. Found by the competitor probe for
the README's comparison table, 2026-10-05.
### 45. Replace `isAdfDocument` with a reader returning `Result<AdfDocument>`.
Lands with item 77: the reader returns item 77's copy. Goal 1 has every call return a result; the
@@ -129,15 +125,6 @@ typed array in `attrs`, as `structuredClone` keeps it, passes the guard and is w
key per element: `ok: true` with content lost. Accept an object whose prototype is
`Object.prototype` or `null`, and an array. Found by the stability review of item 63, 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 after items 7, 46 and 47: the table names HTML, compares item 46's size figure, and sits in
the README item 47 reshapes. Its columns: which directions each converts, whether the round-trip
holds, what an unknown node does, the formats, runtime dependencies and size. Candidates are the
packages an npm search for ADF and markdown returns, marklassian among them. 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.
### 43. Give each markdown input its own reader, strict to its own standard.
Today `markdownToAdf` reads CommonMark and the lossless flavour as one input: text shaped like a
@@ -175,13 +162,6 @@ its paragraph, it reads as the image with a `link` mark to `/uri`, which ADF's `
alone in its paragraph, the image reads as its alt text linked to `/uri`, and its URL drops. A
writer panel chose this reading 3 of 3 (2026-10-04), by Goal 6, which outranks Goal 7.
### 70. Give `package.json` the `keywords` someone searching npm for an ADF converter types.
`package.json` has none, and npm's search ranks on them. Take the GitHub repository's topics, so a
search on npm matches what GitHub already does: adf, atlassian, atlassian-document-format,
commonmark, confluence, converter, html, jira, markdown, typescript. Found while planning
discoverability, 2026-10-04.
### 49. Read a list whose bullet or ordered delimiter changes as two lists, in both readers, and retire `!adf:listBreak`.
Lands after item 43. Today `- a` then `+ b`, or `1.` then `1)`, reads as one list; CommonMark reads
@@ -270,9 +250,9 @@ which counts one fewer.
### 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 `0.2.0` is published with items 47 and 71, so each post links the GitHub repository, the
comparison and a README that opens with what the package is. We draft each post for the place it
goes; the maintainer posts them. Found while planning discoverability, 2026-10-04.
Lands after `0.2.0` is published, so each post links the GitHub repository, the comparison and a
README that opens with what the package is. We draft each post for the place it goes; the
maintainer posts them. Found while planning discoverability, 2026-10-04.
### 38. Spell a lone surrogate in a text node so it survives a UTF-8 encode.