atomic-fns 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +397 -91
- package/dist/array/index.d.ts +9 -0
- package/dist/array/index.js +9 -0
- package/dist/array/list.d.ts +99 -0
- package/dist/array/list.js +133 -0
- package/dist/array/sets.d.ts +130 -0
- package/dist/array/sets.js +213 -0
- package/dist/async/index.d.ts +6 -0
- package/dist/async/index.js +6 -0
- package/dist/async/retry.d.ts +38 -0
- package/dist/async/retry.js +56 -0
- package/dist/async/sleep.d.ts +42 -0
- package/dist/async/sleep.js +76 -0
- package/dist/collections/bisect.d.ts +103 -0
- package/dist/collections/bisect.js +157 -0
- package/dist/collections/deque.d.ts +67 -97
- package/dist/collections/deque.js +197 -256
- package/dist/collections/entries.d.ts +89 -0
- package/dist/collections/entries.js +131 -0
- package/dist/collections/frozen-set.d.ts +42 -0
- package/dist/collections/frozen-set.js +64 -0
- package/dist/collections/group.d.ts +141 -0
- package/dist/collections/group.js +241 -0
- package/dist/collections/heap.d.ts +64 -0
- package/dist/collections/heap.js +205 -0
- package/dist/collections/index.d.ts +15 -623
- package/dist/collections/index.js +14 -844
- package/dist/collections/internal/arrayKeys.d.ts +19 -0
- package/dist/collections/internal/arrayKeys.js +83 -0
- package/dist/collections/internal/invariants.d.ts +4 -0
- package/dist/collections/internal/invariants.js +12 -0
- package/dist/collections/internal/iterable.d.ts +25 -0
- package/dist/collections/internal/iterable.js +62 -0
- package/dist/collections/iterate.d.ts +162 -0
- package/dist/collections/iterate.js +188 -0
- package/dist/collections/lru-cache.d.ts +58 -0
- package/dist/collections/lru-cache.js +164 -0
- package/dist/collections/order.d.ts +19 -0
- package/dist/collections/order.js +38 -0
- package/dist/collections/shape.d.ts +32 -0
- package/dist/collections/shape.js +86 -0
- package/dist/collections/sorted-map.d.ts +171 -0
- package/dist/collections/sorted-map.js +845 -0
- package/dist/collections/sorted-set.d.ts +103 -0
- package/dist/collections/sorted-set.js +147 -0
- package/dist/collections/splay-tree.d.ts +82 -0
- package/dist/collections/splay-tree.js +354 -0
- package/dist/collections/trie.d.ts +58 -0
- package/dist/collections/trie.js +196 -0
- package/dist/decimal/currency.d.ts +211 -0
- package/dist/decimal/currency.js +321 -0
- package/dist/decimal/decimal.d.ts +299 -0
- package/dist/decimal/decimal.js +660 -0
- package/dist/decimal/index.d.ts +11 -148
- package/dist/decimal/index.js +10 -410
- package/dist/decimal/internal/bits.d.ts +2 -0
- package/dist/decimal/internal/bits.js +7 -0
- package/dist/decimal/internal/echo.d.ts +4 -0
- package/dist/decimal/internal/echo.js +6 -0
- package/dist/decimal/internal/isqrt.d.ts +9 -0
- package/dist/decimal/internal/isqrt.js +34 -0
- package/dist/decimal/internal/locale.d.ts +7 -0
- package/dist/decimal/internal/locale.js +24 -0
- package/dist/decimal/internal/minor-units.d.ts +2 -0
- package/dist/decimal/internal/minor-units.js +33 -0
- package/dist/decimal/internal/pow10.d.ts +24 -0
- package/dist/decimal/internal/pow10.js +96 -0
- package/dist/encoding/base64.d.ts +39 -0
- package/dist/encoding/base64.js +53 -0
- package/dist/encoding/hex.d.ts +23 -0
- package/dist/encoding/hex.js +34 -0
- package/dist/encoding/index.d.ts +6 -0
- package/dist/encoding/index.js +6 -0
- package/dist/function/debounce.d.ts +68 -0
- package/dist/function/debounce.js +203 -0
- package/dist/function/index.d.ts +6 -0
- package/dist/function/index.js +6 -0
- package/dist/function/shared.d.ts +2 -0
- package/dist/function/shared.js +5 -0
- package/dist/function/wrap.d.ts +130 -0
- package/dist/function/wrap.js +113 -0
- package/dist/hash/digest.d.ts +18 -0
- package/dist/hash/digest.js +26 -0
- package/dist/hash/hash.d.ts +22 -0
- package/dist/hash/hash.js +252 -0
- package/dist/hash/hashString.d.ts +13 -0
- package/dist/hash/hashString.js +53 -0
- package/dist/hash/index.d.ts +8 -0
- package/dist/hash/index.js +8 -0
- package/dist/hash/stableStringify.d.ts +19 -0
- package/dist/hash/stableStringify.js +102 -0
- package/dist/id/index.d.ts +7 -0
- package/dist/id/index.js +7 -0
- package/dist/id/nanoid.d.ts +16 -0
- package/dist/id/nanoid.js +65 -0
- package/dist/id/uniqueId.d.ts +14 -0
- package/dist/id/uniqueId.js +20 -0
- package/dist/id/uuid.d.ts +25 -0
- package/dist/id/uuid.js +64 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +15 -8
- package/dist/internal/bytes.d.ts +11 -0
- package/dist/internal/bytes.js +33 -0
- package/dist/internal/codec.d.ts +11 -0
- package/dist/internal/codec.js +84 -0
- package/dist/internal/compare.d.ts +10 -0
- package/dist/internal/compare.js +26 -0
- package/dist/internal/crypto.d.ts +5 -0
- package/dist/internal/crypto.js +11 -0
- package/dist/internal/keys.d.ts +12 -0
- package/dist/internal/keys.js +23 -0
- package/dist/internal/kind.d.ts +44 -0
- package/dist/internal/kind.js +139 -0
- package/dist/internal/sparse.d.ts +51 -0
- package/dist/internal/sparse.js +104 -0
- package/dist/internal/text.d.ts +7 -0
- package/dist/internal/text.js +15 -0
- package/dist/internal/timer.d.ts +10 -0
- package/dist/internal/timer.js +17 -0
- package/dist/internal/truncate.d.ts +10 -0
- package/dist/internal/truncate.js +22 -0
- package/dist/internal/walk.d.ts +47 -0
- package/dist/internal/walk.js +100 -0
- package/dist/is/index.d.ts +8 -0
- package/dist/is/index.js +8 -0
- package/dist/is/isArrayLike.d.ts +18 -0
- package/dist/is/isArrayLike.js +25 -0
- package/dist/is/isError.d.ts +13 -0
- package/dist/is/isError.js +18 -0
- package/dist/is/isNil.d.ts +12 -0
- package/dist/is/isNil.js +14 -0
- package/dist/is/isPlainObject.d.ts +15 -0
- package/dist/is/isPlainObject.js +34 -0
- package/dist/number/index.d.ts +7 -0
- package/dist/number/index.js +7 -0
- package/dist/number/round.d.ts +86 -0
- package/dist/number/round.js +130 -0
- package/dist/number/stats.d.ts +52 -0
- package/dist/number/stats.js +115 -0
- package/dist/object/cloneDeep.d.ts +28 -0
- package/dist/object/cloneDeep.js +200 -0
- package/dist/object/index.d.ts +14 -0
- package/dist/object/index.js +13 -0
- package/dist/object/isEqual.d.ts +64 -0
- package/dist/object/isEqual.js +289 -0
- package/dist/object/matches.d.ts +40 -0
- package/dist/object/matches.js +284 -0
- package/dist/object/merge.d.ts +66 -0
- package/dist/object/merge.js +272 -0
- package/dist/object/parsePath.d.ts +22 -0
- package/dist/object/parsePath.js +111 -0
- package/dist/object/path.d.ts +85 -0
- package/dist/object/path.js +208 -0
- package/dist/object/pick.d.ts +91 -0
- package/dist/object/pick.js +180 -0
- package/dist/object/reshape.d.ts +73 -0
- package/dist/object/reshape.js +144 -0
- package/dist/random/index.d.ts +96 -32
- package/dist/random/index.js +215 -53
- package/dist/string/case.d.ts +71 -0
- package/dist/string/case.js +152 -0
- package/dist/string/fold.d.ts +35 -0
- package/dist/string/fold.js +100 -0
- package/dist/string/index.d.ts +6 -187
- package/dist/string/index.js +6 -224
- package/dist/string/truncate.d.ts +25 -0
- package/dist/string/truncate.js +44 -0
- package/dist/string/words.d.ts +27 -0
- package/dist/string/words.js +241 -0
- package/package.json +99 -51
- package/dist/collections/BTree.d.ts +0 -230
- package/dist/collections/BTree.js +0 -1143
- package/dist/collections/Heap.d.ts +0 -69
- package/dist/collections/Heap.js +0 -181
- package/dist/collections/LRUCache.d.ts +0 -83
- package/dist/collections/LRUCache.js +0 -139
- package/dist/collections/SortedMap.d.ts +0 -92
- package/dist/collections/SortedMap.js +0 -131
- package/dist/collections/SortedSet.d.ts +0 -69
- package/dist/collections/SortedSet.js +0 -99
- package/dist/collections/SortedTree.d.ts +0 -103
- package/dist/collections/SortedTree.js +0 -142
- package/dist/collections/SplayTree.d.ts +0 -107
- package/dist/collections/SplayTree.js +0 -351
- package/dist/collections/Trie.d.ts +0 -42
- package/dist/collections/Trie.js +0 -104
- package/dist/collections/abc.d.ts +0 -152
- package/dist/collections/abc.js +0 -39
- package/dist/collections/frozenset.d.ts +0 -19
- package/dist/collections/frozenset.js +0 -33
- package/dist/functools/index.d.ts +0 -106
- package/dist/functools/index.js +0 -203
- package/dist/globals/index.d.ts +0 -268
- package/dist/globals/index.js +0 -447
- package/dist/i18n/currency.d.ts +0 -27
- package/dist/i18n/currency.js +0 -100
- package/dist/i18n/date/index.d.ts +0 -210
- package/dist/i18n/date/index.js +0 -552
- package/dist/i18n/date/utils.d.ts +0 -64
- package/dist/i18n/date/utils.js +0 -192
- package/dist/i18n/duration.d.ts +0 -113
- package/dist/i18n/duration.js +0 -398
- package/dist/i18n/format.d.ts +0 -34
- package/dist/i18n/format.js +0 -378
- package/dist/i18n/index.d.ts +0 -9
- package/dist/i18n/index.js +0 -8
- package/dist/itertools/index.d.ts +0 -251
- package/dist/itertools/index.js +0 -434
- package/dist/math/index.d.ts +0 -79
- package/dist/math/index.js +0 -81
- package/dist/mod.d.ts +0 -1
- package/dist/mod.js +0 -1
- package/dist/operators/index.d.ts +0 -148
- package/dist/operators/index.js +0 -325
- package/dist/types.d.ts +0 -19
- package/dist/types.js +0 -1
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The path grammar behind `get`, `set`, `has`, `unset`, `pick` and `omit`.
|
|
3
|
+
*/
|
|
4
|
+
import { assertNotHugeSparse } from '../internal/sparse.js';
|
|
5
|
+
import { truncateForError } from '../internal/truncate.js';
|
|
6
|
+
const MAX_PATH_LENGTH = 2 ** 20;
|
|
7
|
+
/** Segments that lead to a prototype unless they are own data. */
|
|
8
|
+
export const DANGEROUS_KEYS = new Set([
|
|
9
|
+
'__proto__',
|
|
10
|
+
'constructor',
|
|
11
|
+
'prototype'
|
|
12
|
+
]);
|
|
13
|
+
/**
|
|
14
|
+
* Write `value` under `key`: a plain assignment for an ordinary string key, so a setter on `target`
|
|
15
|
+
* runs, and an own data property for a symbol or one of {@link DANGEROUS_KEYS}, so `__proto__`
|
|
16
|
+
* stays a key and no write reaches a prototype.
|
|
17
|
+
*/
|
|
18
|
+
export function writeKey(target, key, value) {
|
|
19
|
+
if (typeof key === 'string' && !DANGEROUS_KEYS.has(key)) {
|
|
20
|
+
;
|
|
21
|
+
target[key] = value;
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
Object.defineProperty(target, key, {
|
|
25
|
+
value,
|
|
26
|
+
enumerable: true,
|
|
27
|
+
writable: true,
|
|
28
|
+
configurable: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function malformed(path) {
|
|
33
|
+
return new TypeError(`malformed path ${truncateForError(path)}`);
|
|
34
|
+
}
|
|
35
|
+
/** Read the bracket segment at `path[i]` (`[0]`, `['key']`, `["key"]`); returns it and the end. */
|
|
36
|
+
function readBracket(path, i) {
|
|
37
|
+
const quote = path[i + 1];
|
|
38
|
+
if (quote === "'" || quote === '"') {
|
|
39
|
+
let key = '';
|
|
40
|
+
let j = i + 2;
|
|
41
|
+
while (j < path.length && path[j] !== quote) {
|
|
42
|
+
if (path[j] === '\\' && j + 1 < path.length)
|
|
43
|
+
j++;
|
|
44
|
+
key += path[j++];
|
|
45
|
+
}
|
|
46
|
+
if (path[j] !== quote || path[j + 1] !== ']')
|
|
47
|
+
throw malformed(path);
|
|
48
|
+
return [key, j + 2];
|
|
49
|
+
}
|
|
50
|
+
const close = path.indexOf(']', i);
|
|
51
|
+
const index = close < 0 ? '' : path.slice(i + 1, close);
|
|
52
|
+
if (!/^(0|[1-9]\d*)$/.test(index))
|
|
53
|
+
throw malformed(path);
|
|
54
|
+
return [index, close + 1];
|
|
55
|
+
}
|
|
56
|
+
/** Split a string path: `a.b[0]['c.d']` is `a`, `b`, `0`, `c.d`. */
|
|
57
|
+
function splitString(path) {
|
|
58
|
+
const out = [];
|
|
59
|
+
let i = 0;
|
|
60
|
+
let needName = path[0] !== '[';
|
|
61
|
+
for (;;) {
|
|
62
|
+
if (needName) {
|
|
63
|
+
let end = i;
|
|
64
|
+
while (end < path.length && path[end] !== '.' && path[end] !== '[') {
|
|
65
|
+
if (path[end] === ']')
|
|
66
|
+
throw malformed(path);
|
|
67
|
+
end++;
|
|
68
|
+
}
|
|
69
|
+
out.push(path.slice(i, end));
|
|
70
|
+
i = end;
|
|
71
|
+
}
|
|
72
|
+
while (path[i] === '[') {
|
|
73
|
+
const [segment, end] = readBracket(path, i);
|
|
74
|
+
out.push(segment);
|
|
75
|
+
i = end;
|
|
76
|
+
}
|
|
77
|
+
if (i >= path.length)
|
|
78
|
+
return out;
|
|
79
|
+
if (path[i] !== '.')
|
|
80
|
+
throw malformed(path);
|
|
81
|
+
i++;
|
|
82
|
+
needName = path[i] !== '[';
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The segments of `path`. A string splits on `.`, on `[0]` index segments and on `['key']` or
|
|
87
|
+
* `["key"]` segments (with `\\` escaping a quote); an array is taken as its keys, a number segment
|
|
88
|
+
* as its string.
|
|
89
|
+
* @throws {TypeError} for a malformed string path or a segment that is not a string, number or
|
|
90
|
+
* symbol.
|
|
91
|
+
* @throws {RangeError} for a string path over 2^20 characters or a huge sparse array.
|
|
92
|
+
*/
|
|
93
|
+
export function parsePath(path) {
|
|
94
|
+
if (typeof path === 'string') {
|
|
95
|
+
if (path.length > MAX_PATH_LENGTH) {
|
|
96
|
+
throw new RangeError(`path longer than ${String(MAX_PATH_LENGTH)} characters`);
|
|
97
|
+
}
|
|
98
|
+
return path.includes('[') || path.includes(']') ? splitString(path) : path.split('.');
|
|
99
|
+
}
|
|
100
|
+
if (!Array.isArray(path)) {
|
|
101
|
+
throw new TypeError(`a path is a string or an array of keys, got ${typeof path}`);
|
|
102
|
+
}
|
|
103
|
+
assertNotHugeSparse(path);
|
|
104
|
+
return Array.from(path, (segment) => {
|
|
105
|
+
if (typeof segment === 'string' || typeof segment === 'symbol')
|
|
106
|
+
return segment;
|
|
107
|
+
if (typeof segment === 'number')
|
|
108
|
+
return String(segment);
|
|
109
|
+
throw new TypeError('path segments must be strings, numbers or symbols');
|
|
110
|
+
});
|
|
111
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading and writing by path: `get`, `set`, `has`, `unset`.
|
|
3
|
+
*/
|
|
4
|
+
import { type Path } from './parsePath.js';
|
|
5
|
+
/**
|
|
6
|
+
* True when `key` would lead from `base` to a prototype: `__proto__`, `constructor` or
|
|
7
|
+
* `prototype`, unless it is an own data property of an object that is not a function.
|
|
8
|
+
*/
|
|
9
|
+
export declare function reachesPrototype(base: object, key: PropertyKey): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The value at `path` in `obj`, or `defaultValue` when the path is missing or the value is
|
|
12
|
+
* `undefined`. Every segment reads a property as `obj[key]` does, own or inherited, and a string
|
|
13
|
+
* reads as its boxed form, so `get('abc', 'length')` is 3. A `__proto__`, `constructor` or
|
|
14
|
+
* `prototype` segment that is not own data of a non-function object reads as missing, so a path
|
|
15
|
+
* cannot reach a prototype. An empty path names no property and reads as missing.
|
|
16
|
+
* @param obj The object to read.
|
|
17
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
18
|
+
* @param defaultValue Returned when nothing is found.
|
|
19
|
+
* @returns The value found, or `defaultValue`.
|
|
20
|
+
* @throws {TypeError} for a malformed path.
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* get({ a: [{ b: 1 }] }, 'a[0].b') // 1
|
|
24
|
+
* get({ 'a.b': 1 }, "['a.b']") // 1
|
|
25
|
+
* get({ 'a.b': 1 }, ['a.b']) // 1
|
|
26
|
+
* get({}, 'a.b', 'none') // 'none'
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function get(obj: unknown, path: Path, defaultValue?: unknown): unknown;
|
|
30
|
+
/**
|
|
31
|
+
* True when every segment of `path` is an own property along the way, as lodash's `has` checks.
|
|
32
|
+
* A `__proto__`, `constructor` or `prototype` segment that is not own data of a non-function
|
|
33
|
+
* object does not count. The terminal value is not read. An empty path names no property, so it
|
|
34
|
+
* is never present.
|
|
35
|
+
* @param obj The object to test.
|
|
36
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
37
|
+
* @returns Whether the path is present.
|
|
38
|
+
* @throws {TypeError} for a malformed path.
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* has({ a: { b: undefined } }, 'a.b') // true
|
|
42
|
+
* has({ a: [1] }, ['a', 0]) // true
|
|
43
|
+
* has(Object.create({ a: 1 }), 'a') // false: inherited
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function has(obj: unknown, path: Path): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Set the value at `path` in `obj` and return `obj`, as lodash's `set` does. A missing or
|
|
49
|
+
* primitive step is replaced by a new array when the next segment is an index, and by a plain
|
|
50
|
+
* object otherwise. The last segment is assigned, so setters run, except a terminal
|
|
51
|
+
* `constructor` or `prototype` is written as own data. An empty path names no property, so `obj`
|
|
52
|
+
* is returned unchanged.
|
|
53
|
+
* @param obj The object to change. A `null`, `undefined` or primitive `obj` is returned as it is.
|
|
54
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
55
|
+
* @param value The value to store.
|
|
56
|
+
* @returns `obj`.
|
|
57
|
+
* @throws {TypeError} when a `__proto__` or non-terminal `constructor` or `prototype` segment is
|
|
58
|
+
* not own data of a plain object or array; a terminal `constructor` or `prototype` is an own
|
|
59
|
+
* accessor or non-writable property; or a step is inherited.
|
|
60
|
+
* @throws {RangeError} for an array index past the end, or a `length` that would grow an array,
|
|
61
|
+
* so a short path cannot allocate a huge array.
|
|
62
|
+
* @example
|
|
63
|
+
* ```ts
|
|
64
|
+
* set({}, 'a.b', 1) // { a: { b: 1 } }
|
|
65
|
+
* set({}, ['list', '0'], 'x') // { list: ['x'] }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export declare function set<T>(obj: T, path: Path, value: unknown): T;
|
|
69
|
+
/**
|
|
70
|
+
* Delete the property at `path` in `obj`, as lodash's `unset` does.
|
|
71
|
+
* @param obj The object to change.
|
|
72
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
73
|
+
* @returns `true` when the property is gone (or was never there), `false` when it could not be
|
|
74
|
+
* deleted or the path crosses a `__proto__`, `constructor` or `prototype` segment that is not own
|
|
75
|
+
* data of a plain object or array, or an inherited step. An empty path names no property, so
|
|
76
|
+
* nothing is deleted and the result is `true`.
|
|
77
|
+
* @throws {TypeError} for a malformed path.
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* const obj = { a: { b: 1, c: 2 } }
|
|
81
|
+
* unset(obj, 'a.b') // true
|
|
82
|
+
* obj // { a: { c: 2 } }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare function unset(obj: unknown, path: Path): boolean;
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading and writing by path: `get`, `set`, `has`, `unset`.
|
|
3
|
+
*/
|
|
4
|
+
import { isCanonicalArrayIndex } from '../internal/sparse.js';
|
|
5
|
+
import { isPlainObject } from '../is/isPlainObject.js';
|
|
6
|
+
import { DANGEROUS_KEYS, parsePath, writeKey } from './parsePath.js';
|
|
7
|
+
function isContainer(x) {
|
|
8
|
+
return (typeof x === 'object' && x !== null) || typeof x === 'function';
|
|
9
|
+
}
|
|
10
|
+
function isOwnData(base, key) {
|
|
11
|
+
const desc = Object.getOwnPropertyDescriptor(base, key);
|
|
12
|
+
return desc !== undefined && 'value' in desc;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* True when `key` would lead from `base` to a prototype: `__proto__`, `constructor` or
|
|
16
|
+
* `prototype`, unless it is an own data property of an object that is not a function.
|
|
17
|
+
*/
|
|
18
|
+
export function reachesPrototype(base, key) {
|
|
19
|
+
return DANGEROUS_KEYS.has(key) && (typeof base === 'function' || !isOwnData(base, key));
|
|
20
|
+
}
|
|
21
|
+
function unsafeWrite(base, key) {
|
|
22
|
+
if (!DANGEROUS_KEYS.has(key))
|
|
23
|
+
return false;
|
|
24
|
+
return !((Array.isArray(base) || isPlainObject(base)) && isOwnData(base, key));
|
|
25
|
+
}
|
|
26
|
+
function refuse(key) {
|
|
27
|
+
return new TypeError(`refusing to write through "${String(key)}"`);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The value at `path` in `obj`, or `defaultValue` when the path is missing or the value is
|
|
31
|
+
* `undefined`. Every segment reads a property as `obj[key]` does, own or inherited, and a string
|
|
32
|
+
* reads as its boxed form, so `get('abc', 'length')` is 3. A `__proto__`, `constructor` or
|
|
33
|
+
* `prototype` segment that is not own data of a non-function object reads as missing, so a path
|
|
34
|
+
* cannot reach a prototype. An empty path names no property and reads as missing.
|
|
35
|
+
* @param obj The object to read.
|
|
36
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
37
|
+
* @param defaultValue Returned when nothing is found.
|
|
38
|
+
* @returns The value found, or `defaultValue`.
|
|
39
|
+
* @throws {TypeError} for a malformed path.
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* get({ a: [{ b: 1 }] }, 'a[0].b') // 1
|
|
43
|
+
* get({ 'a.b': 1 }, "['a.b']") // 1
|
|
44
|
+
* get({ 'a.b': 1 }, ['a.b']) // 1
|
|
45
|
+
* get({}, 'a.b', 'none') // 'none'
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export function get(obj, path, defaultValue) {
|
|
49
|
+
const segments = parsePath(path);
|
|
50
|
+
if (segments.length === 0)
|
|
51
|
+
return defaultValue;
|
|
52
|
+
let cur = obj;
|
|
53
|
+
for (const key of segments) {
|
|
54
|
+
if (cur === null || cur === undefined)
|
|
55
|
+
return defaultValue;
|
|
56
|
+
const base = Object(cur);
|
|
57
|
+
if (reachesPrototype(base, key))
|
|
58
|
+
return defaultValue;
|
|
59
|
+
cur = base[key];
|
|
60
|
+
}
|
|
61
|
+
return cur === undefined ? defaultValue : cur;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* True when every segment of `path` is an own property along the way, as lodash's `has` checks.
|
|
65
|
+
* A `__proto__`, `constructor` or `prototype` segment that is not own data of a non-function
|
|
66
|
+
* object does not count. The terminal value is not read. An empty path names no property, so it
|
|
67
|
+
* is never present.
|
|
68
|
+
* @param obj The object to test.
|
|
69
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
70
|
+
* @returns Whether the path is present.
|
|
71
|
+
* @throws {TypeError} for a malformed path.
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* has({ a: { b: undefined } }, 'a.b') // true
|
|
75
|
+
* has({ a: [1] }, ['a', 0]) // true
|
|
76
|
+
* has(Object.create({ a: 1 }), 'a') // false: inherited
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export function has(obj, path) {
|
|
80
|
+
const segments = parsePath(path);
|
|
81
|
+
if (segments.length === 0)
|
|
82
|
+
return false;
|
|
83
|
+
let cur = obj;
|
|
84
|
+
for (let i = 0; i < segments.length; i++) {
|
|
85
|
+
const key = segments[i];
|
|
86
|
+
if (cur === null || cur === undefined)
|
|
87
|
+
return false;
|
|
88
|
+
const base = Object(cur);
|
|
89
|
+
if (reachesPrototype(base, key) || !Object.hasOwn(base, key))
|
|
90
|
+
return false;
|
|
91
|
+
if (i < segments.length - 1)
|
|
92
|
+
cur = base[key];
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
function growsArray(target, key, value) {
|
|
97
|
+
if (key === 'length')
|
|
98
|
+
return Object(value) === value || Number(value) > target.length;
|
|
99
|
+
return typeof key === 'string' && isCanonicalArrayIndex(key) && Number(key) > target.length;
|
|
100
|
+
}
|
|
101
|
+
function write(target, key, value, terminal) {
|
|
102
|
+
if (terminal && (key === 'constructor' || key === 'prototype')) {
|
|
103
|
+
const desc = Object.getOwnPropertyDescriptor(target, key);
|
|
104
|
+
if (desc && (!('value' in desc) || !desc.writable))
|
|
105
|
+
throw refuse(key);
|
|
106
|
+
if (desc === undefined) {
|
|
107
|
+
writeKey(target, key, value);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else if (unsafeWrite(target, key))
|
|
112
|
+
throw refuse(key);
|
|
113
|
+
if (Array.isArray(target) && growsArray(target, key, value)) {
|
|
114
|
+
throw new RangeError(key === 'length'
|
|
115
|
+
? 'array length can only shrink, to a primitive number'
|
|
116
|
+
: `array index ${String(key)} is past the end`);
|
|
117
|
+
}
|
|
118
|
+
;
|
|
119
|
+
target[key] = value;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Set the value at `path` in `obj` and return `obj`, as lodash's `set` does. A missing or
|
|
123
|
+
* primitive step is replaced by a new array when the next segment is an index, and by a plain
|
|
124
|
+
* object otherwise. The last segment is assigned, so setters run, except a terminal
|
|
125
|
+
* `constructor` or `prototype` is written as own data. An empty path names no property, so `obj`
|
|
126
|
+
* is returned unchanged.
|
|
127
|
+
* @param obj The object to change. A `null`, `undefined` or primitive `obj` is returned as it is.
|
|
128
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
129
|
+
* @param value The value to store.
|
|
130
|
+
* @returns `obj`.
|
|
131
|
+
* @throws {TypeError} when a `__proto__` or non-terminal `constructor` or `prototype` segment is
|
|
132
|
+
* not own data of a plain object or array; a terminal `constructor` or `prototype` is an own
|
|
133
|
+
* accessor or non-writable property; or a step is inherited.
|
|
134
|
+
* @throws {RangeError} for an array index past the end, or a `length` that would grow an array,
|
|
135
|
+
* so a short path cannot allocate a huge array.
|
|
136
|
+
* @example
|
|
137
|
+
* ```ts
|
|
138
|
+
* set({}, 'a.b', 1) // { a: { b: 1 } }
|
|
139
|
+
* set({}, ['list', '0'], 'x') // { list: ['x'] }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export function set(obj, path, value) {
|
|
143
|
+
const segments = parsePath(path);
|
|
144
|
+
if (!isContainer(obj) || segments.length === 0)
|
|
145
|
+
return obj;
|
|
146
|
+
const last = segments.length - 1;
|
|
147
|
+
let cur = obj;
|
|
148
|
+
let depth = 0;
|
|
149
|
+
for (; depth < last; depth++) {
|
|
150
|
+
const key = segments[depth];
|
|
151
|
+
if (unsafeWrite(cur, key))
|
|
152
|
+
throw refuse(key);
|
|
153
|
+
if (!Object.hasOwn(cur, key) && key in cur) {
|
|
154
|
+
throw new TypeError(`refusing to write through inherited "${String(key)}"`);
|
|
155
|
+
}
|
|
156
|
+
const next = cur[key];
|
|
157
|
+
if (!isContainer(next))
|
|
158
|
+
break;
|
|
159
|
+
cur = next;
|
|
160
|
+
}
|
|
161
|
+
let tail = value;
|
|
162
|
+
for (let i = last; i > depth; i--) {
|
|
163
|
+
const key = segments[i];
|
|
164
|
+
const fresh = typeof key === 'string' && isCanonicalArrayIndex(key) ? [] : {};
|
|
165
|
+
write(fresh, key, tail, i === last);
|
|
166
|
+
tail = fresh;
|
|
167
|
+
}
|
|
168
|
+
write(cur, segments[depth], tail, depth === last);
|
|
169
|
+
return obj;
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Delete the property at `path` in `obj`, as lodash's `unset` does.
|
|
173
|
+
* @param obj The object to change.
|
|
174
|
+
* @param path A dotted string with `[0]` and `['key']` segments, or an array of keys.
|
|
175
|
+
* @returns `true` when the property is gone (or was never there), `false` when it could not be
|
|
176
|
+
* deleted or the path crosses a `__proto__`, `constructor` or `prototype` segment that is not own
|
|
177
|
+
* data of a plain object or array, or an inherited step. An empty path names no property, so
|
|
178
|
+
* nothing is deleted and the result is `true`.
|
|
179
|
+
* @throws {TypeError} for a malformed path.
|
|
180
|
+
* @example
|
|
181
|
+
* ```ts
|
|
182
|
+
* const obj = { a: { b: 1, c: 2 } }
|
|
183
|
+
* unset(obj, 'a.b') // true
|
|
184
|
+
* obj // { a: { c: 2 } }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export function unset(obj, path) {
|
|
188
|
+
const segments = parsePath(path);
|
|
189
|
+
if (segments.length === 0)
|
|
190
|
+
return true;
|
|
191
|
+
let cur = obj;
|
|
192
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
193
|
+
if (!isContainer(cur))
|
|
194
|
+
return true;
|
|
195
|
+
const key = segments[i];
|
|
196
|
+
if (unsafeWrite(cur, key))
|
|
197
|
+
return false;
|
|
198
|
+
if (!Object.hasOwn(cur, key))
|
|
199
|
+
return !(key in cur);
|
|
200
|
+
cur = cur[key];
|
|
201
|
+
}
|
|
202
|
+
if (!isContainer(cur))
|
|
203
|
+
return true;
|
|
204
|
+
const key = segments[segments.length - 1];
|
|
205
|
+
if (unsafeWrite(cur, key))
|
|
206
|
+
return false;
|
|
207
|
+
return Reflect.deleteProperty(cur, key);
|
|
208
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copies with some keys: `pick`, `omit`, `pickBy`, `omitBy`.
|
|
3
|
+
*/
|
|
4
|
+
import { type Path } from './parsePath.js';
|
|
5
|
+
/** One path or a list of them; in a list, each entry is a path or a single key. */
|
|
6
|
+
export type Paths = string | readonly (Path | PropertyKey)[];
|
|
7
|
+
/**
|
|
8
|
+
* Keys for the precise {@link pick}/{@link omit} overloads, excluding arrays, index
|
|
9
|
+
* signatures, and string keys containing path syntax (`.`, `[` or `]`).
|
|
10
|
+
*/
|
|
11
|
+
export type PlainKey<T> = T extends readonly unknown[] ? never : string extends keyof T ? never : number extends keyof T ? never : symbol extends keyof T ? never : Exclude<keyof T, `${string}${'.' | '[' | ']'}${string}`>;
|
|
12
|
+
/**
|
|
13
|
+
* What {@link pickBy} and {@link omitBy} return: a plain object, so an array's elements come back
|
|
14
|
+
* under their index keys.
|
|
15
|
+
*/
|
|
16
|
+
export type PickedBy<T> = T extends readonly unknown[] ? Record<string, T[number]> : Partial<T>;
|
|
17
|
+
/**
|
|
18
|
+
* A new object with the values at `paths` in `obj`. Each path is read as {@link has} reads it:
|
|
19
|
+
* own properties only, never through a prototype-reaching segment, and a path that is missing is
|
|
20
|
+
* left out. The containers on the way are new, arrays where the source has an array and the next
|
|
21
|
+
* segment is an index; the values at the end of each path are the source's own, not copies.
|
|
22
|
+
* Tuples of individual plain keys have precise result types; union keys and index signatures
|
|
23
|
+
* keep partial results.
|
|
24
|
+
* @param obj The object to read.
|
|
25
|
+
* @param paths A path, or a list of paths or keys.
|
|
26
|
+
* @returns A new object.
|
|
27
|
+
* @throws {TypeError} for a malformed path.
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* pick({ a: 1, b: 2, c: 3 }, ['a', 'c']) // { a: 1, c: 3 }
|
|
31
|
+
* pick({ a: { b: 1, c: 2 } }, 'a.b') // { a: { b: 1 } }
|
|
32
|
+
* pick({ list: [{ id: 1, x: 2 }] }, ['list[0].id']) // { list: [{ id: 1 }] }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function pick<T extends object, const P extends readonly PlainKey<T>[]>(obj: T & (T extends readonly unknown[] ? never : string extends keyof T ? never : number extends keyof T ? never : symbol extends keyof T ? never : unknown), paths: P): number extends P['length'] ? Partial<Pick<T, P[number]>> : true extends {
|
|
36
|
+
[I in keyof P]: P[I][] extends {
|
|
37
|
+
[K in P[I]]: K[];
|
|
38
|
+
}[P[I]] ? false : true;
|
|
39
|
+
}[number] ? Partial<T> : Pick<T, P[number]>;
|
|
40
|
+
/** {@link pick} with paths or keys that cannot determine an exact set of properties. */
|
|
41
|
+
export declare function pick<T>(obj: T, paths: Paths): Partial<T>;
|
|
42
|
+
/**
|
|
43
|
+
* A copy of `obj` without the values at `paths`. Copies own enumerable string and symbol keys
|
|
44
|
+
* of an object; the elements and own enumerable symbol keys of an array. The plain objects and
|
|
45
|
+
* arrays along each path are copied too, so `obj` is never changed; every other value is kept by
|
|
46
|
+
* reference. A null-prototype object copies to a null-prototype object.
|
|
47
|
+
* Tuples of individual plain keys have precise result types; union keys and index signatures
|
|
48
|
+
* keep partial results.
|
|
49
|
+
* @param obj A plain object or array.
|
|
50
|
+
* @param paths A path, or a list of paths or keys.
|
|
51
|
+
* @returns A new plain object or array.
|
|
52
|
+
* @throws {TypeError} when `obj`, or a value a path walks into, is not a plain object or array, or
|
|
53
|
+
* has its own `toJSON` function or accessor: copying a class instance into a plain object would
|
|
54
|
+
* lose its prototype, and a copy would lose or misbind any `toJSON` that hides fields.
|
|
55
|
+
* @throws {RangeError} for a path more than 1000 levels deep.
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* omit({ a: 1, b: 2, c: 3 }, ['a', 'c']) // { b: 2 }
|
|
59
|
+
* omit({ user: { name: 'a', password: 'p' } }, 'user.password') // { user: { name: 'a' } }
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare function omit<T extends object, const P extends readonly PlainKey<T>[]>(obj: T & (T extends readonly unknown[] ? never : string extends keyof T ? never : number extends keyof T ? never : symbol extends keyof T ? never : unknown), paths: P): number extends P['length'] ? Partial<Omit<T, P[number]>> : true extends {
|
|
63
|
+
[I in keyof P]: P[I][] extends {
|
|
64
|
+
[K in P[I]]: K[];
|
|
65
|
+
}[P[I]] ? false : true;
|
|
66
|
+
}[number] ? Partial<T> : Omit<T, P[number]>;
|
|
67
|
+
/** {@link omit} with paths or keys that cannot determine an exact set of properties. */
|
|
68
|
+
export declare function omit<T extends object>(obj: T | null | undefined, paths: Paths): Partial<T>;
|
|
69
|
+
/**
|
|
70
|
+
* A new plain object with the own enumerable string keys of `obj` for which `predicate` is truthy.
|
|
71
|
+
* @param obj The object to read.
|
|
72
|
+
* @param predicate Called with `(value, key, obj)`.
|
|
73
|
+
* @returns A new object.
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* pickBy({ a: 1, b: '2', c: 3 }, (value) => typeof value === 'number') // { a: 1, c: 3 }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare function pickBy<T extends object>(obj: T | null | undefined, predicate: (value: T[keyof T], key: keyof T & string, obj: T) => unknown): PickedBy<T>;
|
|
80
|
+
/**
|
|
81
|
+
* A new plain object with the own enumerable string keys of `obj` for which `predicate` is falsy:
|
|
82
|
+
* the complement of {@link pickBy}.
|
|
83
|
+
* @param obj The object to read.
|
|
84
|
+
* @param predicate Called with `(value, key, obj)`.
|
|
85
|
+
* @returns A new object.
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* omitBy({ a: 1, b: undefined }, (value) => value === undefined) // { a: 1 }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function omitBy<T extends object>(obj: T | null | undefined, predicate: (value: T[keyof T], key: keyof T & string, obj: T) => unknown): PickedBy<T>;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copies with some keys: `pick`, `omit`, `pickBy`, `omitBy`.
|
|
3
|
+
*/
|
|
4
|
+
import { isPlainObject } from '../is/isPlainObject.js';
|
|
5
|
+
import { enumerableKeys, isEnumerable } from '../internal/keys.js';
|
|
6
|
+
import { assertNotHugeSparse, isCanonicalArrayIndex, walkArrayIndices } from '../internal/sparse.js';
|
|
7
|
+
import { enterDepth, exitDepth, guardDepth } from '../internal/walk.js';
|
|
8
|
+
import { parsePath, writeKey } from './parsePath.js';
|
|
9
|
+
import { reachesPrototype } from './path.js';
|
|
10
|
+
function toPathList(paths) {
|
|
11
|
+
if (typeof paths === 'string')
|
|
12
|
+
return [parsePath(paths)];
|
|
13
|
+
if (!Array.isArray(paths))
|
|
14
|
+
throw new TypeError(`expected a path or a list of paths, got ${typeof paths}`);
|
|
15
|
+
assertNotHugeSparse(paths);
|
|
16
|
+
return Array.from(paths, (path) => typeof path === 'string' || Array.isArray(path)
|
|
17
|
+
? parsePath(path)
|
|
18
|
+
: parsePath([path]));
|
|
19
|
+
}
|
|
20
|
+
function nodeAt(root, parts) {
|
|
21
|
+
let node = root;
|
|
22
|
+
for (const part of parts) {
|
|
23
|
+
node.kids ??= new Map();
|
|
24
|
+
let next = node.kids.get(part);
|
|
25
|
+
if (next === undefined) {
|
|
26
|
+
next = {};
|
|
27
|
+
node.kids.set(part, next);
|
|
28
|
+
}
|
|
29
|
+
node = next;
|
|
30
|
+
}
|
|
31
|
+
return node;
|
|
32
|
+
}
|
|
33
|
+
export function pick(obj, paths) {
|
|
34
|
+
const list = toPathList(paths);
|
|
35
|
+
const root = { out: {} };
|
|
36
|
+
pathLoop: for (const parts of list) {
|
|
37
|
+
if (parts.length === 0)
|
|
38
|
+
continue;
|
|
39
|
+
let src = obj;
|
|
40
|
+
let node = root;
|
|
41
|
+
/** `nodes[i]` is the trie node for `parts[i]`, `sources[i]` the container it is read from. */
|
|
42
|
+
const nodes = [];
|
|
43
|
+
const sources = [];
|
|
44
|
+
for (const key of parts) {
|
|
45
|
+
sources.push(src);
|
|
46
|
+
node = nodeAt(node, [key]);
|
|
47
|
+
nodes.push(node);
|
|
48
|
+
if (node.leaf || src === null || src === undefined)
|
|
49
|
+
continue pathLoop;
|
|
50
|
+
const base = Object(src);
|
|
51
|
+
if (reachesPrototype(base, key) || !Object.hasOwn(base, key))
|
|
52
|
+
continue pathLoop;
|
|
53
|
+
src = base[key];
|
|
54
|
+
}
|
|
55
|
+
node.leaf = true;
|
|
56
|
+
let parent = root;
|
|
57
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
58
|
+
const child = nodes[i];
|
|
59
|
+
if (child.out === undefined) {
|
|
60
|
+
const next = parts[i + 1];
|
|
61
|
+
const index = typeof next === 'string' && isCanonicalArrayIndex(next);
|
|
62
|
+
child.out = Array.isArray(sources[i + 1]) && index ? [] : {};
|
|
63
|
+
writeKey(parent.out, parts[i], child.out);
|
|
64
|
+
}
|
|
65
|
+
parent = child;
|
|
66
|
+
}
|
|
67
|
+
writeKey(parent.out, parts[parts.length - 1], src);
|
|
68
|
+
}
|
|
69
|
+
return root.out;
|
|
70
|
+
}
|
|
71
|
+
/** An array whose prototype is `Array.prototype` of this realm or of another one: not a subclass. */
|
|
72
|
+
function isUnsubclassedArray(x) {
|
|
73
|
+
if (!Array.isArray(x))
|
|
74
|
+
return false;
|
|
75
|
+
const proto = Object.getPrototypeOf(x);
|
|
76
|
+
return (proto === Array.prototype ||
|
|
77
|
+
(Array.isArray(proto) && isPlainObject(Object.getPrototypeOf(proto))));
|
|
78
|
+
}
|
|
79
|
+
/** An own `toJSON` function or accessor, which a copy would lose or keep bound to the source. */
|
|
80
|
+
function hasOwnToJSON(x) {
|
|
81
|
+
const desc = Object.getOwnPropertyDescriptor(x, 'toJSON');
|
|
82
|
+
if (desc === undefined)
|
|
83
|
+
return false;
|
|
84
|
+
return desc.get !== undefined || desc.set !== undefined || typeof desc.value === 'function';
|
|
85
|
+
}
|
|
86
|
+
function isOmitContainer(x) {
|
|
87
|
+
return (isUnsubclassedArray(x) || isPlainObject(x)) && !hasOwnToJSON(x);
|
|
88
|
+
}
|
|
89
|
+
function omitIn(value, trie) {
|
|
90
|
+
enterDepth();
|
|
91
|
+
try {
|
|
92
|
+
let out;
|
|
93
|
+
let keys;
|
|
94
|
+
if (Array.isArray(value)) {
|
|
95
|
+
const array = [];
|
|
96
|
+
array.length = value.length;
|
|
97
|
+
walkArrayIndices(value, (event) => {
|
|
98
|
+
if (event.kind !== 'index')
|
|
99
|
+
return;
|
|
100
|
+
const child = trie.kids?.get(String(event.index));
|
|
101
|
+
if (child?.leaf)
|
|
102
|
+
return;
|
|
103
|
+
const element = value[event.index];
|
|
104
|
+
array[event.index] = child?.kids ? omitStep(element, child) : element;
|
|
105
|
+
});
|
|
106
|
+
out = array;
|
|
107
|
+
keys = Object.getOwnPropertySymbols(value).filter((key) => isEnumerable(value, key));
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
out = Object.getPrototypeOf(value) === null ? Object.create(null) : {};
|
|
111
|
+
keys = enumerableKeys(value);
|
|
112
|
+
}
|
|
113
|
+
const record = value;
|
|
114
|
+
for (const key of keys) {
|
|
115
|
+
const child = trie.kids?.get(key);
|
|
116
|
+
if (child?.leaf)
|
|
117
|
+
continue;
|
|
118
|
+
writeKey(out, key, child?.kids ? omitStep(record[key], child) : record[key]);
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
exitDepth();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function omitStep(value, trie) {
|
|
127
|
+
if (value === null || (typeof value !== 'object' && typeof value !== 'function'))
|
|
128
|
+
return value;
|
|
129
|
+
if (!isOmitContainer(value))
|
|
130
|
+
throw new TypeError('omit cannot copy a non-plain object');
|
|
131
|
+
return omitIn(value, trie);
|
|
132
|
+
}
|
|
133
|
+
export function omit(obj, paths) {
|
|
134
|
+
const list = toPathList(paths);
|
|
135
|
+
if (obj === null || obj === undefined)
|
|
136
|
+
return {};
|
|
137
|
+
if (!isOmitContainer(obj))
|
|
138
|
+
throw new TypeError('omit takes a plain object or array');
|
|
139
|
+
const trie = {};
|
|
140
|
+
for (const parts of list)
|
|
141
|
+
if (parts.length > 0)
|
|
142
|
+
nodeAt(trie, parts).leaf = true;
|
|
143
|
+
return guardDepth(() => omitIn(obj, trie));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* A new plain object with the own enumerable string keys of `obj` for which `predicate` is truthy.
|
|
147
|
+
* @param obj The object to read.
|
|
148
|
+
* @param predicate Called with `(value, key, obj)`.
|
|
149
|
+
* @returns A new object.
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* pickBy({ a: 1, b: '2', c: 3 }, (value) => typeof value === 'number') // { a: 1, c: 3 }
|
|
153
|
+
* ```
|
|
154
|
+
*/
|
|
155
|
+
export function pickBy(obj, predicate) {
|
|
156
|
+
const out = {};
|
|
157
|
+
if (obj === null || obj === undefined)
|
|
158
|
+
return out;
|
|
159
|
+
const record = obj;
|
|
160
|
+
for (const key of Object.keys(record)) {
|
|
161
|
+
const value = record[key];
|
|
162
|
+
if (predicate(value, key, obj))
|
|
163
|
+
writeKey(out, key, value);
|
|
164
|
+
}
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A new plain object with the own enumerable string keys of `obj` for which `predicate` is falsy:
|
|
169
|
+
* the complement of {@link pickBy}.
|
|
170
|
+
* @param obj The object to read.
|
|
171
|
+
* @param predicate Called with `(value, key, obj)`.
|
|
172
|
+
* @returns A new object.
|
|
173
|
+
* @example
|
|
174
|
+
* ```ts
|
|
175
|
+
* omitBy({ a: 1, b: undefined }, (value) => value === undefined) // { a: 1 }
|
|
176
|
+
* ```
|
|
177
|
+
*/
|
|
178
|
+
export function omitBy(obj, predicate) {
|
|
179
|
+
return pickBy(obj, (value, key, all) => !predicate(value, key, all));
|
|
180
|
+
}
|