From 885aaadd4f773e777534cb90fb638d9680f4a897 Mon Sep 17 00:00:00 2001 From: Derrick Hammer Date: Thu, 7 Sep 2023 19:30:34 -0400 Subject: [PATCH] refactor: custom json parse not needed --- src/parse.ts | 376 --------------------------------------------------- 1 file changed, 376 deletions(-) delete mode 100644 src/parse.ts diff --git a/src/parse.ts b/src/parse.ts deleted file mode 100644 index 2daccc9..0000000 --- a/src/parse.ts +++ /dev/null @@ -1,376 +0,0 @@ -// @ts-nocheck - -import { objAsString } from "./objAsString.js"; -import { Err } from "./types.js"; - -// json_parse extracted from the json-bigint npm library -// regexpxs extracted from -// (c) BSD-3-Clause -// https://github.com/fastify/secure-json-parse/graphs/contributors and https://github.com/hapijs/bourne/graphs/contributors -const suspectProtoRx = - /(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])/; -const suspectConstructorRx = - /(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)/; -let json_parse = function (options) { - "use strict"; - - // This is a function that can parse a JSON text, producing a JavaScript - // data structure. It is a simple, recursive descent parser. It does not use - // eval or regular expressions, so it can be used as a model for implementing - // a JSON parser in other languages. - - // We are defining the function inside of another function to avoid creating - // global variables. - - // Default options one can override by passing options to the parse() - let _options = { - strict: false, // not being strict means do not generate syntax errors for "duplicate key" - storeAsString: false, // toggles whether the values should be stored as BigNumber (default) or a string - alwaysParseAsBig: false, // toggles whether all numbers should be Big - protoAction: "error", - constructorAction: "error", - }; - - // If there are options, then use them to override the default _options - if (options !== undefined && options !== null) { - if (options.strict === true) { - _options.strict = true; - } - if (options.storeAsString === true) { - _options.storeAsString = true; - } - _options.alwaysParseAsBig = options.alwaysParseAsBig === true ? options.alwaysParseAsBig : false; - - if (typeof options.constructorAction !== "undefined") { - if ( - options.constructorAction === "error" || - options.constructorAction === "ignore" || - options.constructorAction === "preserve" - ) { - _options.constructorAction = options.constructorAction; - } else { - throw new Error( - `Incorrect value for constructorAction option, must be "error", "ignore" or undefined but passed ${options.constructorAction}` - ); - } - } - - if (typeof options.protoAction !== "undefined") { - if (options.protoAction === "error" || options.protoAction === "ignore" || options.protoAction === "preserve") { - _options.protoAction = options.protoAction; - } else { - throw new Error( - `Incorrect value for protoAction option, must be "error", "ignore" or undefined but passed ${options.protoAction}` - ); - } - } - } - - let at, // The index of the current character - ch, // The current character - escapee = { - '"': '"', - "\\": "\\", - "/": "/", - b: "\b", - f: "\f", - n: "\n", - r: "\r", - t: "\t", - }, - text, - error = function (m) { - // Call error when something is wrong. - - throw { - name: "SyntaxError", - message: m, - at: at, - text: text, - }; - }, - next = function (c) { - // If a c parameter is provided, verify that it matches the current character. - - if (c && c !== ch) { - error("Expected '" + c + "' instead of '" + ch + "'"); - } - - // Get the next character. When there are no more characters, - // return the empty string. - - ch = text.charAt(at); - at += 1; - return ch; - }, - number = function () { - // Parse a number value. - - let number, - string = ""; - - if (ch === "-") { - string = "-"; - next("-"); - } - while (ch >= "0" && ch <= "9") { - string += ch; - next(); - } - if (ch === ".") { - string += "."; - while (next() && ch >= "0" && ch <= "9") { - string += ch; - } - } - if (ch === "e" || ch === "E") { - string += ch; - next(); - if (ch === "-" || ch === "+") { - string += ch; - next(); - } - while (ch >= "0" && ch <= "9") { - string += ch; - next(); - } - } - number = +string; - if (!isFinite(number)) { - error("Bad number"); - } else { - if (Number.isSafeInteger(number)) return !_options.alwaysParseAsBig ? number : BigInt(number); - // Number with fractional part should be treated as number(double) including big integers in scientific notation, i.e 1.79e+308 - else return _options.storeAsString ? string : /[.eE]/.test(string) ? number : BigInt(string); - } - }, - string = function () { - // Parse a string value. - - let hex, - i, - string = "", - uffff; - - // When parsing for string values, we must look for " and \ characters. - - if (ch === '"') { - let startAt = at; - while (next()) { - if (ch === '"') { - if (at - 1 > startAt) string += text.substring(startAt, at - 1); - next(); - return string; - } - if (ch === "\\") { - if (at - 1 > startAt) string += text.substring(startAt, at - 1); - next(); - if (ch === "u") { - uffff = 0; - for (i = 0; i < 4; i += 1) { - hex = parseInt(next(), 16); - if (!isFinite(hex)) { - break; - } - uffff = uffff * 16 + hex; - } - string += String.fromCharCode(uffff); - } else if (typeof escapee[ch] === "string") { - string += escapee[ch]; - } else { - break; - } - startAt = at; - } - } - } - error("Bad string"); - }, - white = function () { - // Skip whitespace. - - while (ch && ch <= " ") { - next(); - } - }, - word = function () { - // true, false, or null. - - switch (ch) { - case "t": - next("t"); - next("r"); - next("u"); - next("e"); - return true; - case "f": - next("f"); - next("a"); - next("l"); - next("s"); - next("e"); - return false; - case "n": - next("n"); - next("u"); - next("l"); - next("l"); - return null; - } - error("Unexpected '" + ch + "'"); - }, - value, // Place holder for the value function. - array = function () { - // Parse an array value. - - let array = []; - - if (ch === "[") { - next("["); - white(); - if (ch === "]") { - next("]"); - return array; // empty array - } - while (ch) { - array.push(value()); - white(); - if (ch === "]") { - next("]"); - return array; - } - next(","); - white(); - } - } - error("Bad array"); - }, - object = function () { - // Parse an object value. - - let key, - object = Object.create(null); - - if (ch === "{") { - next("{"); - white(); - if (ch === "}") { - next("}"); - return object; // empty object - } - while (ch) { - key = string(); - white(); - next(":"); - if (_options.strict === true && Object.hasOwnProperty.call(object, key)) { - error('Duplicate key "' + key + '"'); - } - - if (suspectProtoRx.test(key) === true) { - if (_options.protoAction === "error") { - error("Object contains forbidden prototype property"); - } else if (_options.protoAction === "ignore") { - value(); - } else { - object[key] = value(); - } - } else if (suspectConstructorRx.test(key) === true) { - if (_options.constructorAction === "error") { - error("Object contains forbidden constructor property"); - } else if (_options.constructorAction === "ignore") { - value(); - } else { - object[key] = value(); - } - } else { - object[key] = value(); - } - - white(); - if (ch === "}") { - next("}"); - return object; - } - next(","); - white(); - } - } - error("Bad object"); - }; - - value = function () { - // Parse a JSON value. It could be an object, an array, a string, a number, - // or a word. - - white(); - switch (ch) { - case "{": - return object(); - case "[": - return array(); - case '"': - return string(); - case "-": - return number(); - default: - return ch >= "0" && ch <= "9" ? number() : word(); - } - }; - - // Return the json_parse function. It will have access to all of the above - // functions and variables. - - return function (source, reviver) { - let result; - - text = source + ""; - at = 0; - ch = " "; - result = value(); - white(); - if (ch) { - error("Syntax error"); - } - - // If there is a reviver function, we recursively walk the new structure, - // passing each name/value pair to the reviver function for possible - // transformation, starting with a temporary root object that holds the result - // in an empty key. If there is not a reviver function, we simply return the - // result. - - return typeof reviver === "function" - ? (function walk(holder, key) { - let v, - value = holder[key]; - if (value && typeof value === "object") { - Object.keys(value).forEach(function (k) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - }); - } - return reviver.call(holder, key, value); - })({ "": result }, "") - : result; - }; -}; - -// parseJSON is a wrapper for JSONbig.parse that returns an error rather than -// throwing an error. JSONbig is an alternative to JSON.parse that decodes -// every number as a bigint. This is required when working with the skyd API -// because the skyd API uses 64 bit precision for all of its numbers, and -// therefore cannot be parsed losslessly by javascript. The skyd API is -// cryptographic, therefore full precision is required. -function parseJSON(json: string): [any, Err] { - try { - let obj = json_parse({ alwaysParseAsBig: true })(json); - return [obj, null]; - } catch (err: any) { - return [{}, objAsString(err)]; - } -} - -export { parseJSON };