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

Answer product-owner round 2: one retry rule, any unsupported-node-shape at the empty path, in the paragraph and the error table, and the memory refusal says it ran the engine out of memory

This commit is contained in:
2026-10-13 12:04:22 +02:00
parent e6fa3db1f5
commit 2b5992858e
3 changed files with 5 additions and 5 deletions
+3 -3
View File
@@ -411,8 +411,8 @@ typed on `ConvertError` takes both.
A call reports the first refusal in document order and stops, so a document with several surfaces
them one per call. Every refusal is deterministic — there is no I/O anywhere — so a retry returns
the identical error: fix the input, or set the document aside. The exception is memory running
short, which an engine may report as `unsupported-node-shape` at the empty path, and JavaScriptCore
(Bun, Safari) reports the same way as a string too long to build: retry such a call once.
short, which returns `unsupported-node-shape` at the empty path, the code and path of markdown past
the length bound. Retry once any call that returns that; a repeat is a lasting refusal.
### Parsing
@@ -445,7 +445,7 @@ The emitter raises these, and so does a parse, which asks the emitter how to spe
| Code | Fires when | What you can do |
| --- | --- | --- |
| `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, 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 the longest string or array the JavaScript engine builds | 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 portable line or task list, report it as a bug. Past 536870888 characters or the engine's limit, 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, 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 the longest string or array the JavaScript engine builds, or runs it short of memory | 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 portable line or task list, report it as a bug. Past 536870888 characters or the engine's limit, 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 |
## The guarantees
+1 -1
View File
@@ -27,7 +27,7 @@ test('refuses a string past the bound as too long on every engine, and names any
assert.deepEqual(withinEngineLimits(thrown('RangeError', 'Invalid string length')), tooLong())
assert.deepEqual(withinEngineLimits(thrown('InternalError', 'allocation size overflow')), tooLong())
assert.deepEqual(withinEngineLimits(thrown('RangeError', 'Out of memory')), {
error: { code: 'unsupported-node-shape', message: 'the conversion passed this JavaScript engine\'s longest string or array, or its heap (Out of memory)', path: [] },
error: { code: 'unsupported-node-shape', message: 'the conversion passed this JavaScript engine\'s longest string or array, or ran it out of memory (Out of memory)', path: [] },
ok: false,
})
assert.equal(withinEngineLimits(thrown('RangeError', 'Invalid array length')).ok, false)
+1 -1
View File
@@ -36,6 +36,6 @@ export function withinEngineLimits<T>(convert: () => Result<T>): Result<T> {
if (pastLongestString.includes(thrown)) return tooLong()
// A stack overflow is a bug (docs/decisions.md §Nothing recurses unbounded), so it stays a throw.
if (!pastEngineLimit.includes(thrown)) throw error
return failure('unsupported-node-shape', `the conversion passed this JavaScript engine's longest string or array, or its heap (${error.message})`, [])
return failure('unsupported-node-shape', `the conversion passed this JavaScript engine's longest string or array, or ran it out of memory (${error.message})`, [])
}
}