All questions

Partial JSON Parser

Premium

Partial JSON Parser

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":

  • Unterminated strings are closed: {"name":"Ali{ name: 'Ali' }.
  • Open objects and arrays are closed: {"a":1{ a: 1 }, [1,2[1, 2].
  • A dangling key, colon, or comma is dropped: {"a":{}, [1,2,[1, 2].
  • An incomplete trailing value is dropped or trimmed: a partial keyword like fal is dropped; an unfinishable number tail like 12. becomes 12.

Signature

function partialJsonParser(text: string): unknown;

Examples

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

Notes

  • Prefix, not garbage — assume the text is a truncated valid document. You do not need to repair transposed or misplaced characters.
  • Keep valid numbers12 stays 12; only trim a tail that cannot end a number (12., 1e, a lone -).
  • Drop unguessable tokens — a partial keyword (tru, fal, nul) cannot be completed safely, so drop the pair or element that holds it.
  • Respect escapes — a \" inside a string is part of the string, not its end; a trailing lone backslash is dropped.
  • Out of scope — comments, single quotes, trailing-comma tolerance in valid JSON, and other JSON5 relaxations.

FAQ

Why not just wait for the full JSON before parsing?
For streaming structured output — an LLM returning a JSON object token by token — you want to render fields the instant they arrive. Parsing the best-valid-so-far lets the UI show a form filling in live instead of a spinner until the last byte.
What assumption makes this tractable?
The input is treated as a prefix of some valid JSON — a stream cut off mid-token, not arbitrary garbage. That means you only need to close what is open and drop the one incomplete token at the end, rather than repair arbitrary corruption.
How are incomplete numbers and literals handled?
A number that is still valid (like 12) is kept; a tail that cannot end a number (12., 1e, a lone minus) is trimmed. A partial keyword like tru or fal cannot be guessed safely, so the whole pair or element 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.

Upgrade to Premium