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:
@@ -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
|
||||
|
||||
@@ -1,26 +1,31 @@
|
||||
# @larvit/adf-codec
|
||||
|
||||
Lossless conversion between **Atlassian Document Format** (ADF), an extended markdown flavour, and
|
||||
an HTML dialect.
|
||||
[](https://www.npmjs.com/package/@larvit/adf-codec)
|
||||
[](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
@@ -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",
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user