sdxc

Type to search, or start from one of these:

[ API design ]

@sdxc/json-pointer

Parse, stringify, get and set RFC 6901 JSON Pointers

npm add @sdxc/json-pointer
pnpm add @sdxc/json-pointer
yarn add @sdxc/json-pointer
bun add @sdxc/json-pointer
Installs with
@sdxc/result

Parse, stringify, get and set RFC 6901 JSON Pointers.

A JSON Pointer names a value inside a JSON document as a /-separated path. ~ in a member name is written ~0 and / is written ~1, so a key holding either still points at itself. The empty string is the whole document.

Installation

npm add @sdxc/json-pointer

Fallible calls return @sdxc/result values.

Usage

import { get, parse, set, stringify } from "@sdxc/json-pointer";
import { unwrap } from "@sdxc/result";

stringify(["a/b", "m~n"]); // "/a~1b/m~0n"
unwrap(parse("/a~1b/m~0n")); // ["a/b", "m~n"]

let document = { foo: ["bar", "baz"], "a/b": 1 };
unwrap(get(document, "/foo/0")); // "bar"
unwrap(get(document, "/a~1b")); // 1
unwrap(set(document, "/foo/0", "qux")); // { foo: ["qux", "baz"], "a/b": 1 }

API

stringify(segments: readonly (string | number)[]): string

Writes path segments as a JSON Pointer. The empty list is ""; each segment is / plus its escaped text, and numbers are String()'d so 0 and "0" select the same index.

parse(pointer: string): Result<string[], JsonPointerParseError>

Reads a pointer into unescaped tokens. "" is []. Any other string that does not start with /, or that contains a ~ not followed by 0 or 1, fails.

get(document: unknown, pointer: string): Result<unknown, JsonPointerError>

Walks document along pointer. A missing member, an out-of-range index, or a walk through a scalar fails rather than returning undefined.

set(document: unknown, pointer: string, value: unknown): Result<unknown, JsonPointerError>

Returns a new tree with value stored at pointer. The empty pointer replaces the document; undefined is not a JSON value and fails. Intermediate tokens must already resolve — creating missing parents is RFC 6902 add.

Types

JsonPointerError

A pointer that cannot be applied: the string is not RFC 6901, or a token has no member, index, or container to land on.

JsonPointerParseError

A string that is not a JSON Pointer. Extends JsonPointerError, so get and set can return a parse failure as the same error type.

Pattern: Report a validation issue as a pointer

Flatten a schema path to keys, then stringify, so a member named a/b still points at itself in the problem's errors list.

import { stringify } from "@sdxc/json-pointer";

function toPointer(path: readonly (string | number | { key: string | number })[]): string {
	return stringify(path.map((segment) => (typeof segment === "object" ? segment.key : segment)));
}

toPointer([{ key: "users" }, { key: 0 }, "a/b"]); // "/users/0/a~1b"

Pattern: Update one field without inventing parents

set copies the tree and writes the leaf. A pointer whose parent is missing fails, so a PATCH that would create /a/b on {} is refused here and left to JSON Patch add.

import { set } from "@sdxc/json-pointer";
import { isFailure } from "@sdxc/result";

let next = set({ a: { b: 1 } }, "/a/b", 2);
if (isFailure(next)) throw next.error;
// { a: { b: 2 } }

let missing = set({}, "/a/b", 1);
isFailure(missing); // true

Written by Sergio Xalambrí. Follow @sergiodxa for new packages, or sponsor the work.