A JSON formatter is a parse-and-serialize pipeline, not search and replace. The parser proves that text can become a data model; the serializer emits a consistent representation with chosen whitespace.
The two-line demo is simple. Production behavior depends on empty input, syntax errors, duplicate keys, JSON variants, unsupported values, huge documents, tree rendering, and whether sensitive payloads leave the browser.
The minimal pipeline
JSON.parse returns objects, arrays, strings, numbers, booleans, or null. JSON.stringify traverses that value and emits standard JSON; its third argument controls indentation, while omission creates minified output.
Regex formatting cannot reliably distinguish braces inside strings, escaped quotes, Unicode escapes, and nested structures. Parsing must come first.
const parsed = JSON.parse(input);
const pretty = JSON.stringify(parsed, null, 2);
const minified = JSON.stringify(parsed);Formatting also checks syntax
If JSON.parse succeeds, text is syntactically valid standard JSON. If it throws, the formatter should preserve input and show an error rather than creating partial output.
This makes a formatter a syntax validator, but not a schema validator. It cannot know whether age should be an integer or email is required without a separate contract.
What stringify normalizes
Original whitespace, key layout, escape style, and insignificant zeros are not preserved. Duplicate object keys are important: JSON.parse keeps the final value, so earlier values cannot be recovered after parsing.
Standard JSON cannot represent undefined, functions, symbols, BigInt, NaN, or Infinity. Tools formatting in-memory JavaScript values need explicit policies for them.
JSONC and JSON5 need a declared mode
Comments, trailing commas, single quotes, and unquoted keys are not standard JSON. A JSON5 parser can accept them and then serialize standard JSON, but comments and source formatting will disappear.
ToolGarden tries JSON.parse first and JSON5 for supported relaxed syntax. Utilities return a success-or-error union instead of manipulating React state or leaking exceptions.
type Outcome =
| { ok: true; output: string; parsed: unknown }
| { ok: false; message: string };Tree view and performance
A tree recursively renders object entries and array indices with stable paths, expansion state, and type-aware syntax. It should derive from the same parsed value as the text output.
Thousands of nodes can block rendering. Collapse deep levels, virtualize long lists, cap recursion, or offer text-only mode. JSON.parse and stringify are synchronous, so Workers or size limits may be needed for large documents.
Error and privacy contracts
Parser messages vary across engines. A useful UI can show the native message and estimated location, then explain likely comma, quote, escape, or truncation problems without pretending recovery is certain.
Browser-local parsing avoids an upload, but users should still redact secrets before sharing output.
- Never format JSON with regex alone.
- Keep original input on error.
- Declare JSON5/JSONC normalization.
- Warn about duplicate-key loss.
- Separate syntax from schema validation.
Key takeaways
A dependable formatter parses first, preserves invalid input, serializes one parsed model, and states variant support and normalization effects. The core is simple; the surrounding contracts create trust.