mrkeyoor.com_
Sat 08 Aug 21:58 UTC
npmUtilsupdated 08 Aug 2026

@stoplight/json

@stoplight/json is a TypeScript utility collection for source-aware JSON work, especially API-description tooling. Its main parser returns decoded data, diagnostics, an abstract syntax tree, and a line-offset map, which lets editors translate between cursor positions and JSON paths. The package also converts JSON paths to URI-fragment pointers, detects and resolves reference shapes, traverses objects, preserves key order, and offers non-throwing parse and cycle-tolerant stringify helpers. It is broader than a JSON parser and carries conventions from Stoplight's OpenAPI toolchain.

Verdict

Useful infrastructure for editors and API tooling that genuinely need diagnostics, AST ranges, position mapping, and Stoplight reference helpers together. For ordinary JSON parsing, pointer handling, or cycle-safe output, pick the focused underlying package and avoid the surprising safeParse and safeStringify semantics.

API stability4/5Version 3 exposes many small named functions through a flat index, and the 3.x line has remained compatible enough for widespread transitive use. Type declarations cover AST nodes, parse options, and parser results. Stability is harder to reason about because the surface includes parsing, pointers, references, bundling, traversal, ordered objects, and resolvers, while there is no exports map to declare supported subpaths.
Docs2/5The README gives a useful function index, parsing example, position-mapping example, and a live TypeDoc site. However, its parseWithPointers description and example refer to result.pointers, which current source does not return. Critical edge behavior for safeParse, safeStringify, URI-fragment-only pointer decoding, replaced default parser options, cyclic AST parents, and ordered-object results is left to source and tests.
Maintenance3/5Version 3.21.7 was published on 2024-09-02, and GitHub reports the last repository push on 2024-12-09. The repository is not archived and reports 22 open issues and PRs, but no newer release or push appears in the following twenty months before this guide's date. The old Node floor and jsonc-parser 2.2 dependency also show a compatibility-first posture rather than active modernization.
Ecosystem4/5The npm downloads endpoint reports 3,698,463 downloads in its last-week window, reflecting heavy use through Stoplight and OpenAPI dependency trees. GitHub reports only 31 stars, so most adoption is infrastructural rather than direct. Compatibility with @stoplight/types, ordered objects, JSON references, and source locations is valuable inside that ecosystem but less compelling for unrelated applications.

Use it if

  • You need parsed JSON data plus diagnostics and AST ranges for an editor, linter, or API-description tool
  • You need to map zero-based line and character positions to JSON paths and back
  • Your code already uses Stoplight types, JSON references, or ordered-object utilities and benefits from matching helpers
  • You need URI-fragment JSON Pointer encoding and decoding for paths containing slashes, tildes, or Unicode
Skip it if

Setup reality

Install with npm install @stoplight/json. There are no peers, native builds, credentials, or required config, and the package publishes CommonJS, an ESM module field, and TypeScript declarations. The runtime dependency tree is not tiny: lodash, jsonc-parser 2.2.x, safe-stable-stringify, @stoplight/path, @stoplight/types, and @stoplight/ordered-object-literal are direct dependencies. API naming hides several important contracts. parseWithPointers does not throw for ordinary syntax errors; inspect result.diagnostics before trusting result.data, and use result.ast plus result.lineMap for location helpers. Its default options disallow comments, but passing your own options object replaces that default, so state disallowComments explicitly when combining it with duplicate-key or key-order settings. Line and character positions are zero-based. pathToPointer returns URI-fragment form beginning with #, and pointerToPath rejects a pointer without that hash; use another helper if you need bare /a/b pointer syntax. safeParse returns undefined on invalid JSON, but it returns non-string inputs unchanged and preserves a numeric string when conversion would change its textual representation. safeStringify first tries JSON.stringify, then falls back to safe-stable-stringify for cycles, yet it returns a top-level string unchanged. stringify wraps that helper and throws only when no string can be produced. AST nodes have parent links, so they are cyclic even though the root parent is removed. preserveKeyOrder creates special ordered objects and can affect enumeration through Proxy-related helpers. Browser use is advertised, but the collection includes much more than most front-end bundles need. Import focused functions and confirm tree-shaking in your actual bundler.

Patterns

Parse data and check syntax diagnosticsparse-with-diagnostics

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

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

Syntax problems are reported in diagnostics rather than thrown. Do not treat data as valid before checking that array.

Parse JSON with comments intentionallyallow-json-comments

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

Comments are disallowed by the default options object. Passing a custom options object changes that contract, so keep the choice explicit.

Report duplicate object keysdetect-duplicate-keys

const result = parseWithPointers(
  '{"port": 3000, "port": 4000}',
  { disallowComments: true, ignoreDuplicateKeys: false }
);

const duplicates = result.diagnostics.filter((d) => d.message === 'DuplicateKey');

Duplicate detection is enabled only when ignoreDuplicateKeys is exactly false. The decoded object still cannot retain both values under one key.

Find the JSON path at a cursor positionmap-position-to-path

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

const parsed = parseWithPointers(`{
  "address": { "street": 123 }
}`);
const path = getJsonPathForPosition(parsed, { line: 1, character: 25 });
// ['address', 'street'] for a position inside that value

Line and character indexes are zero-based. Out-of-range positions and positions without a matching path can return undefined.

Find the source range for a JSON pathmap-path-to-location

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

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

The helper needs the parseWithPointers result because it walks that result's AST. It returns undefined when the exact path is missing.

Convert a path to URI-fragment JSON Pointerencode-json-pointer

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

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

The return value begins with # and percent-encodes URI-fragment content. Slash and tilde inside segments receive JSON Pointer escaping.

Convert a URI-fragment pointer to a pathdecode-json-pointer

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

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

pointerToPath requires the # prefix. A bare '/paths/~1users/get' string throws URIError.

Parse without a try and catch blocksafe-parse-invalid-json

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

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

undefined is also a possible outcome for JSON.stringify-related values elsewhere, so do not use this helper when you need structured error details.

Notice precision-sensitive numeric inputpreserve-large-number-text

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

safeParse returns the original string when JavaScript number conversion would change its textual value. This differs from JSON.parse, which returns a number.

Serialize a circular objectstringify-circular-data

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

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

The helper tries JSON.stringify first, then safe-stable-stringify. A top-level string is returned unchanged rather than JSON-quoted.

Replace cycles with pointer referencesdecycle-with-references

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

const root = { name: 'root' };
root.child = { parent: root };

console.log(decycle(root));
// { name: 'root', child: { parent: { $ref: '#' } } }

decycle creates a copied structure and represents an ancestor cycle as a {$ref} object using URI-fragment JSON Pointer syntax.

Visit every object property with its parent pathtraverse-properties

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

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

The traversal recursively follows every non-null object and has no cycle detection. Decycle or guard cyclic inputs before using it.

Alternatives

PackageRegistryPick it when
jsonc-parsernpmYou mainly need tolerant parsing, AST edits, locations, and JSON-with-comments support without Stoplight's larger helper collection
json-source-mapnpmYou need decoded JSON plus direct source locations for values and keys through JSON Pointer paths
json-pointernpmYou only need RFC 6901 pointer compile, get, set, and remove operations
safe-stable-stringifynpmYour only requirement is deterministic cycle-safe stringification with a focused API