flashman
← All guides

Format JSON without mistaking a rewrite for an edit

Pretty-print and minify JSON with the parser's stored values, including negative zero, exponents, duplicate keys, escaped slashes, and the trailing newline.

2026-10-19 · 8 min read

  • json
  • api
  • formatting

A JSON formatter is a parser followed by a printer. Flashman pretty-prints with two-space JSON.stringify and a final newline. Minify uses JSON.stringify with neither the spaces nor that newline. Both modes show the value the parser stored, in the form the printer chooses.

Use formatting to read a payload. Use a diff against the original text before you treat every changed line as a product bug. Several legal JSON texts are one value and more than one byte string.

Let numbers take the printer's form

Negative zero is stored as zero. The text -0 pretty-prints as 0 and a newline, and a field written -0 prints as 0. 1.0 prints as 1. 1e2 prints as 100. 1e20 prints as the decimal 100000000000000000000. 1e21 prints as 1e+21. The plus is part of the printer's exponent form, not a sign someone typed.

Integers past the exact range change digits. 9007199254740993 prints as 9007199254740992. The number-bases tool, given that same decimal text, stops in the same rounded integer because both paths go through a JavaScript number. If the protocol needs every digit, send the value as a string and document that.

  • Diff source text against pretty text before review.
  • Accept 0 as the printed form of -0.
  • Accept 100 as the printed form of 1e2.
  • Refuse a rewritten long integer instead of shipping it.

Keep the first key and the last value

Duplicate keys are legal in the text and one key in the object. {"z":1,"a":1,"a":2,"m":3} prints z, then a, then m, and a is 2. Order is first-seen order. The value is last-seen. Alphabetical order is a different transform, and this formatter does not apply it.

An escaped slash is a text variant of the same string. {"s":"a\/b"} minifies with a plain slash. Checksums of the file change. Semantics of a later parse do not. A trailing comma is not in that family: {"a":1,} throws Expected double-quoted property name. A leading U+FEFF throws Unexpected token. Delete those by hand. The formatter will not skip them.

Know which mode adds the newline

Pretty-print of the root number 1 is the character 1 and one newline. Minify is the character 1. Pretty-print of {} is an opening brace, a newline, a closing brace, and a newline. A pipeline that hashes the tool output has to name the mode. The newline is not optional decoration on pretty-print.

An empty box, or a box of only spaces, never reaches the parser. The tool returns an empty string and does not say Invalid JSON. A root true, null, or number is valid input. Do not add braces just to satisfy the page.

Hand the stable text to the next tool

MATLAB struct generation parses the JSON again. After a format, 1e21 is already 1e+21 in the struct line, and -0 is already 0. Nested objects still fail the struct tool, and that failure is independent of canonical numbers. Format first so the struct input is one object with one value per key.

Put the source, the pretty text, and the minify text in the review when a checksum moved. Use the JSON tool for the rewrite, diff for the bytes, the struct tool for the MATLAB assignments, and the number-bases tool only on a decimal you still trust. The note should say which mode you hashed.

Try these tools