UNPKG

@finnair/path

Version:
158 lines (157 loc) 5.91 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.UnionMatcher = exports.IndexMatcher = exports.PropertyMatcher = exports.AnyProperty = exports.AnyIndex = exports.PathMatcher = void 0; const Path_js_1 = require("./Path.js"); const matchers_js_1 = require("./matchers.js"); Object.defineProperty(exports, "PropertyMatcher", { enumerable: true, get: function () { return matchers_js_1.PropertyMatcher; } }); Object.defineProperty(exports, "IndexMatcher", { enumerable: true, get: function () { return matchers_js_1.IndexMatcher; } }); Object.defineProperty(exports, "AnyIndex", { enumerable: true, get: function () { return matchers_js_1.AnyIndex; } }); Object.defineProperty(exports, "AnyProperty", { enumerable: true, get: function () { return matchers_js_1.AnyProperty; } }); Object.defineProperty(exports, "UnionMatcher", { enumerable: true, get: function () { return matchers_js_1.UnionMatcher; } }); class PathMatcher { expressions; allowGaps; constructor(expressions) { this.expressions = expressions; this.allowGaps = expressions.some((expression) => expression.allowGaps); Object.freeze(this.expressions); Object.freeze(this); } find(root, collector) { if (this.expressions.length === 0) { collector(Path_js_1.Path.ROOT, root); } if (typeof root !== 'object') { return; } const currentPath = []; const handlers = []; for (let i = 0; i < this.expressions.length - 1; i++) { handlers[i] = intermediateHandler(i, this.expressions); } handlers[this.expressions.length - 1] = resultHandler(); this.expressions[0].find(root, handlers[0]); function intermediateHandler(index, expressions) { return (value, component) => { currentPath[index] = component; return expressions[index + 1].find(value, handlers[index + 1]); }; } function resultHandler() { return (value, component) => { return collector(Path_js_1.Path.of(...currentPath, component), value); }; } } findAll(root, acceptUndefined) { const results = []; this.find(root, (path, value) => { if (value !== undefined || acceptUndefined) { results.push({ path, value }); return true; } return true; }); return results; } findFirst(root, acceptUndefined) { let result = undefined; this.find(root, (path, value) => { if (value !== undefined || acceptUndefined) { result = { path, value }; return false; } return true; }); return result; } findValues(root, acceptUndefined) { const results = []; this.find(root, (path, value) => { if (value !== undefined || acceptUndefined) { results.push(value); return true; } return true; }); return results; } findFirstValue(root, acceptUndefined) { let result = undefined; this.find(root, (path, value) => { if (value !== undefined || acceptUndefined) { result = value; return false; } return true; }); return result; } /** * Exact match: path length must match the number of expressions and all expressions must match. Only sibling paths match. * * @param path * @returns true if path is an exact match to expressions */ match(path) { if (path.length !== this.expressions.length) { return false; } for (let index = 0; index < this.expressions.length; index++) { if (!this.expressions[index].test(path.componentAt(index))) { return false; } } return true; } /** * Prefix match: path length must be equal or longer than the number of expressions and all expressions must match. All sibling and child paths match. * * @param path * @returns true the start the path matches */ prefixMatch(path) { if (path.length < this.expressions.length) { return false; } for (let index = 0; index < this.expressions.length; index++) { if (!this.expressions[index].test(path.componentAt(index))) { return false; } } return true; } /** * Partial match: path length can be less than or more than the number of expressions, but all corresponding expressions must match. All parent, sibling and child paths match. * * @param path * @returns true if all path components match */ partialMatch(path) { for (let index = 0; index < this.expressions.length && index < path.length; index++) { if (!this.expressions[index].test(path.componentAt(index))) { return false; } } return true; } toJSON() { return this.expressions.reduce((str, expression) => str + expression.toString(), '$'); } static of(...path) { return new PathMatcher(path.map(component => { const type = typeof component; if (type === 'number') { return new matchers_js_1.IndexMatcher(component); } if (type === 'string') { return new matchers_js_1.PropertyMatcher(component); } if ((0, matchers_js_1.isPathExpression)(component)) { return component; } throw new Error(`Unrecognized PathComponent: ${component} of type ${type}`); })); } } exports.PathMatcher = PathMatcher;