first commit

This commit is contained in:
Stefan Hacker
2026-04-03 09:38:48 +02:00
commit 37ad745546
47450 changed files with 3120798 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
# JSON Pointer - `json-pointer`
Fast implementation of [JSON Pointer (RFC 6901)][json-pointer]
specification in TypeScript.
[json-pointer]: https://tools.ietf.org/html/rfc6901
## Usage
Can find a value in a JSON object using three methods: (1) JSON Pointer string,
(2) array of steps, or (3) a pre-compiled function.
## Examples
Find the value in a JSON document at some specific location.
### Find by JSON Pointer string
```js
import { findByPointer } from '@jsonjoy.com/json-pointer';
const doc = {
foo: {
bar: 123,
},
};
const res = findByPointer(doc, '/foo/bar');
```
### Find by path array
Alternatively, you can specify an array of steps, such as `['foo', 'bar']`. Or,
use the `parseJsonPointer` function to convert a JSON Pointer string to an array.
```js
import { find, parseJsonPointer } from '@jsonjoy.com/json-pointer';
const doc = {
foo: {
bar: 123,
},
};
const path = parseJsonPointer('/foo/bar');
const ref = find(doc, path);
console.log(ref);
// { val: 123, obj: { bar: 123 }, key: 'bar' }
```
### Pre-compiled function
If you know the path in advance, you can compile a function that will find the
value at that location, it will work few times faster than the previous methods.
```js
import { $$find } from '@jsonjoy.com/json-pointer/lib/codegen';
const doc = {
foo: {
bar: 123,
},
};
const finder = $$find(['foo', 'bar']);
const res = finder(doc);
```
## Low-level API
Convert JSON Pointer to path array and back.
```js
import { parseJsonPointer } from '@jsonjoy.com/json-pointer';
console.log(parseJsonPointer('/f~0o~1o/bar/1/baz'));
// [ 'f~o/o', 'bar', '1', 'baz' ]
console.log(formatJsonPointer(['f~o/o', 'bar', '1', 'baz']));
// /f~0o~1o/bar/1/baz
```
Decode and encode a single step of JSON Pointer.
```js
console.log(unescapeComponent('~0~1'));
// ~/
console.log(escapeComponent('~/'));
// ~0~1
```
+3
View File
@@ -0,0 +1,3 @@
import type { JavaScript } from '@jsonjoy.com/codegen';
import type { Path } from '../types';
export declare const $$find: (path: Path) => JavaScript<(doc: unknown) => unknown>;
+15
View File
@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.$$find = void 0;
const $$find = (path) => {
if (path.length === 0)
return '(function(x){return x})';
let fn = '(function(){var h=Object.prototype.hasOwnProperty;return(function(o){var k,u=void 0;try{';
for (let i = 0; i < path.length; i++) {
fn += 'k=' + JSON.stringify(path[i]) + ';';
fn += 'if(!h.call(o,k))return u;o=o[k];';
}
fn += 'return o}catch(e){return u}})})()';
return fn;
};
exports.$$find = $$find;
+7
View File
@@ -0,0 +1,7 @@
import type { Reference } from '../find';
import type { Path } from '../types';
import { type JavaScriptLinked } from '@jsonjoy.com/util/lib/codegen';
type Fn = (val: unknown) => Reference;
export declare const $$findRef: (path: Path) => JavaScriptLinked<Fn>;
export declare const $findRef: (path: Path) => Fn;
export {};
+48
View File
@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.$findRef = exports.$$findRef = void 0;
const codegen_1 = require("@jsonjoy.com/util/lib/codegen");
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const $$findRef = (path) => {
if (!path.length) {
return {
deps: [],
js: /* js */ `(function(){return function(val){return {val:val}}})`,
};
}
let loop = '';
for (let i = 0; i < path.length; i++) {
const key = JSON.stringify(path[i]);
loop += /* js */ `
obj = val;
key = ${key};
if (obj instanceof Array) {
var length = obj.length;
if (key === '-') key = length;
else {
var key2 = ${~~path[i]};
${String(~~path[i]) !== String(path[i]) ? `if ('' + key2 !== key) throw new Error('INVALID_INDEX');` : ''}
${~~path[i] < 0 ? `throw new Error('INVALID_INDEX');` : ''}
key = key2;
}
val = obj[key];
} else if (typeof obj === 'object' && !!obj) {
val = has(obj, key) ? obj[key] : undefined;
} else throw new Error('NOT_FOUND');
`;
}
const js = /* js */ `(function(has, path){
return function(val) {
var obj, key;
${loop}
return {val:val, obj:obj, key:key};
};
})`;
return {
deps: [hasOwnProperty_1.hasOwnProperty, path],
js,
};
};
exports.$$findRef = $$findRef;
const $findRef = (path) => (0, codegen_1.compileClosure)((0, exports.$$findRef)(path));
exports.$findRef = $findRef;
+2
View File
@@ -0,0 +1,2 @@
export { $$find } from './find';
export { $$findRef, $findRef } from './findRef';
+8
View File
@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.$findRef = exports.$$findRef = exports.$$find = void 0;
var find_1 = require("./find");
Object.defineProperty(exports, "$$find", { enumerable: true, get: function () { return find_1.$$find; } });
var findRef_1 = require("./findRef");
Object.defineProperty(exports, "$$findRef", { enumerable: true, get: function () { return findRef_1.$$findRef; } });
Object.defineProperty(exports, "$findRef", { enumerable: true, get: function () { return findRef_1.$findRef; } });
+48
View File
@@ -0,0 +1,48 @@
import type { Path } from './types';
export interface Reference {
/** Target value where pointer is pointing. */
readonly val: unknown;
/** Object which contains the target value. */
readonly obj?: unknown | object | unknown[];
/** Key which targets the target value in the object. */
readonly key?: string | number;
}
/**
* Finds a target in document specified by JSON Pointer. Also returns the
* object containing the target and key used to reference that object.
*
* Throws Error('NOT_FOUND') if pointer does not result into a value in the middle
* of the path. If the last element of the path does not result into a value, the
* lookup succeeds with `val` set to `undefined`. It can be used to discriminate
* missing values, because `undefined` is not a valid JSON value.
*
* If last element in array is targeted using "-", e.g. "/arr/-", use
* `isArrayEnd` to verify that:
*
* ```js
* const ref = find({arr: [1, 2, 3], ['arr', '-']});
* if (isArrayReference(ref)) {
* if (isArrayEnd(ref)) {
* // ...
* }
* }
* ```
*
* @param skipLast Number of steps to skip at the end. Useful to find reference of
* parent step, without constructing a new `Path` array.
*/
export declare const find: (val: unknown, path: Path) => Reference;
export interface ArrayReference<T = unknown> {
/** `undefined` in case JSON Pointer points to last element, e.g. "/foo/-". */
readonly val: undefined | T;
readonly obj: T[];
readonly key: number;
}
export declare const isArrayReference: <T = unknown>(ref: Reference) => ref is ArrayReference<T>;
export declare const isArrayEnd: (ref: ArrayReference) => boolean;
export interface ObjectReference<T = unknown> {
readonly val: T;
readonly obj: Record<string, T>;
readonly key: string;
}
export declare const isObjectReference: <T = unknown>(ref: Reference) => ref is ObjectReference<T>;
+71
View File
@@ -0,0 +1,71 @@
"use strict";
/* tslint:disable no-string-throw */
Object.defineProperty(exports, "__esModule", { value: true });
exports.isObjectReference = exports.isArrayEnd = exports.isArrayReference = exports.find = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const { isArray } = Array;
/**
* Finds a target in document specified by JSON Pointer. Also returns the
* object containing the target and key used to reference that object.
*
* Throws Error('NOT_FOUND') if pointer does not result into a value in the middle
* of the path. If the last element of the path does not result into a value, the
* lookup succeeds with `val` set to `undefined`. It can be used to discriminate
* missing values, because `undefined` is not a valid JSON value.
*
* If last element in array is targeted using "-", e.g. "/arr/-", use
* `isArrayEnd` to verify that:
*
* ```js
* const ref = find({arr: [1, 2, 3], ['arr', '-']});
* if (isArrayReference(ref)) {
* if (isArrayEnd(ref)) {
* // ...
* }
* }
* ```
*
* @param skipLast Number of steps to skip at the end. Useful to find reference of
* parent step, without constructing a new `Path` array.
*/
const find = (val, path) => {
const pathLength = path.length;
if (!pathLength)
return { val };
let obj;
let key;
for (let i = 0; i < pathLength; i++) {
obj = val;
key = path[i];
if (isArray(obj)) {
const length = obj.length;
if (key === '-')
key = length;
else {
if (typeof key === 'string') {
const key2 = ~~key;
if ('' + key2 !== key)
throw new Error('INVALID_INDEX');
key = key2;
if (key < 0)
throw new Error('INVALID_INDEX');
}
}
val = obj[key];
}
else if (typeof obj === 'object' && !!obj) {
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, key) ? obj[key] : undefined;
}
else
throw new Error('NOT_FOUND');
}
const ref = { val, obj, key };
return ref;
};
exports.find = find;
const isArrayReference = (ref) => isArray(ref.obj) && typeof ref.key === 'number';
exports.isArrayReference = isArrayReference;
const isArrayEnd = (ref) => ref.obj.length === ref.key;
exports.isArrayEnd = isArrayEnd;
const isObjectReference = (ref) => typeof ref.obj === 'object' && typeof ref.key === 'string';
exports.isObjectReference = isObjectReference;
+1
View File
@@ -0,0 +1 @@
export * from './v5';
+4
View File
@@ -0,0 +1,4 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./v5"), exports);
+2
View File
@@ -0,0 +1,2 @@
import type { Reference } from '../find';
export declare const findByPointer: (pointer: string, val: unknown) => Reference;
+40
View File
@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findByPointer = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const util_1 = require("../util");
const { isArray } = Array;
const findByPointer = (pointer, val) => {
if (!pointer)
return { val };
let obj;
let key;
let indexOfSlash = 0;
let indexAfterSlash = 1;
while (indexOfSlash > -1) {
indexOfSlash = pointer.indexOf('/', indexAfterSlash);
const component = indexOfSlash > -1 ? pointer.substring(indexAfterSlash, indexOfSlash) : pointer.substring(indexAfterSlash);
indexAfterSlash = indexOfSlash + 1;
key = (0, util_1.unescapeComponent)(component);
obj = val;
if (isArray(obj)) {
if (key === '-')
key = obj.length;
else {
if (!(0, util_1.isValidIndex)(key))
throw new Error('INVALID_INDEX');
key = Number(key);
if (key < 0)
throw new Error('INVALID_INDEX');
}
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, String(key)) ? obj[key] : undefined;
}
else if (typeof obj === 'object' && !!obj) {
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, String(key)) ? obj[key] : undefined;
}
else
throw new Error('NOT_FOUND');
}
return { val, obj, key };
};
exports.findByPointer = findByPointer;
+2
View File
@@ -0,0 +1,2 @@
import type { Reference } from '../find';
export declare const findByPointer: (pointer: string, val: unknown) => Reference;
+47
View File
@@ -0,0 +1,47 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findByPointer = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const util_1 = require("../util");
const { isArray } = Array;
const findByPointer = (pointer, val) => {
if (!pointer)
return { val };
let obj;
let key;
let indexOfSlash = 0;
pointer = pointer.substr(1);
while (pointer) {
indexOfSlash = pointer.indexOf('/');
let component;
if (indexOfSlash > -1) {
component = pointer.substring(0, indexOfSlash);
pointer = pointer.substring(indexOfSlash + 1);
}
else {
component = pointer;
pointer = '';
}
key = (0, util_1.unescapeComponent)(component);
obj = val;
if (isArray(obj)) {
if (key === '-')
key = obj.length;
else {
if (!(0, util_1.isValidIndex)(key))
throw new Error('INVALID_INDEX');
key = Number(key);
if (key < 0)
throw new Error('INVALID_INDEX');
}
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, String(key)) ? obj[key] : undefined;
}
else if (typeof obj === 'object' && !!obj) {
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, String(key)) ? obj[key] : undefined;
}
else
throw new Error('NOT_FOUND');
}
return { val, obj, key };
};
exports.findByPointer = findByPointer;
+2
View File
@@ -0,0 +1,2 @@
import type { Reference } from '../find';
export declare const findByPointer: (pointer: string, val: unknown) => Reference;
+47
View File
@@ -0,0 +1,47 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findByPointer = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const util_1 = require("../util");
const { isArray } = Array;
const findByPointer = (pointer, val) => {
if (!pointer)
return { val };
let obj;
let key;
let indexOfSlash = 0;
pointer = pointer.substr(1);
while (pointer) {
indexOfSlash = pointer.indexOf('/');
let component;
if (indexOfSlash > -1) {
component = pointer.substring(0, indexOfSlash);
pointer = pointer.substring(indexOfSlash + 1);
}
else {
component = pointer;
pointer = '';
}
key = (0, util_1.unescapeComponent)(component);
obj = val;
if (isArray(obj)) {
if (key === '-')
key = obj.length;
else {
if (!(0, util_1.isInteger)(key))
throw new Error('INVALID_INDEX');
key = Number(key);
if (key < 0)
throw new Error('INVALID_INDEX');
}
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, String(key)) ? obj[key] : undefined;
}
else if (typeof obj === 'object' && !!obj) {
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, String(key)) ? obj[key] : undefined;
}
else
throw new Error('NOT_FOUND');
}
return { val, obj, key };
};
exports.findByPointer = findByPointer;
+2
View File
@@ -0,0 +1,2 @@
import type { Reference } from '../find';
export declare const findByPointer: (pointer: string, val: unknown) => Reference;
+39
View File
@@ -0,0 +1,39 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findByPointer = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const util_1 = require("../util");
const { isArray } = Array;
const findByPointer = (pointer, val) => {
if (!pointer)
return { val };
let obj;
let key;
let indexOfSlash = 0;
let indexAfterSlash = 1;
while (indexOfSlash > -1) {
indexOfSlash = pointer.indexOf('/', indexAfterSlash);
const component = indexOfSlash > -1 ? pointer.substring(indexAfterSlash, indexOfSlash) : pointer.substring(indexAfterSlash);
indexAfterSlash = indexOfSlash + 1;
key = (0, util_1.unescapeComponent)(component);
obj = val;
if (isArray(obj)) {
if (key === '-')
key = obj.length;
else {
// if (!isValidIndex(key)) throw new Error('INVALID_INDEX');
key = ~~key;
if (key < 0)
throw new Error('INVALID_INDEX');
}
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, key) ? obj[~~key] : undefined;
}
else if (typeof obj === 'object' && !!obj) {
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, key) ? obj[key] : undefined;
}
else
throw new Error('NOT_FOUND');
}
return { val, obj, key };
};
exports.findByPointer = findByPointer;
+2
View File
@@ -0,0 +1,2 @@
import type { Reference } from '../find';
export declare const findByPointer: (pointer: string, val: unknown) => Reference;
+43
View File
@@ -0,0 +1,43 @@
"use strict";
/* tslint:disable no-string-throw */
Object.defineProperty(exports, "__esModule", { value: true });
exports.findByPointer = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const util_1 = require("../util");
const { isArray } = Array;
const findByPointer = (pointer, val) => {
if (!pointer)
return { val };
let obj;
let key;
let indexOfSlash = 0;
let indexAfterSlash = 1;
while (indexOfSlash > -1) {
indexOfSlash = pointer.indexOf('/', indexAfterSlash);
key = indexOfSlash > -1 ? pointer.substring(indexAfterSlash, indexOfSlash) : pointer.substring(indexAfterSlash);
indexAfterSlash = indexOfSlash + 1;
obj = val;
if (isArray(obj)) {
const length = obj.length;
if (key === '-')
key = length;
else {
const key2 = ~~key;
if ('' + key2 !== key)
throw new Error('INVALID_INDEX');
key = key2;
if (key < 0)
throw 'INVALID_INDEX';
}
val = obj[key];
}
else if (typeof obj === 'object' && !!obj) {
key = (0, util_1.unescapeComponent)(key);
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, key) ? obj[key] : undefined;
}
else
throw 'NOT_FOUND';
}
return { val, obj, key };
};
exports.findByPointer = findByPointer;
+2
View File
@@ -0,0 +1,2 @@
import type { Reference } from '../find';
export declare const findByPointer: (pointer: string, val: unknown) => [Reference["obj"], Reference["key"]];
+39
View File
@@ -0,0 +1,39 @@
"use strict";
/* tslint:disable no-string-throw */
Object.defineProperty(exports, "__esModule", { value: true });
exports.findByPointer = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const util_1 = require("../util");
const { isArray } = Array;
const findByPointer = (pointer, val) => {
if (!pointer)
return [val, ''];
let obj;
let key;
let indexOfSlash = 0;
let indexAfterSlash = 1;
while (indexOfSlash > -1) {
indexOfSlash = pointer.indexOf('/', indexAfterSlash);
key = indexOfSlash > -1 ? pointer.substring(indexAfterSlash, indexOfSlash) : pointer.substring(indexAfterSlash);
indexAfterSlash = indexOfSlash + 1;
obj = val;
if (isArray(obj)) {
if (key === '-')
key = obj.length;
else {
key = ~~key;
if (key < 0)
throw 'INVALID_INDEX';
}
val = obj[key];
}
else if (typeof obj === 'object' && !!obj) {
key = (0, util_1.unescapeComponent)(key);
val = (0, hasOwnProperty_1.hasOwnProperty)(obj, key) ? obj[key] : undefined;
}
else
throw 'NOT_FOUND';
}
return [obj, key];
};
exports.findByPointer = findByPointer;
+2
View File
@@ -0,0 +1,2 @@
import type { Path } from './types';
export declare const get: (val: unknown, path: Path) => unknown | undefined;
+33
View File
@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.get = void 0;
const hasOwnProperty_1 = require("@jsonjoy.com/util/lib/hasOwnProperty");
const get = (val, path) => {
const pathLength = path.length;
let key;
if (!pathLength)
return val;
for (let i = 0; i < pathLength; i++) {
key = path[i];
if (val instanceof Array) {
if (typeof key !== 'number') {
if (key === '-')
return undefined;
const key2 = ~~key;
if ('' + key2 !== key)
return undefined;
key = key2;
}
val = val[key];
}
else if (typeof val === 'object') {
if (!val || !(0, hasOwnProperty_1.hasOwnProperty)(val, key))
return undefined;
val = val[key];
}
else
return undefined;
}
return val;
};
exports.get = get;
+13
View File
@@ -0,0 +1,13 @@
/**
* `json-pointer`
*
* Implements helper functions for [JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901) specification.
*
* @module
*/
export * from './types';
export * from './util';
export * from './validate';
export * from './get';
export * from './find';
export * from './findByPointer';
+16
View File
@@ -0,0 +1,16 @@
"use strict";
/**
* `json-pointer`
*
* Implements helper functions for [JSON Pointer (RFC 6901)](https://tools.ietf.org/html/rfc6901) specification.
*
* @module
*/
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./types"), exports);
tslib_1.__exportStar(require("./util"), exports);
tslib_1.__exportStar(require("./validate"), exports);
tslib_1.__exportStar(require("./get"), exports);
tslib_1.__exportStar(require("./find"), exports);
tslib_1.__exportStar(require("./findByPointer"), exports);
+2
View File
@@ -0,0 +1,2 @@
export type PathStep = string | number;
export type Path = readonly PathStep[];
+2
View File
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
+38
View File
@@ -0,0 +1,38 @@
import type { Path } from './types';
/**
* Un-escapes a JSON pointer path component.
*/
export declare function unescapeComponent(component: string): string;
/**
* Escapes a JSON pointer path component.
*/
export declare function escapeComponent(component: string): string;
/**
* Convert JSON pointer like "/foo/bar" to array like ["", "foo", "bar"], while
* also un-escaping reserved characters.
*/
export declare function parseJsonPointer(pointer: string): Path;
/**
* Escape and format a path array like ["", "foo", "bar"] to JSON pointer
* like "/foo/bar".
*/
export declare function formatJsonPointer(path: Path): string;
export declare const toPath: (pointer: string | Path) => Path;
/**
* Returns true if `parent` contains `child` path, false otherwise.
*/
export declare function isChild(parent: Path, child: Path): boolean;
export declare function isPathEqual(p1: Path, p2: Path): boolean;
/**
* Returns true if JSON Pointer points to root value, false otherwise.
*/
export declare const isRoot: (path: Path) => boolean;
/**
* Returns parent path, e.g. for ['foo', 'bar', 'baz'] returns ['foo', 'bar'].
*/
export declare function parent(path: Path): Path;
/**
* Check if path component can be a valid array index.
*/
export declare function isValidIndex(index: string | number): boolean;
export declare const isInteger: (str: string) => boolean;
+117
View File
@@ -0,0 +1,117 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isInteger = exports.isRoot = exports.toPath = void 0;
exports.unescapeComponent = unescapeComponent;
exports.escapeComponent = escapeComponent;
exports.parseJsonPointer = parseJsonPointer;
exports.formatJsonPointer = formatJsonPointer;
exports.isChild = isChild;
exports.isPathEqual = isPathEqual;
exports.parent = parent;
exports.isValidIndex = isValidIndex;
const r1 = /~1/g;
const r2 = /~0/g;
const r3 = /~/g;
const r4 = /\//g;
/**
* Un-escapes a JSON pointer path component.
*/
function unescapeComponent(component) {
if (component.indexOf('~') === -1)
return component;
return component.replace(r1, '/').replace(r2, '~');
}
/**
* Escapes a JSON pointer path component.
*/
function escapeComponent(component) {
if (component.indexOf('/') === -1 && component.indexOf('~') === -1)
return component;
return component.replace(r3, '~0').replace(r4, '~1');
}
/**
* Convert JSON pointer like "/foo/bar" to array like ["", "foo", "bar"], while
* also un-escaping reserved characters.
*/
function parseJsonPointer(pointer) {
if (!pointer)
return [];
// TODO: Performance of this line can be improved: (1) don't use .split(); (2) don't use .map().
return pointer.slice(1).split('/').map(unescapeComponent);
}
/**
* Escape and format a path array like ["", "foo", "bar"] to JSON pointer
* like "/foo/bar".
*/
function formatJsonPointer(path) {
if ((0, exports.isRoot)(path))
return '';
return '/' + path.map((component) => escapeComponent(String(component))).join('/');
}
const toPath = (pointer) => (typeof pointer === 'string' ? parseJsonPointer(pointer) : pointer);
exports.toPath = toPath;
/**
* Returns true if `parent` contains `child` path, false otherwise.
*/
function isChild(parent, child) {
if (parent.length >= child.length)
return false;
for (let i = 0; i < parent.length; i++)
if (parent[i] !== child[i])
return false;
return true;
}
function isPathEqual(p1, p2) {
if (p1.length !== p2.length)
return false;
for (let i = 0; i < p1.length; i++)
if (p1[i] !== p2[i])
return false;
return true;
}
// export function getSharedPath(one: Path, two: Path): Path {
// const min = Math.min(one.length, two.length);
// const res: string[] = [];
// for (let i = 0; i < min; i++) {
// if (one[i] === two[i]) res.push(one[i]);
// else break;
// }
// return res as Path;
// }
/**
* Returns true if JSON Pointer points to root value, false otherwise.
*/
const isRoot = (path) => !path.length;
exports.isRoot = isRoot;
/**
* Returns parent path, e.g. for ['foo', 'bar', 'baz'] returns ['foo', 'bar'].
*/
function parent(path) {
if (path.length < 1)
throw new Error('NO_PARENT');
return path.slice(0, path.length - 1);
}
/**
* Check if path component can be a valid array index.
*/
function isValidIndex(index) {
if (typeof index === 'number')
return true;
const n = Number.parseInt(index, 10);
return String(n) === index && n >= 0;
}
const isInteger = (str) => {
const len = str.length;
let i = 0;
let charCode;
while (i < len) {
charCode = str.charCodeAt(i);
if (charCode >= 48 && charCode <= 57) {
i++;
continue;
}
return false;
}
return true;
};
exports.isInteger = isInteger;
+3
View File
@@ -0,0 +1,3 @@
import type { Path } from './types';
export declare const validateJsonPointer: (pointer: string | Path | unknown) => void;
export declare const validatePath: (path: Path | unknown) => void;
+33
View File
@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validatePath = exports.validateJsonPointer = void 0;
const validateJsonPointer = (pointer) => {
if (typeof pointer === 'string') {
if (pointer) {
if (pointer[0] !== '/')
throw new Error('POINTER_INVALID');
if (pointer.length > 1024)
throw new Error('POINTER_TOO_LONG');
}
}
else
(0, exports.validatePath)(pointer);
};
exports.validateJsonPointer = validateJsonPointer;
const { isArray } = Array;
const validatePath = (path) => {
if (!isArray(path))
throw new Error('Invalid path.');
if (path.length > 256)
throw new Error('Path too long.');
for (const step of path) {
switch (typeof step) {
case 'string':
case 'number':
continue;
default:
throw new Error('Invalid path step.');
}
}
};
exports.validatePath = validatePath;
+69
View File
@@ -0,0 +1,69 @@
{
"name": "@jsonjoy.com/json-pointer",
"packageManager": "yarn@4.5.0",
"publishConfig": {
"access": "public"
},
"version": "1.0.2",
"description": "High-performance JSON Pointer implementation",
"author": {
"name": "streamich",
"url": "https://github.com/streamich"
},
"homepage": "https://github.com/jsonjoy-com/json-pointer",
"repository": "jsonjoy-com/json-pointer",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/streamich"
},
"keywords": [
"json-pointer",
"json",
"pointer",
"jit",
"selector",
"pick"
],
"engines": {
"node": ">=10.0"
},
"main": "lib/index.js",
"types": "lib/index.d.ts",
"typings": "lib/index.d.ts",
"files": [
"LICENSE",
"lib/"
],
"license": "Apache-2.0",
"scripts": {
"format": "biome format ./src",
"format:fix": "biome format --write ./src",
"lint": "biome lint ./src",
"lint:fix": "biome lint --apply ./src",
"clean": "npx rimraf@6.0.1 lib typedocs coverage gh-pages yarn-error.log",
"build": "tsc --project tsconfig.build.json --module commonjs --target es2020 --outDir lib",
"test": "vitest ./src",
"coverage": "vitest run --coverage",
"typedoc": "npx typedoc@0.25.13 --tsconfig tsconfig.build.json",
"build:pages": "npx rimraf@6.0.1 gh-pages && mkdir -p gh-pages && cp -r typedocs/* gh-pages && cp -r coverage gh-pages/coverage",
"deploy:pages": "gh-pages -d gh-pages",
"publish-coverage-and-typedocs": "yarn typedoc && yarn coverage && yarn build:pages && yarn deploy:pages"
},
"peerDependencies": {
"tslib": "2"
},
"dependencies": {
"@jsonjoy.com/codegen": "^1.0.0",
"@jsonjoy.com/util": "^1.9.0"
},
"devDependencies": {
"@biomejs/biome": "^1.9.3",
"@types/benchmark": "^2.1.5",
"@vitest/coverage-v8": "^2.1.2",
"benchmark": "^2.1.4",
"config-galore": "^1.0.0",
"tslib": "^2.7.0",
"typescript": "^5.6.2",
"vitest": "^2.1.2"
}
}