basant307/AI_Governance_Project
048
1import {codeFrameColumns} from '@babel/code-frame';2import indexToPosition from 'index-to-position';3 4const getCodePoint = character => `\\u{${character.codePointAt(0).toString(16)}}`;5 6export class JSONError extends Error {7 name = 'JSONError';8 fileName;9 #input;10 #jsonParseError;11 #message;12 #codeFrame;13 #rawCodeFrame;14 15 constructor(messageOrOptions) {16 // JSONError constructor used accept string17 // TODO[>=9]: Remove this `if` on next major version18 if (typeof messageOrOptions === 'string') {19 super();20 this.#message = messageOrOptions;21 } else {22 const {jsonParseError, fileName, input} = messageOrOptions;23 // We cannot pass message to `super()`, otherwise the message accessor will be overridden.24 // https://262.ecma-international.org/14.0/#sec-error-message25 super(undefined, {cause: jsonParseError});26 27 this.#input = input;28 this.#jsonParseError = jsonParseError;29 this.fileName = fileName;30 }31 32 Error.captureStackTrace?.(this, JSONError);33 }34 35 get message() {36 this.#message ??= `${addCodePointToUnexpectedToken(this.#jsonParseError.message)}${this.#input === '' ? ' while parsing empty string' : ''}`;37 38 const {codeFrame} = this;39 return `${this.#message}${this.fileName ? ` in ${this.fileName}` : ''}${codeFrame ? `\n\n${codeFrame}\n` : ''}`;40 }41 42 set message(message) {43 this.#message = message;44 }45 46 #getCodeFrame(highlightCode) {47 // TODO[>=9]: Remove this `if` on next major version48 if (!this.#jsonParseError) {49 return;50 }51 52 const input = this.#input;53 54 const location = getErrorLocation(input, this.#jsonParseError.message);55 if (!location) {56 return;57 }58 59 return codeFrameColumns(input, {start: location}, {highlightCode});60 }61 62 get codeFrame() {63 this.#codeFrame ??= this.#getCodeFrame(/* highlightCode */ true);64 return this.#codeFrame;65 }66 67 get rawCodeFrame() {68 this.#rawCodeFrame ??= this.#getCodeFrame(/* highlightCode */ false);69 return this.#rawCodeFrame;70 }71}72 73const getErrorLocation = (string, message) => {74 const match = message.match(/in JSON at position (?<index>\d+)(?: \(line (?<line>\d+) column (?<column>\d+)\))?$/);75 76 if (!match) {77 return;78 }79 80 const {index, line, column} = match.groups;81 82 if (line && column) {83 return {line: Number(line), column: Number(column)};84 }85 86 return indexToPosition(string, Number(index), {oneBased: true});87};88 89const addCodePointToUnexpectedToken = message => message.replace(90 // TODO[engine:node@>=20]: The token always quoted after Node.js 2091 /(?<=^Unexpected token )(?<quote>')?(.)\k<quote>/,92 (_, _quote, token) => `"${token}"(${getCodePoint(token)})`,93);94 95export default function parseJson(string, reviver, fileName) {96 if (typeof reviver === 'string') {97 fileName = reviver;98 reviver = undefined;99 }100 101 try {102 return JSON.parse(string, reviver);103 } catch (error) {104 throw new JSONError({105 jsonParseError: error,106 fileName,107 input: string,108 });109 }110}111 