Skip to content

Commit

Permalink
Remove json-parse-even-better-errors dependency (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker committed Nov 22, 2023
1 parent 1927b6d commit 1acdef5
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 18 deletions.
31 changes: 18 additions & 13 deletions index.js
@@ -1,7 +1,8 @@
import fallback from 'json-parse-even-better-errors';
import {codeFrameColumns} from '@babel/code-frame';
import indexToPosition from 'index-to-position';

const getCodePoint = character => `\\u{${character.codePointAt(0).toString(16)}}`;

export class JSONError extends Error {
name = 'JSONError';
fileName;
Expand Down Expand Up @@ -32,7 +33,7 @@ const generateCodeFrame = (string, location, highlightCode = true) =>
codeFrameColumns(string, {start: location}, {highlightCode});

const getErrorLocation = (string, message) => {
const match = message.match(/in JSON at position (?<index>\d+)(?: \(line (?<line>\d+) column (?<column>\d+)\))? while parsing/);
const match = message.match(/in JSON at position (?<index>\d+)(?: \(line (?<line>\d+) column (?<column>\d+)\))?$/);

if (!match) {
return;
Expand All @@ -55,9 +56,15 @@ const getErrorLocation = (string, message) => {
return indexToPosition(string, index, {oneBased: true});
};

export default function parseJson(string, reviver, filename) {
const addCodePointToUnexpectedToken = message => message.replace(
// TODO[engine:node@>=20]: The token always quoted after Node.js 20
/(?<=^Unexpected token )(?<quote>')?(.)\k<quote>/,
(_, _quote, token) => `"${token}"(${getCodePoint(token)})`,
);

export default function parseJson(string, reviver, fileName) {
if (typeof reviver === 'string') {
filename = reviver;
fileName = reviver;
reviver = undefined;
}

Expand All @@ -68,20 +75,18 @@ export default function parseJson(string, reviver, filename) {
message = error.message;
}

try {
fallback(string, reviver);
} catch (error) {
message = error.message;
let location;
if (string) {
location = getErrorLocation(string, message);
message = addCodePointToUnexpectedToken(message);
} else {
message += ' while parsing empty string';
}

message = message.replaceAll('\n', '');
const jsonError = new JSONError(message);

if (filename) {
jsonError.fileName = filename;
}
jsonError.fileName = fileName;

const location = getErrorLocation(string, message);
if (location) {
jsonError.codeFrame = generateCodeFrame(string, location);
jsonError.rawCodeFrame = generateCodeFrame(string, location, /* highlightCode */ false);
Expand Down
3 changes: 1 addition & 2 deletions package.json
Expand Up @@ -39,8 +39,7 @@
],
"dependencies": {
"@babel/code-frame": "^7.22.13",
"index-to-position": "^0.1.1",
"json-parse-even-better-errors": "^3.0.0",
"index-to-position": "^0.1.2",
"type-fest": "^4.7.1"
},
"devDependencies": {
Expand Down
29 changes: 26 additions & 3 deletions test.js
Expand Up @@ -8,14 +8,14 @@ const NODE_JS_VERSION = Number(process.versions.node.split('.')[0]);

const errorMessageRegex = (() => {
if (NODE_JS_VERSION < 20) {
return /Unexpected token "}"/;
return /Unexpected token "}"\(\\u{7d}\) in JSON at position 16/;
}

if (NODE_JS_VERSION < 21) {
return /Expected double-quoted property name in JSON at position 16 while parsing/;
return /Expected double-quoted property name in JSON at position 16/;
}

return /Expected double-quoted property name in JSON at position 16 \(line 3 column 1\) while parsing/;
return /Expected double-quoted property name in JSON at position 16 \(line 3 column 1\)/;
})();
const errorMessageRegexWithFileName = new RegExp(errorMessageRegex.source + '.*in foo\\.json');
const INVALID_JSON_STRING = outdent`
Expand Down Expand Up @@ -103,6 +103,29 @@ test('empty string', t => {
parseJson('');
} catch (error) {
t.true(error instanceof JSONError);
t.is(error.message, 'Unexpected end of JSON input while parsing empty string');
t.is(error.rawCodeFrame, undefined);
}

try {
parseJson(' ');
} catch (error) {
t.true(error instanceof JSONError);
t.is(error.message, 'Unexpected end of JSON input');
t.is(error.rawCodeFrame, undefined);
}
});

test('Unexpected tokens', t => {
try {
parseJson('a');
} catch (error) {
t.true(error instanceof JSONError);
const firstLine = error.message.split('\n')[0];
if (NODE_JS_VERSION === 18) {
t.is(firstLine, 'Unexpected token "a"(\\u{61}) in JSON at position 0');
} else {
t.is(firstLine, 'Unexpected token "a"(\\u{61}), "a" is not valid JSON');
}
}
});

0 comments on commit 1acdef5

Please sign in to comment.