Skip to content

Repository files navigation

jsoncraft

A zero-dependency, TypeScript-first JSON toolkit for querying, transforming, and converting JSON data.

npm versionnpm downloadsLicense: MITZero dependenciesTypeScriptNode.js


jsoncraft is a single, focused library and CLI for everything you do with JSON: query it (JSONPath), transform it (pick, omit, flatten, groupBy, ...), convert between formats (JSON ↔ YAML/CSV/JSONL/Properties/TOML), format it with colors, diff and merge it, and validate it against a lightweight schema — all with zero runtime dependencies.

It runs anywhere JavaScript does: Node.js, Bun, Deno, and modern browsers.

✨ Features

  • 🔍 Query — A practical JSONPath engine with filters, slices, wildcards, and recursive descent.
  • 🔁 Transformpick, omit, map, filter, renameKeys, flatten, unflatten, groupBy, sortBy, chunk, unique.
  • 🔄 Convert — Bidirectional conversion between JSON, YAML, CSV, JSONL, Java Properties, and TOML.
  • 🎨 Format — Pretty-print with ANSI colors, key sorting, depth limiting, compact mode.
  • 📊 Diff & Patch — Structural deep diff with JSONPath locations and patch application.
  • 🧬 Merge — Configurable deep merge with array strategies (replace / concat / merge-by-index), plus intersect and union.
  • ✅ Validate — A tiny Zod-inspired schema validator with coercion, enums, ranges, and defaults.
  • 🖥️ CLI — A friendly jc command for the terminal, reading from files or stdin.
  • 📦 Zero dependencies — Only your runtime. Nothing else.
  • 🔒 Type-safe — Strict TypeScript with full type inference.

📦 Installation

npm install @cryptoteep/jsoncraft
# or
bun add @cryptoteep/jsoncraft
# or
pnpm add @cryptoteep/jsoncraft

For CLI-only usage, install globally:

npm install -g @cryptoteep/jsoncraft

🚀 Quick start

As a library

import{query,pick,omit,flatten,groupBy,sortBy,convert,format,diff,merge,validate,}from'@cryptoteep/jsoncraft';// ── Query with JSONPath ─────────────────────────────────constdata={store: {book: [{category: 'reference',author: 'Nigel Rees',price: 8.95},{category: 'fiction',author: 'Herman Melville',price: 8.99},{category: 'fiction',author: 'J.R.R. Tolkien',price: 22.99},],},};query(data,'$.store.book[*].author');// → ['Nigel Rees', 'Herman Melville', 'J.R.R. Tolkien']query(data,'$..book[?(@.price < 10)].author');// → ['Nigel Rees', 'Herman Melville']// ── Transform ──────────────────────────────────────────constusers=[{id: 1,name: 'Alice',password: 'x'},{id: 2,name: 'Bob',password: 'y'}];users.map((u)=>pick(u,['id','name']));// → [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]flatten({a: {b: {c: 1}}});// → { 'a.b.c': 1 }groupBy([{role: 'admin'},{role: 'user'},{role: 'admin'}],'role');// → { admin: [...], user: [...] }// ── Convert formats ────────────────────────────────────convert('[{"id":1},{"id":2}]','json','yaml');// →// - id: 1// - id: 2convert('a: 1\nb: 2','yaml','json');// → '{"a":1,"b":2}'// ── Diff & merge ───────────────────────────────────────diff({a: 1,b: 2},{a: 1,c: 3});// → [// { path: '$.b', type: 'remove', oldValue: 2 },// { path: '$.c', type: 'add', value: 3 },// ]merge({a: 1,b: {x: 1}},{b: {y: 2},c: 3});// → { a: 1, b: { x: 1, y: 2 }, c: 3 }// ── Validate ───────────────────────────────────────────constschema={type: 'object',properties: {name: {type: 'string',required: true},age: {type: 'number',min: 0,max: 150},role: {type: 'string',enum: ['admin','user']},},};validate({name: 'Alice',age: 30,role: 'admin'},schema);// → { valid: true, errors: [], value: {...}}

As a CLI

# Query JSON with JSONPath
jc query '$.store.book[*].author' books.json
jc query '$..book[?(@.price < 10)].title' books.json
# Pipe through stdin
cat data.json | jc query '$.users[*].name'# Pick / omit keys
jc pick id,name users.json
jc omit password,token users.json
# Convert formats
jc convert --to yaml package.json
jc convert --from yaml --to json config.yaml
jc convert --to csv users.json
# Pretty-print with colors
jc format data.json
cat data.json | jc format --color
# Diff and merge
jc diff old.json new.json
jc merge base.json override.json
# Validate against a schema
jc validate schema.json data.json
# Stats and structure
jc stats big-file.json
jc flatten nested.json

📖 Documentation

Query (JSONPath)

The query engine supports a practical subset of JSONPath:

ExpressionMeaning
$The root object
.keyObject property
['key']Object property (bracket form)
[index]Array index (supports negative)
[start:stop]Array slice
[*]Wildcard — all elements / all keys
..keyRecursive descent
[?(expr)]Filter expression

Filter expressions support:

  • @ — current node
  • @.field — field of current node
  • Comparisons: == != < <= > >=
  • exists(@.field) — existence check
query(data,'$.store.book[0].title');// first book's titlequery(data,'$.store.book[-1]');// last bookquery(data,'$.store.book[0:2]');// first two books (slice)query(data,'$..author');// all authors anywherequery(data,'$.store.book[?(@.price < 10)]');// books under 10query(data,'$.store.book[?(@.category == "fiction")]');query(data,'$.store.*');// all store children

Transform

import{pick,omit,map,filter,renameKeys,flatten,unflatten,groupBy,sortBy,chunk,unique,clone}from'@cryptoteep/jsoncraft';clone(value);// deep clonepick(obj,['id','name']);// keep only these keysomit(obj,['password']);// remove these keysmap(arr,fn);// map arrayfilter(arr,predicate);// filter arrayrenameKeys(obj,{old: 'new'});// rename keysflatten(obj);// { a: { b: 1 }} → { 'a.b': 1 }unflatten(obj);// { 'a.b': 1 } → { a: { b: 1 }}groupBy(arr,'role');// group array by keysortBy(arr,'age','desc');// sort arraychunk(arr,3);// split into chunksunique(arr);// deduplicate

Convert

import{convert,parse,stringify}from'@cryptoteep/jsoncraft';convert(input,'json','yaml');// JSON string → YAML stringparse(input,'csv');// parse CSV into JSONstringify(value,'toml');// serialize to TOML

Supported formats: json, yaml, csv, jsonl, properties, toml.

Note: The YAML and TOML implementations cover the common subset used in configuration files. They are not full-spec implementations. For complex documents, consider a dedicated parser.

Format

import{format,formatCompact,colorize,size,countNodes,depth}from'@cryptoteep/jsoncraft';format(value,{indent: 2,color: true,sortKeys: true});formatCompact(value);colorize(jsonString);size(value);// bytes when JSON-stringifiedcountNodes(value);// total nodes in treedepth(value);// max nesting depth

Diff & Merge

import{diff,applyPatch,merge,mergeMany,intersect,union}from'@cryptoteep/jsoncraft';constentries=diff(before,after);constrestored=applyPatch(before,entries);merge(a,b,{arrays: 'concat'});mergeMany([a,b,c]);intersect(a,b);// keys in both, deeply equalunion(arrA,arrB);// deduplicated concatenation

Validate

import{validate,formatErrors}from'@cryptoteep/jsoncraft';constschema={type: 'object',properties: {port: {type: 'number',min: 1,max: 65535,default: 3000},host: {type: 'string',required: true},debug: {type: 'boolean',coerce: true},mode: {type: 'string',enum: ['dev','staging','prod']},},};constresult=validate(config,schema);if(!result.valid){console.error(formatErrors(result));}

Schema nodes support: type, required, default, enum, min, max, pattern (strings), coerce, items (arrays), properties (objects).

🌳 Browser & Deno support

jsoncraft ships as ESM with no Node.js-specific imports in the core library (only the CLI uses node:fs and node:process). Import it directly in a browser or Deno project:

<scripttype="module">import{query}from'https://esm.sh/jsoncraft';console.log(query(data,'$.users[*].name'));</script>

🤝 Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines on how to get started, coding standards, and the pull-request process.

Some areas where help is especially appreciated:

  • 🐛 Bug reports and reproducible test cases
  • 📝 Documentation improvements and translations
  • 🧪 More format edge cases (YAML/TOML/CSV roundtrips)
  • 🔌 New transform operators and query filter functions
  • 🎨 CLI enhancements (interactive mode, autocompletion)

📜 License

MIT © Cryptoteep

See LICENSE for the full text.

💖 Sponsors

If jsoncraft saves you time, consider sponsoring the project or just starring the repo — it really helps.

About

A zero-dependency, TypeScript-first JSON toolkit for querying, transforming, and converting JSON data. JSONPath, YAML/CSV/TOML conversion, diff, merge, validate — runs on Node.js, Bun, Deno, and browsers.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages