mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-08 08:44:37 +08:00
JSON.parse's SyntaxError messages were shaped like V8's but differed from
Node's in several ways:
- Every positional message now ends with V8's "(line L column C)", where
\n, \r and \r\n end lines.
- Positions are UTF-16 offsets, as in Node, not byte offsets.
- An object or array cut off after '{', a property name, a value or an
array element reports the token V8 expected ("Expected property name or
'}'", "Expected ':' after property name", "Expected ',' or '}' after
property value", "Expected ',' or ']' after array element") instead of
"Unexpected end of JSON input".
- After a comma in an object the message is "Expected double-quoted
property name".
- An unterminated string reports the end of the input, and a truncated
\u escape is a "Bad Unicode escape" there.
- A leading zero followed by a digit is an "Unexpected number".
- A misspelled literal names the first differing character, or the end of
the input.
- An unexpected character is named with the source as V8 does: whole when
it is under 21 units, otherwise ten units of context on each side; the
sources "NaN", "Infinity", "undefined" and "[object Object]" name only
themselves; a quote or a number there is an "Unexpected string" or
"Unexpected number".
The new corpus program 7993-json-parse-error-messages pins 76 inputs
against Node, including non-ASCII text before the error, line breaks, and
long sources with split surrogate pairs at the context edges.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
31 lines
1.8 KiB
TypeScript
31 lines
1.8 KiB
TypeScript
// JSON.parse syntax error messages, exactly as Node's V8 writes them: the
|
|
// expected token at the end of the input inside objects and arrays, the
|
|
// position as a UTF-16 offset with its line and column (\n, \r and \r\n
|
|
// end lines), the unexpected character named with the source (whole when
|
|
// short, ten units of context on each side when longer), and the special
|
|
// sources that name only themselves.
|
|
const inputs: string[] = [
|
|
"", " ", "[", "[{", "{", '{"a"', '{"a":', '{"a":1', '{"a":1,', '{"a":1,}', "{,", "{1:2}", "{'a':1}",
|
|
'{"a" 1}', '{"a":1 "b":2}', "[1", "[1,", "[1,]", "[1 2]", "[,1]", '"abc', '"a\\', '"\\u12', '"\\u12x4"',
|
|
'"\\u12"', '"\\x"', "tru", "nul", "fals", "t1", 'n"', "-", "-x", "1.", "1.e", "1e", "1e+", "01", "-01",
|
|
"[01]", "+1", "1 2", "{} x", "[]]", "\u0001", '"\u0001"', '{"a":[1,{"b":', '[{"a":1},', '{"a":{"b":{}',
|
|
"[[[", " [ \n { \n", "\n\n{", "\r\n\r\n{", "\r\r{", '{"a":tru}', "NaN", "Infinity", "undefined",
|
|
"[object Object]", " NaN", "-Infinity", "[-]",
|
|
// Positions count UTF-16 units: non-ASCII text before the error.
|
|
'{"é":1 x}', '["😀" 1]', '{"😀😀":', '"é\u0001"', "é",
|
|
// Long sources: the unexpected character with its context.
|
|
'{"name":"some long value","other":x}', '[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,]',
|
|
'x{"name":"some long value","other":1}', '{"name":"some long value","other":1}x', '{"a":"0123456789abcdef"x}',
|
|
'["😀😀😀😀😀😀", x, "😀😀😀😀😀😀"]', '["😀😀😀😀😀😀",x]', '{"k":[true,false,null,"s",1.5e3,-2] ]',
|
|
'\n\n {\n "a": [1, 2,\n 3 4]\n }',
|
|
];
|
|
for (const text of inputs) {
|
|
try {
|
|
JSON.parse(text);
|
|
console.log(JSON.stringify(text), "parsed");
|
|
} catch (e) {
|
|
const err = e as Error;
|
|
console.log(JSON.stringify(text), err.name, JSON.stringify(err.message));
|
|
}
|
|
}
|