npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lacspace/json-repair

v1.1.0

Published

Extract and repair JSON from messy LLM output — strip ```json fences and prose, extract every embedded value, repair with diagnostics, fix trailing commas, single quotes, unquoted keys and Python literals, and close truncated objects. Zero-dependency, iso

Readme

@lacspace/json-repair

Extract and repair JSON from messy LLM output — zero dependencies.

npm version minzipped types license

Models promise you JSON and hand you JSON wrapped in prose, fenced in ```json, with trailing commas, single quotes, unquoted keys, True/None, or cut off mid-object. This turns all of that back into valid, parsed data — in a package small enough to drop into any function, edge runtime or bundle. No dependencies, isomorphic, fully typed.

  • 🧲 extractJson — pull the JSON out of prose and ```json fences (string-aware, so braces inside strings don't fool it)
  • 🧲 extractAllJson / parseAllJson — pull every JSON value out of the text, not just the first (batches of tool calls, one object per fence/line)
  • 🩹 repairJson — trailing commas, single quotes, unquoted keys, True/False/None, NaN/Infinity, // & /* */ comments, missing commas, and truncated output
  • 🔎 diagnoseJson / repairJsonWithDiagnostics — repair and get a typed list of what was wrong (for logging, warnings, trust checks)
  • ✅ parseJson / safeParseJson — extract → repair → parse, with a fallback or a never-throwing result
  • 🌊 parsePartial — best-effort parse of half-streamed JSON, so a streaming UI can render fields as they arrive
  • 🌍 Zero dependencies · isomorphic (Node ≥18, browser, edge, serverless) · fully typed · provider-agnostic & keyless

New in 1.1.0 — additive, fully backward-compatible. Two new capabilities: extractAllJson / parseAllJson to recover every JSON value embedded in a response (not just the first), and diagnoseJson / repairJsonWithDiagnostics to repair while reporting the exact malformations found. Every existing API is unchanged.

Install

npm i @lacspace/json-repair

The one you'll reach for

import { parseJson } from "@lacspace/json-repair";

const reply = `Sure! Here's the data:
\`\`\`json
{
  name: 'Ada Lovelace',   // unquoted key + single quotes
  active: True,           // python literal
  scores: [10, 20, 30,],  // trailing comma
}
\`\`\`
Hope that helps!`;

parseJson(reply);
// → { name: "Ada Lovelace", active: true, scores: [10, 20, 30] }

parseJson runs extract → repair → JSON.parse for you. Point it at the raw model response — fences, prose and all.

Never throw: safeParseJson and fallback

import { safeParseJson, parseJson } from "@lacspace/json-repair";

const r = safeParseJson<{ ok: boolean }>(model.output);
if (r.ok) use(r.value);
else console.warn("bad JSON:", r.error.message);

// …or supply a fallback and keep the happy path linear:
const cfg = parseJson(model.output, { fallback: { ok: false } });

Streaming? Render as it arrives with parsePartial

import { parsePartial } from "@lacspace/json-repair";

// A chunk that stopped mid-string:
parsePartial('{"title":"Weekly digest","body":"Here is what happe');
// → { title: "Weekly digest", body: "Here is what happe" }

// A field whose value hasn't started yet is simply left out:
parsePartial('{"title":"Weekly digest","body":');
// → { title: "Weekly digest" }

Feed it each accumulated buffer as tokens stream in — open strings, arrays and objects are closed on the fly, so you always get a usable object.

Many values at once: extractAllJson / parseAllJson

When a model emits several JSON values — a batch of tool calls, one object per fenced block, a list of records — grab them all in order:

import { extractAllJson, parseAllJson } from "@lacspace/json-repair";

const reply = `First:
\`\`\`json
{ id: 1, }
\`\`\`
Then: [2, 3, 4,] and finally {"id":5}`;

extractAllJson(reply);
// → ['{ id: 1, }', '[2, 3, 4,]', '{"id":5}']   (raw substrings, not yet repaired)

parseAllJson(reply);
// → [{ id: 1 }, [2, 3, 4], { id: 5 }]           (each one extracted, repaired, parsed)

Each value is repaired independently; a truncated final value is still returned (as a tail) so parsePartial/repairJson can finish it. Unparseable pieces are skipped unless you pass a fallback, which is used in their place so the array length matches.

What was wrong? diagnoseJson / repairJsonWithDiagnostics

Repair while learning why the input needed repairing — useful for logging, surfacing a warning, or judging whether a model response is trustworthy:

import { repairJsonWithDiagnostics, diagnoseJson } from "@lacspace/json-repair";

const r = repairJsonWithDiagnostics("Here you go:\n```json\n{ name: 'Ada', active: True, }\n```");
r.output;                    // → '{"name":"Ada","active":true}'
r.valid;                     // → false (input was not already valid)
r.changed;                   // → true
r.issues.map(i => i.kind);
// → ["wrapped-in-text", "single-quotes", "unquoted-keys", "python-literals", "trailing-comma"]

diagnoseJson('{"a":1,"b":2}'); // → []  (valid JSON → no issues)

Issue kinds: wrapped-in-text, trailing-comma, single-quotes, unquoted-keys, comments, python-literals, non-finite, unterminated-string, unclosed-structure. Each issue also carries a human-readable message.

Just the pieces

import { extractJson, repairJson } from "@lacspace/json-repair";

extractJson('blah blah {"a":1,"b":"} not a brace"} trailing');
// → '{"a":1,"b":"} not a brace"}'   (string-aware — the "}" inside the value is ignored)

repairJson('{"a":1,"b":{"c":2');   // truncated
// → '{"a":1,"b":{"c":2}}'

repairJson('{"a":1,"b":2}');        // already valid → returned byte-for-byte
// → '{"a":1,"b":2}'

API

| Function | Signature | Does | | --- | --- | --- | | extractJson | (text: string) => string \| undefined | Strip ```json/bare ``` fences and prose; return the first balanced {…}/[…] (or the tail if truncated). undefined if none found. | | extractAllJson | (text: string) => string[] | Like extractJson but returns every balanced JSON value in the text, in order (empty array if none). | | parseAllJson<T> | (text: string, opts?: ParseJsonOptions<T>) => T[] | Extract all + repair + parse each value. Skips unparseable pieces (or uses opts.fallback in their place). | | repairJson | (str: string) => string | Fix common breakage and return valid JSON text. Valid JSON is returned unchanged. | | diagnoseJson | (input: string) => JsonIssue[] | List the malformations found in a JSON-ish string ([] for valid JSON). Each JsonIssue is { kind, message }. | | repairJsonWithDiagnostics | (input: string) => RepairDiagnostics | Repair and report: { output, input, valid, changed, issues }. output equals repairJson(input). | | parseJson<T> | (text: string, opts?: ParseJsonOptions<T>) => T | Extract + repair + parse. Throws JsonRepairError on failure, or returns opts.fallback if given. | | safeParseJson<T> | (text: string, opts?) => { ok: true; value: T } \| { ok: false; error: Error } | Never-throwing parseJson. | | parsePartial<T> | (text: string) => T \| undefined | Best-effort parse of incomplete/streaming JSON. | | JsonRepairError | class extends Error | Thrown by parseJson; carries a .snippet of the offending text. |

ParseJsonOptions<T> — { repair?: boolean = true; extract?: boolean = true; fallback?: T }. Turn extract off when your input is already bare JSON; turn repair off to parse strictly.

How it works

extractJson runs a small string-aware scanner: it strips a code fence if present, finds the first { or [, then walks forward tracking string state and escapes so a } inside a string value never closes the structure early. If the input ends before the structure closes (streaming), it returns everything from the opening bracket.

repairJson and parsePartial share a lenient recursive-descent reader. Instead of a pile of regexes, it reads the messy input into a plain JavaScript value — tolerating single quotes, unquoted keys, // & /* */ comments, True/False/None, missing commas, and unterminated strings/objects/arrays — and then JSON.stringify re-emits strict JSON. One pass, every fix. Object keys named __proto__ are dropped, so a malicious payload can't pollute Object.prototype.

Honest limitations

  • Not a spec-strict validator. The goal is to recover usable data from almost-JSON, not to reject every deviation. If you need strict validation of the recovered shape, pipe the result through @lacspace/validate.
  • Non-finite numbers become null. JSON has no NaN/Infinity, so those (and undefined) are normalised to null.
  • Unquoted values must be recognised literals or numbers. Unquoted object keys are repaired, but an unknown bareword in a value position (e.g. {status: active}) is treated as garbage so parseJson can honour its fallback/error contract rather than silently coercing junk to a string. Quote such values.
  • Ambiguous missing commas ({"a":1 "b":2}) are repaired; deeply corrupted input where structure itself is lost may parse to something unexpected — always safeParse untrusted output.
  • Numbers are IEEE-754. Very large integers beyond Number.MAX_SAFE_INTEGER lose precision, exactly as JSON.parse does.

Licensing

Free under the Lacspace Free Licence — permissive freedoms. Use it in personal and commercial projects at no cost; just keep the notice. See the Lacspace Licence Centre.


The Lacspace Developer Platform

@lacspace/json-repair is part of 80+ zero-dependency, isomorphic TypeScript packages — one standard library for the modern web. Explore the ecosystem:

  • 📦 This package, documented — https://developer.lacspace.com/packages/json-repair
  • 🗂️ All 80+ packages — https://developer.lacspace.com/packages
  • 🧭 Developer handbook — guides & runnable recipes — https://developer.lacspace.com/handbook
  • 🧪 Live playground — run any package in your browser — https://developer.lacspace.com/playground
  • 🖥️ Finished app templates — https://templates.lacspace.com
  • 🚀 Scaffold a full app — npm create lacspace-app@latest

Free under the Lacspace Free Licence — a permissive, free-to-use licence.