mirror of
https://github.com/larvit/adf-codec.git
synced 2026-11-12 11:48:29 +01:00
Answer product-owner round 1: 0 🔴, 4 🟡 (0 misread); keep unreleased calls out of the Breaking entries and sharpen the feature page's intro
This commit is contained in:
+28
-24
@@ -2,13 +2,32 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- `docs/feature-table.md` sets real documents beside what `adfToLosslessMarkdown`,
|
||||
- **Breaking:** `adfToPortableMarkdown` refuses, as `unsupported-node-shape`, a known block holding
|
||||
`text`, a known non-text inline node holding `text` or non-empty `content`, and a known block that
|
||||
takes no content, such as `rule`, holding non-empty `content`. `adfToLosslessMarkdown` now refuses
|
||||
them inside a carried node too, and `losslessMarkdownToAdf` refuses a carry holding one.
|
||||
`MIGRATION.md` says how to convert stored markdown.
|
||||
- **Breaking:** `losslessMarkdownToAdf` gives a `date`, `emoji`, `inlineCard`, `mention`, `status`
|
||||
or `mediaInline` only the marks Atlassian's schema lets it hold: `**!adf:mention[@A]{id=…}**` now
|
||||
reads as a plain mention. A link or directive mark around only nodes that cannot take it is
|
||||
`unsupported-node-shape`, even in markdown `adfToLosslessMarkdown` wrote. A link around hard
|
||||
breaks alone still reads as before. `adfToLosslessMarkdown` writes a node holding a mark its type
|
||||
cannot take as `!adf:carry{json="…"}`, except an inline card a link marks, which it refuses.
|
||||
`MIGRATION.md` says how to convert stored markdown.
|
||||
- **Breaking:** `adfToLosslessMarkdown` and `adfToPortableMarkdown` refuse an inline card a link marks
|
||||
as `unsupported-node-shape` at the card's path, and `losslessMarkdownToAdf` refuses a carry
|
||||
holding one, since Atlassian's schema gives a card no link mark. `MIGRATION.md` says what to do.
|
||||
- **Breaking:** every reader gives code text no mark but `link` and `annotation`, as Atlassian's
|
||||
schema requires: ``**`npm ci`**`` now reads as plain code, and a directive mark other than a link
|
||||
around only code spans is `unsupported-node-shape`. `adfToLosslessMarkdown` writes code text
|
||||
holding another mark as `!adf:carry{json="…"}`, and `adfToPortableMarkdown` drops that mark.
|
||||
- **Breaking:** `losslessMarkdownToAdf` gives text no `border` mark, as Atlassian's schema requires:
|
||||
`!adf:border[x]{color="#091e42" size=2}` is `unsupported-node-shape`, and only a
|
||||
`mediaInline` takes `border`. `adfToLosslessMarkdown` writes text holding `border` as `!adf:carry{json="…"}`.
|
||||
`MIGRATION.md` says how to convert stored markdown.
|
||||
- `docs/feature-table.md` sets example documents beside what `adfToLosslessMarkdown`,
|
||||
`adfToPortableMarkdown` and `adfToHtml` write for them, and says whether each output reads back to
|
||||
the same document.
|
||||
- **Breaking:** `adfToHtml`, `adfToPortableMarkdown`, `htmlToAdf` and `losslessMarkdownToAdf` refuse
|
||||
a block or non-text inline node holding `text`, and a leaf block or non-text inline node holding
|
||||
`content`, as `adfToLosslessMarkdown` already did outside a carried node, which it now also
|
||||
refuses. `MIGRATION.md` says how to convert a stored document.
|
||||
- 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. The README's first comparison table lists the npm packages running in Node that convert ADF
|
||||
@@ -25,31 +44,16 @@
|
||||
node's JSON in `data-adf` and showing its content, links included. Every URL is written as the
|
||||
ADF holds it, `javascript:` included: sanitize HTML from an author you do not trust before
|
||||
showing it.
|
||||
It refuses, carried or not and as `unsupported-node-shape`, a known block holding `text`, a known
|
||||
non-text inline node holding `text` or non-empty `content`, and a known block that takes no
|
||||
content, such as `rule`, holding non-empty `content`.
|
||||
- `htmlToAdf` reads `adfToHtml`'s HTML back to the document it came from, a carry element from its
|
||||
`data-adf`. It reads that HTML as a browser's `innerHTML` writes it too (a raw `"` in text,
|
||||
` `, a raw `<` or `>` in an attribute value) and as a form post sends it (`\r\n` for each
|
||||
line feed). An edit to an emoji's, mention's or status's text becomes its `text`; an edit to a
|
||||
date's or a card's text alone is refused. It refuses any other HTML, including an edit to what a
|
||||
carry element shows, with the codes README §The calls lists.
|
||||
- **Breaking:** `losslessMarkdownToAdf` gives a `date`, `emoji`, `inlineCard`, `mention`, `status`
|
||||
or `mediaInline` only the marks Atlassian's schema lets it hold: `**!adf:mention[@A]{id=…}**` now
|
||||
reads as a plain mention. A link or directive mark around only nodes that cannot take it is
|
||||
`unsupported-node-shape`, even in markdown `adfToLosslessMarkdown` wrote. A link around hard
|
||||
breaks alone still reads as before. `adfToLosslessMarkdown` writes a node holding a mark its type
|
||||
cannot take as `!adf:carry{json="…"}`, except an inline card a link marks, which it refuses.
|
||||
`MIGRATION.md` says how to convert stored markdown.
|
||||
- **Breaking:** `adfToLosslessMarkdown` and `adfToPortableMarkdown` refuse an inline card a link marks
|
||||
as `unsupported-node-shape` at the card's path, and `losslessMarkdownToAdf` refuses a carry
|
||||
holding one, since Atlassian's schema gives a card no link mark. `adfToHtml` and `htmlToAdf` do
|
||||
the same. `MIGRATION.md` says what to do.
|
||||
- **Breaking:** every reader gives code text no mark but `link` and `annotation`, as Atlassian's
|
||||
schema requires: ``**`npm ci`**`` now reads as plain code, and a directive mark other than a link
|
||||
around only code spans is `unsupported-node-shape`. `adfToLosslessMarkdown` writes code text
|
||||
holding another mark as `!adf:carry{json="…"}`, and `adfToPortableMarkdown` drops that mark.
|
||||
- **Breaking:** `losslessMarkdownToAdf` gives text no `border` mark, as Atlassian's schema requires:
|
||||
`!adf:border[x]{color="#091e42" size=2}` is `unsupported-node-shape`, and only a
|
||||
`mediaInline` takes `border`. `adfToLosslessMarkdown` writes text holding `border` as `!adf:carry{json="…"}`.
|
||||
`MIGRATION.md` says how to convert stored markdown.
|
||||
It also refuses a carry element holding a shape `adfToHtml` refuses.
|
||||
- `adfToLosslessMarkdown` and `adfToPortableMarkdown` write an `em`, `strike`, `strong` or `link`
|
||||
mark once across the hard breaks between two texts it marks: `_One\` then `Two_`, where they
|
||||
wrote `_One_\` then `_Two_`. They write an `em`, `strike` or `strong` mark once around a code
|
||||
|
||||
@@ -301,7 +301,7 @@ documentation says, on 2026-10-28.
|
||||
|
||||
Serves [Goals](#goals) 1, 2 and 8. Pure functions, each taking a whole document and returning a
|
||||
whole result; no I/O, no configuration. [What each call writes](https://github.com/larvit/adf-codec/blob/main/docs/feature-table.md)
|
||||
sets real documents beside each writer's output and says whether that output reads back the same.
|
||||
sets example documents beside each writer's output and says whether that output reads back the same.
|
||||
|
||||
```ts
|
||||
adfToLosslessMarkdown(doc: AdfDocument): Result<string>
|
||||
@@ -528,7 +528,7 @@ content. No stylesheet ships. The complete dialect:
|
||||
| `table`, `tableRow`, `tableCell`, `tableHeader` | `<table>`, `<thead>` for a first row of `tableHeader` cells alone, `<tbody>`, `<tr>`, `<td>` and `<th>`; a cell's first paragraph stands as an item's does, and `<td colspan="2" rowspan="2" style="background-color:#fffae6" data-colwidth="120,80">` writes its attributes |
|
||||
| `text` marked `code`, `em`, `strong` | `<code>`, `<em>`, `<strong>`, the first mark outermost |
|
||||
| an attribute its type holds that its element does not write, such as `localId`, on a paragraph, heading, quote, list, list item, table, row, cell, code block, rule, emoji, mention, status, date or card | `data-*` named as HTML's `dataset` names it: `<p data-local-id="a1f3">` |
|
||||
| any other node, or a node holding what its element cannot, except an inline card a link marks, which is refused ([The errors](#the-errors)) | `<div class="adf-carry" data-adf="{…}"><p>its content</p></div>`, a `<span>` inline |
|
||||
| any other node, or a node holding what its element cannot, except a shape Atlassian's schema forbids, which is refused ([The errors](#the-errors)) | `<div class="adf-carry" data-adf="{…}"><p>its content</p></div>`, a `<span>` inline |
|
||||
|
||||
- Every URL is written as the ADF holds it, `javascript:` included: a link's, an image's, a
|
||||
card's, and a carried link's in the carry element. Sanitize the HTML before showing a document from
|
||||
@@ -649,11 +649,12 @@ Every call can raise these:
|
||||
- **Writing, in `adfToLosslessMarkdown`**: a node not riding the carry that carries one mark type
|
||||
twice. Keep the ADF and show the document read-only; where you built the ADF, fix
|
||||
what the message names.
|
||||
- **Writing, in `adfToHtml`, `adfToLosslessMarkdown` and `adfToPortableMarkdown`**: what Atlassian's
|
||||
schema gives no node, even inside a node that rides the carry: an inline card marked by a link, a
|
||||
block or a non-text inline node holding `text`, or a leaf block or a non-text inline node holding
|
||||
`content`. Keep the ADF and pass the document over or show it read-only; where you built the ADF,
|
||||
remove what the error's `path` and message name.
|
||||
- **Writing, in `adfToHtml`, `adfToLosslessMarkdown` and `adfToPortableMarkdown`**: a shape
|
||||
Atlassian's schema forbids, even inside a node that rides the carry: an inline card a link marks,
|
||||
a known block holding `text`, a known non-text inline node holding `text` or non-empty `content`,
|
||||
or a known block that takes no content, such as `rule`, holding non-empty `content`. Keep the ADF
|
||||
and pass the document over or show it read-only; where you built the ADF, remove what the error's
|
||||
`path` and message name.
|
||||
- **Writing, in `adfToPortableMarkdown`**: a line or task list the portable writer cannot spell.
|
||||
This is a bug in this library: report it.
|
||||
- **Past the engine's longest string**:
|
||||
|
||||
+4
-7
@@ -463,8 +463,7 @@ and `<span … data-data>` 2. The maintainer took the leading spelling of each,
|
||||
- a mention is `<span class="adf-mention" data-access-level="CONTAINER" data-id="5b10a2" data-user-type="DEFAULT">@Mikael</span>`, its `text` the content;
|
||||
- a card holding `data` and no URL is `<a class="adf-inline-card" href="https://example.com/plan" data-data="{…}">Release plan</a>`, `href` the URL its `data` holds and the text its name, else that URL. A card holding both `data` and a `url` rides the carry: its `href`, read back, could not say which of the two URLs it spells.
|
||||
|
||||
A sixth panel (2026-11-05, three readers in the same roles) picked each of these 3 of 3 for a table,
|
||||
which until then rode the carry:
|
||||
A sixth panel (2026-11-05, three readers in the same roles) picked each of these 3 of 3 for a table:
|
||||
|
||||
- a first row of header cells alone in `<thead>` and the rest in `<tbody>`, a row to a line, over a
|
||||
bare `<table>` of `<tr>` rows and over a line per cell;
|
||||
@@ -472,9 +471,6 @@ which until then rode the carry:
|
||||
- a cell's attributes as `<td colspan="2" rowspan="2" style="background-color:#fffae6" data-colwidth="120,80">`,
|
||||
over `data-*` for all four.
|
||||
|
||||
A `background` holding anything but letters and digits after an optional `#` rides the carry, so no
|
||||
value can end the `style` declaration.
|
||||
|
||||
## `htmlToAdf` also reads the dialect as a browser serializes it
|
||||
|
||||
2026-10-28, the maintainer. Goal 6. Valid while a viewer/editor app may show `adfToHtml`'s HTML in a
|
||||
@@ -773,8 +769,9 @@ writer refuses alike, with one code, message and path, wherever the shape stands
|
||||
too, and a carry reader refuses it with the same code and the writers' message after its holder's
|
||||
name. The first step refuses an `inlineCard` with a `link` mark as `unsupported-node-shape`: the
|
||||
schema gives a card the `annotation` mark alone (§The node tables answer to Atlassian's schema),
|
||||
and HTML nests no `<a>` in an `<a>`. It also refuses a block or non-text inline node holding `text`,
|
||||
and a leaf block or non-text inline node holding a non-empty `content`.
|
||||
and HTML nests no `<a>` in an `<a>`. The first step also refuses a known block holding `text`, a
|
||||
known non-text inline node holding `text` or non-empty `content`, and a known block that takes no
|
||||
content holding non-empty `content`.
|
||||
|
||||
Nothing else joins the first step. Nothing refuses a node type, mark or attribute the schema does
|
||||
not name (§Unknown nodes ride the carry), a known node where no section spells it, or a mark a node
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# What each call writes
|
||||
|
||||
`feature-table/build.mjs` writes this page from the corpus and the built package, and `./ci.sh` fails where the page differs.
|
||||
Each section sets a sample ADF document beside what each call writes for it, then reads that output back: `adfToLosslessMarkdown` with `losslessMarkdownToAdf`, `adfToPortableMarkdown` with `portableMarkdownToAdf`, `adfToHtml` with `htmlToAdf`. `holds` means the reader gives the same document, `loses` a different one, and `refused` that the writer or reader returned an error, whose code the section names.
|
||||
|
||||
Each output is read back by its format's reader. `holds` means that gives the same document, `loses` a different one, and `refused` an error whose code the example names.
|
||||
A result covers that example alone, and the examples are plain. Portable markdown drops every attribute, so a document holding one loses it even where its row says `holds`: to edit and save back, use `adfToLosslessMarkdown` and `losslessMarkdownToAdf`. An image holding an attribute, as editor-written ones do, rides the carry element in HTML, where this page shows `<img>`.
|
||||
|
||||
`./feature-table/write.sh` writes this page. Don't edit it by hand.
|
||||
|
||||
| Example | Lossless | Portable | HTML |
|
||||
| --- | --- | --- | --- |
|
||||
|
||||
@@ -8,16 +8,18 @@ const writers = [
|
||||
|
||||
const intro = `# What each call writes
|
||||
|
||||
\`feature-table/build.mjs\` writes this page from the corpus and the built package, and \`./ci.sh\` fails where the page differs.
|
||||
Each section sets a sample ADF document beside what each call writes for it, then reads that output back: \`adfToLosslessMarkdown\` with \`losslessMarkdownToAdf\`, \`adfToPortableMarkdown\` with \`portableMarkdownToAdf\`, \`adfToHtml\` with \`htmlToAdf\`. \`holds\` means the reader gives the same document, \`loses\` a different one, and \`refused\` that the writer or reader returned an error, whose code the section names.
|
||||
|
||||
Each output is read back by its format's reader. \`holds\` means that gives the same document, \`loses\` a different one, and \`refused\` an error whose code the example names.
|
||||
A result covers that example alone, and the examples are plain. Portable markdown drops every attribute, so a document holding one loses it even where its row says \`holds\`: to edit and save back, use \`adfToLosslessMarkdown\` and \`losslessMarkdownToAdf\`. An image holding an attribute, as editor-written ones do, rides the carry element in HTML, where this page shows \`<img>\`.
|
||||
|
||||
\`./feature-table/write.sh\` writes this page. Don't edit it by hand.
|
||||
`
|
||||
|
||||
// `library` holds the package's calls, so a test can hand in what a real document cannot make them do.
|
||||
// `library` is a parameter, so a test can hand in calls that refuse, which no corpus example makes them do.
|
||||
export function renderFeatureTable(examples, library) {
|
||||
const written = examples.map(({ doc, name }) => ({ doc, name, outcomes: writers.map((writer) => outcome(doc, writer, library)) }))
|
||||
const rows = written.map(({ name, outcomes }) => `| [${name}](#${name.toLowerCase().replaceAll(' ', '-')}) | ${outcomes.map(({ result }) => result).join(' | ')} |`)
|
||||
const head = `| Example | ${writers.map(({ column }) => column).join(' | ')} |\n| --- | --- | --- | --- |`
|
||||
const head = `| Example | ${writers.map(({ column }) => column).join(' | ')} |\n| --- | ${writers.map(() => '---').join(' | ')} |`
|
||||
return [intro, [head, ...rows].join('\n') + '\n', ...written.map(section)].join('\n')
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user