diff --git a/AGENTS.md b/AGENTS.md index d793301..8d6e6d2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,9 +91,10 @@ Pre-1.0, normal 0.x rules. The error surface is a contract too. `ConvertError` is `{ code, message, path, position? }` — the code from a closed list a consumer may switch exhaustively, the message free text, the path the node's place from the document root, the position where a parse read the refusal in its input. -A message reads `rule: violation` — a rule alone states a truth the reader must invert before it -reads as a failure — and where the flavour's claim refuses ordinary prose it names the escape that -unclaims the form claimed: `\:::` or `\|` for a line, `\:` for an inline directive. +A message names the violation, not the rule alone — a rule by itself states a truth the reader +must invert before it reads as a failure — and where the flavour's claim refuses ordinary prose it +names the escape that unclaims the form claimed: `\:::` for a directive line, `\|` for every pipe +row, `\:` for an inline directive. Adding, removing or renaming a code is breaking, so a milestone meeting a new failure cause reuses a code where one fits; the list is complete at `0.1.0`. A code names the cause; where one cause recurs across node types or across directions, one code covers them all and diff --git a/src/adf/document.test.ts b/src/adf/document.test.ts index 5da7137..149f40f 100644 --- a/src/adf/document.test.ts +++ b/src/adf/document.test.ts @@ -19,6 +19,8 @@ test('names the check anything that is not a doc node failed', () => { assert.equal(fault(undefined), 'an ADF document is an object: found undefined') assert.equal(fault([]), 'an ADF document is an object: found an array') assert.equal(fault('doc'), 'an ADF document is an object: found "doc"') + assert.equal(fault('x'.repeat(200000)), `an ADF document is an object: found "${'x'.repeat(40)}…"`) + assert.equal(fault(function named(first: number, second: number) { return first + second }), 'an ADF document is an object: found a function') assert.equal(fault({ fields: { description: { type: 'doc', version: 1 } } }), 'an ADF document holds content, type and version alone: found the key fields') assert.equal(fault({ extra: 1, type: 'doc', version: 1 }), 'an ADF document holds content, type and version alone: found the key extra') assert.equal(fault({ version: 1 }), 'an ADF document holds type "doc": found no type field') diff --git a/src/adf/document.ts b/src/adf/document.ts index e3a76bd..cfa8afe 100644 --- a/src/adf/document.ts +++ b/src/adf/document.ts @@ -90,7 +90,8 @@ function isRecord(value: unknown): value is Record { } function describe(value: unknown): string { - if (typeof value === 'string') return JSON.stringify(value) + if (typeof value === 'string') return JSON.stringify(value.length > 40 ? `${value.slice(0, 40)}…` : value) + if (typeof value === 'function') return 'a function' if (typeof value === 'object' && value !== null) return Array.isArray(value) ? 'an array' : 'an object' return String(value) } diff --git a/src/markdown/parse/blocks.ts b/src/markdown/parse/blocks.ts index 051c0a4..0eb6a49 100644 --- a/src/markdown/parse/blocks.ts +++ b/src/markdown/parse/blocks.ts @@ -406,7 +406,7 @@ function pipeTableBlock(rows: readonly [string[], ...string[][]], position: Sour return faultedBlock('a pipe table carries no column alignment ADF could hold: this delimiter row holds an alignment colon', position) } if (delimiter === undefined || !delimiter.every(isPipeDelimiter)) { - return faultedBlock('a pipe table underlines its header with a row of `-` runs: this one has none; \\| keeps the line literal text', position) + return faultedBlock('a pipe table underlines its header with a row of `-` runs: this one has none; \\| at the start of every row keeps them literal text', position) } const ragged = [delimiter, ...body].find((row) => row.length !== header.length) if (ragged !== undefined) return faultedBlock(`a pipe table row holds ${cellCount(ragged.length)} where its header holds ${cellCount(header.length)}`, position) diff --git a/src/markdown/parse/markdown-to-adf.test.ts b/src/markdown/parse/markdown-to-adf.test.ts index 1d1e99c..93675a5 100644 --- a/src/markdown/parse/markdown-to-adf.test.ts +++ b/src/markdown/parse/markdown-to-adf.test.ts @@ -182,8 +182,8 @@ test('claims the line a pipe opens and gives the rest back to the block walk', ( }) test('names the pipe table a claimed line does not spell', () => { - assert.equal(content(markdownToAdf('| a | b |\n')), 'malformed-pipe-table: a pipe table underlines its header with a row of `-` runs: this one has none; \\| keeps the line literal text') - assert.equal(content(markdownToAdf('| a |\n| x |\n')), 'malformed-pipe-table: a pipe table underlines its header with a row of `-` runs: this one has none; \\| keeps the line literal text') + assert.equal(content(markdownToAdf('| a | b |\n')), 'malformed-pipe-table: a pipe table underlines its header with a row of `-` runs: this one has none; \\| at the start of every row keeps them literal text') + assert.equal(content(markdownToAdf('| a |\n| x |\n')), 'malformed-pipe-table: a pipe table underlines its header with a row of `-` runs: this one has none; \\| at the start of every row keeps them literal text') assert.equal(content(markdownToAdf('| a | b |\n| :--- | ---: |\n')), 'malformed-pipe-table: a pipe table carries no column alignment ADF could hold: this delimiter row holds an alignment colon') assert.equal(content(markdownToAdf('| a | b |\n| --- |\n')), 'malformed-pipe-table: a pipe table row holds 1 cell where its header holds 2 cells') assert.equal(content(markdownToAdf('| a |\n| --- |\n| b | c |\n')), 'malformed-pipe-table: a pipe table row holds 2 cells where its header holds 1 cell')