diff --git a/src/index.test.ts b/src/index.test.ts new file mode 100644 index 0000000..0d6f7a8 --- /dev/null +++ b/src/index.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from "vitest"; +import { MalformedJSON, parse } from "./index"; + +describe("malformed JSON handling", () => { + it("throws for malformed numbers inside arrays", () => { + expect(() => parse("[1, .05, 2]")).toThrow(MalformedJSON); + }); + + it("throws for malformed numbers inside objects", () => { + expect(() => parse('{"a": .05, "b": 2}')).toThrow(MalformedJSON); + }); + + it("keeps parsing after an empty array with spaces", () => { + expect(parse('[{"id":1,"arr":["hello"]},{"id":2,"arr":[ ],"more":"yaya"},{"id":3,"arr":["!"]}]')).toEqual([ + { id: 1, arr: ["hello"] }, + { id: 2, arr: [], more: "yaya" }, + { id: 3, arr: ["!"] }, + ]); + }); + + it("keeps parsing after an object comma with spaces", () => { + expect(parse('{"a":1, }')).toEqual({ a: 1 }); + }); + + it("keeps parsing after an array comma with spaces", () => { + expect(parse("[1, ]")).toEqual([1]); + }); +}); diff --git a/src/index.ts b/src/index.ts index ea6977d..3a56a70 100644 --- a/src/index.ts +++ b/src/index.ts @@ -35,6 +35,8 @@ const _parseJSON = (jsonString: string, allow: number) => { throw new MalformedJSON(`${msg} at position ${index}`); }; + const isPartialJSON = (e: unknown) => e instanceof PartialJSON; + const parseAny: () => any = () => { skipBlank(); if (index >= length) markPartialJSON("Unexpected end of input"); @@ -108,15 +110,22 @@ const _parseJSON = (jsonString: string, allow: number) => { const value = parseAny(); obj[key] = value; } catch (e) { - if (Allow.OBJ & allow) return obj; - else throw e; + if (Allow.OBJ & allow && isPartialJSON(e)) return obj; + throw e; } skipBlank(); - if (jsonString[index] === ",") index++; // skip comma + if (jsonString[index] === ",") { + index++; // skip comma + skipBlank(); + } } } catch (e) { + if (!isPartialJSON(e)) { + if (index >= length) markPartialJSON("Expected '}' at end of object"); + throw e; + } if (Allow.OBJ & allow) return obj; - else markPartialJSON("Expected '}' at end of object"); + markPartialJSON("Expected '}' at end of object"); } index++; // skip final brace return obj; @@ -124,6 +133,7 @@ const _parseJSON = (jsonString: string, allow: number) => { const parseArr = () => { index++; // skip initial bracket + skipBlank(); const arr = []; try { while (jsonString[index] !== "]") { @@ -131,9 +141,11 @@ const _parseJSON = (jsonString: string, allow: number) => { skipBlank(); if (jsonString[index] === ",") { index++; // skip comma + skipBlank(); } } } catch (e) { + if (!isPartialJSON(e)) throw e; if (Allow.ARR & allow) { return arr; }