When a language model streams a JSON object, you receive it a few characters at a time: {"nam, then e": "Al, then ice", "ro. JSON.parse throws on every one of those fragments because they are not valid JSON yet. A partial JSON parser fills that gap — given a truncated string, it returns the best-valid value it can recover so far, so a streaming UI can render fields as they arrive instead of waiting for the final byte.
Implement partialJsonParser(text). The input is a prefix of some valid JSON — a stream cut off mid-token, not arbitrary corruption. Return the parsed value for the completed portion, or undefined when nothing can be recovered.
The recovery rules follow from "close what is open, drop what is dangling":
{"name":"Ali → { name: 'Ali' }.{"a":1 → { a: 1 }, [1,2 → [1, 2].{"a": → {}, [1,2, → [1, 2].fal is dropped; an unfinishable number tail like 12. becomes 12.function partialJsonParser(text: string): unknown;
partialJsonParser('{"name":"Ali'); // { name: 'Ali' }
partialJsonParser('{"a":1,"b":[2,3'); // { a: 1, b: [2, 3] }
partialJsonParser('{"ok":true,"x":fal'); // { ok: true } (partial pair dropped)
partialJsonParser('[1,2,3]'); // [1, 2, 3] (already valid — parsed as-is)
partialJsonParser('"hel'); // 'hel'
partialJsonParser(''); // undefined
12 stays 12; only trim a tail that cannot end a number (12., 1e, a lone -).tru, fal, nul) cannot be completed safely, so drop the pair or element that holds it.\" inside a string is part of the string, not its end; a trailing lone backslash is dropped.Unlock the solution & editor
Runnable editor + tests
Solve in the browser with instant Jest feedback.
Detailed solutions
Walkthroughs, edge cases, and complexity notes.
Multi-framework variants
React, Vue, Vanilla, Angular — same question, different stacks.