| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- const STR = 0b000000001;
- const NUM = 0b000000010;
- const ARR = 0b000000100;
- const OBJ = 0b000001000;
- const NULL = 0b000010000;
- const BOOL = 0b000100000;
- const NAN = 0b001000000;
- const INFINITY = 0b010000000;
- const MINUS_INFINITY = 0b100000000;
- const INF = INFINITY | MINUS_INFINITY;
- const SPECIAL = NULL | BOOL | INF | NAN;
- const ATOM = STR | NUM | SPECIAL;
- const COLLECTION = ARR | OBJ;
- const ALL = ATOM | COLLECTION;
- const Allow = {
- STR,
- NUM,
- ARR,
- OBJ,
- NULL,
- BOOL,
- NAN,
- INFINITY,
- MINUS_INFINITY,
- INF,
- SPECIAL,
- ATOM,
- COLLECTION,
- ALL,
- };
- // The JSON string segment was unable to be parsed completely
- class PartialJSON extends Error {
- }
- class MalformedJSON extends Error {
- }
- /**
- * Parse incomplete JSON
- * @param {string} jsonString Partial JSON to be parsed
- * @param {number} allowPartial Specify what types are allowed to be partial, see {@link Allow} for details
- * @returns The parsed JSON
- * @throws {PartialJSON} If the JSON is incomplete (related to the `allow` parameter)
- * @throws {MalformedJSON} If the JSON is malformed
- */
- function parseJSON(jsonString, allowPartial = Allow.ALL) {
- if (typeof jsonString !== 'string') {
- throw new TypeError(`expecting str, got ${typeof jsonString}`);
- }
- if (!jsonString.trim()) {
- throw new Error(`${jsonString} is empty`);
- }
- return _parseJSON(jsonString.trim(), allowPartial);
- }
- const _parseJSON = (jsonString, allow) => {
- const length = jsonString.length;
- let index = 0;
- const markPartialJSON = (msg) => {
- throw new PartialJSON(`${msg} at position ${index}`);
- };
- const throwMalformedError = (msg) => {
- throw new MalformedJSON(`${msg} at position ${index}`);
- };
- const parseAny = () => {
- skipBlank();
- if (index >= length)
- markPartialJSON('Unexpected end of input');
- if (jsonString[index] === '"')
- return parseStr();
- if (jsonString[index] === '{')
- return parseObj();
- if (jsonString[index] === '[')
- return parseArr();
- if (jsonString.substring(index, index + 4) === 'null' ||
- (Allow.NULL & allow && length - index < 4 && 'null'.startsWith(jsonString.substring(index)))) {
- index += 4;
- return null;
- }
- if (jsonString.substring(index, index + 4) === 'true' ||
- (Allow.BOOL & allow && length - index < 4 && 'true'.startsWith(jsonString.substring(index)))) {
- index += 4;
- return true;
- }
- if (jsonString.substring(index, index + 5) === 'false' ||
- (Allow.BOOL & allow && length - index < 5 && 'false'.startsWith(jsonString.substring(index)))) {
- index += 5;
- return false;
- }
- if (jsonString.substring(index, index + 8) === 'Infinity' ||
- (Allow.INFINITY & allow && length - index < 8 && 'Infinity'.startsWith(jsonString.substring(index)))) {
- index += 8;
- return Infinity;
- }
- if (jsonString.substring(index, index + 9) === '-Infinity' ||
- (Allow.MINUS_INFINITY & allow &&
- 1 < length - index &&
- length - index < 9 &&
- '-Infinity'.startsWith(jsonString.substring(index)))) {
- index += 9;
- return -Infinity;
- }
- if (jsonString.substring(index, index + 3) === 'NaN' ||
- (Allow.NAN & allow && length - index < 3 && 'NaN'.startsWith(jsonString.substring(index)))) {
- index += 3;
- return NaN;
- }
- return parseNum();
- };
- const parseStr = () => {
- const start = index;
- let escape = false;
- index++; // skip initial quote
- while (index < length && (jsonString[index] !== '"' || (escape && jsonString[index - 1] === '\\'))) {
- escape = jsonString[index] === '\\' ? !escape : false;
- index++;
- }
- if (jsonString.charAt(index) == '"') {
- try {
- return JSON.parse(jsonString.substring(start, ++index - Number(escape)));
- }
- catch (e) {
- throwMalformedError(String(e));
- }
- }
- else if (Allow.STR & allow) {
- try {
- return JSON.parse(jsonString.substring(start, index - Number(escape)) + '"');
- }
- catch (e) {
- // SyntaxError: Invalid escape sequence
- return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf('\\')) + '"');
- }
- }
- markPartialJSON('Unterminated string literal');
- };
- const parseObj = () => {
- index++; // skip initial brace
- skipBlank();
- const obj = {};
- try {
- while (jsonString[index] !== '}') {
- skipBlank();
- if (index >= length && Allow.OBJ & allow)
- return obj;
- const key = parseStr();
- skipBlank();
- index++; // skip colon
- try {
- const value = parseAny();
- Object.defineProperty(obj, key, { value, writable: true, enumerable: true, configurable: true });
- }
- catch (e) {
- if (Allow.OBJ & allow)
- return obj;
- else
- throw e;
- }
- skipBlank();
- if (jsonString[index] === ',')
- index++; // skip comma
- }
- }
- catch (e) {
- if (Allow.OBJ & allow)
- return obj;
- else
- markPartialJSON("Expected '}' at end of object");
- }
- index++; // skip final brace
- return obj;
- };
- const parseArr = () => {
- index++; // skip initial bracket
- const arr = [];
- try {
- while (jsonString[index] !== ']') {
- arr.push(parseAny());
- skipBlank();
- if (jsonString[index] === ',') {
- index++; // skip comma
- }
- }
- }
- catch (e) {
- if (Allow.ARR & allow) {
- return arr;
- }
- markPartialJSON("Expected ']' at end of array");
- }
- index++; // skip final bracket
- return arr;
- };
- const parseNum = () => {
- if (index === 0) {
- if (jsonString === '-' && Allow.NUM & allow)
- markPartialJSON("Not sure what '-' is");
- try {
- return JSON.parse(jsonString);
- }
- catch (e) {
- if (Allow.NUM & allow) {
- try {
- if ('.' === jsonString[jsonString.length - 1])
- return JSON.parse(jsonString.substring(0, jsonString.lastIndexOf('.')));
- return JSON.parse(jsonString.substring(0, jsonString.lastIndexOf('e')));
- }
- catch (e) { }
- }
- throwMalformedError(String(e));
- }
- }
- const start = index;
- if (jsonString[index] === '-')
- index++;
- while (jsonString[index] && !',]}'.includes(jsonString[index]))
- index++;
- if (index == length && !(Allow.NUM & allow))
- markPartialJSON('Unterminated number literal');
- try {
- return JSON.parse(jsonString.substring(start, index));
- }
- catch (e) {
- if (jsonString.substring(start, index) === '-' && Allow.NUM & allow)
- markPartialJSON("Not sure what '-' is");
- try {
- return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf('e')));
- }
- catch (e) {
- throwMalformedError(String(e));
- }
- }
- };
- const skipBlank = () => {
- while (index < length && ' \n\r\t'.includes(jsonString[index])) {
- index++;
- }
- };
- return parseAny();
- };
- // using this function with malformed JSON is undefined behavior
- const partialParse = (input) => parseJSON(input, Allow.ALL ^ Allow.NUM);
- export { partialParse, PartialJSON, MalformedJSON };
- //# sourceMappingURL=parser.mjs.map
|