116 lines
3.6 KiB
Plaintext
116 lines
3.6 KiB
Plaintext
import { TypeBoxError } from '../../type/error/index.mjs';
|
|
// ------------------------------------------------------------------
|
|
// Errors
|
|
// ------------------------------------------------------------------
|
|
export class ValuePointerRootSetError extends TypeBoxError {
|
|
constructor(value, path, update) {
|
|
super('Cannot set root value');
|
|
this.value = value;
|
|
this.path = path;
|
|
this.update = update;
|
|
}
|
|
}
|
|
export class ValuePointerRootDeleteError extends TypeBoxError {
|
|
constructor(value, path) {
|
|
super('Cannot delete root value');
|
|
this.value = value;
|
|
this.path = path;
|
|
}
|
|
}
|
|
// ------------------------------------------------------------------
|
|
// ValuePointer
|
|
// ------------------------------------------------------------------
|
|
/** Provides functionality to update values through RFC6901 string pointers */
|
|
// prettier-ignore
|
|
function Escape(component) {
|
|
return component.indexOf('~') === -1 ? component : component.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
}
|
|
/** Formats the given pointer into navigable key components */
|
|
// prettier-ignore
|
|
export function* Format(pointer) {
|
|
if (pointer === '')
|
|
return;
|
|
let [start, end] = [0, 0];
|
|
for (let i = 0; i < pointer.length; i++) {
|
|
const char = pointer.charAt(i);
|
|
if (char === '/') {
|
|
if (i === 0) {
|
|
start = i + 1;
|
|
}
|
|
else {
|
|
end = i;
|
|
yield Escape(pointer.slice(start, end));
|
|
start = i + 1;
|
|
}
|
|
}
|
|
else {
|
|
end = i;
|
|
}
|
|
}
|
|
yield Escape(pointer.slice(start));
|
|
}
|
|
/** Sets the value at the given pointer. If the value at the pointer does not exist it is created */
|
|
// prettier-ignore
|
|
export function Set(value, pointer, update) {
|
|
if (pointer === '')
|
|
throw new ValuePointerRootSetError(value, pointer, update);
|
|
let [owner, next, key] = [null, value, ''];
|
|
for (const component of Format(pointer)) {
|
|
if (next[component] === undefined)
|
|
next[component] = {};
|
|
owner = next;
|
|
next = next[component];
|
|
key = component;
|
|
}
|
|
owner[key] = update;
|
|
}
|
|
/** Deletes a value at the given pointer */
|
|
// prettier-ignore
|
|
export function Delete(value, pointer) {
|
|
if (pointer === '')
|
|
throw new ValuePointerRootDeleteError(value, pointer);
|
|
let [owner, next, key] = [null, value, ''];
|
|
for (const component of Format(pointer)) {
|
|
if (next[component] === undefined || next[component] === null)
|
|
return;
|
|
owner = next;
|
|
next = next[component];
|
|
key = component;
|
|
}
|
|
if (Array.isArray(owner)) {
|
|
const index = parseInt(key);
|
|
owner.splice(index, 1);
|
|
}
|
|
else {
|
|
delete owner[key];
|
|
}
|
|
}
|
|
/** Returns true if a value exists at the given pointer */
|
|
// prettier-ignore
|
|
export function Has(value, pointer) {
|
|
if (pointer === '')
|
|
return true;
|
|
let [owner, next, key] = [null, value, ''];
|
|
for (const component of Format(pointer)) {
|
|
if (next[component] === undefined)
|
|
return false;
|
|
owner = next;
|
|
next = next[component];
|
|
key = component;
|
|
}
|
|
return Object.getOwnPropertyNames(owner).includes(key);
|
|
}
|
|
/** Gets the value at the given pointer */
|
|
// prettier-ignore
|
|
export function Get(value, pointer) {
|
|
if (pointer === '')
|
|
return value;
|
|
let current = value;
|
|
for (const component of Format(pointer)) {
|
|
if (current[component] === undefined)
|
|
return undefined;
|
|
current = current[component];
|
|
}
|
|
return current;
|
|
}
|