parse-json
Advanced tools
Comparing version
@@ -43,4 +43,4 @@ import type {JsonObject} from 'type-fest'; | ||
parseJson(json); | ||
// JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' | ||
// | ||
// JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
// 1 | { | ||
@@ -52,4 +52,4 @@ // 2 | "foo": true, | ||
parseJson(json, 'foo.json'); | ||
// JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' in foo.json | ||
// | ||
// JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) in foo.json | ||
// 1 | { | ||
@@ -59,2 +59,6 @@ // 2 | "foo": true, | ||
// | ^ | ||
// fileName: 'foo.json', | ||
// [cause]: SyntaxError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
// at JSON.parse (<anonymous>) | ||
// at ... | ||
@@ -71,4 +75,4 @@ // You can also add the filename at a later point | ||
} | ||
// JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' in foo.json | ||
// | ||
// JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) in foo.json | ||
// 1 | { | ||
@@ -78,2 +82,7 @@ // 2 | "foo": true, | ||
// | ^ | ||
// fileName: 'foo.json', | ||
// [cause]: SyntaxError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
// at JSON.parse (<anonymous>) | ||
// at ... | ||
``` | ||
@@ -98,4 +107,4 @@ */ | ||
parseJson(json); | ||
// JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' | ||
// | ||
// JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
// 1 | { | ||
@@ -107,4 +116,4 @@ // 2 | "foo": true, | ||
parseJson(json, 'foo.json'); | ||
// JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' in foo.json | ||
// | ||
// JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) in foo.json | ||
// 1 | { | ||
@@ -114,2 +123,6 @@ // 2 | "foo": true, | ||
// | ^ | ||
// fileName: 'foo.json', | ||
// [cause]: SyntaxError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
// at JSON.parse (<anonymous>) | ||
// at ... | ||
@@ -126,4 +139,4 @@ // You can also add the filename at a later point | ||
} | ||
// JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' in foo.json | ||
// | ||
// JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) in foo.json | ||
// 1 | { | ||
@@ -133,4 +146,9 @@ // 2 | "foo": true, | ||
// | ^ | ||
// fileName: 'foo.json', | ||
// [cause]: SyntaxError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
// at JSON.parse (<anonymous>) | ||
// at ... | ||
``` | ||
*/ | ||
export default function parseJson(string: string, filename?: string): JsonObject; |
88
index.js
@@ -9,12 +9,25 @@ import {codeFrameColumns} from '@babel/code-frame'; | ||
fileName; | ||
codeFrame; | ||
rawCodeFrame; | ||
#input; | ||
#jsonParseError; | ||
#message; | ||
#codeFrame; | ||
#rawCodeFrame; | ||
constructor(message) { | ||
// We cannot pass message to `super()`, otherwise the message accessor will be overridden. | ||
// https://262.ecma-international.org/14.0/#sec-error-message | ||
super(); | ||
constructor(messageOrOptions) { | ||
// JSONError constructor used accept string | ||
// TODO[>=9]: Remove this `if` on next major version | ||
if (typeof messageOrOptions === 'string') { | ||
super(); | ||
this.#message = messageOrOptions; | ||
} else { | ||
const {jsonParseError, fileName, input} = messageOrOptions; | ||
// We cannot pass message to `super()`, otherwise the message accessor will be overridden. | ||
// https://262.ecma-international.org/14.0/#sec-error-message | ||
super(undefined, {cause: jsonParseError}); | ||
this.#message = message; | ||
this.#input = input; | ||
this.#jsonParseError = jsonParseError; | ||
this.fileName = fileName; | ||
} | ||
Error.captureStackTrace?.(this, JSONError); | ||
@@ -24,4 +37,6 @@ } | ||
get message() { | ||
const {fileName, codeFrame} = this; | ||
return `${this.#message}${fileName ? ` in ${fileName}` : ''}${codeFrame ? `\n\n${codeFrame}\n` : ''}`; | ||
this.#message ??= `${addCodePointToUnexpectedToken(this.#jsonParseError.message)}${this.#input === '' ? ' while parsing empty string' : ''}`; | ||
const {codeFrame} = this; | ||
return `${this.#message}${this.fileName ? ` in ${this.fileName}` : ''}${codeFrame ? `\n\n${codeFrame}\n` : ''}`; | ||
} | ||
@@ -32,7 +47,30 @@ | ||
} | ||
#getCodeFrame(highlightCode) { | ||
// TODO[>=9]: Remove this `if` on next major version | ||
if (!this.#jsonParseError) { | ||
return; | ||
} | ||
const input = this.#input; | ||
const location = getErrorLocation(input, this.#jsonParseError.message); | ||
if (!location) { | ||
return; | ||
} | ||
return codeFrameColumns(input, {start: location}, {highlightCode}); | ||
} | ||
get codeFrame() { | ||
this.#codeFrame ??= this.#getCodeFrame(/* highlightCode */ true); | ||
return this.#codeFrame; | ||
} | ||
get rawCodeFrame() { | ||
this.#rawCodeFrame ??= this.#getCodeFrame(/* highlightCode */ false); | ||
return this.#rawCodeFrame; | ||
} | ||
} | ||
const generateCodeFrame = (string, location, highlightCode = true) => | ||
codeFrameColumns(string, {start: location}, {highlightCode}); | ||
const getErrorLocation = (string, message) => { | ||
@@ -74,27 +112,11 @@ const match = message.match(/in JSON at position (?<index>\d+)(?: \(line (?<line>\d+) column (?<column>\d+)\))?$/); | ||
let message; | ||
try { | ||
return JSON.parse(string, reviver); | ||
} catch (error) { | ||
message = error.message; | ||
throw new JSONError({ | ||
jsonParseError: error, | ||
fileName, | ||
input: string, | ||
}); | ||
} | ||
let location; | ||
if (string) { | ||
location = getErrorLocation(string, message); | ||
message = addCodePointToUnexpectedToken(message); | ||
} else { | ||
message += ' while parsing empty string'; | ||
} | ||
const jsonError = new JSONError(message); | ||
jsonError.fileName = fileName; | ||
if (location) { | ||
jsonError.codeFrame = generateCodeFrame(string, location); | ||
jsonError.rawCodeFrame = generateCodeFrame(string, location, /* highlightCode */ false); | ||
} | ||
throw jsonError; | ||
} |
{ | ||
"name": "parse-json", | ||
"version": "8.1.0", | ||
"version": "8.2.0", | ||
"description": "Parse JSON with more helpful errors", | ||
@@ -23,3 +23,3 @@ "license": "MIT", | ||
"scripts": { | ||
"test": "xo && nyc ava && tsd" | ||
"test": "xo && c8 ava && tsd" | ||
}, | ||
@@ -42,14 +42,14 @@ "files": [ | ||
"dependencies": { | ||
"@babel/code-frame": "^7.22.13", | ||
"index-to-position": "^0.1.2", | ||
"type-fest": "^4.7.1" | ||
"@babel/code-frame": "^7.26.2", | ||
"index-to-position": "^1.0.0", | ||
"type-fest": "^4.37.0" | ||
}, | ||
"devDependencies": { | ||
"ava": "^5.3.1", | ||
"nyc": "^15.1.0", | ||
"ava": "^6.2.0", | ||
"c8": "^10.1.3", | ||
"outdent": "^0.8.0", | ||
"strip-ansi": "^7.1.0", | ||
"tsd": "^0.29.0", | ||
"xo": "^0.56.0" | ||
"tsd": "^0.31.2", | ||
"xo": "^0.60.0" | ||
} | ||
} |
@@ -21,6 +21,3 @@ # parse-json | ||
/* | ||
undefined:3 | ||
} | ||
^ | ||
SyntaxError: Unexpected token } | ||
SyntaxError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
*/ | ||
@@ -31,3 +28,3 @@ | ||
/* | ||
JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' | ||
JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
@@ -43,3 +40,3 @@ 1 | { | ||
/* | ||
JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' in foo.json | ||
JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) in foo.json | ||
@@ -50,2 +47,6 @@ 1 | { | ||
| ^ | ||
fileName: 'foo.json', | ||
[cause]: SyntaxError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
at JSON.parse (<anonymous>) | ||
at ... | ||
*/ | ||
@@ -65,3 +66,3 @@ | ||
/* | ||
JSONError: Unexpected token } in JSON at position 16 while parsing near '{ "foo": true,}' in foo.json | ||
JSONError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) in foo.json | ||
@@ -72,2 +73,7 @@ 1 | { | ||
| ^ | ||
fileName: 'foo.json', | ||
[cause]: SyntaxError: Expected double-quoted property name in JSON at position 16 (line 3 column 1) | ||
at JSON.parse (<anonymous>) | ||
at ... | ||
*/ | ||
@@ -74,0 +80,0 @@ ``` |
11195
17.57%210
16.67%120
5.26%+ Added
- Removed
Updated
Updated
Updated