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

Answer architecture round 1: 0 🔴, 2 🟡; the slot's line ending is a value the slot does not take, and its message offers the space again

This commit is contained in:
2026-10-14 00:05:02 +02:00
committed by Lillem4n
parent ed401ec7b6
commit 5cd07cafec
5 changed files with 7 additions and 7 deletions
+1 -1
View File
@@ -29,7 +29,7 @@
`content` key.
- **Breaking:** `unspellable-character`, `unspellable-line-start` and `unspellable-whitespace` leave
`ConvertErrorCode`. A line ending in an `emoji`, `mention` or `status` directive's content slot is
`unsupported-node-shape`, as a null character there already was. A carriage return in text is
refused as `unsupported-node-shape`. A carriage return in text is
spelled `
` and a null character `!adf:text{text="\u0000"}`; a paragraph line opening with a
code span is spelled as that code span, its backticks opening no fence; a code block holding
either character, a code span holding a null character, a text node holding no text or holding
+1 -1
View File
@@ -448,7 +448,7 @@ Every call can raise these:
| --- | --- | --- |
| `engine-limit` | in every call: a conversion that passes the longest array, `Map` or `Set` the JavaScript engine builds, or that the engine reports as out of memory; on JavaScriptCore (Bun, Safari), also one that passes its longest string, 2^31 − 1 characters | retry once; if it repeats, writing: set the document aside, keeping the ADF and passing it over or showing it read-only; reading: shorten the markdown, or nest its lists and quotes less deeply |
| `unsupported-nesting-depth` | blocks, marks, an attribute's JSON or a carried node's JSON nest past 500 levels | keep the ADF and pass the document over, or show it read-only; flatten the input where you are the one who wrote it |
| `unsupported-node-shape` | parsing, in `losslessMarkdownToAdf`: markdown spells a node with an attribute, value, argument or body its type does not take, or without one it needs, puts a line ending or a null character in an `emoji`, `mention` or `status` content slot, wraps a directive mark around nothing or only hard breaks, writes as a directive a node or mark the lossless flavour spells as CommonMark, or one that, written out as plain CommonMark, would be longer than 536870888 characters, or puts a reserved directive out of place: `!adf:textBreak{}` parting nothing, `!adf:doc` anywhere but as the whole document. Emitting, in `adfToLosslessMarkdown`: a node not riding the carry that carries one mark type twice, a block or a non-text inline node holding `text`, or a leaf block or a non-text inline node holding `content`. Emitting, in `adfToPortableMarkdown`: a line or task list the portable writer cannot spell, a bug in this library. Emitting, in both writers: a document whose markdown would be longer than 536870888 characters, V8's longest string, on every engine; in `adfToPortableMarkdown`, also a document whose text alone is that long, edge whitespace included. In every call: a conversion that passes V8's or SpiderMonkey's longest string | fix what the message names; [`spec/flavour.md`](https://github.com/larvit/adf-codec/blob/main/spec/flavour.md) lists every type's attributes and body. For a line ending or null character in a content slot, write the node as `!adf:carry`. For a portable line or task list, report it as a bug. Past 536870888 characters or the engine's longest string, writing: set the document aside, keeping the ADF and passing it over or showing it read-only; reading: shorten the markdown, or nest its lists and quotes less deeply |
| `unsupported-node-shape` | parsing, in `losslessMarkdownToAdf`: markdown spells a node with an attribute, value, argument or body its type does not take, or without one it needs, puts a line ending or a null character in an `emoji`, `mention` or `status` content slot, wraps a directive mark around nothing or only hard breaks, writes as a directive a node or mark the lossless flavour spells as CommonMark, or one that, written out as plain CommonMark, would be longer than 536870888 characters, or puts a reserved directive out of place: `!adf:textBreak{}` parting nothing, `!adf:doc` anywhere but as the whole document. Emitting, in `adfToLosslessMarkdown`: a node not riding the carry that carries one mark type twice, a block or a non-text inline node holding `text`, or a leaf block or a non-text inline node holding `content`. Emitting, in `adfToPortableMarkdown`: a line or task list the portable writer cannot spell, a bug in this library. Emitting, in both writers: a document whose markdown would be longer than 536870888 characters, V8's longest string, on every engine; in `adfToPortableMarkdown`, also a document whose text alone is that long, edge whitespace included. In every call: a conversion that passes V8's or SpiderMonkey's longest string | fix what the message names; [`spec/flavour.md`](https://github.com/larvit/adf-codec/blob/main/spec/flavour.md) lists every type's attributes and body. For a line ending in a content slot, replace it with a space; for it or a null character, write the node as `!adf:carry`. For a portable line or task list, report it as a bug. Past 536870888 characters or the engine's longest string, writing: set the document aside, keeping the ADF and passing it over or showing it read-only; reading: shorten the markdown, or nest its lists and quotes less deeply |
## The guarantees
+3 -3
View File
@@ -437,9 +437,9 @@ handles one cause alike whichever node, attribute or direction raised it.
- A code names the cause; where one cause recurs across node types, across one mark's attributes
or across directions, one code covers them all and `path` and `message` say which —
`unsupported-nesting-depth` is the 500-level guard whichever direction hits it.
A line ending or a null character an inline directive's content slot spells in input is
`unsupported-node-shape`, as both take one fix, the carry; the emitter carries such a node
(2026-10-14).
A line ending or a null character in an inline directive's content slot is a value the slot does
not take, so `unsupported-node-shape` as below, `message` naming the character; the emitter
carries such a node (2026-10-14).
- A claim code names the spelling claimed, never the node that spelling would have built: a
malformed `!adf:table` is a `malformed-directive`, and an alignment colon a
`malformed-pipe-table` — the flavour's own delimiter row is `-` runs, so the grammar refuses the
+1 -1
View File
@@ -107,7 +107,7 @@ export function readSoleStringAttribute(span: DirectiveSpan, key: string): Read<
// An inline directive never spans lines, and no content slot holds a null character; the emitter carries such a node.
export function slotFault(type: string, text: string): ConvertFault | undefined {
if (/[\n\r]/.test(text)) return unsupportedNodeShape(`the ${type} content slot holds a line ending, which no inline directive spans: write the node as !adf:carry`)
if (/[\n\r]/.test(text)) return unsupportedNodeShape(`the ${type} content slot holds a line ending, which no inline directive spans: replace it with a space, or write the node as !adf:carry`)
return holdsNullCharacter(text) ? unsupportedNodeShape(`the ${type} content slot holds a null character: write the node as !adf:carry`) : undefined
}
+1 -1
View File
@@ -1103,7 +1103,7 @@ test('names the content slot no lone plain text node reads back from', () => {
assert.equal(code(losslessMarkdownToAdf('!adf:status[<div>]{color=yellow}\n')), 'unmappable-html')
assert.equal(code(losslessMarkdownToAdf('!adf:date[<div>]{timestamp=1}\n')), 'unmappable-html')
assert.equal(code(losslessMarkdownToAdf('!adf:widget[<div>]\n')), 'unmappable-html')
const spans = 'unsupported-node-shape: the status content slot holds a line ending, which no inline directive spans: write the node as !adf:carry'
const spans = 'unsupported-node-shape: the status content slot holds a line ending, which no inline directive spans: replace it with a space, or write the node as !adf:carry'
assert.equal(content(losslessMarkdownToAdf('!adf:status[!adf:text{text="\\n"}]{color=yellow}\n')), spans)
assert.equal(content(losslessMarkdownToAdf('!adf:status[a&#10;b]{color=yellow}\n')), spans)
assert.equal(content(losslessMarkdownToAdf('!adf:status[a&#13;b]{color=yellow}\n')), spans)