@stryke/json
Version:
A package containing JSON parsing/stringify utilities used by Storm Software.
53 lines (51 loc) • 2.07 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_utils_strip_comments = require('./strip-comments.cjs');
//#region src/utils/parse.ts
const suspectProtoRx = /"(?:_|\\u0{2}5[Ff]){2}(?:p|\\u0{2}70)(?:r|\\u0{2}72)(?:o|\\u0{2}6[Ff])(?:t|\\u0{2}74)(?:o|\\u0{2}6[Ff])(?:_|\\u0{2}5[Ff]){2}"\s*:/;
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)"\s*:/;
const JsonSigRx = /^\s*["[{]|^\s*-?\d{1,16}(?:\.\d{1,17})?(?:E[+-]?\d+)?\s*$/i;
function jsonParseTransform(key, value) {
if (key === "__proto__" || key === "constructor" && value && typeof value === "object" && "prototype" in value) {
console.warn(`Dropping "${key}" key to prevent prototype pollution.`);
return;
}
return value;
}
function parse(value, options = {}) {
if (typeof value !== "string") return value;
let stripped = require_utils_strip_comments.stripComments(value);
if (stripped[0] === "\"" && stripped[stripped.length - 1] === "\"" && !stripped.includes("\\")) return stripped.slice(1, -1);
stripped = stripped.trim();
if (stripped.length <= 9) switch (stripped.toLowerCase()) {
case "true": return true;
case "false": return false;
case "undefined": return;
case "null": return null;
case "nan": return NaN;
case "infinity": return Number.POSITIVE_INFINITY;
case "-infinity": return Number.NEGATIVE_INFINITY;
}
if (!JsonSigRx.test(stripped)) {
if (options.strict) throw new Error("Invalid JSON");
return stripped;
}
try {
if (suspectProtoRx.test(stripped) || suspectConstructorRx.test(stripped)) {
if (options.strict) throw new Error("Possible prototype pollution");
return JSON.parse(stripped, jsonParseTransform);
}
return JSON.parse(stripped);
} catch (error) {
if (options.strict) throw error;
return value;
}
}
function safeParse(value, options = {}) {
return parse(value, {
...options,
strict: true
});
}
//#endregion
exports.parse = parse;
exports.safeParse = safeParse;