summaryrefslogtreecommitdiff
path: root/node_modules/@jet/environment/json/reader/key-path.js
blob: 1bb25ff20e4ef877a1b8826ac8024b35426ec1b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"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