UNPKG

@finnair/path

Version:
121 lines (120 loc) 3.36 kB
import { Path } from './Path.js'; export function isPathExpression(component) { return !!component && typeof component.test === 'function' && typeof component.find === 'function'; } export class IndexMatcher { index; allowGaps = true; constructor(index) { this.index = index; Path.validateIndex(index); } find(current, callback) { if (Array.isArray(current) && this.index < current.length) { return callback(current[this.index], this.index); } return true; } test(component) { return component === this.index; } toString() { return Path.indexToString(this.index); } } export class PropertyMatcher { property; allowGaps = false; constructor(property) { this.property = property; Path.validateProperty(property); } find(current, callback) { if (typeof current === 'object' && current.hasOwnProperty(this.property)) { return callback(current[this.property], this.property); } return true; } test(component) { return String(component) === this.property; } toString() { return Path.propertyToString(this.property); } } export class UnionMatcher { components; constructor(components) { this.components = components; if (components.length < 2) { throw new Error('Expected at least 2 properties'); } components.forEach(Path.validateComponent); } find(current, callback) { if (typeof current === 'object') { for (const component of this.components) { if (current.hasOwnProperty(component)) { if (!callback(current[component], component)) { return false; } } } } return true; } test(component) { const str = String(component); return this.components.find(component => String(component) === str) !== undefined; } get allowGaps() { return this.components.some(component => typeof component === 'number'); } toString() { return `[${this.components.map(this.propertyToString).join(',')}]`; } static of(...components) { return new UnionMatcher(components); } propertyToString(property) { return JSON.stringify(property); } } export const AnyIndex = { allowGaps: false, find: (current, callback) => { if (Array.isArray(current)) { for (let i = 0; i < current.length; i++) { if (!callback(current[i], i)) { return false; } } } return true; }, test: (component) => { return typeof component === 'number' && Number.isInteger(component) && component >= 0; }, toString: () => { return '[*]'; }, }; export const AnyProperty = { allowGaps: false, find: (current, callback) => { if (typeof current === 'object') { for (let key in current) { if (!callback(current[key], key)) { return false; } } } return true; }, test: () => { return true; }, toString: () => { return '.*'; }, };