UNPKG

@scalar/typebox

Version:

Json Schema Type Builder with Static Type Resolution for TypeScript

116 lines (115 loc) 3.65 kB
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; }