mrkeyoor.com_
Wed 23 Sept 02:51 UTC
npmUtilsupdated 22 Sept 2026

@stoplight/json review

@stoplight/json 3.21.7 is a source-aware JSON toolkit for editors, linters, and API-description tooling, and our browser build measured 107.3 KB minified. parseWithPointers returns decoded data, syntax diagnostics, an AST, and a line map so callers can translate cursor positions into JSON paths and back. Other exports encode URI-fragment JSON Pointers, detect and resolve reference objects, traverse values, preserve key order, parse without throwing, and stringify cycles. Patch 3.21.7 reverted an earlier change identified in the release notes as stop-184; it adds no documented feature. This package carries Stoplight's conventions and six direct dependencies, so ordinary JSON.parse and JSON.stringify users are buying much more machinery than they need.

Verdict

@stoplight/json 3.21.7 installed in 3.2 seconds, occupied 7 MB across 9 packages, and produced a 37.6 KB gzipped bundle in our sandbox. It earns that cost in source-aware editors and Stoplight API tooling; ordinary parsing, pointer handling, or cycle-safe output should use a focused package.

We installed it

Lab card: what happened when we installed @stoplight/jsonScreenshot of @stoplight/json documentation
Install✓ · 3.2s9 packages on disk · 7 MB
ImportESM import works · require() works · CommonJS package
Browser37.6 KBgzipped (107.3 KB minified), bundled with esbuild
TypesTypeScript types bundled
Known vulns00 critical · 0 high · 0 moderate · 0 low (npm audit)

Answers from our run

Does @stoplight/json install cleanly?

Yes. In a fresh container with an empty cache, npm install @stoplight/json finished in 3 seconds, leaving 9 packages and 7 MB on disk. npm audit reported no known vulnerabilities.

How much does @stoplight/json add to a browser bundle?

37.6 KB gzipped (107.3 KB minified) when the whole package is bundled for the browser with esbuild. Importing only part of it is usually smaller.

Does @stoplight/json work with both ESM and CommonJS?

Yes. Both import '@stoplight/json' and require('@stoplight/json') worked in Node 22 in our run. The package is published as CommonJS.

Does @stoplight/json include TypeScript types?

Yes, type declarations ship inside the package, so no @types install is needed.

@stoplight/json or jsonc-parser: which should you use?

jsonc-parser: Use it for tolerant parsing, AST edits, locations, and JSON with comments without Stoplight's wider helper set. @stoplight/json 3.21.7 installed in 3.2 seconds, occupied 7 MB across 9 packages, and produced a 37.6 KB gzipped bundle in our sandbox.

When should you not use @stoplight/json?

You only need JSON.parse or JSON.stringify. Our install brought 9 packages and 7 MB for a much broader tool collection.

API stability4/5Version 3.21.7 exports many small named utilities from one flat entry, with bundled declarations covering parser results, AST nodes, locations, paths, references, ordered values, and traversal callbacks. Widespread transitive use suggests the 3.x contract has remained workable. The surface is still broad enough that patch behavior can be hard to infer, and 3.21.7 is itself a revert of stop-184. Without an exports map, the package also does not define supported subpaths for consumers who try to avoid the main entry.
Docs2/5The README indexes the main utilities, shows source-aware parsing and both position-mapping directions, and links to a working TypeDoc site. Its central parseWithPointers example is stale: it accesses result.pointers, while the current implementation returns data, diagnostics, ast, and lineMap. The docs also omit safeParse's pass-through and precision behavior, safeStringify's unquoted top-level strings, hash-only pointer decoding, replaced parser defaults, cyclic AST parents, and traversal's lack of cycle protection.
Maintenance3/5npm published 3.21.7 on 2024-09-02, GitHub records the last push on 2024-12-09, and the repository is not archived. It has 31 stars and reports 22 open issues and pull requests. The latest patch reverted a prior change rather than adding a new capability, and there was no newer release by our 2026-08-26 check. Node 8.3 support and jsonc-parser 2.2.x show a compatibility-first package that has not followed current upstream parser releases.
Ecosystem4/5The npm endpoint counted 3,906,462 downloads in the latest completed week. Much of that reach comes through Stoplight and OpenAPI dependency graphs, where @stoplight/types, path handling, ordered objects, JSON references, diagnostics, and locations already share conventions. Direct project interest is smaller at 31 GitHub stars. Outside that toolchain, the measured 9-package install and 37.6 KB gzip bundle make focused packages more attractive for one or two JSON operations.

Use it if

  • An editor or linter needs decoded JSON plus diagnostics, AST ranges, and zero-based line and character mapping.
  • API-description code already uses Stoplight path, type, reference, or ordered-object conventions.
  • JSON paths containing slashes, tildes, or Unicode must convert to and from URI-fragment pointer form.
  • One dependency should cover location-aware parsing, reference traversal, cycle handling, and ordered objects.
Skip it if

Setup reality

We installed @stoplight/json 3.21.7 in a fresh unprivileged Node 22 Bookworm sandbox. npm completed in 3.2 seconds and left 9 packages using 7 MB on disk. The package is 368 KB unpacked, declares 6 direct dependencies and 0 peers, uses Apache-2.0, and supports Node 8.3 or newer. npm audit found 0 known vulnerabilities. Both require() and ESM import worked against its CommonJS package without an exports map. TypeScript declarations are bundled. Our browser build measured 107.3 KB minified and 37.6 KB gzipped.

There are no credentials, native builds, or config files. parseWithPointers reports normal syntax failures in diagnostics rather than throwing, so check that array before trusting data. Its default options disallow comments. Passing a replacement options object can lose that default, so include disallowComments explicitly alongside duplicate-key or key-order settings. Line and character coordinates are zero-based, and the location helpers require the AST and line map from the parse result.

pathToPointer returns URI-fragment syntax beginning with #. pointerToPath expects that hash and throws URIError for a bare /a/b pointer. safeParse returns undefined for invalid JSON, passes a non-string through, and can preserve a numeric string when JavaScript number conversion changes its textual value. safeStringify first tries JSON.stringify and falls back to safe-stable-stringify for cycles, yet a top-level string is returned without JSON quoting.

AST nodes link to parents and are cyclic even though the root parent is removed. Do not JSON.stringify the AST directly. traverse recursively follows object properties without cycle detection, so guard or decycle cyclic input first. Ordered-object helpers use special representation and Proxy-related behavior to retain insertion choices. Browser support exists, but a 37.6 KB gzip full import is expensive for a single pointer or parse helper; verify tree-shaking or install the focused underlying package.

Patterns

Parse and inspect syntax diagnostics parse-with-diagnostics

import { parseWithPointers } from '@stoplight/json';

const result = parseWithPointers('{"name": "Ada",}');
if (result.diagnostics.length) {
  console.error(result.diagnostics);
} else {
  console.log(result.data);
}

Ordinary syntax problems appear in diagnostics instead of throwing. Check the array before using data.

Allow comments explicitly allow-json-comments

const result = parseWithPointers(
  '{ /* owner */ "name": "Ada" }',
  { disallowComments: false }
);

The default disallows comments. Passing an options object replaces defaults, so state the comment policy with the other parser switches.

Detect duplicate keys report-duplicate-keys

const result = parseWithPointers(
  '{"port": 3000, "port": 4000}',
  { disallowComments: true, ignoreDuplicateKeys: false }
);
const duplicates = result.diagnostics.filter(
  (item) => item.message === 'DuplicateKey'
);

Detection requires ignoreDuplicateKeys to be false. The decoded object still cannot retain both values under one property name.

Find the path under a cursor map-position-to-json-path

import { getJsonPathForPosition, parseWithPointers } from '@stoplight/json';

const parsed = parseWithPointers('{\n  "address": { "street": 123 }\n}');
const path = getJsonPathForPosition(parsed, { line: 1, character: 25 });

Line and character indexes start at 0. A position outside a matching AST node can return undefined.

Find a property's source range map-json-path-to-range

import { getLocationForJsonPath } from '@stoplight/json';

const location = getLocationForJsonPath(parsed, ['address', 'street']);
if (location) console.log(location.range.start, location.range.end);

Pass the original parseWithPointers result because this lookup walks its AST and line map. Missing paths return undefined.

Encode a path as a pointer encode-uri-fragment-pointer

import { pathToPointer } from '@stoplight/json';

const pointer = pathToPointer(['paths', '/users', 'get']);
// #/paths/~1users/get

The helper returns URI-fragment form with a leading #. Slash and tilde inside segments use JSON Pointer escaping.

Decode a pointer into path segments decode-uri-fragment-pointer

import { pointerToPath } from '@stoplight/json';

const path = pointerToPath('#/paths/~1users/get');

The leading # is mandatory. Passing /paths/~1users/get without it throws URIError.

Handle invalid JSON as undefined parse-without-throwing

import { safeParse } from '@stoplight/json';

const value = safeParse('{broken');
if (value === undefined) console.log('invalid JSON');

safeParse also returns non-string inputs unchanged, so validate the input type when that pass-through would be surprising.

Keep precision-sensitive numeric text preserve-large-number-text

const value = safeParse('9007199254740993');
console.log(typeof value, value);

The result can remain the original string when JavaScript number conversion would alter its decimal text.

Serialize a circular object stringify-circular-value

import { safeStringify } from '@stoplight/json';

const user = { name: 'Ada' };
user.self = user;
const json = safeStringify(user, null, 2);

The fallback handles cycles, but a top-level string is returned unchanged instead of being wrapped in JSON quotes.

Replace ancestor cycles with references decycle-with-json-pointers

import { decycle } from '@stoplight/json';

const root = { name: 'root' };
root.child = { parent: root };
const copied = decycle(root);

Ancestor cycles become {$ref: '#...'} objects using URI-fragment JSON Pointer syntax in a copied structure.

Visit properties with their paths traverse-object-properties

import { traverse } from '@stoplight/json';

traverse(document, ({ parentPath, property, propertyValue }) => {
  if (property === '$ref') {
    console.log([...parentPath, property], propertyValue);
  }
});

traverse has no cycle detection. Decycle the value or track visited objects before walking cyclic graphs.

Alternatives

PackageRegistryPick it when
jsonc-parsernpmUse it for tolerant parsing, AST edits, locations, and JSON with comments without Stoplight's wider helper set.
json-source-mapnpmUse it when decoded JSON and source positions keyed by JSON Pointer are the only required result.
json-pointernpmUse it for focused RFC 6901 compile, get, set, and remove operations.
safe-stable-stringifynpmUse it when deterministic, cycle-safe stringification is the sole requirement.

More utils guides

lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →

How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.