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

Answer prose round 1: 0 🔴, 6 🟡 (0 misread); reword the spanning comments, spec and changelog entry

This commit is contained in:
2026-10-31 03:56:44 +01:00
committed by Lillem4n
parent f77b9f91a1
commit b2b124277a
4 changed files with 17 additions and 13 deletions
+8 -6
View File
@@ -33,12 +33,14 @@
`!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.
- `adfToLosslessMarkdown` and `adfToPortableMarkdown` write an emphasis or a link once across the
hard breaks between two texts it marks: `_One\` then `Two_`, where they wrote `_One_\` then
`_Two_`. They write an emphasis once across code spans, as ``**Run `npm ci` first**``, and
`adfToLosslessMarkdown` also across mentions, emoji, dates, statuses, inline cards and inline
media, as `**Ping !adf:mention[@A]{id=x} now**`, and a link across those but inline media. Each
reads back as before; a line that would read back otherwise is written as before.
- `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
span: ``**Run `npm ci` first**``. `adfToLosslessMarkdown` also writes those three once across
mentions, emoji, dates, statuses, inline cards and inline media, as
`**Ping !adf:mention[@A]{id=x} now**`, and a link once across mentions, emoji, dates, statuses
and inline cards. The markdown reads back to the same ADF as before. Where the joined line would
not, the writers write the line as before.
- Every reader keeps the URL and title of an image inside a link's text, where it dropped them:
after the link comes `(image)`, which links to the image, so
`[look at ![the moon](moon.png "Full") tonight](/moon)` reads as
+6 -4
View File
@@ -564,10 +564,12 @@ marks array in order, outermost first: `_!adf:underline[x]_` gives marks `[em, u
the array, not a set — and opens each spelling once over the longest run of adjacent inline nodes
carrying an identical mark, attributes included, at that depth: `attrs: {}` differs from no `attrs`,
and a directive spells it `{attrs=empty}`. A run breaks at every node the emitter carries, so no
emitted carry sits inside a mark spelling. An emphasis or link run also spans the nodes between two
it marks that take no mark of its type, where the line reads back so: `_One\` then `Two_` is one
`em` over two texts and the hard break between, ``**Run `npm ci` first**`` one `strong` around
plain code. `adfToPortableMarkdown` spans hard breaks and code spans the same way.
emitted carry sits inside a mark spelling. An `em`, `strike`, `strong` or `link` run also spans a
node between two of its nodes when that node cannot hold the run's mark. It does so only where the
spanned line reads back to the same marks; otherwise the run breaks there. So `_One\` then `Two_`
is one `em` run over two texts, the hard break between them unmarked, and
``**Run `npm ci` first**`` is one `strong` run around unmarked code. `adfToPortableMarkdown` spans
hard breaks and code spans the same way.
An inline node whose marks no nesting spells — a node holding a mark Atlassian's schema withholds
from it, a mark type the first list above does not hold, an attrs key its spelling does not list, a value that is not the
+2 -2
View File
@@ -6,13 +6,13 @@ import { takesMark } from '../../adf/inline-nodes.ts'
type Carries = (node: AdfNode, index: number) => boolean
// The nodes, each that an emphasis or link run skips between two nodes it marks holding the run's mark at the run's depth, or `nodes` itself where no run skips one.
// Lends each emphasis or link run's mark to the nodes inside the run that cannot hold it; returns `nodes` itself where no run skips a node.
export function spanSkippedNodes(nodes: readonly AdfNode[], carries: Carries): readonly AdfNode[] {
const spanned = [...nodes]
return spanRuns(spanned, 0, spanned.length, 0, carries) ? spanned : nodes
}
// Groups the runs as `inlineRuns` does, then lends each run's mark to the nodes it skips; returns whether it lent any.
// Groups the runs as `inlineRuns` does.
function spanRuns(spanned: AdfNode[], first: number, end: number, depth: number, carries: Carries): boolean {
if (depth > largestNesting) return false
let lent = false
+1 -1
View File
@@ -166,7 +166,7 @@ export function trimmedEdges(leaves: readonly AdfNode[]): AdfNode[] {
// Terminates: a pass that changes a leaf drops whitespace from the leaf's edge or takes a mark off that whitespace, and merging adds no whitespace or mark.
for (let current = leaves; ; ) {
const merged = withoutEdgeBreaks(mergeAdjacentText(current, joinsWhenEditorNormal))
// Whitespace beside a code span a run spans keeps the run's mark, where the line written spanned reads it.
// Whitespace beside a code span inside a run keeps the run's mark, since the writer spans the run across the code.
const spanned = spanSkippedNodes(merged, () => false)
let changed = false
const trimmed: AdfNode[] = []