json-hero-path
A lightweight TypeScript library for querying, filtering, and updating deeply nested JSON objects using compact, JSONPath-like path strings.
Repository Health
Technical Analysis
@jsonhero/path is a small, dependency-free TypeScript library that lets you read, filter, and mutate deeply nested JSON structures using a compact path syntax similar to JSONPath. Instead of chaining manual property lookups and array-index checks, you construct a JSONHeroPath from a string like $.people.*.favouriteThings and use first() or all() to pull out matching values, optionally alongside the exact path each value was found at.
Beyond reads, the library supports in-place mutation through set() and merge(), and exposes path introspection (parent, root, child(), components) so higher-level tools — such as JSON Hero, the project this library was extracted from — can build path-aware UI features like breadcrumbs, renaming, and value editors on top of arbitrary JSON documents.
What You Get
- String-based path queries - Parse paths like
$.people.*.favouriteThings.*into typed components and resolve them against any JSON object. - first() / all() result retrieval -
first()returns a single match,all()returns every match, both with an optionalincludePathflag that returns the matched path alongside each value. - In-place set and merge -
set()overwrites every value a path resolves to;merge()appends into matched arrays or shallow-merges into matched objects. - Path introspection -
.parent,.root,.child(key), and.componentsexpose a path’s structure for building path-aware tooling such as breadcrumbs or renaming UIs. - JSON Pointer interop -
JSONHeroPath.fromPointer()and.jsonPointer()convert to and from RFC 6901 JSON Pointer strings.
Common Use Cases
- Filtering deeply nested API responses - Extract every value at a shape like
$.orders.*.items.*.skuwithout writing recursive traversal code. - Building JSON explorer/editor UIs - Power path-aware features (selection, breadcrumbs, renaming) in tools like JSON Hero that let users click through arbitrary JSON documents.
- Bulk-updating nested fields - Use
set()ormerge()to apply a change to every object matched by a wildcard path, such as resetting a field across all items in an array. - Interop with JSON Pointer tooling - Convert JSONHeroPath paths to and from JSON Pointer strings when integrating with pointer-based specs or libraries.
Under The Hood
Architecture
JSONHeroPath models a path as an ordered list of PathComponent objects — StartPathComponent, SimpleKeyPathComponent, WildcardPathComponent, and SlicePathComponent — each implementing a shared query(results) method, a clean strategy pattern where every component owns its own parsing and traversal logic. A PathBuilder tokenizes an input string with regex (splitting on unescaped dots) and delegates each token to the matching component’s fromString() factory. The all() method on JSONHeroPath folds the components list into a single traversal: it threads an array of QueryResult objects (tracking depth, resolved sub-path, and current value) through each component in sequence, flattening nested-array results at the end. set() and merge() are built entirely on top of all({ includePath: true }), reusing the same traversal rather than duplicating query logic — a small but deliberate design choice that keeps read and write paths consistent.
Tech Stack
Written in strict-mode TypeScript, targeting ES5 with CommonJS output via tsc. The published package ships compiled JavaScript plus .d.ts declarations from lib/. It has zero runtime dependencies — lodash appears only as a devDependency for the test suite. Tooling is tslint (now-deprecated) plus prettier for formatting, and jest with ts-jest for running tests directly against the TypeScript sources.
Code Quality
Four Jest test files (parsing, path construction, JSON Pointer conversion, and set/merge updates) exercise the public API against realistic nested-object fixtures, covering wildcards, slices, escaping, and edge cases like missing array indices. There is no CI workflow configured in the repository, so tests appear to run only locally and via the prepublishOnly/preversion npm script hooks. Error handling favors silent skips (returning null/empty arrays when a path segment doesn’t resolve) over thrown exceptions, except for a couple of explicit SyntaxError/Error throws in path parsing and JSON-Pointer-on-wildcard cases. Naming is consistent and the component/interface split keeps each file narrowly scoped.
API Design
The public surface is deliberately small: construct a JSONHeroPath from a string or component array, then call first()/all() to read or set()/merge() to write — no configuration objects or builder chains required for the common case. Path strings read naturally close to JSONPath/lodash-style dot notation, and helper accessors (.parent, .root, .child()) let consumers manipulate paths as values rather than re-parsing strings. Full TypeScript types ship with the package, so editor autocomplete and type-checking work immediately with no extra @types install.