Rewrap the broken lines, and say plainly how an adf: fence stays code

This commit is contained in:
2026-10-03 15:06:11 +02:00
parent fb78063f12
commit 912c5039aa
4 changed files with 29 additions and 28 deletions
+2 -2
View File
@@ -9,8 +9,8 @@
`type`: text holding an unescaped `!adf:` and a code fence whose info string opens `adf:` are `type`: text holding an unescaped `!adf:` and a code fence whose info string opens `adf:` are
claimed, and `adf` is an ordinary code block language. Convert stored markdown per `MIGRATION.md`. claimed, and `adf` is an ordinary code block language. Convert stored markdown per `MIGRATION.md`.
- **Breaking:** `markdownToAdf` and `plainMarkdownToAdf` read markdown holding no block as a - **Breaking:** `markdownToAdf` and `plainMarkdownToAdf` read markdown holding no block as a
document whose `content` is empty, as Atlassian's schema requires; `!adf:doc {content=none}` spells a document holding no document whose `content` is empty, as Atlassian's schema requires; `!adf:doc {content=none}`
`content` key. spells a document holding no `content` key.
- `markdownToAdf(adfToMarkdown(doc))` deep-equals `doc`: two adjacent text nodes a reader would - `markdownToAdf(adfToMarkdown(doc))` deep-equals `doc`: two adjacent text nodes a reader would
join are parted by `!adf:textBreak{}`, an empty `attrs`, `content` or `marks` is spelled join are parted by `!adf:textBreak{}`, an empty `attrs`, `content` or `marks` is spelled
`{attrs=empty}`, `{content=empty}` or `{marks=empty}`, `-0` is spelled `-0`, and a `codeBlock` `{attrs=empty}`, `{content=empty}` or `{marks=empty}`, `-0` is spelled `-0`, and a `codeBlock`
+7 -8
View File
@@ -212,14 +212,13 @@ Serves Goals 1, 3 and 4.
`0.2.0`, well-formed HTML means what the HTML standard says, read or written. The bullets below `0.2.0`, well-formed HTML means what the HTML standard says, read or written. The bullets below
name every exception. name every exception.
- Plain CommonMark is valid input to `markdownToAdf` apart from the raw HTML `unmappable-html` - Plain CommonMark is valid input to `markdownToAdf` apart from the raw HTML `unmappable-html`
names, with four carve-outs — literal text matching directive, pipe-table or strikethrough names, with four carve-outs — literal text matching directive, pipe-table or strikethrough syntax,
syntax, and a code fence whose info string opens `adf:`, is claimed (escapable — `spec/flavour.md`) and a code fence whose info string opens `adf:`, are claimed (escapable — `spec/flavour.md`) — and
— and one gap: a CommonMark image fits only as one gap: a CommonMark image fits only as its own title-less paragraph; mid-text and titled images
its own title-less paragraph; mid-text and titled images are error results, save an image inside are error results, save an image inside another's description, which flattens into the alt text.
another's description, which flattens into the alt text. Converting back yields the library's Converting back yields the library's canonical spelling, which round-trips byte-identically —
canonical spelling, which round-trips byte-identically — where it converts back at all: a parse where it converts back at all: a parse succeeding is no promise of that, so keep the source until
succeeding is no promise of that, so keep the source until the way back succeeds. the way back succeeds. ``` ` `` ` ``` reads cleanly and then refuses.
``` ` `` ` ``` reads cleanly and then refuses.
- Four CommonMark spellings parse without an error and build a document the reference - Four CommonMark spellings parse without an error and build a document the reference
implementation renders differently: `[](/url)` and `[]()` stay literal text against CommonMark's implementation renders differently: `[](/url)` and `[]()` stay literal text against CommonMark's
empty link, a list continuing past a marker change stays one list against CommonMark's two, a empty link, a list continuing past a marker change stays one list against CommonMark's two, a
+5 -4
View File
@@ -19,7 +19,8 @@ One directory per contract kind:
model), `unspellable` (parses but the flavour has no spelling) or `pending` (a parser gap). model), `unspellable` (parses but the flavour has no spelling) or `pending` (a parser gap).
JSON is two-space indent, keys sorted, and a document read back must deep-equal the fixture's JSON is two-space indent, keys sorted, and a document read back must deep-equal the fixture's
(`docs/decisions.md` §Equality is deep). `spec.json` is the vendored, upstream machine-readable suite, byte-exact from (`docs/decisions.md` §Equality is deep). `spec.json` is the vendored, upstream machine-readable
[spec.commonmark.org](https://spec.commonmark.org/0.31.2/spec.json) (CommonMark 0.31.2, © John suite, byte-exact from [spec.commonmark.org](https://spec.commonmark.org/0.31.2/spec.json)
MacFarlane, [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/)), and is not (CommonMark 0.31.2, © John MacFarlane,
re-serialized by the corpus gate. [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/)), and is not re-serialized by the
corpus gate.
+15 -14
View File
@@ -4,10 +4,11 @@ The grammar of the extended markdown `adfToMarkdown` emits and `markdownToAdf` p
CommonMark is a subset apart from raw HTML (below), with four carve-outs: literal text that matches CommonMark is a subset apart from raw HTML (below), with four carve-outs: literal text that matches
directive syntax below or reads as a pipe table is claimed by the flavour, a matched `~~` pair directive syntax below or reads as a pipe table is claimed by the flavour, a matched `~~` pair
spells `strike` (escape the `!adf:`, `|` or `~` to keep it literal), and a code fence whose info spells `strike` (escape the `!adf:`, `|` or `~` to keep it literal), and a code fence whose info
string opens `adf:` is the opaque carry (The opaque carry says how to keep it code) — and one gap: a CommonMark string opens `adf:` is the opaque carry (wrap it as a bare fence in `!adf:codeBlock
image fits only as its own title-less paragraph — mid-text and titled images are named errors. The {language="adf:…"}` to keep it code) — and one gap: a CommonMark image fits only as its own
emitted form is contract (`docs/decisions.md` §The formats are API). Per-node syntaxes build on this title-less paragraph — mid-text and titled images are named errors. The emitted form is contract
grammar in the sections below. (`docs/decisions.md` §The formats are API). Per-node syntaxes build on this grammar in the sections
below.
## Canonical form ## Canonical form
@@ -446,8 +447,8 @@ Attributes and the carry fallback read as in the block sections, the carry in it
the nodes below, `emoji`, `mention` and `status` spell their `text` attribute in the content slot as the nodes below, `emoji`, `mention` and `status` spell their `text` attribute in the content slot as
plain text: `[]` is the empty string, absent content is the absent attribute, non-empty content plain text: `[]` is the empty string, absent content is the absent attribute, non-empty content
parsing to anything but one text node carrying neither marks, attributes nor content is a named parsing to anything but one text node carrying neither marks, attributes nor content is a named
error, and so is a `text` key in `{attrs}`. An enclosing mark spelling does not reach into the slot. The rest take no content, error, and so is a `text` key in `{attrs}`. An enclosing mark spelling does not reach into the slot.
`!adf:text` included; content on a node that takes none is a named error. The rest take no content, `!adf:text` included; content on a node that takes none is a named error.
- `date` — Attributes: `localId` (string), `timestamp` (string, epoch milliseconds). - `date` — Attributes: `localId` (string), `timestamp` (string, epoch milliseconds).
- `emoji` — Attributes: `id` (string), `localId` (string), `shortName` (string, `:name:`), `text` - `emoji` — Attributes: `id` (string), `localId` (string), `shortName` (string, `:name:`), `text`
@@ -527,14 +528,14 @@ that depth: `attrs: {}` differs from no `attrs`, and a directive spells it `{att
breaks at every node the emitter carries, so no emitted carry sits inside a mark spelling. breaks at every node the emitter carries, so no emitted carry sits inside a mark spelling.
An inline node whose marks no nesting spells — a mark type not listed here, an attrs key its An inline node whose marks no nesting spells — a mark type not listed here, an attrs key its
spelling does not list, a value that is not the spelling's type, an attribute the spelling needs spelling does not list, a value that is not the spelling's type, an attribute the spelling needs and
and the mark lacks, an empty `attrs` on a mark CommonMark spells, an order putting a code span outside another mark, `code` over anything but a the mark lacks, an empty `attrs` on a mark CommonMark spells, an order putting a code span outside
text node or over text holding a newline, or a spelling CommonMark's flanking rules cannot open or another mark, `code` over anything but a text node or over text holding a newline, or a spelling
close where the run sits (`un**-real**istic`), or one CommonMark's matching pairs elsewhere — the CommonMark's flanking rules cannot open or close where the run sits (`un**-real**istic`), or one
intra-word `*` runs together with a neighbouring `**`, and the multiple-of-3 rule can leave the CommonMark's matching pairs elsewhere — the intra-word `*` runs together with a neighbouring `**`,
merged run's pairing to another delimiter — rides the inline carry whole. An opaque carry inside a and the multiple-of-3 rule can leave the merged run's pairing to another delimiter — rides the
mark spelling is a named error in input: the carry restores its node exactly, marks included inline carry whole. An opaque carry inside a mark spelling is a named error in input: the carry
(`docs/decisions.md` §Unknown nodes ride the carry). restores its node exactly, marks included (`docs/decisions.md` §Unknown nodes ride the carry).
``` ```
!adf:textColor[**Overdue**]{color="#ae2e24"}, H!adf:subsup[2]{type=sub}O, !adf:underline[signed]. !adf:textColor[**Overdue**]{color="#ae2e24"}, H!adf:subsup[2]{type=sub}O, !adf:underline[signed].