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,284 @@
1
+ /**
2
+ * Partial deep matching: `isMatch`, `matches`.
3
+ */
4
+ import { isPlainObject } from '../is/isPlainObject.js';
5
+ import { enumerableKeys } from '../internal/keys.js';
6
+ import { walkArray } from '../internal/sparse.js';
7
+ import { enterDepth, exitDepth, guardDepth } from '../internal/walk.js';
8
+ import { isEqual } from './isEqual.js';
9
+ /** Steps one call may take before it throws, so no input can keep it running for long. */
10
+ const MAX_MATCH_STEPS = 2 ** 25;
11
+ /** Message of the `RangeError` a call throws past {@link MAX_MATCH_STEPS}. */
12
+ const STEPS_ERROR = `matching took more than ${String(MAX_MATCH_STEPS)} steps`;
13
+ /** Answers one call remembers; past this it stops remembering, so only time grows, not memory. */
14
+ const MAX_REMEMBERED_PAIRS = 2 ** 20;
15
+ function step(pending, count = 1) {
16
+ pending.steps += count;
17
+ if (pending.steps > MAX_MATCH_STEPS)
18
+ throw new RangeError(STEPS_ERROR);
19
+ }
20
+ function isObject(value) {
21
+ return typeof value === 'object' && value !== null;
22
+ }
23
+ function remember(pending, shape, target, answer) {
24
+ if (pending.remembered >= MAX_REMEMBERED_PAIRS)
25
+ return false;
26
+ let answers = pending.answers.get(shape);
27
+ if (answers === undefined)
28
+ pending.answers.set(shape, (answers = new WeakMap()));
29
+ answers.set(target, answer);
30
+ pending.remembered++;
31
+ return true;
32
+ }
33
+ /** Settle the answer of a pair that opened at `depth` when the tentative list was `mark` long. */
34
+ function settle(pending, shape, target, ok, depth, mark, low) {
35
+ const { tentative } = pending;
36
+ if (!ok || low >= depth) {
37
+ for (let i = mark; i < tentative.length; i++) {
38
+ const entry = tentative[i];
39
+ const answers = pending.answers.get(entry.shape);
40
+ if (ok) {
41
+ answers?.set(entry.target, true);
42
+ }
43
+ else {
44
+ answers?.delete(entry.target);
45
+ pending.remembered--;
46
+ }
47
+ }
48
+ tentative.length = mark;
49
+ remember(pending, shape, target, ok);
50
+ return;
51
+ }
52
+ step(pending, tentative.length - mark);
53
+ for (let i = mark; i < tentative.length; i++)
54
+ tentative[i].low = low;
55
+ pending.low = Math.min(pending.low, low);
56
+ const entry = { shape, target, low };
57
+ if (remember(pending, shape, target, entry))
58
+ pending.tentative.push(entry);
59
+ }
60
+ /** Match a plain-object or array `shape` against an object `target` below the top. */
61
+ function matchPair(target, shape, pending) {
62
+ const known = pending.answers.get(shape)?.get(target);
63
+ if (known !== undefined) {
64
+ if (typeof known === 'boolean')
65
+ return known;
66
+ pending.low = Math.min(pending.low, known.low);
67
+ return true;
68
+ }
69
+ let partners = pending.open.get(shape);
70
+ const openAt = partners?.get(target);
71
+ if (openAt !== undefined) {
72
+ pending.low = Math.min(pending.low, openAt);
73
+ return true;
74
+ }
75
+ if (partners === undefined)
76
+ pending.open.set(shape, (partners = new Map()));
77
+ const depth = ++pending.depth;
78
+ const outerLow = pending.low;
79
+ const mark = pending.tentative.length;
80
+ partners.set(target, depth);
81
+ pending.low = Number.POSITIVE_INFINITY;
82
+ enterDepth();
83
+ let ok;
84
+ try {
85
+ ok = Array.isArray(shape)
86
+ ? matchArray(target, shape, pending)
87
+ : matchObject(target, shape, pending, false);
88
+ }
89
+ finally {
90
+ exitDepth();
91
+ partners.delete(target);
92
+ pending.depth--;
93
+ }
94
+ const low = pending.low;
95
+ pending.low = outerLow;
96
+ settle(pending, shape, target, ok, depth, mark, low);
97
+ return ok;
98
+ }
99
+ /**
100
+ * Whether each shape in `wanted` can have a candidate of its own, by augmenting paths (Kuhn's
101
+ * algorithm), so the answer does not depend on the order of either array.
102
+ */
103
+ function assign(candidates, wanted, pending) {
104
+ const owner = new Array(candidates.length).fill(-1);
105
+ const seenBy = new Array(candidates.length).fill(-1);
106
+ const fits = (shape, candidate) => matchValue(candidates[candidate], wanted[shape], pending, false);
107
+ const unplaced = [];
108
+ // First fit, where every candidate before `firstFree` is taken; augmenting paths repair the rest.
109
+ let firstFree = 0;
110
+ for (let shape = 0; shape < wanted.length; shape++) {
111
+ let placed = false;
112
+ for (let candidate = firstFree; candidate < candidates.length && !placed; candidate++) {
113
+ if (owner[candidate] >= 0)
114
+ step(pending);
115
+ else if (fits(shape, candidate)) {
116
+ owner[candidate] = shape;
117
+ placed = true;
118
+ }
119
+ }
120
+ while (firstFree < candidates.length && owner[firstFree] >= 0)
121
+ firstFree++;
122
+ if (!placed)
123
+ unplaced.push(shape);
124
+ }
125
+ for (const root of unplaced) {
126
+ const path = [{ shape: root, next: 0 }];
127
+ const taken = [];
128
+ let placed = false;
129
+ while (path.length > 0 && !placed) {
130
+ const frame = path[path.length - 1];
131
+ if (frame.next === candidates.length) {
132
+ path.pop();
133
+ taken.pop();
134
+ continue;
135
+ }
136
+ const candidate = frame.next++;
137
+ if (seenBy[candidate] === root) {
138
+ step(pending);
139
+ continue;
140
+ }
141
+ if (!fits(frame.shape, candidate))
142
+ continue;
143
+ seenBy[candidate] = root;
144
+ taken.push(candidate);
145
+ if (owner[candidate] < 0) {
146
+ for (let i = 0; i < path.length; i++)
147
+ owner[taken[i]] = path[i].shape;
148
+ placed = true;
149
+ }
150
+ else {
151
+ path.push({ shape: owner[candidate], next: 0 });
152
+ }
153
+ }
154
+ if (!placed)
155
+ return false;
156
+ }
157
+ return true;
158
+ }
159
+ function matchArray(target, source, pending) {
160
+ const wantedValues = new Map();
161
+ const wantedShapes = [];
162
+ let unmet = 0;
163
+ walkArray(source, (event) => {
164
+ if (event.kind !== 'value')
165
+ return;
166
+ step(pending);
167
+ if (isObject(event.value)) {
168
+ wantedShapes.push(event.value);
169
+ }
170
+ else {
171
+ wantedValues.set(event.value, (wantedValues.get(event.value) ?? 0) + 1);
172
+ unmet++;
173
+ }
174
+ });
175
+ const candidates = [];
176
+ walkArray(target, (event) => {
177
+ if (event.kind !== 'value')
178
+ return;
179
+ step(pending);
180
+ if (isObject(event.value)) {
181
+ if (wantedShapes.length > 0)
182
+ candidates.push(event.value);
183
+ return;
184
+ }
185
+ const count = wantedValues.get(event.value);
186
+ if (count !== undefined && count > 0) {
187
+ wantedValues.set(event.value, count - 1);
188
+ unmet--;
189
+ }
190
+ });
191
+ if (unmet > 0 || wantedShapes.length > candidates.length)
192
+ return false;
193
+ return assign(candidates, wantedShapes, pending);
194
+ }
195
+ function matchObject(target, source, pending, top) {
196
+ const keys = enumerableKeys(source);
197
+ if (target === null || target === undefined)
198
+ return keys.length === 0;
199
+ if (!top && Array.isArray(target))
200
+ return false;
201
+ const base = Object(target);
202
+ for (const key of keys) {
203
+ const wanted = source[key];
204
+ if (wanted === undefined) {
205
+ if (!(key in base) || base[key] !== undefined)
206
+ return false;
207
+ }
208
+ else if (!matchValue(base[key], wanted, pending, false)) {
209
+ return false;
210
+ }
211
+ }
212
+ return true;
213
+ }
214
+ function matchValue(target, source, pending, top) {
215
+ step(pending);
216
+ const isArray = Array.isArray(source);
217
+ if (!isArray && !isPlainObject(source))
218
+ return isEqual(target, source);
219
+ if (isArray && !Array.isArray(target))
220
+ return false;
221
+ if (top) {
222
+ enterDepth();
223
+ try {
224
+ return isArray
225
+ ? matchArray(target, source, pending)
226
+ : matchObject(target, source, pending, true);
227
+ }
228
+ finally {
229
+ exitDepth();
230
+ }
231
+ }
232
+ if (!isObject(target))
233
+ return false;
234
+ return matchPair(target, source, pending);
235
+ }
236
+ /**
237
+ * True when `obj` has every key of `source`, deeply, with an {@link isEqual} value, as lodash's
238
+ * `isMatch` checks. A plain object in `source` matches an object with at least its own enumerable
239
+ * keys, symbols included, and a key whose source value is `undefined` must be present with the
240
+ * value `undefined`. An array in `source` matches an array that holds a match for each of its
241
+ * elements, each element of `obj` serving one, so arrays match as subsets in any order. A hole is
242
+ * not an element: it wants nothing in `source` and offers nothing in `obj`, as an absent key does.
243
+ * Anything else in `source`, a `Date` or `Map` included, must be {@link isEqual} to the value found.
244
+ * At the top, `obj` may be any value: a primitive is read as its boxed form, and `null` or
245
+ * `undefined` matches only a `source` with no keys.
246
+ *
247
+ * Cycles are assumed to match, and each pair of objects is answered once.
248
+ * @param obj The value to test.
249
+ * @param source The partial shape to look for.
250
+ * @returns Whether `obj` matches.
251
+ * @throws {RangeError} past 1000 levels of nesting, or past 33554432 steps of work.
252
+ * @example
253
+ * ```ts
254
+ * isMatch({ a: 1, b: { c: 2, d: 3 } }, { b: { c: 2 } }) // true
255
+ * isMatch({ tags: ['a', 'b', 'c'] }, { tags: ['c', 'a'] }) // true
256
+ * isMatch({ a: 1 }, { a: undefined }) // false
257
+ * isMatch({}, { a: {} }) // false
258
+ * ```
259
+ */
260
+ export function isMatch(obj, source) {
261
+ return guardDepth(() => matchValue(obj, source, {
262
+ open: new Map(),
263
+ answers: new WeakMap(),
264
+ tentative: [],
265
+ remembered: 0,
266
+ depth: 0,
267
+ low: Number.POSITIVE_INFINITY,
268
+ steps: 0
269
+ }, true));
270
+ }
271
+ /**
272
+ * A predicate that tells whether a value matches `source`, by the rules of {@link isMatch}; it is
273
+ * lodash's `matches` shorthand as a function to pass to `filter`, `find` and the like.
274
+ * @param source The partial shape to look for.
275
+ * @returns `(obj) => isMatch(obj, source)`.
276
+ * @example
277
+ * ```ts
278
+ * const users = [{ name: 'a', active: true }, { name: 'b', active: false }]
279
+ * users.filter(matches({ active: true })) // [{ name: 'a', active: true }]
280
+ * ```
281
+ */
282
+ export function matches(source) {
283
+ return (obj) => isMatch(obj, source);
284
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Writing sources into a target: `merge`, `defaults`, `defaultsDeep`.
3
+ */
4
+ /**
5
+ * Merge the own enumerable string and symbol keys of each source into `target`, deeply, and
6
+ * return `target`, as lodash's `merge` does. A plain object merges into a plain object and an array
7
+ * into an array; anything else, or a container of the other kind, is assigned in its place (a
8
+ * plain object or array from a source is copied first, with its prototype, so `target` never
9
+ * shares it). An `undefined` source value does not replace a key the target has. Keys are
10
+ * assigned, so setters run; `__proto__`, `constructor` and `prototype` are defined as own data.
11
+ * Replacing an own `constructor` function with an object is refused.
12
+ * Each key gets its own copy of a source object it shares with another key.
13
+ * @param target The object to change.
14
+ * @param sources Objects to merge in, left to right; sources that are not objects are skipped.
15
+ * @returns `target`.
16
+ * @throws {TypeError} when `target` is not an object, or for a key of it that is read-only or
17
+ * has only a getter.
18
+ * @throws {RangeError} past 1000 levels of nesting, for an array index or `length` that would
19
+ * grow an array past its end, for a huge sparse source array, or when shared objects would be
20
+ * copied past 500000 units of work.
21
+ * @example
22
+ * ```ts
23
+ * merge({ a: [{ b: 2 }], d: 1 }, { a: [{ c: 3 }] }) // { a: [{ b: 2, c: 3 }], d: 1 }
24
+ * ```
25
+ */
26
+ export declare function merge<T extends object>(target: T, ...sources: unknown[]): T;
27
+ /**
28
+ * Fill each key of `target` that reads `undefined` with the first source that has it, and return
29
+ * `target`, as lodash's `defaults` does. A string key only inherited from `Object.prototype`
30
+ * (such as `toString`) also counts as missing; one inherited from a class does not. A key `target`
31
+ * has only a getter for is left alone. Only the own enumerable string and symbol keys of each
32
+ * source are considered.
33
+ * Existing own symbol data properties keep their descriptors when filled.
34
+ * @param target The object to fill.
35
+ * @param sources Objects to read defaults from, left to right; sources that are not objects are
36
+ * skipped.
37
+ * @returns `target`.
38
+ * @throws {TypeError} when `target` is not an object.
39
+ * @throws {RangeError} for an array index past the end of an array `target`.
40
+ * @example
41
+ * ```ts
42
+ * defaults({ a: 1 }, { a: 3, b: 2 }) // { a: 1, b: 2 }
43
+ * ```
44
+ */
45
+ export declare function defaults<T extends object>(target: T, ...sources: unknown[]): T;
46
+ /**
47
+ * {@link defaults}, all the way down: where `target` and a source both hold a plain object (or
48
+ * both an array) at a key, the source fills the missing keys inside it. A filled plain object or
49
+ * array is copied, with its prototype, so `target` never shares it with a source; a cycle back to
50
+ * a source itself points at `target`.
51
+ * Filling `__proto__` is refused unless the target has a null prototype; `constructor` and
52
+ * `prototype` are filled as own data, and inherited values are never descended into.
53
+ * Only own enumerable string and symbol keys of each source are considered.
54
+ * @param target The object to fill.
55
+ * @param sources Objects to read defaults from, left to right; sources that are not objects are
56
+ * skipped.
57
+ * @returns `target`.
58
+ * @throws {TypeError} when `target` is not an object.
59
+ * @throws {RangeError} past 1000 levels of nesting, for an index past the end of an array, for a
60
+ * huge sparse source array, or when shared objects would be copied past 500000 units of work.
61
+ * @example
62
+ * ```ts
63
+ * defaultsDeep({ a: { b: 2 } }, { a: { b: 1, c: 3 } }) // { a: { b: 2, c: 3 } }
64
+ * ```
65
+ */
66
+ export declare function defaultsDeep<T extends object>(target: T, ...sources: unknown[]): T;
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Writing sources into a target: `merge`, `defaults`, `defaultsDeep`.
3
+ */
4
+ import { isPlainObject } from '../is/isPlainObject.js';
5
+ import { enumerableKeys } from '../internal/keys.js';
6
+ import { assertNotHugeSparse, isCanonicalArrayIndex } from '../internal/sparse.js';
7
+ import { enterDepth, exitDepth, guardDepth, RevisitBudget } from '../internal/walk.js';
8
+ import { writeKey } from './parsePath.js';
9
+ const MERGE_BUDGET = 500_000;
10
+ const BUDGET_ERROR = `input repeats shared objects past ${String(MERGE_BUDGET)} units of work`;
11
+ /** An index or `length` write that would grow an array past its end. */
12
+ function assertInRange(t, key, value) {
13
+ if (!Array.isArray(t) || typeof key !== 'string')
14
+ return;
15
+ const grows = key === 'length' && (Object(value) === value || Number(value) > t.length);
16
+ if (grows || (isCanonicalArrayIndex(key) && Number(key) > t.length)) {
17
+ throw new RangeError(`array index ${key} is past the end`);
18
+ }
19
+ }
20
+ function assertTarget(target, name) {
21
+ if (target === null || typeof target !== 'object') {
22
+ throw new TypeError(`${name} target must be an object`);
23
+ }
24
+ }
25
+ /** Record the (source, target) pair, and say whether it was recorded already. */
26
+ function walkedBefore(state, s, t) {
27
+ let targets = state.pairs.get(s);
28
+ if (targets?.has(t))
29
+ return true;
30
+ if (targets === undefined) {
31
+ targets = new WeakSet();
32
+ state.pairs.set(s, targets);
33
+ }
34
+ targets.add(t);
35
+ return false;
36
+ }
37
+ /**
38
+ * Write each key of source `s` into target `t` with `writeEntry`, one level deeper. An `existing`
39
+ * target (one `target` already held, not a fresh copy) is walked once per source object. Charges
40
+ * the revisit budget and grows an array target to an array source's length.
41
+ */
42
+ function walkInto(t, s, state, existing, writeEntry) {
43
+ if (existing && walkedBefore(state, s, t))
44
+ return;
45
+ const keys = enumerableKeys(s);
46
+ state.budget.note(s, keys.length);
47
+ enterDepth();
48
+ try {
49
+ if (Array.isArray(s) && Array.isArray(t)) {
50
+ assertNotHugeSparse(s);
51
+ if (t.length < s.length)
52
+ t.length = s.length;
53
+ }
54
+ for (const key of keys)
55
+ writeEntry(key);
56
+ }
57
+ finally {
58
+ exitDepth();
59
+ }
60
+ }
61
+ /**
62
+ * Copy `source` with `fill`, into an empty array or an object with the prototype of `source`.
63
+ * While `fill` runs, `source` maps to the copy, so a cycle in `source` points back at the copy.
64
+ */
65
+ function copyWith(state, source, fill) {
66
+ const copy = Array.isArray(source)
67
+ ? []
68
+ : Object.create(Object.getPrototypeOf(source));
69
+ state.copies.set(source, copy);
70
+ try {
71
+ fill(copy);
72
+ }
73
+ finally {
74
+ state.copies.delete(source);
75
+ }
76
+ return copy;
77
+ }
78
+ function mergeKey(t, s, key, state) {
79
+ const sv = s[key];
80
+ assertInRange(t, key, sv);
81
+ const tv = Object.hasOwn(t, key) ? t[key] : undefined;
82
+ if (key === 'constructor' && typeof tv === 'function' && sv !== null && typeof sv === 'object') {
83
+ return;
84
+ }
85
+ if (sv === undefined && key in t)
86
+ return;
87
+ const svArray = Array.isArray(sv);
88
+ if (!svArray && !isPlainObject(sv)) {
89
+ writeKey(t, key, sv);
90
+ return;
91
+ }
92
+ const source = sv;
93
+ const same = svArray ? Array.isArray(tv) : isPlainObject(tv);
94
+ if (same) {
95
+ mergeInto(tv, source, state, true);
96
+ return;
97
+ }
98
+ const copy = state.copies.get(source) ??
99
+ copyWith(state, source, (fresh) => mergeInto(fresh, source, state, false));
100
+ writeKey(t, key, copy);
101
+ }
102
+ function mergeInto(t, s, state, existing) {
103
+ walkInto(t, s, state, existing, (key) => mergeKey(t, s, key, state));
104
+ }
105
+ /**
106
+ * Merge the own enumerable string and symbol keys of each source into `target`, deeply, and
107
+ * return `target`, as lodash's `merge` does. A plain object merges into a plain object and an array
108
+ * into an array; anything else, or a container of the other kind, is assigned in its place (a
109
+ * plain object or array from a source is copied first, with its prototype, so `target` never
110
+ * shares it). An `undefined` source value does not replace a key the target has. Keys are
111
+ * assigned, so setters run; `__proto__`, `constructor` and `prototype` are defined as own data.
112
+ * Replacing an own `constructor` function with an object is refused.
113
+ * Each key gets its own copy of a source object it shares with another key.
114
+ * @param target The object to change.
115
+ * @param sources Objects to merge in, left to right; sources that are not objects are skipped.
116
+ * @returns `target`.
117
+ * @throws {TypeError} when `target` is not an object, or for a key of it that is read-only or
118
+ * has only a getter.
119
+ * @throws {RangeError} past 1000 levels of nesting, for an array index or `length` that would
120
+ * grow an array past its end, for a huge sparse source array, or when shared objects would be
121
+ * copied past 500000 units of work.
122
+ * @example
123
+ * ```ts
124
+ * merge({ a: [{ b: 2 }], d: 1 }, { a: [{ c: 3 }] }) // { a: [{ b: 2, c: 3 }], d: 1 }
125
+ * ```
126
+ */
127
+ export function merge(target, ...sources) {
128
+ assertTarget(target, 'merge');
129
+ const budget = new RevisitBudget(MERGE_BUDGET, BUDGET_ERROR);
130
+ return guardDepth(() => {
131
+ for (const source of sources) {
132
+ if (source === null || typeof source !== 'object')
133
+ continue;
134
+ mergeInto(target, source, { copies: new WeakMap(), pairs: new WeakMap(), budget }, true);
135
+ }
136
+ return target;
137
+ });
138
+ }
139
+ function descriptorAlongChain(obj, key) {
140
+ for (let cur = obj; cur; cur = Object.getPrototypeOf(cur)) {
141
+ const desc = Object.getOwnPropertyDescriptor(cur, key);
142
+ if (desc)
143
+ return desc;
144
+ }
145
+ return undefined;
146
+ }
147
+ /**
148
+ * Whether `defaults` fills `key` of `target`: it reads `undefined`, or it is a string key only
149
+ * `Object.prototype` has, and it is not a getter without a setter.
150
+ */
151
+ function needsDefault(target, key, value) {
152
+ const fill = value === undefined ||
153
+ (typeof key !== 'symbol' &&
154
+ !Object.hasOwn(target, key) &&
155
+ value === Object.prototype[key]);
156
+ if (!fill)
157
+ return false;
158
+ if (key === '__proto__')
159
+ return Object.getPrototypeOf(target) === null;
160
+ const desc = descriptorAlongChain(target, key);
161
+ return !(desc && 'get' in desc && desc.set === undefined);
162
+ }
163
+ function writeDefault(target, key, value) {
164
+ const desc = typeof key === 'symbol' ? Object.getOwnPropertyDescriptor(target, key) : undefined;
165
+ if (desc && 'value' in desc) {
166
+ ;
167
+ target[key] = value;
168
+ }
169
+ else {
170
+ writeKey(target, key, value);
171
+ }
172
+ }
173
+ /**
174
+ * Fill each key of `target` that reads `undefined` with the first source that has it, and return
175
+ * `target`, as lodash's `defaults` does. A string key only inherited from `Object.prototype`
176
+ * (such as `toString`) also counts as missing; one inherited from a class does not. A key `target`
177
+ * has only a getter for is left alone. Only the own enumerable string and symbol keys of each
178
+ * source are considered.
179
+ * Existing own symbol data properties keep their descriptors when filled.
180
+ * @param target The object to fill.
181
+ * @param sources Objects to read defaults from, left to right; sources that are not objects are
182
+ * skipped.
183
+ * @returns `target`.
184
+ * @throws {TypeError} when `target` is not an object.
185
+ * @throws {RangeError} for an array index past the end of an array `target`.
186
+ * @example
187
+ * ```ts
188
+ * defaults({ a: 1 }, { a: 3, b: 2 }) // { a: 1, b: 2 }
189
+ * ```
190
+ */
191
+ export function defaults(target, ...sources) {
192
+ assertTarget(target, 'defaults');
193
+ for (const source of sources) {
194
+ if (source === null || typeof source !== 'object')
195
+ continue;
196
+ const record = source;
197
+ for (const key of enumerableKeys(record)) {
198
+ if (!needsDefault(target, key, target[key]))
199
+ continue;
200
+ const value = record[key];
201
+ assertInRange(target, key, value);
202
+ writeDefault(target, key, value);
203
+ }
204
+ }
205
+ return target;
206
+ }
207
+ /** `value`, or a copy of it filled the way `defaultsDeep` fills, when it is a plain object or array. */
208
+ function copyOf(value, state) {
209
+ if (!Array.isArray(value) && !isPlainObject(value))
210
+ return value;
211
+ return (state.copies.get(value) ?? copyWith(state, value, (copy) => fillInto(copy, value, state, false)));
212
+ }
213
+ function fillKey(t, s, key, state) {
214
+ const tv = t[key];
215
+ if (needsDefault(t, key, tv)) {
216
+ const sv = s[key];
217
+ if (sv === undefined)
218
+ return;
219
+ assertInRange(t, key, sv);
220
+ writeDefault(t, key, copyOf(sv, state));
221
+ return;
222
+ }
223
+ if (!Object.hasOwn(t, key))
224
+ return;
225
+ const tvArray = Array.isArray(tv);
226
+ if (!tvArray && !isPlainObject(tv))
227
+ return;
228
+ const sv = s[key];
229
+ const sameKind = tvArray ? Array.isArray(sv) : isPlainObject(sv);
230
+ if (sameKind)
231
+ fillInto(tv, sv, state, true);
232
+ }
233
+ function fillInto(t, s, state, existing) {
234
+ walkInto(t, s, state, existing, (key) => fillKey(t, s, key, state));
235
+ }
236
+ /**
237
+ * {@link defaults}, all the way down: where `target` and a source both hold a plain object (or
238
+ * both an array) at a key, the source fills the missing keys inside it. A filled plain object or
239
+ * array is copied, with its prototype, so `target` never shares it with a source; a cycle back to
240
+ * a source itself points at `target`.
241
+ * Filling `__proto__` is refused unless the target has a null prototype; `constructor` and
242
+ * `prototype` are filled as own data, and inherited values are never descended into.
243
+ * Only own enumerable string and symbol keys of each source are considered.
244
+ * @param target The object to fill.
245
+ * @param sources Objects to read defaults from, left to right; sources that are not objects are
246
+ * skipped.
247
+ * @returns `target`.
248
+ * @throws {TypeError} when `target` is not an object.
249
+ * @throws {RangeError} past 1000 levels of nesting, for an index past the end of an array, for a
250
+ * huge sparse source array, or when shared objects would be copied past 500000 units of work.
251
+ * @example
252
+ * ```ts
253
+ * defaultsDeep({ a: { b: 2 } }, { a: { b: 1, c: 3 } }) // { a: { b: 2, c: 3 } }
254
+ * ```
255
+ */
256
+ export function defaultsDeep(target, ...sources) {
257
+ assertTarget(target, 'defaultsDeep');
258
+ const budget = new RevisitBudget(MERGE_BUDGET, BUDGET_ERROR);
259
+ return guardDepth(() => {
260
+ for (const source of sources) {
261
+ if (source === null || typeof source !== 'object')
262
+ continue;
263
+ const state = {
264
+ copies: new WeakMap([[source, target]]),
265
+ pairs: new WeakMap(),
266
+ budget
267
+ };
268
+ fillInto(target, source, state, true);
269
+ }
270
+ return target;
271
+ });
272
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The path grammar behind `get`, `set`, `has`, `unset`, `pick` and `omit`.
3
+ */
4
+ /** A dotted string with `[0]` and `['key']` segments, or an array of keys. */
5
+ export type Path = string | readonly PropertyKey[];
6
+ /** Segments that lead to a prototype unless they are own data. */
7
+ export declare const DANGEROUS_KEYS: ReadonlySet<PropertyKey>;
8
+ /**
9
+ * Write `value` under `key`: a plain assignment for an ordinary string key, so a setter on `target`
10
+ * runs, and an own data property for a symbol or one of {@link DANGEROUS_KEYS}, so `__proto__`
11
+ * stays a key and no write reaches a prototype.
12
+ */
13
+ export declare function writeKey(target: object, key: PropertyKey, value: unknown): void;
14
+ /**
15
+ * The segments of `path`. A string splits on `.`, on `[0]` index segments and on `['key']` or
16
+ * `["key"]` segments (with `\\` escaping a quote); an array is taken as its keys, a number segment
17
+ * as its string.
18
+ * @throws {TypeError} for a malformed string path or a segment that is not a string, number or
19
+ * symbol.
20
+ * @throws {RangeError} for a string path over 2^20 characters or a huge sparse array.
21
+ */
22
+ export declare function parsePath(path: Path): PropertyKey[];