diff --git a/docs/docs/intro.mdx b/docs/docs/intro.mdx index 59098cf..db950db 100644 --- a/docs/docs/intro.mdx +++ b/docs/docs/intro.mdx @@ -5,11 +5,11 @@ import TabItem from "@theme/TabItem"; JSON P3 implements JSONPath following the [IETF JSONPath draft](https://datatracker.ietf.org/doc/html/draft-ietf-jsonpath-base-20) specification, JSON Pointer described by [RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901), and JSON Patch described by [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902). -JSONPath is a mini language for selecting values from JSON-like data. A JSONPath query has the potential to return multiple values from a data structure, along with their locations. This implementation is non-evaluating and read-only. We strictly follow the [IETF JSONPath draft](https://datatracker.ietf.org/doc/html/draft-ietf-jsonpath-base-20). +**JSONPath** is a mini language for selecting values from JSON-like data. A JSONPath query has the potential to return multiple values from a data structure, along with their locations. This implementation is non-evaluating and read-only. We strictly follow the [IETF JSONPath draft](https://datatracker.ietf.org/doc/html/draft-ietf-jsonpath-base-20). -JSON Pointer is a syntax for targeting a single value in JSON-like data. JSON Pointers can be _resolved_ against data to retrieve the value, or used as part of a JSON Patch operation. +**JSON Pointer** is a syntax for targeting a single value in JSON-like data. JSON Pointers can be _resolved_ against data to retrieve the value, or used as part of a JSON Patch operation. -JSON Patch is a standard for describing update operations to perform on JSON-like data. You can _apply_ a patch to _add_, _remove_, _replace_, _move_, _copy_ and _move_ values within a JSON document. +**JSON Patch** is a standard for describing update operations to perform on JSON-like data. You can _apply_ a patch to _add_, _remove_, _replace_, _copy_ and _move_ values within a JSON document. We use the term _JSON-like data_ to describe arbitrary, possibly nested, JavaScript arrays and objects, plus primitive strings, numbers, booleans and `null`, as you might expect from `JSON.parse()`. When traversing JSON-like data, we only resolve an object's direct properties, and the `length` property of arrays and strings is ignored. diff --git a/docs/docs/quick-start.md b/docs/docs/quick-start.md index cc91f72..50b07a6 100644 --- a/docs/docs/quick-start.md +++ b/docs/docs/quick-start.md @@ -122,15 +122,78 @@ console.log(nodes.values()); // [ 'John', 'Sally', 'Jane' ] ## JSON Pointer -TODO: +Resolve a JSON Pointer ([RFC 6901](https://datatracker.ietf.org/doc/html/rfc6901)) against some data using `jsonpointer.resolve()`. + +```javascript +import { jsonpointer } from "json-p3"; + +const data = { + users: [ + { name: "Sue", score: 100 }, + { name: "John", score: 86 }, + { name: "Sally", score: 84 }, + { name: "Jane", score: 55 }, + ], +}; + +const rv = jsonpointer.resolve("/users/1", data); +console.log(rv); // { name: 'John', score: 86 } +``` + +`resolve()` is a convenience function equivalent to `new JSONPointer(pointer).resolve(data)`. Use the [`JSONPointer`](./api/classes/jsonpointer.JSONPointer.md) constructor when you need to resolve the same pointer repeatedly against different data. + +```javascript +import { JSONPointer } from "json-p3"; + +const someData = { + users: [ + { name: "Sue", score: 100 }, + { name: "John", score: 86 }, + { name: "Sally", score: 84 }, + ], +}; + +const otherData = { + users: [{ name: "Brian" }, { name: "Roy" }], +}; + +const pointer = new JSONPointer("/users/1"); +console.log(pointer.resolve(someData)); // { name: 'John', score: 86 } +console.log(pointer.resolve(otherData)); // { name: 'Roy' } +``` ### Errors and fallbacks -TODO: +If the pointer can't be resolved against the argument JSON value, one of [`JSONPointerIndexError`](./api/classes/jsonpointer.JSONPointerIndexError.md), [`JSONPointerKeyError`](./api/classes/jsonpointer.JSONPointerKeyError.md) or [`JSONPointerTypeError`](./api/classes/jsonpointer.JSONPointerTypeError.md) is thrown. All three exceptions inherit from [`JSONPointerResolutionError`](./api/classes/jsonpointer.JSONPointerResolutionError.md). + +```javascript +// .. continued from above +const rv = pointer.resolve("/users/1/age", data); +// JSONPointerKeyError: no such property ("/users/1/age") +``` + +A fallback value can be given as a third argument, which will be returned in the event of a `JSONPointerResolutionError`. + +```javascript +// .. continued from above +const rv = pointer.resolve("/users/1/age", data, -1); +console.log(rv); // -1 +``` ### Relative JSON Pointers -TODO: +We support [Relative JSON Pointers](https://www.ietf.org/id/draft-hha-relative-json-pointer-00.html) via the [`to(rel)`](./api/classes/jsonpointer.JSONPointer.md#to) method of `JSONPointer`, where `rel` is a relative JSON pointer string, and a new `JSONPointer` is returned. + +```javascript +import { JSONPointer } from "json-p3"; + +const data = { foo: { bar: [1, 2, 3], baz: [4, 5, 6] } }; +const pointer = new JSONPointer("/foo/bar/2"); + +console.log(pointer.resolve(data)); // 3 +console.log(pointer.to("0-1").resolve(data)); // 2 +console.log(pointer.to("2/baz/2").resolve(data)); // 6 +``` ## JSON Patch diff --git a/src/path/environment.ts b/src/path/environment.ts index e099b40..2485cea 100644 --- a/src/path/environment.ts +++ b/src/path/environment.ts @@ -128,6 +128,8 @@ export class JSONPathEnvironment { return this.compile(path).query(value); } + // TODO: match(path, value): boolean + protected setupFilterFunctions(): void { this.functionRegister.set("count", new CountFilterFunction()); this.functionRegister.set("length", new LengthFilterFunction()); diff --git a/src/pointer/errors.ts b/src/pointer/errors.ts index 71e43ef..bd6bd91 100644 --- a/src/pointer/errors.ts +++ b/src/pointer/errors.ts @@ -9,6 +9,9 @@ export class JSONPointerError extends Error { } } +/** + * Base class for JSON Pointer resolution errors. + */ export class JSONPointerResolutionError extends JSONPointerError { constructor(readonly message: string) { super(message); @@ -17,6 +20,9 @@ export class JSONPointerResolutionError extends JSONPointerError { } } +/** + * Error thrown due to an out of range index when resolving a JSON Pointer. + */ export class JSONPointerIndexError extends JSONPointerResolutionError { constructor(readonly message: string) { super(message); @@ -25,6 +31,9 @@ export class JSONPointerIndexError extends JSONPointerResolutionError { } } +/** + * Error thrown due to a missing property when resolving a JSON Pointer. + */ export class JSONPointerKeyError extends JSONPointerResolutionError { constructor(readonly message: string) { super(message); @@ -33,6 +42,9 @@ export class JSONPointerKeyError extends JSONPointerResolutionError { } } +/** + * Error thrown due to invalid JSON Pointer syntax. + */ export class JSONPointerSyntaxError extends JSONPointerError { constructor(readonly message: string) { super(message); @@ -41,6 +53,9 @@ export class JSONPointerSyntaxError extends JSONPointerError { } } +/** + * Error thrown when trying to resolve a property or index against a primitive value. + */ export class JSONPointerTypeError extends JSONPointerResolutionError { constructor(readonly message: string) { super(message);