Skip to content

Latest commit

 

History

History

README.md

@jsonfold/core

Compact and readable JSON formatting for humans.

jsonfold makes pretty-printed JSON more compact without turning it back into unreadable one-line JSON.

Most JSON serializers offer two extremes:

  • compact machine output:
{"meta":{"version":1,"ok":true},"ids":[1,2,3,4],"matrix":[[1,2],[3,4]]}
  • fully expanded pretty-printing for humans:
{
  "meta": {
    "version": 1,
    "ok": true
  },
  "ids": [
    1,
    2,
    3,
    4
  ],
  "matrix": [
    [
      1,
      2
    ],
    [
      3,
      4
    ]
  ]
}

jsonfold sits in the middle. It keeps the readable structure of pretty JSON, but selectively folds small containers and packs short scalar runs when they fit within a target line width.

{
  "meta": { "version": 1, "ok": true },
  "ids": [ 1, 2, 3, 4 ],
  "matrix": [ [ 1, 2 ], [ 3, 4 ] ]
}

This package provides the JavaScript implementation of jsonfold for Node.js and modern ES modules.

If you want the background story, design goals, implementation details, and examples, start with the article:

📖 Article

The article explains:

  • why existing pretty-printing often becomes unreadable,
  • the folding/packing approach,
  • streaming constraints,
  • bounded buffering,
  • and how the formatter works internally.

Features

  • Streaming filter around existing JSON serializers
  • Width-aware packing and folding
  • Bounded buffering
  • No full JSON tree reparsing
  • Human-readable output for large nested documents
  • Configurable compaction levels
  • Multiple built-in presets
  • Works with standard JSON.stringify(..., null, 2) output

Installation

npm install @jsonfold/core

Or from source:

git clone https://github.com/yairlenga/jsonfold
cd jsonfold/javascript
npm install

Basic Usage

import { format_json } from "@jsonfold/core";

const obj = {
  meta: { version: 1, ok: true },
  ids: [1, 2, 3, 4],
  matrix: [[1, 2], [3, 4]],
};

console.log(format_json(obj));

Output:

{
  "meta": { "version": 1, "ok": true },
  "ids": [ 1, 2, 3, 4 ],
  "matrix": [ [ 1, 2 ], [ 3, 4 ] ]
}

Streaming usage:

import fs from "node:fs";
import { create_writer } from "@jsonfold/core";

const out = create_writer(fs.createWriteStream("out.json"));

out.write(prettyPrintedJson);
out.close();

Configuration Presets

default

Balanced default settings.

format_json(obj, undefined, "default");

Typical behavior:

  • fold small objects/lists,
  • allow limited nested folding,
  • preserve readability.

low

Conservative compaction.

format_json(obj, undefined, "low");

Disables nested folding/joining.


med

Moderate compaction.

format_json(obj, undefined, "med");

Allows folding while restricting nested joins.


high

More aggressive packing and folding.

format_json(obj, undefined, "high");

Allows:

  • larger packed scalar groups,
  • deeper nesting,
  • more aggressive joining.

max

Maximum compaction subject only to width limits.

format_json(obj, undefined, "max");

Useful for very dense but still readable output.


CLI Usage

Read JSON from stdin

By default, jsonfold reads a single JSON document from standard input, parses it with JSON.parse(), and writes formatted output using JSON.stringify(..., null, 2).

jsonfold < input.json
jq ... | jsonfold

Use a preset

jsonfold --compact=max < input.json

Control width

jsonfold --width=100 < input.json

Read from file

jsonfold --input data.json

Use the built-in demo document

jsonfold --compact=high --demo

Sort object keys

jsonfold --sort-keys < input.json

Verbose output

jsonfold --verbose < input.json

Algorithm Overview

The formatter operates directly on the pretty-printed line stream generated by:

JSON.stringify(value, null, 2)

It does not implement a full JSON parser.

Instead, it tracks container frames and applies three phases.


Phase 1: Pack

Join consecutive scalar items onto the same line.

Example:

{
  "obj": {
    "version": 1,
    "ok": true
  },
  "list": [
    1,
    2,
    3,
    4
  ]
}

becomes:

{
  "obj": {
    "version": 1, "ok": true
  },
  "list": [
    1, 2, 3, 4
  ]
}

Subject to width and item limits.


Phase 2: Fold

Collapse single-content-line containers.

Example:

{
  "obj": {
    "version": 1, "ok": true
  },
  "list": [
    1, 2, 3, 4
  ]
}

becomes:

{
  "obj": { "version": 1, "ok": true },
  "list": [ 1, 2, 3, 4 ]
}

Phase 3: Grid

Align repeated folded rows into readable columns.

When a container holds multiple folded arrays or objects with a similar structure, jsonfold can align corresponding values to improve readability.

Example:

[
  { "id": 1, "name": "Alice", "score": 95 },
  { "id": 20, "name": "Bob", "score": 87 },
  { "id": 300, "name": "Charlie", "score": 100 }
]

becomes:

[
  { "id":   1, "name": "Alice",   "score":  95 },
  { "id":  20, "name": "Bob",     "score":  87 },
  { "id": 300, "name": "Charlie", "score": 100 }
]

Object grids require all rows to contain the same property names in the same order. Array grids require all rows to contain the same number of elements.

Grid alignment is applied only when:

  • all rows have compatible structure,
  • the aligned output fits within the configured width,
  • and the number of rows satisfies the configured limits.

Phase 4: Join

Merge folded containers together.

Example:

[
  [1, 2],
  [3, 4]
]

becomes:

[ [1, 2], [3, 4] ]

Performance Notes

jsonfold is designed primarily for readability and streaming behavior.

The implementation:

  • avoids reparsing full JSON trees,
  • buffers only currently open frames,
  • streams output once folding is no longer possible,
  • and can operate incrementally on large documents.

The repository includes benchmark scripts comparing:

  • JSON.stringify()
  • folded vs. unfolded modes
  • streaming vs. string-building approaches

License

MIT License