Skip to content

Commit

Permalink
added .rel() method to pre-compile relative pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
Phillip Clark committed May 13, 2021
1 parent ab59597 commit 03b7b06
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 4 deletions.
32 changes: 29 additions & 3 deletions src/pointer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
JsonStringPointer,
UriFragmentIdentifierPointer,
Pointer,
RelativeJsonPointer,
PathSegments,
Encoder,
JsonStringPointerListItem,
Expand Down Expand Up @@ -547,16 +548,41 @@ export class JsonPointer {
return parent.get(target);
}

/**
* Creates a new JsonPointer instance to the specified relative location, based on this pointer's location in the object graph.
* @param ptr the relative pointer (relative to this)
* @returns A new instance that points to the relative location.
*/
rel(ptr: RelativeJsonPointer): JsonPointer {
const p = this.path;
const decoded = decodeRelativePointer(ptr) as string[];
const n = parseInt(decoded[0]);
if (n > p.length) throw new Error('Relative location does not exist.');
const r = p.slice(0, p.length - n).concat(decoded.slice(1));
if (decoded[0][decoded[0].length - 1] == '#') {
// It references the path segment/name, not the value
const name = r[r.length - 1] as string;
throw new Error(
`We won't compile a pointer that will always return '${name}'. Use JsonPointer.relative(target, ptr) instead.`,
);
}
return new JsonPointer(r);
}

/**
* Resolves the specified relative pointer path against the specified target object, and gets the target object's value at the relative pointer's location.
* @param target the target of the operation
* @param rel the relative pointer (relative to this)
* @param ptr the relative pointer (relative to this)
* @returns the value at the relative pointer's resolved path; otherwise undefined.
*/
relative(target: unknown, rel: JsonStringPointer): unknown {
relative(target: unknown, ptr: RelativeJsonPointer): unknown {
const p = this.path;
const decoded = decodeRelativePointer(rel) as string[];
const decoded = decodeRelativePointer(ptr) as string[];
const n = parseInt(decoded[0]);
if (n > p.length) {
// out of bounds
return undefined;
}
const r = p.slice(0, p.length - n).concat(decoded.slice(1));
const other = new JsonPointer(r);
if (decoded[0][decoded[0].length - 1] == '#') {
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type PathSegments = PathSegment[];
export type JsonStringPointer = string;
export type UriFragmentIdentifierPointer = string;
export type Pointer = JsonStringPointer | UriFragmentIdentifierPointer;
export type RelativeJsonPointer = string;

/**
* List item used when listing pointers and their values in an object graph.
Expand Down
3 changes: 2 additions & 1 deletion src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
JsonStringPointer,
UriFragmentIdentifierPointer,
Pointer,
RelativeJsonPointer,
PathSegment,
PathSegments,
Decoder,
Expand Down Expand Up @@ -149,7 +150,7 @@ export function encodeUriFragmentIdentifier(
const InvalidRelativePointerError =
'Invalid Relative JSON Pointer syntax. Relative pointer must begin with a non-negative integer, followed by either the number sign (#), or a JSON Pointer.';

export function decodeRelativePointer(ptr: JsonStringPointer): PathSegments {
export function decodeRelativePointer(ptr: RelativeJsonPointer): PathSegments {
if (typeof ptr !== 'string') {
throw new TypeError(
'Invalid type: Relative JSON Pointers are represented as strings.',
Expand Down

0 comments on commit 03b7b06

Please sign in to comment.