From a339d02aa4505de4f416a088d3ccf16c3a8626eb Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:59:48 -0400 Subject: [PATCH 01/13] fix: distinguish malformed JSON from partial arrays --- src/index.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/index.ts b/src/index.ts index ea6977d..70831a0 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,18 @@ 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 } } catch (e) { - if (Allow.OBJ & allow) return obj; - else markPartialJSON("Expected '}' at end of object"); + if (isPartialJSON(e)) { + if (Allow.OBJ & allow) return obj; + markPartialJSON("Expected '}' at end of object"); + } + throw e; } index++; // skip final brace return obj; @@ -124,6 +129,7 @@ const _parseJSON = (jsonString: string, allow: number) => { const parseArr = () => { index++; // skip initial bracket + skipBlank(); const arr = []; try { while (jsonString[index] !== "]") { @@ -131,13 +137,17 @@ const _parseJSON = (jsonString: string, allow: number) => { skipBlank(); if (jsonString[index] === ",") { index++; // skip comma + skipBlank(); } } } catch (e) { - if (Allow.ARR & allow) { - return arr; + if (isPartialJSON(e)) { + if (Allow.ARR & allow) { + return arr; + } + markPartialJSON("Expected ']' at end of array"); } - markPartialJSON("Expected ']' at end of array"); + throw e; } index++; // skip final bracket return arr; From 1a9d22d8228a8537bd2fee2b3e45b6a55c6eea23 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Mon, 15 Jun 2026 13:59:57 -0400 Subject: [PATCH 02/13] test: cover malformed array parsing --- src/index.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/index.test.ts diff --git a/src/index.test.ts b/src/index.test.ts new file mode 100644 index 0000000..baec682 --- /dev/null +++ b/src/index.test.ts @@ -0,0 +1,16 @@ +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("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: ["!"] }, + ]); + }); +}); From 895233c0a43f3bcf9c07199ec7b9cba01760a6d7 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:06:10 -0400 Subject: [PATCH 03/13] Address malformed JSON review feedback --- src/index.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index 70831a0..818aee4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -114,14 +114,15 @@ const _parseJSON = (jsonString: string, allow: number) => { throw e; } skipBlank(); - if (jsonString[index] === ",") index++; // skip comma + if (jsonString[index] === ",") { + index++; // skip comma + skipBlank(); + } } } catch (e) { - if (isPartialJSON(e)) { - if (Allow.OBJ & allow) return obj; - markPartialJSON("Expected '}' at end of object"); - } - throw e; + if (!isPartialJSON(e)) throw e; + if (Allow.OBJ & allow) return obj; + markPartialJSON("Expected '}' at end of object"); } index++; // skip final brace return obj; @@ -141,13 +142,11 @@ const _parseJSON = (jsonString: string, allow: number) => { } } } catch (e) { - if (isPartialJSON(e)) { - if (Allow.ARR & allow) { - return arr; - } - markPartialJSON("Expected ']' at end of array"); + if (!isPartialJSON(e)) throw e; + if (Allow.ARR & allow) { + return arr; } - throw e; + markPartialJSON("Expected ']' at end of array"); } index++; // skip final bracket return arr; From ddbf63f453c02927e90763b2ce6a7648b2164b61 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:06:11 -0400 Subject: [PATCH 04/13] Add malformed object JSON tests --- src/index.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/index.test.ts b/src/index.test.ts index baec682..7dbe6f2 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -6,6 +6,10 @@ describe("malformed JSON handling", () => { 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"] }, @@ -13,4 +17,8 @@ describe("malformed JSON handling", () => { { id: 3, arr: ["!"] }, ]); }); + + it("keeps parsing after an object comma with spaces", () => { + expect(parse('{"a":1, }')).toEqual({ a: 1 }); + }); }); From 3ae30e4f8a736b4f1f54b2d8b767ddb562ca9bca Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:35:11 -0400 Subject: [PATCH 05/13] test: cover array comma whitespace --- src/index.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/index.test.ts b/src/index.test.ts index 7dbe6f2..0d6f7a8 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -21,4 +21,8 @@ describe("malformed JSON handling", () => { 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]); + }); }); From ca2b1c4908bb68d59f71528da91bf054c0291710 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Wed, 1 Jul 2026 03:30:55 -0400 Subject: [PATCH 06/13] fix: preserve partial object errors at EOF --- src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 818aee4..3a56a70 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,7 +120,10 @@ const _parseJSON = (jsonString: string, allow: number) => { } } } catch (e) { - if (!isPartialJSON(e)) throw e; + if (!isPartialJSON(e)) { + if (index >= length) markPartialJSON("Expected '}' at end of object"); + throw e; + } if (Allow.OBJ & allow) return obj; markPartialJSON("Expected '}' at end of object"); } From 0d9e7931293114677dce8e9a9e21d3e5d4be9c68 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:12:44 -0400 Subject: [PATCH 07/13] fix: exclude vitest sources from the published library build --- tsconfig.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index b260e24..75a0979 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,5 +11,11 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true - } + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/**/*.test.ts" + ] } From c374dd5cb705ea3daa027a52f66bb35832592a1f Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:13:46 -0400 Subject: [PATCH 08/13] fix: limit partial number recovery to valid terminal suffixes --- src/index.ts | 34 +++++++++++----------------------- src/number-regressions.test.ts | 21 +++++++++++++++++++++ 2 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 src/number-regressions.test.ts diff --git a/src/index.ts b/src/index.ts index 3a56a70..d4bf34d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -156,35 +156,23 @@ const _parseJSON = (jsonString: string, allow: number) => { }; const parseNum = () => { - if (index === 0) { - if (jsonString === "-") throwMalformedError("Not sure what '-' is"); - try { - return JSON.parse(jsonString); - } catch (e) { - if (Allow.NUM & allow) - try { - return JSON.parse(jsonString.substring(0, jsonString.lastIndexOf("e"))); - } catch (e) {} - throwMalformedError(String(e)); - } - } - const start = index; + while (index < length && !",]} \n\r\t".includes(jsonString[index])) index++; + const token = jsonString.substring(start, index); + const atEnd = index === length; - if (jsonString[index] === "-") index++; - while (jsonString[index] && ",]}".indexOf(jsonString[index]) === -1) index++; - - if (index == length && !(Allow.NUM & allow)) markPartialJSON("Unterminated number literal"); + if (start > 0 && atEnd && !(Allow.NUM & allow)) markPartialJSON("Unterminated number literal"); try { - return JSON.parse(jsonString.substring(start, index)); + return JSON.parse(token); } catch (e) { - if (jsonString.substring(start, index) === "-") markPartialJSON("Not sure what '-' is"); - try { - return JSON.parse(jsonString.substring(start, jsonString.lastIndexOf("e"))); - } catch (e) { - throwMalformedError(String(e)); + if (token === "-" && atEnd && start > 0) markPartialJSON("Not sure what '-' is"); + if (atEnd && Allow.NUM & allow) { + const partial = token.match(/^(-?(?:0|[1-9]\d*)(?:\.\d+)?)[eE][+-]?$/) + ?? token.match(/^(-?(?:0|[1-9]\d*))\.$/); + if (partial) return JSON.parse(partial[1]); } + throwMalformedError(String(e)); } }; diff --git a/src/number-regressions.test.ts b/src/number-regressions.test.ts new file mode 100644 index 0000000..7231cf8 --- /dev/null +++ b/src/number-regressions.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from "vitest"; +import { Allow, MalformedJSON, parse } from "./index"; + +describe("partial number suffixes", () => { + it.each(["123.", "123e", "123E", "123e+", "123E-", "-123."])("completes only a valid unfinished suffix: %s", (input) => { + const expected = input.startsWith("-") ? -123 : 123; + expect(parse(input)).toBe(expected); + expect(parse(`[${input}`)).toEqual([expected]); + }); + it.each(["1evil", "1e+oops", "01e", "1.e", "1e2e"])("rejects malformed exponent text: %s", (input) => { + expect(() => parse(input)).toThrow(MalformedJSON); + expect(() => parse(`[${input}]`)).toThrow(MalformedJSON); + }); + it.each(["[1e,2]", "[1.,2]", "[1E+]", '[1e+2junk]'])("does not repair numbers terminated by a delimiter: %s", (input) => { + expect(() => parse(input)).toThrow(MalformedJSON); + }); + it("keeps complete numbers and the partial-number opt-out", () => { + expect(parse("-1.25E+2", 0)).toBe(-125); + expect(parse("[1.25", Allow.ARR)).toEqual([]); + }); +}); From 96fc71bfe17f362d76a017837be159bdd61c42b2 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:16:27 -0400 Subject: [PATCH 09/13] fix: require json object colons and collection separators --- src/index.ts | 9 ++++++++- src/separator-regressions.test.ts | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/separator-regressions.test.ts diff --git a/src/index.ts b/src/index.ts index d4bf34d..0888900 100644 --- a/src/index.ts +++ b/src/index.ts @@ -102,9 +102,12 @@ const _parseJSON = (jsonString: string, allow: number) => { try { while (jsonString[index] !== "}") { skipBlank(); - if (index >= length && Allow.OBJ & allow) return obj; + if (index >= length) markPartialJSON("Expected an object key"); + if (jsonString[index] !== '"') throwMalformedError("Expected a quoted object key"); const key = parseStr(); skipBlank(); + if (index >= length) markPartialJSON("Expected ':' after object key"); + if (jsonString[index] !== ":") throwMalformedError("Expected ':' after object key"); index++; // skip colon try { const value = parseAny(); @@ -117,6 +120,8 @@ const _parseJSON = (jsonString: string, allow: number) => { if (jsonString[index] === ",") { index++; // skip comma skipBlank(); + } else if (index < length && jsonString[index] !== "}") { + throwMalformedError("Expected ',' or '}' after object value"); } } } catch (e) { @@ -142,6 +147,8 @@ const _parseJSON = (jsonString: string, allow: number) => { if (jsonString[index] === ",") { index++; // skip comma skipBlank(); + } else if (index < length && jsonString[index] !== "]") { + throwMalformedError("Expected ',' or ']' after array value"); } } } catch (e) { diff --git a/src/separator-regressions.test.ts b/src/separator-regressions.test.ts new file mode 100644 index 0000000..f6e1fb1 --- /dev/null +++ b/src/separator-regressions.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from "vitest"; +import { Allow, MalformedJSON, PartialJSON, parse } from "./index"; + +describe("object and array separators", () => { + it.each(['{"a" 1}', '{"a"::1}', '{foo:1}', '[true false]', '["a" "b"]', '[1 2]', '{"a":1 "b":2}', '[{},{} {}]'])("rejects a missing separator or unquoted key: %s", (input) => { + expect(() => parse(input)).toThrow(MalformedJSON); + }); + it.each(['{', '{"a"', '{"a":'])("still recovers unfinished object prefixes: %s", (input) => { + expect(parse(input)).toEqual({}); + expect(() => parse(input, 0)).toThrow(PartialJSON); + }); + it("retains valid nesting and permitted incomplete containers", () => { + expect(parse('{"a":[1,true,{"b":"c"}]}')).toEqual({a:[1,true,{b:"c"}]}); + expect(parse('{"a":1')).toEqual({a:1}); + expect(parse('[1,2', Allow.ARR | Allow.NUM)).toEqual([1,2]); + }); +}); From 2b9aa17a5b36914f62a6ffd982dd0dfc35e48e43 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:17:57 -0400 Subject: [PATCH 10/13] fix: reject trailing content after a complete json value --- src/index.ts | 5 ++++- src/trailing-content.test.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/trailing-content.test.ts diff --git a/src/index.ts b/src/index.ts index 0888900..97f3502 100644 --- a/src/index.ts +++ b/src/index.ts @@ -188,7 +188,10 @@ const _parseJSON = (jsonString: string, allow: number) => { index++; } }; - return parseAny(); + const value = parseAny(); + skipBlank(); + if (index < length) throwMalformedError("Unexpected content after JSON value"); + return value; }; const parse = parseJSON; diff --git a/src/trailing-content.test.ts b/src/trailing-content.test.ts new file mode 100644 index 0000000..73ee11a --- /dev/null +++ b/src/trailing-content.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, it } from "vitest"; +import { MalformedJSON, parse } from "./index"; + +describe("complete document boundary", () => { + it.each(['true false', 'null garbage', '"hello" "world"', '{} []', '[] trailing', 'Infinityx', 'NaNtail'])("rejects content after the first value: %s", (input) => { + expect(() => parse(input)).toThrow(MalformedJSON); + }); + it.each(['true', 'null', '"hello"', '{}', '[]', '123', '-1.5e2'])("accepts trailing whitespace: %s", (input) => { + expect(parse(`${input} \n\t`)).toEqual(JSON.parse(input)); + }); + it("still accepts incomplete atoms and containers", () => { + expect(parse('tr')).toBe(true); + expect(parse('Inf')).toBe(Infinity); + expect(parse('1e+')).toBe(1); + expect(parse('[1,')).toEqual([1]); + expect(parse('{"a":')).toEqual({}); + }); +}); From 025b660ce0fce1c671e6cb81d2a216e949af1b3b Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:22:33 -0400 Subject: [PATCH 11/13] fix: preserve malformed value errors at object end of input --- src/index.ts | 5 +---- src/number-regressions.test.ts | 1 + 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 97f3502..99101b5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -125,10 +125,7 @@ const _parseJSON = (jsonString: string, allow: number) => { } } } catch (e) { - if (!isPartialJSON(e)) { - if (index >= length) markPartialJSON("Expected '}' at end of object"); - throw e; - } + if (!isPartialJSON(e)) throw e; if (Allow.OBJ & allow) return obj; markPartialJSON("Expected '}' at end of object"); } diff --git a/src/number-regressions.test.ts b/src/number-regressions.test.ts index 7231cf8..acfda9c 100644 --- a/src/number-regressions.test.ts +++ b/src/number-regressions.test.ts @@ -10,6 +10,7 @@ describe("partial number suffixes", () => { it.each(["1evil", "1e+oops", "01e", "1.e", "1e2e"])("rejects malformed exponent text: %s", (input) => { expect(() => parse(input)).toThrow(MalformedJSON); expect(() => parse(`[${input}]`)).toThrow(MalformedJSON); + expect(() => parse(`{"value":${input}`)).toThrow(MalformedJSON); }); it.each(["[1e,2]", "[1.,2]", "[1E+]", '[1e+2junk]'])("does not repair numbers terminated by a delimiter: %s", (input) => { expect(() => parse(input)).toThrow(MalformedJSON); From 79fd2e47696298a4809573ffde1710f1af88a777 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Sat, 12 Sep 2026 08:46:43 -0400 Subject: [PATCH 12/13] fix: reject malformed numbers before applying partial opt-out --- src/index.ts | 15 ++++++++++----- src/strict-number-classification.test.ts | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 src/strict-number-classification.test.ts diff --git a/src/index.ts b/src/index.ts index 99101b5..8057031 100644 --- a/src/index.ts +++ b/src/index.ts @@ -165,19 +165,24 @@ const _parseJSON = (jsonString: string, allow: number) => { const token = jsonString.substring(start, index); const atEnd = index === length; - if (start > 0 && atEnd && !(Allow.NUM & allow)) markPartialJSON("Unterminated number literal"); - + let value; try { - return JSON.parse(token); + value = JSON.parse(token); } catch (e) { if (token === "-" && atEnd && start > 0) markPartialJSON("Not sure what '-' is"); - if (atEnd && Allow.NUM & allow) { + if (atEnd) { const partial = token.match(/^(-?(?:0|[1-9]\d*)(?:\.\d+)?)[eE][+-]?$/) ?? token.match(/^(-?(?:0|[1-9]\d*))\.$/); - if (partial) return JSON.parse(partial[1]); + if (partial) { + if (Allow.NUM & allow) return JSON.parse(partial[1]); + if (start > 0) markPartialJSON("Unterminated number literal"); + } } throwMalformedError(String(e)); } + // Only valid numeric tokens can be incomplete streaming numbers. + if (start > 0 && atEnd && !(Allow.NUM & allow)) markPartialJSON("Unterminated number literal"); + return value; }; const skipBlank = () => { diff --git a/src/strict-number-classification.test.ts b/src/strict-number-classification.test.ts new file mode 100644 index 0000000..a50a76f --- /dev/null +++ b/src/strict-number-classification.test.ts @@ -0,0 +1,15 @@ +import { expect, it } from "vitest"; +import { Allow, MalformedJSON, parse } from "./index"; + +it.each(["[oops", "[01", "[1evil"])("rejects malformed array numbers with NUM disabled: %s", (input) => { + expect(() => parse(input, Allow.ARR)).toThrow(MalformedJSON); +}); +it.each(['{"value":oops', '{"value":01', '{"value":1evil'])("rejects malformed object numbers with NUM disabled: %s", (input) => { + expect(() => parse(input, Allow.OBJ)).toThrow(MalformedJSON); +}); +it("preserves strict root whitespace and streaming numeric opt-out", () => { + expect(parse(" 1", 0)).toBe(1); + expect(parse("\n-1.5\t", 0)).toBe(-1.5); + expect(parse("[1.25", Allow.ARR)).toEqual([]); + expect(parse("[1e+", Allow.ARR)).toEqual([]); +}); From d9b5d5950ced4312552512ff9f65a649b9bd8c58 Mon Sep 17 00:00:00 2001 From: Rupayon Haldar <80724680+rupayon123@users.noreply.github.com> Date: Mon, 21 Sep 2026 13:16:09 -0400 Subject: [PATCH 13/13] Preserve whitespace inside unfinished JSON strings --- src/index.ts | 3 ++- src/partial-string-whitespace.test.ts | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 src/partial-string-whitespace.test.ts diff --git a/src/index.ts b/src/index.ts index 8057031..86b51c5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,8 @@ function parseJSON(jsonString: string, allowPartial: number = Allow.ALL): any { if (!jsonString.trim()) { throw new Error(`${jsonString} is empty`); } - return _parseJSON(jsonString.trim(), allowPartial); + // Trailing whitespace may belong to an unfinished string value. + return _parseJSON(jsonString.trimStart(), allowPartial); } const _parseJSON = (jsonString: string, allow: number) => { diff --git a/src/partial-string-whitespace.test.ts b/src/partial-string-whitespace.test.ts new file mode 100644 index 0000000..74f5a5d --- /dev/null +++ b/src/partial-string-whitespace.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from "vitest"; +import { Allow, parse } from "./index"; + +describe("whitespace inside unfinished strings", () => { + it.each([" ", " ", "\u00a0", "\u2003"])("preserves a trailing %j", (suffix) => { + expect(parse('"text' + suffix)).toBe("text" + suffix); + expect(parse('["text' + suffix)).toEqual(["text" + suffix]); + expect(parse('{"key":"text' + suffix)).toEqual({ key: "text" + suffix }); + }); + it("still ignores surrounding whitespace outside a complete value", () => { + expect(parse(' "text " \n')).toBe("text "); + expect(parse(' [1,2] \n')).toEqual([1,2]); + }); + it("retains the partial-string opt-out", () => { + expect(parse('["text ', Allow.ARR)).toEqual([]); + }); +});