"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.keyPathContains = exports.keyPathEndsWith = exports.keyPathStartsWith = exports.keyPathsEqual = exports.isKeyPathThis = exports.thisKeyPath = exports.keysOf = void 0; const optional_1 = require("../../types/optional"); /** * A global cache containing parsed string key paths * with components separated by a dot. */ const parsedKeyPaths = {}; /** * Extract the individual keys from a key path in order * to traverse into an object to access a specific value. * * @param keyPath - A key path to extract the keys from. * @returns An array containing the keys making up `keyPath`. */ function keysOf(keyPath) { // TODO: Normalizing into an array is potentially a bottleneck. // Do we want to do this differently for slower environments? if (Array.isArray(keyPath)) { return keyPath; } else { switch (typeof keyPath) { case "string": { const existingKeyPath = parsedKeyPaths[keyPath]; if ((0, optional_1.isSome)(existingKeyPath)) { return existingKeyPath; } else { const newKeyPath = Object.freeze(keyPath.split(".")); parsedKeyPaths[keyPath] = newKeyPath; return newKeyPath; } } case "number": { return [keyPath]; } case "symbol": { return [keyPath]; } default: { throw new TypeError(`${keyPath.toString()} is not a KeyPath`); } } } } exports.keysOf = keysOf; /** * A key path representing an object itself. */ exports.thisKeyPath = Object.freeze([]); /** * Determine whether a given key path is the `this` (identity) key path. * @param keyPath - A key path to test. */ function isKeyPathThis(keyPath) { return Array.isArray(keyPath) && keyPath.length === 0; } exports.isKeyPathThis = isKeyPathThis; /** * Determines whether two key paths are equivalent taking into account * that the key paths may have different representations. * * @param lhs - A key path to compare. * @param rhs - Another key path to compare. */ function keyPathsEqual(lhs, rhs) { // 1. Are the key paths equal through value semantics? if (lhs === rhs) { return true; } const lhsKeys = keysOf(lhs); const rhsKeys = keysOf(rhs); // 2. Do we have the same number of keys in each path? if (lhsKeys.length !== rhsKeys.length) { return false; } // 3. Do any of the keys in our paths differ? for (let index = 0, length = lhsKeys.length; index < length; index += 1) { if (lhsKeys[index] !== rhsKeys[index]) { return false; } } // 4. We have passed all checks and are considered equal. return true; } exports.keyPathsEqual = keyPathsEqual; /** * Determine whether a given key path starts with a specified key. * * @param haystack - A key path to perform a prefix check on. * @param needle - The key to check for. */ function keyPathStartsWith(haystack, needle) { if (haystack === needle) { return true; } else { const keys = keysOf(haystack); if (keys.length === 0) { return false; } return keys[0] === needle; } } exports.keyPathStartsWith = keyPathStartsWith; /** * Determine whether a given key path ends with a specified key. * * @param haystack - A key path to perform a suffix check on. * @param needle - The key to check for. */ function keyPathEndsWith(haystack, needle) { if (haystack === needle) { return true; } else { const keys = keysOf(haystack); if (keys.length === 0) { return false; } return keys[keys.length - 1] === needle; } } exports.keyPathEndsWith = keyPathEndsWith; /** * Determine whether a given key path contains a specified key. * * @param haystack - A key path to search. * @param needle - The key to search for. */ function keyPathContains(haystack, needle) { if (haystack === needle) { return true; } else { const keys = keysOf(haystack); return keys.includes(needle); } } exports.keyPathContains = keyPathContains; //# sourceMappingURL=key-path.js.map