json-source-map
Parses and stringifies JSON while mapping every key and value to its exact line, column, and character position.
Repository Health
Technical Analysis
json-source-map is a small, dependency-free JavaScript library that replaces JSON.parse/JSON.stringify with versions that also return a pointers map. Every entry in that map is keyed by an RFC 6901 JSON Pointer path and gives the precise line, column, and character offset where the key and value begin and end in the original (or generated) JSON text.
Beyond source-mapping, it extends what native JSON handling supports: an optional bigint mode parses out-of-range integers as native BigInt instead of silently losing precision, and an optional es6 mode serializes Map, Set, and typed arrays directly. It is best known as the source-mapping engine behind JSON Schema validators such as Ajv, which use it to point users at the exact span of a value that failed validation.
What You Get
- Drop-in
parse(json)/stringify(data, _, space)functions that return{ data|json, pointers } - A
pointersobject mapping every JSON Pointer path to{ key, keyEnd, value, valueEnd }location ranges (line/column/pos) - An optional
bigintparse mode that preserves integers beyondNumber.MAX_SAFE_INTEGER/MIN_SAFE_INTEGERas nativeBigInt - An optional
es6stringify mode that serializesMap,Set, and typed arrays as JSON - Zero runtime dependencies and CommonJS output that runs unmodified in Node or the browser
Common Use Cases
- Pinpointing JSON Schema validation errors to an exact line/column in the source document
- Building source maps for JSON-based DSLs or config languages that compile to JSON
- Synchronizing a form view and a raw-JSON view in a visual data editor
- Underlining the exact offending span of a key or value in JSON linting/IDE tooling
Under The Hood
Architecture
The entire library is one file (index.js, ~460 lines) exporting two independent closures, parse and stringify, each carrying its own private line/column/pos counters and a pointers accumulator. parse is a hand-written recursive-descent scanner (_parse → parseObject/parseArray/parseString/parseNumber) that advances character-by-character via getChar/backChar, calling map(ptr, 'value')/map(ptr, 'valueEnd') before and after each token so the JSON-grammar walk and the pointer-mapping bookkeeping are interleaved rather than separated into distinct layers. stringify mirrors this shape in reverse, walking the input data with _stringify and recording the same location metadata as it emits output. There is no dependency injection or module boundary between grammar and mapping concerns — changing core traversal logic means editing this single file directly.
Tech Stack
Plain ES5-style JavaScript (var, no destructuring) published as a CommonJS module (exports.parse, exports.stringify) with zero runtime dependencies, so it runs unmodified in Node or a browser. Dev tooling is dated but complete: ESLint 6 (eslint:recommended plus a custom ruleset in .eslintrc.yml) for linting, Mocha 3 with Node’s assert for tests, nyc (Istanbul) for coverage, Coveralls for CI coverage reporting, and Travis CI (.travis.yml) for build automation. There is no bundler, no TypeScript, and no build step — the raw source file ships as-is.
Code Quality
The test suite (spec/index.js, ~700 lines) is extensive relative to the library’s size: it asserts exact line/column/pos values for nested objects and arrays across both parse and stringify, using assert.deepStrictEqual against hand-computed pointer maps rather than loose equality. Error handling mirrors native JSON.parse/JSON.stringify semantics deliberately, throwing the same SyntaxError messages on malformed input. There is no static type system (no TypeScript/Flow annotations or .d.ts file bundled), naming is terse but consistent, and linting is enforced via the checked-in ESLint config, though CI (Travis) is no longer an active service.
What Makes It Unique
Native JSON.parse/JSON.stringify return no positional information at all once a document round-trips through them — this library fills that gap by attaching a JSON Pointer-addressed location map to both directions, which is why several JSON Schema validators (most notably Ajv) depend on it specifically to report exactly where a value failed validation. Its secondary contribution — parsing oversized integers into BigInt and serializing Map/Set/typed arrays — extends the JSON data model slightly beyond what the language’s built-in JSON object supports, though this part follows patterns established elsewhere rather than being novel on its own.