diff --git a/MIGRATION.md b/MIGRATION.md index 2ed7b74..c6bf824 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -3,14 +3,14 @@ ## From `0.2.0` to `0.3.0` Every reader skips code text when it spells a mark other than a link, and `losslessMarkdownToAdf` -also skips every other node Atlassian's schema withholds the mark from, text included for `border`: +also skips every other node Atlassian's schema withholds the mark from: | Input | `0.2.0` | `0.3.0` | | --- | --- | --- | | a `date`, `emoji`, `inlineCard`, `mention`, `status` or `mediaInline` inside a mark's spelling (`**!adf:mention[@A]{id=x}**`) | the node holds the mark | the node holds only marks its type takes; text beside it keeps the mark | | a link around only nodes that cannot take it, hard breaks aside, or a directive mark around only such nodes or code spans (`[!adf:status[Done]{color=green}](/u)`) | the nodes hold the mark | `unsupported-node-shape`; write the mark around text beside them | | a code span inside any mark's spelling but a link's (``**`npm ci`**``) | the code text holds the mark | the code text holds only `code`, and a link where one wraps it | -| text inside `!adf:border[…]` (`!adf:border[x]{color="#091e42" size=2}`) | the text holds `border` | `unsupported-node-shape` where the mark wraps only text, else the text holds no `border`; `border` marks a `mediaInline` alone | +| text inside `!adf:border[…]` (`!adf:border[x]{color="#091e42" size=2}`) | the text holds `border` | the text holds none, and where nothing the spelling wraps takes `border`, `unsupported-node-shape`: delete the spelling and keep its text. Only a `mediaInline` takes `border` | `0.3.0`'s `adfToLosslessMarkdown` writes a node holding a withheld mark as `!adf:carry{json="…"}`, where `0.2.0` wrote these spellings. `0.3.0` reads markdown stored from such a document without the diff --git a/README.md b/README.md index d2e5b78..06aa83e 100644 --- a/README.md +++ b/README.md @@ -412,7 +412,6 @@ Ping !adf:mention[@Mikael]{id=5b10a2} — !adf:status[In review]{color=yellow} | --- | --- | | `blockquote`, `bulletList`, `codeBlock`, `heading`, `listItem`, `orderedList`, `paragraph`, `rule` carrying `localId`, marks or a value CommonMark cannot spell | the same node in directive form, `!adf:paragraph {localId=…}` | | `border` | an inline directive mark around a `mediaInline`, the one inline node that takes it | -| `subsup`, `textColor`, `underline` | inline directive marks around their text, `!adf:textColor[**Overdue**]{color="#ae2e24"}` | | `caption`, `media`, `mediaGroup`, `mediaSingle` | the media family; an image CommonMark cannot spell, a stored file, a caption | | `date`, `emoji`, `inlineCard`, `mediaInline`, `mention`, `status` | inline leaves; `emoji`, `mention` and `status` spell their `text` in the `[content]` slot | | `decisionList`, `decisionItem` | containers | @@ -421,6 +420,7 @@ Ping !adf:mention[@Mikael]{id=5b10a2} — !adf:status[In review]{color=yellow} | `layoutSection`, `layoutColumn` | containers | | `link` with an attribute besides `href` and `title`, or a target CommonMark cannot spell | `!adf:link[text]{attrs}` | | `panel` | a container, the type its argument: `!adf:panel info` | +| `subsup`, `textColor`, `underline` | inline directive marks around their text, `!adf:textColor[**Overdue**]{color="#ae2e24"}` | | `syncBlock`, `bodiedSyncBlock` | a leaf and a container | | `table`, `tableRow`, `tableCell`, `tableHeader` richer than a pipe table | containers nesting block content | | `taskList`, `taskItem`, `blockTaskItem` | containers, the state an argument: `!adf:taskItem DONE` | @@ -625,7 +625,7 @@ Every call can raise these: - puts a line ending or a null character in an `emoji`, `mention` or `status` content slot: replace a line ending with a space, or, for either, write the node as `!adf:carry`; - wraps a directive mark around nothing, or only around nodes that take no such mark, such as a - hard break, a mention or a code span; + hard break, a mention, a code span or, for `border`, text; - writes a link whose text holds something besides hard breaks, but no node that takes a link, such as `[!adf:status[Done]{color=green}](/u)`: write the link around text beside them; - writes as a directive a node or mark the lossless flavour spells as CommonMark; diff --git a/src/markdown/inline-content.ts b/src/markdown/inline-content.ts index 766ef80..9af406d 100644 --- a/src/markdown/inline-content.ts +++ b/src/markdown/inline-content.ts @@ -259,7 +259,8 @@ function directiveMarkPieces(scan: Scan, name: string, mark: AdfMark, slot: read } if (nodes.some(holdsOwnMarks)) return failure('unsupported-node-shape', ownMarksInMark, scan.shared.path) if (!nodes.some((node) => marksItem(node, mark.type))) { - return failure('unsupported-node-shape', `the ${name} mark wraps the [content] it marks: this one wraps only nodes that take no ${name} mark: write the ${name} mark around text beside them`, scan.shared.path) + const fix = mark.type === 'border' ? 'only a mediaInline takes border: delete the border spelling' : `write the ${name} mark around text beside them` + return failure('unsupported-node-shape', `the ${name} mark wraps the [content] it marks: this one wraps only nodes that take no ${name} mark: ${fix}`, scan.shared.path) } const refused = mark.type === 'link' ? refuseLinkDirective(scan, mark, nodes, index) : undefined if (refused !== undefined) return refused diff --git a/src/markdown/parse/markdown-to-adf.test.ts b/src/markdown/parse/markdown-to-adf.test.ts index b38c02a..8fedf61 100644 --- a/src/markdown/parse/markdown-to-adf.test.ts +++ b/src/markdown/parse/markdown-to-adf.test.ts @@ -927,7 +927,7 @@ test('gives an inline node no mark Atlassian\'s schema withholds from it', () => assert.deepEqual(read('!adf:border[!adf:mediaInline{id=m1}]{color="#091e42" size=2}\n'), [{ content: [{ ...media, marks: [border] }], type: 'paragraph' }]) assert.deepEqual(read('[!adf:mediaInline{id=m1}](/u)\n'), [{ content: [{ ...media, marks: [link('/u')] }], type: 'paragraph' }]) assert.deepEqual(read('!adf:border[a !adf:mediaInline{id=m1}]{color="#091e42" size=2}\n'), [{ content: [{ text: 'a ', type: 'text' }, { ...media, marks: [border] }], type: 'paragraph' }]) - const unborderable = 'unsupported-node-shape: the border mark wraps the [content] it marks: this one wraps only nodes that take no border mark: write the border mark around text beside them' + const unborderable = 'unsupported-node-shape: the border mark wraps the [content] it marks: this one wraps only nodes that take no border mark: only a mediaInline takes border: delete the border spelling' assert.equal(read('!adf:border[a]{color="#091e42" size=2}\n'), unborderable) assert.equal(read('_!adf:border[a]{color="#091e42" size=2}_\n'), unborderable) assert.equal(read('!adf:underline[!adf:border[a]{color="#091e42" size=2}]\n'), unborderable)