Skip to content

Commit 1acdef5

Browse files
authoredNov 22, 2023
Remove json-parse-even-better-errors dependency (#47)
1 parent 1927b6d commit 1acdef5

File tree

3 files changed

+45
-18
lines changed

3 files changed

+45
-18
lines changed
 

‎index.js

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
import fallback from 'json-parse-even-better-errors';
21
import {codeFrameColumns} from '@babel/code-frame';
32
import indexToPosition from 'index-to-position';
43

4+
const getCodePoint = character => `\\u{${character.codePointAt(0).toString(16)}}`;
5+
56
export class JSONError extends Error {
67
name = 'JSONError';
78
fileName;
@@ -32,7 +33,7 @@ const generateCodeFrame = (string, location, highlightCode = true) =>
3233
codeFrameColumns(string, {start: location}, {highlightCode});
3334

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

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

58-
export default function parseJson(string, reviver, filename) {
59+
const addCodePointToUnexpectedToken = message => message.replace(
60+
// TODO[engine:node@>=20]: The token always quoted after Node.js 20
61+
/(?<=^Unexpected token )(?<quote>')?(.)\k<quote>/,
62+
(_, _quote, token) => `"${token}"(${getCodePoint(token)})`,
63+
);
64+
65+
export default function parseJson(string, reviver, fileName) {
5966
if (typeof reviver === 'string') {
60-
filename = reviver;
67+
fileName = reviver;
6168
reviver = undefined;
6269
}
6370

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

71-
try {
72-
fallback(string, reviver);
73-
} catch (error) {
74-
message = error.message;
78+
let location;
79+
if (string) {
80+
location = getErrorLocation(string, message);
81+
message = addCodePointToUnexpectedToken(message);
82+
} else {
83+
message += ' while parsing empty string';
7584
}
7685

77-
message = message.replaceAll('\n', '');
7886
const jsonError = new JSONError(message);
7987

80-
if (filename) {
81-
jsonError.fileName = filename;
82-
}
88+
jsonError.fileName = fileName;
8389

84-
const location = getErrorLocation(string, message);
8590
if (location) {
8691
jsonError.codeFrame = generateCodeFrame(string, location);
8792
jsonError.rawCodeFrame = generateCodeFrame(string, location, /* highlightCode */ false);

‎package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@
3939
],
4040
"dependencies": {
4141
"@babel/code-frame": "^7.22.13",
42-
"index-to-position": "^0.1.1",
43-
"json-parse-even-better-errors": "^3.0.0",
42+
"index-to-position": "^0.1.2",
4443
"type-fest": "^4.7.1"
4544
},
4645
"devDependencies": {

‎test.js

+26-3
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ const NODE_JS_VERSION = Number(process.versions.node.split('.')[0]);
88

99
const errorMessageRegex = (() => {
1010
if (NODE_JS_VERSION < 20) {
11-
return /Unexpected token "}"/;
11+
return /Unexpected token "}"\(\\u{7d}\) in JSON at position 16/;
1212
}
1313

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

18-
return /Expected double-quoted property name in JSON at position 16 \(line 3 column 1\) while parsing/;
18+
return /Expected double-quoted property name in JSON at position 16 \(line 3 column 1\)/;
1919
})();
2020
const errorMessageRegexWithFileName = new RegExp(errorMessageRegex.source + '.*in foo\\.json');
2121
const INVALID_JSON_STRING = outdent`
@@ -103,6 +103,29 @@ test('empty string', t => {
103103
parseJson('');
104104
} catch (error) {
105105
t.true(error instanceof JSONError);
106+
t.is(error.message, 'Unexpected end of JSON input while parsing empty string');
106107
t.is(error.rawCodeFrame, undefined);
107108
}
109+
110+
try {
111+
parseJson(' ');
112+
} catch (error) {
113+
t.true(error instanceof JSONError);
114+
t.is(error.message, 'Unexpected end of JSON input');
115+
t.is(error.rawCodeFrame, undefined);
116+
}
117+
});
118+
119+
test('Unexpected tokens', t => {
120+
try {
121+
parseJson('a');
122+
} catch (error) {
123+
t.true(error instanceof JSONError);
124+
const firstLine = error.message.split('\n')[0];
125+
if (NODE_JS_VERSION === 18) {
126+
t.is(firstLine, 'Unexpected token "a"(\\u{61}) in JSON at position 0');
127+
} else {
128+
t.is(firstLine, 'Unexpected token "a"(\\u{61}), "a" is not valid JSON');
129+
}
130+
}
108131
});

0 commit comments

Comments
 (0)
Please sign in to comment.