atomic-fns 1.1.7 → 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.
Files changed (216) hide show
  1. package/README.md +405 -60
  2. package/dist/array/index.d.ts +9 -0
  3. package/dist/array/index.js +9 -0
  4. package/dist/array/list.d.ts +99 -0
  5. package/dist/array/list.js +133 -0
  6. package/dist/array/sets.d.ts +130 -0
  7. package/dist/array/sets.js +213 -0
  8. package/dist/async/index.d.ts +6 -0
  9. package/dist/async/index.js +6 -0
  10. package/dist/async/retry.d.ts +38 -0
  11. package/dist/async/retry.js +56 -0
  12. package/dist/async/sleep.d.ts +42 -0
  13. package/dist/async/sleep.js +76 -0
  14. package/dist/collections/bisect.d.ts +103 -0
  15. package/dist/collections/bisect.js +157 -0
  16. package/dist/collections/deque.d.ts +67 -97
  17. package/dist/collections/deque.js +197 -249
  18. package/dist/collections/entries.d.ts +89 -0
  19. package/dist/collections/entries.js +131 -0
  20. package/dist/collections/frozen-set.d.ts +42 -0
  21. package/dist/collections/frozen-set.js +64 -0
  22. package/dist/collections/group.d.ts +141 -0
  23. package/dist/collections/group.js +241 -0
  24. package/dist/collections/heap.d.ts +64 -0
  25. package/dist/collections/heap.js +205 -0
  26. package/dist/collections/index.d.ts +15 -642
  27. package/dist/collections/index.js +14 -716
  28. package/dist/collections/internal/arrayKeys.d.ts +19 -0
  29. package/dist/collections/internal/arrayKeys.js +83 -0
  30. package/dist/collections/internal/invariants.d.ts +4 -0
  31. package/dist/collections/internal/invariants.js +12 -0
  32. package/dist/collections/internal/iterable.d.ts +25 -0
  33. package/dist/collections/internal/iterable.js +62 -0
  34. package/dist/collections/iterate.d.ts +162 -0
  35. package/dist/collections/iterate.js +188 -0
  36. package/dist/collections/lru-cache.d.ts +58 -0
  37. package/dist/collections/lru-cache.js +164 -0
  38. package/dist/collections/order.d.ts +19 -0
  39. package/dist/collections/order.js +38 -0
  40. package/dist/collections/shape.d.ts +32 -0
  41. package/dist/collections/shape.js +86 -0
  42. package/dist/collections/sorted-map.d.ts +171 -0
  43. package/dist/collections/sorted-map.js +845 -0
  44. package/dist/collections/sorted-set.d.ts +103 -0
  45. package/dist/collections/sorted-set.js +147 -0
  46. package/dist/collections/splay-tree.d.ts +82 -0
  47. package/dist/collections/splay-tree.js +354 -0
  48. package/dist/collections/trie.d.ts +58 -0
  49. package/dist/collections/trie.js +196 -0
  50. package/dist/decimal/currency.d.ts +211 -0
  51. package/dist/decimal/currency.js +321 -0
  52. package/dist/decimal/decimal.d.ts +299 -0
  53. package/dist/decimal/decimal.js +660 -0
  54. package/dist/decimal/index.d.ts +11 -145
  55. package/dist/decimal/index.js +10 -374
  56. package/dist/decimal/internal/bits.d.ts +2 -0
  57. package/dist/decimal/internal/bits.js +7 -0
  58. package/dist/decimal/internal/echo.d.ts +4 -0
  59. package/dist/decimal/internal/echo.js +6 -0
  60. package/dist/decimal/internal/isqrt.d.ts +9 -0
  61. package/dist/decimal/internal/isqrt.js +34 -0
  62. package/dist/decimal/internal/locale.d.ts +7 -0
  63. package/dist/decimal/internal/locale.js +24 -0
  64. package/dist/decimal/internal/minor-units.d.ts +2 -0
  65. package/dist/decimal/internal/minor-units.js +33 -0
  66. package/dist/decimal/internal/pow10.d.ts +24 -0
  67. package/dist/decimal/internal/pow10.js +96 -0
  68. package/dist/encoding/base64.d.ts +39 -0
  69. package/dist/encoding/base64.js +53 -0
  70. package/dist/encoding/hex.d.ts +23 -0
  71. package/dist/encoding/hex.js +34 -0
  72. package/dist/encoding/index.d.ts +6 -0
  73. package/dist/encoding/index.js +6 -0
  74. package/dist/function/debounce.d.ts +68 -0
  75. package/dist/function/debounce.js +203 -0
  76. package/dist/function/index.d.ts +6 -0
  77. package/dist/function/index.js +6 -0
  78. package/dist/function/shared.d.ts +2 -0
  79. package/dist/function/shared.js +5 -0
  80. package/dist/function/wrap.d.ts +130 -0
  81. package/dist/function/wrap.js +113 -0
  82. package/dist/hash/digest.d.ts +18 -0
  83. package/dist/hash/digest.js +26 -0
  84. package/dist/hash/hash.d.ts +22 -0
  85. package/dist/hash/hash.js +252 -0
  86. package/dist/hash/hashString.d.ts +13 -0
  87. package/dist/hash/hashString.js +53 -0
  88. package/dist/hash/index.d.ts +8 -0
  89. package/dist/hash/index.js +8 -0
  90. package/dist/hash/stableStringify.d.ts +19 -0
  91. package/dist/hash/stableStringify.js +102 -0
  92. package/dist/id/index.d.ts +7 -0
  93. package/dist/id/index.js +7 -0
  94. package/dist/id/nanoid.d.ts +16 -0
  95. package/dist/id/nanoid.js +65 -0
  96. package/dist/id/uniqueId.d.ts +14 -0
  97. package/dist/id/uniqueId.js +20 -0
  98. package/dist/id/uuid.d.ts +25 -0
  99. package/dist/id/uuid.js +64 -0
  100. package/dist/index.d.ts +15 -8
  101. package/dist/index.js +15 -8
  102. package/dist/internal/bytes.d.ts +11 -0
  103. package/dist/internal/bytes.js +33 -0
  104. package/dist/internal/codec.d.ts +11 -0
  105. package/dist/internal/codec.js +84 -0
  106. package/dist/internal/compare.d.ts +10 -0
  107. package/dist/internal/compare.js +26 -0
  108. package/dist/internal/crypto.d.ts +5 -0
  109. package/dist/internal/crypto.js +11 -0
  110. package/dist/internal/keys.d.ts +12 -0
  111. package/dist/internal/keys.js +23 -0
  112. package/dist/internal/kind.d.ts +44 -0
  113. package/dist/internal/kind.js +139 -0
  114. package/dist/internal/sparse.d.ts +51 -0
  115. package/dist/internal/sparse.js +104 -0
  116. package/dist/internal/text.d.ts +7 -0
  117. package/dist/internal/text.js +15 -0
  118. package/dist/internal/timer.d.ts +10 -0
  119. package/dist/internal/timer.js +17 -0
  120. package/dist/internal/truncate.d.ts +10 -0
  121. package/dist/internal/truncate.js +22 -0
  122. package/dist/internal/walk.d.ts +47 -0
  123. package/dist/internal/walk.js +100 -0
  124. package/dist/is/index.d.ts +8 -0
  125. package/dist/is/index.js +8 -0
  126. package/dist/is/isArrayLike.d.ts +18 -0
  127. package/dist/is/isArrayLike.js +25 -0
  128. package/dist/is/isError.d.ts +13 -0
  129. package/dist/is/isError.js +18 -0
  130. package/dist/is/isNil.d.ts +12 -0
  131. package/dist/is/isNil.js +14 -0
  132. package/dist/is/isPlainObject.d.ts +15 -0
  133. package/dist/is/isPlainObject.js +34 -0
  134. package/dist/number/index.d.ts +7 -0
  135. package/dist/number/index.js +7 -0
  136. package/dist/number/round.d.ts +86 -0
  137. package/dist/number/round.js +130 -0
  138. package/dist/number/stats.d.ts +52 -0
  139. package/dist/number/stats.js +115 -0
  140. package/dist/object/cloneDeep.d.ts +28 -0
  141. package/dist/object/cloneDeep.js +200 -0
  142. package/dist/object/index.d.ts +14 -0
  143. package/dist/object/index.js +13 -0
  144. package/dist/object/isEqual.d.ts +64 -0
  145. package/dist/object/isEqual.js +289 -0
  146. package/dist/object/matches.d.ts +40 -0
  147. package/dist/object/matches.js +284 -0
  148. package/dist/object/merge.d.ts +66 -0
  149. package/dist/object/merge.js +272 -0
  150. package/dist/object/parsePath.d.ts +22 -0
  151. package/dist/object/parsePath.js +111 -0
  152. package/dist/object/path.d.ts +85 -0
  153. package/dist/object/path.js +208 -0
  154. package/dist/object/pick.d.ts +91 -0
  155. package/dist/object/pick.js +180 -0
  156. package/dist/object/reshape.d.ts +73 -0
  157. package/dist/object/reshape.js +144 -0
  158. package/dist/random/index.d.ts +96 -32
  159. package/dist/random/index.js +215 -50
  160. package/dist/string/case.d.ts +71 -0
  161. package/dist/string/case.js +152 -0
  162. package/dist/string/fold.d.ts +35 -0
  163. package/dist/string/fold.js +100 -0
  164. package/dist/string/index.d.ts +6 -187
  165. package/dist/string/index.js +6 -226
  166. package/dist/string/truncate.d.ts +25 -0
  167. package/dist/string/truncate.js +44 -0
  168. package/dist/string/words.d.ts +27 -0
  169. package/dist/string/words.js +241 -0
  170. package/package.json +101 -58
  171. package/dist/collections/BTree.d.ts +0 -229
  172. package/dist/collections/BTree.js +0 -1165
  173. package/dist/collections/Heap.d.ts +0 -69
  174. package/dist/collections/Heap.js +0 -181
  175. package/dist/collections/LRUCache.d.ts +0 -80
  176. package/dist/collections/LRUCache.js +0 -126
  177. package/dist/collections/SortedMap.d.ts +0 -92
  178. package/dist/collections/SortedMap.js +0 -131
  179. package/dist/collections/SortedSet.d.ts +0 -69
  180. package/dist/collections/SortedSet.js +0 -99
  181. package/dist/collections/SortedTree.d.ts +0 -103
  182. package/dist/collections/SortedTree.js +0 -141
  183. package/dist/collections/SplayTree.d.ts +0 -105
  184. package/dist/collections/SplayTree.js +0 -338
  185. package/dist/collections/Trie.d.ts +0 -42
  186. package/dist/collections/Trie.js +0 -104
  187. package/dist/collections/abc.d.ts +0 -152
  188. package/dist/collections/abc.js +0 -39
  189. package/dist/collections/frozenset.d.ts +0 -19
  190. package/dist/collections/frozenset.js +0 -30
  191. package/dist/functools/index.d.ts +0 -130
  192. package/dist/functools/index.js +0 -235
  193. package/dist/globals/index.d.ts +0 -285
  194. package/dist/globals/index.js +0 -463
  195. package/dist/i18n/currency.d.ts +0 -24
  196. package/dist/i18n/currency.js +0 -85
  197. package/dist/i18n/date/index.d.ts +0 -203
  198. package/dist/i18n/date/index.js +0 -531
  199. package/dist/i18n/date/utils.d.ts +0 -65
  200. package/dist/i18n/date/utils.js +0 -290
  201. package/dist/i18n/duration.d.ts +0 -112
  202. package/dist/i18n/duration.js +0 -392
  203. package/dist/i18n/format.d.ts +0 -31
  204. package/dist/i18n/format.js +0 -506
  205. package/dist/i18n/index.d.ts +0 -8
  206. package/dist/i18n/index.js +0 -8
  207. package/dist/itertools/index.d.ts +0 -255
  208. package/dist/itertools/index.js +0 -437
  209. package/dist/math/index.d.ts +0 -96
  210. package/dist/math/index.js +0 -98
  211. package/dist/mod.d.ts +0 -1
  212. package/dist/mod.js +0 -1
  213. package/dist/operators/index.d.ts +0 -152
  214. package/dist/operators/index.js +0 -305
  215. package/dist/types.d.ts +0 -19
  216. 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
+ }