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.
Files changed (216) hide show
  1. package/README.md +397 -91
  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 -256
  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 -623
  27. package/dist/collections/index.js +14 -844
  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 -148
  55. package/dist/decimal/index.js +10 -410
  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 -53
  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 -224
  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 +99 -51
  171. package/dist/collections/BTree.d.ts +0 -230
  172. package/dist/collections/BTree.js +0 -1143
  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 -83
  176. package/dist/collections/LRUCache.js +0 -139
  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 -142
  183. package/dist/collections/SplayTree.d.ts +0 -107
  184. package/dist/collections/SplayTree.js +0 -351
  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 -33
  191. package/dist/functools/index.d.ts +0 -106
  192. package/dist/functools/index.js +0 -203
  193. package/dist/globals/index.d.ts +0 -268
  194. package/dist/globals/index.js +0 -447
  195. package/dist/i18n/currency.d.ts +0 -27
  196. package/dist/i18n/currency.js +0 -100
  197. package/dist/i18n/date/index.d.ts +0 -210
  198. package/dist/i18n/date/index.js +0 -552
  199. package/dist/i18n/date/utils.d.ts +0 -64
  200. package/dist/i18n/date/utils.js +0 -192
  201. package/dist/i18n/duration.d.ts +0 -113
  202. package/dist/i18n/duration.js +0 -398
  203. package/dist/i18n/format.d.ts +0 -34
  204. package/dist/i18n/format.js +0 -378
  205. package/dist/i18n/index.d.ts +0 -9
  206. package/dist/i18n/index.js +0 -8
  207. package/dist/itertools/index.d.ts +0 -251
  208. package/dist/itertools/index.js +0 -434
  209. package/dist/math/index.d.ts +0 -79
  210. package/dist/math/index.js +0 -81
  211. package/dist/mod.d.ts +0 -1
  212. package/dist/mod.js +0 -1
  213. package/dist/operators/index.d.ts +0 -148
  214. package/dist/operators/index.js +0 -325
  215. package/dist/types.d.ts +0 -19
  216. package/dist/types.js +0 -1
@@ -0,0 +1,200 @@
1
+ /**
2
+ * `cloneDeep`: a structural copy that keeps prototypes, symbol keys, sharing and cycles.
3
+ */
4
+ import { isEnumerable } from '../internal/keys.js';
5
+ import { bytesOf, kindOf, typedArrayLength, typedArrayName, unbox } from '../internal/kind.js';
6
+ import { isCanonicalArrayIndex, walkArray } from '../internal/sparse.js';
7
+ import { enterDepth, exitDepth, guardDepth } from '../internal/walk.js';
8
+ const dateTime = Date.prototype.getTime;
9
+ const mapEntries = Map.prototype.entries;
10
+ const mapSet = Map.prototype.set;
11
+ const setValues = Set.prototype.values;
12
+ const setAdd = Set.prototype.add;
13
+ /** This realm's typed array constructors by `[[TypedArrayName]]`. */
14
+ const VIEW_CONSTRUCTORS = new Map([
15
+ 'Int8Array',
16
+ 'Uint8Array',
17
+ 'Uint8ClampedArray',
18
+ 'Int16Array',
19
+ 'Uint16Array',
20
+ 'Int32Array',
21
+ 'Uint32Array',
22
+ 'Float16Array',
23
+ 'Float32Array',
24
+ 'Float64Array',
25
+ 'BigInt64Array',
26
+ 'BigUint64Array'
27
+ ].flatMap((name) => {
28
+ const ctor = globalThis[name];
29
+ return typeof ctor === 'function' ? [[name, ctor]] : [];
30
+ }));
31
+ function defineValue(out, key, value) {
32
+ Object.defineProperty(out, key, { value, enumerable: true, writable: true, configurable: true });
33
+ }
34
+ /**
35
+ * Copy the own enumerable symbol keys of `src` onto `out`, and the string keys `strings` names,
36
+ * cloning each value.
37
+ */
38
+ function copyKeys(src, out, copies, strings) {
39
+ const record = src;
40
+ if (strings !== 'none') {
41
+ for (const key of Object.keys(src)) {
42
+ if (strings === 'non-index' && isCanonicalArrayIndex(key))
43
+ continue;
44
+ defineValue(out, key, cloneValue(record[key], copies));
45
+ }
46
+ }
47
+ for (const sym of Object.getOwnPropertySymbols(src)) {
48
+ if (!isEnumerable(src, sym))
49
+ continue;
50
+ defineValue(out, sym, cloneValue(record[sym], copies));
51
+ }
52
+ }
53
+ function withPrototype(out, src) {
54
+ const proto = Object.getPrototypeOf(src);
55
+ if (Object.getPrototypeOf(out) !== proto)
56
+ Object.setPrototypeOf(out, proto);
57
+ return out;
58
+ }
59
+ /** Record `out` as the copy of `src`, then copy the keys of `src` onto it. */
60
+ function finish(src, out, copies, strings) {
61
+ copies.set(src, out);
62
+ copyKeys(src, out, copies, strings);
63
+ return out;
64
+ }
65
+ function cloneBuffer(src, copies) {
66
+ const known = copies.get(src);
67
+ if (known !== undefined)
68
+ return known;
69
+ const bytes = bytesOf(src);
70
+ let out;
71
+ if (Object.prototype.toString.call(src) === '[object SharedArrayBuffer]') {
72
+ const shared = src;
73
+ out = new SharedArrayBuffer(bytes.length, shared.growable ? { maxByteLength: shared.maxByteLength } : undefined);
74
+ }
75
+ else {
76
+ const buffer = src;
77
+ out = new ArrayBuffer(bytes.length, buffer.resizable ? { maxByteLength: buffer.maxByteLength } : undefined);
78
+ }
79
+ new Uint8Array(out).set(bytes);
80
+ return finish(src, withPrototype(out, src), copies, 'all');
81
+ }
82
+ function cloneView(src, copies) {
83
+ const name = typedArrayName(src);
84
+ const isDataView = name === undefined;
85
+ const buffer = cloneBuffer(src.buffer, copies);
86
+ // The buffer's own keys can lead back to this view, which is then copied already.
87
+ const known = copies.get(src);
88
+ if (known !== undefined)
89
+ return known;
90
+ let offset = 0;
91
+ let length = 0;
92
+ try {
93
+ offset = src.byteOffset;
94
+ length = isDataView ? src.byteLength : (typedArrayLength(src) ?? 0);
95
+ }
96
+ catch {
97
+ // Detached or out-of-bounds DataViews have no readable offset or length.
98
+ }
99
+ const ctor = isDataView ? DataView : VIEW_CONSTRUCTORS.get(name);
100
+ if (ctor === undefined)
101
+ throw new TypeError(`cannot copy a ${name ?? 'view'}`);
102
+ return finish(src, withPrototype(new ctor(buffer, offset, length), src), copies, 'none');
103
+ }
104
+ function cloneObject(src, copies) {
105
+ switch (kindOf(src)) {
106
+ case 'plain':
107
+ return finish(src, Object.create(Object.getPrototypeOf(src)), copies, 'all');
108
+ case 'array': {
109
+ const list = src;
110
+ const out = withPrototype([], src);
111
+ copies.set(src, out);
112
+ out.length = list.length;
113
+ walkArray(list, (event) => {
114
+ if (event.kind === 'value')
115
+ out[event.index] = cloneValue(event.value, copies);
116
+ });
117
+ copyKeys(src, out, copies, 'non-index');
118
+ return out;
119
+ }
120
+ case 'map': {
121
+ const out = withPrototype(new Map(), src);
122
+ copies.set(src, out);
123
+ for (const [key, value] of mapEntries.call(src)) {
124
+ mapSet.call(out, key, cloneValue(value, copies));
125
+ }
126
+ copyKeys(src, out, copies, 'all');
127
+ return out;
128
+ }
129
+ case 'set': {
130
+ const out = withPrototype(new Set(), src);
131
+ copies.set(src, out);
132
+ for (const value of setValues.call(src)) {
133
+ setAdd.call(out, cloneValue(value, copies));
134
+ }
135
+ copyKeys(src, out, copies, 'all');
136
+ return out;
137
+ }
138
+ case 'date':
139
+ return finish(src, withPrototype(new Date(dateTime.call(src)), src), copies, 'all');
140
+ case 'regexp': {
141
+ const re = src;
142
+ const out = withPrototype(new RegExp(re.source, re.flags), src);
143
+ out.lastIndex = src.lastIndex;
144
+ return finish(src, out, copies, 'all');
145
+ }
146
+ case 'buffer':
147
+ return cloneBuffer(src, copies);
148
+ case 'view':
149
+ return cloneView(src, copies);
150
+ case 'boxed': {
151
+ const primitive = unbox(src);
152
+ const out = withPrototype(Object(primitive), src);
153
+ // A String wrapper lists one index key per character; only its symbol keys are copied.
154
+ return finish(src, out, copies, typeof primitive === 'string' ? 'none' : 'all');
155
+ }
156
+ default:
157
+ return src;
158
+ }
159
+ }
160
+ function cloneValue(value, copies) {
161
+ if (value === null || typeof value !== 'object')
162
+ return value;
163
+ const known = copies.get(value);
164
+ if (known !== undefined)
165
+ return known;
166
+ enterDepth();
167
+ try {
168
+ return cloneObject(value, copies);
169
+ }
170
+ finally {
171
+ exitDepth();
172
+ }
173
+ }
174
+ /**
175
+ * A deep copy of `value`. Plain objects, arrays, `Map`, `Set`, `Date`, `RegExp`, typed arrays,
176
+ * `DataView`, `ArrayBuffer`, `SharedArrayBuffer` and boxed primitives are copied with their
177
+ * prototype (a subclass stays a subclass) and their own enumerable symbol keys; all but typed
178
+ * arrays, `DataView` and `String` wrappers also keep their own enumerable string keys, and arrays
179
+ * keep their holes. `Map` keys keep their identity while values are copied. A subclass copy gets
180
+ * the prototype only: its constructor does not run, so it has none of its private fields. A
181
+ * resizable or growable buffer stays so, and a detached one copies as an empty buffer. Class
182
+ * instances, functions, errors, promises and every other object are kept by reference:
183
+ * `structuredClone` throws on them, and copying their fields would produce an object whose private
184
+ * state and invariants are gone. An object reached twice is copied once, so shared references and
185
+ * cycles stay shared and cyclic in the copy, and views over one buffer share one copied buffer.
186
+ * @param value The value to copy.
187
+ * @returns The copy.
188
+ * @throws {RangeError} past 1000 levels of nesting.
189
+ * @throws {TypeError} for a typed array kind this runtime has no constructor for.
190
+ * @example
191
+ * ```ts
192
+ * const src = { when: new Date(0), tags: new Set(['a']), list: [{ id: 1 }] }
193
+ * const copy = cloneDeep(src)
194
+ * copy.list[0] === src.list[0] // false
195
+ * copy.when.getTime() // 0
196
+ * ```
197
+ */
198
+ export function cloneDeep(value) {
199
+ return guardDepth(() => cloneValue(value, new Map()));
200
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Objects by path, structure and shape: `get`, `set`, `has`, `unset`, deep equality, and the
3
+ * object helpers that copy, merge and match.
4
+ * @module object
5
+ */
6
+ export { cloneDeep } from './cloneDeep.js';
7
+ export { type EqualityCustomizer, isEqual, isEqualWith } from './isEqual.js';
8
+ export { isMatch, matches } from './matches.js';
9
+ export { defaults, defaultsDeep, merge } from './merge.js';
10
+ export type { Path } from './parsePath.js';
11
+ export { get, has, set, unset } from './path.js';
12
+ export { omit, omitBy, type Paths, type PickedBy, pick, pickBy, type PlainKey } from './pick.js';
13
+ export { type FlattenOptions, flattenObject, invert, mapKeys, mapValues } from './reshape.js';
14
+ export { isPlainObject } from '../is/isPlainObject.js';
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Objects by path, structure and shape: `get`, `set`, `has`, `unset`, deep equality, and the
3
+ * object helpers that copy, merge and match.
4
+ * @module object
5
+ */
6
+ export { cloneDeep } from './cloneDeep.js';
7
+ export { isEqual, isEqualWith } from './isEqual.js';
8
+ export { isMatch, matches } from './matches.js';
9
+ export { defaults, defaultsDeep, merge } from './merge.js';
10
+ export { get, has, set, unset } from './path.js';
11
+ export { omit, omitBy, pick, pickBy } from './pick.js';
12
+ export { flattenObject, invert, mapKeys, mapValues } from './reshape.js';
13
+ export { isPlainObject } from '../is/isPlainObject.js';
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Decides one pair for {@link isEqualWith}: `true` or `false` to answer, `undefined` to let
3
+ * `isEqualWith` compare the pair itself. `key` is the key, index or Map key the pair was found
4
+ * under, and `undefined` for the two values passed in.
5
+ */
6
+ export type EqualityCustomizer = (a: unknown, b: unknown, key: unknown) => boolean | undefined;
7
+ /**
8
+ * Deep structural equality, lodash's `isEqual` with the platform's rules. Primitives compare by
9
+ * SameValueZero, so `NaN` equals `NaN`, `0` equals `-0`, and `1` does not equal `1n`. Plain objects
10
+ * compare by own enumerable keys (symbols included), arrays by index (a hole equals `undefined`;
11
+ * other keys are ignored), `Map` by key membership and then value, `Set` by membership, Dates by
12
+ * time, RegExps by source, flags and `lastIndex` (SameValueZero), typed arrays, `DataView` and
13
+ * `ArrayBuffer` by content, boxed primitives by their primitive, `arguments` like an array, and
14
+ * errors by name, message, own `cause` and `errors` and own enumerable properties (not `stack`,
15
+ * nor JavaScriptCore's `line`, `column` and `sourceURL`), as Node's `isDeepStrictEqual` does.
16
+ * Both sides must be of one class,
17
+ * or its twin from another realm. Any other object (a class instance, a function, a promise) equals
18
+ * only itself; use {@link isEqualWith} to compare such types.
19
+ *
20
+ * Cycles and shared objects are compared once each. Nesting past 1000 levels, or more than 2^24
21
+ * objects in one comparison, throws `RangeError`.
22
+ * @param a Any value.
23
+ * @param b Any value.
24
+ * @returns Whether `a` and `b` are structurally equal.
25
+ * @example
26
+ * ```ts
27
+ * class Point {
28
+ * constructor(public x: number, public y: number) {}
29
+ * }
30
+ * isEqual({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] }) // true
31
+ * isEqual(new Map([[1, NaN]]), new Map([[1, NaN]])) // true
32
+ * isEqual(new Set([{}]), new Set([{}])) // false: members are matched by SameValueZero
33
+ * isEqual(new Point(1, 2), new Point(1, 2)) // false: class instances compare by identity
34
+ * ```
35
+ */
36
+ export declare function isEqual(a: unknown, b: unknown): boolean;
37
+ /**
38
+ * {@link isEqual} with a `customizer` that may decide any pair first. It sees the two values passed
39
+ * in, then every nested pair with the key it was found under; returning `true` or `false` answers
40
+ * that pair, and `undefined` leaves it to `isEqual`'s rules. This is how to compare class instances
41
+ * by their fields, or values of a type like `Decimal` by its own `equals`. Set members and Map keys
42
+ * still match by SameValueZero and never reach the customizer; to compare those by content, decide
43
+ * the Set or Map pair itself.
44
+ *
45
+ * The customizer need not be transitive (a tolerance such as `Math.abs(a - b) <= 1` works), so each
46
+ * pair of objects is remembered as walked rather than joined into a class: a shared pair is walked
47
+ * once, and two cycles of different lengths are walked until they line up, which counts toward the
48
+ * nesting limit. Nesting past 1000 levels, or more than 2^24 pairs in one comparison, throws
49
+ * `RangeError`.
50
+ * @param a Any value.
51
+ * @param b Any value.
52
+ * @param customizer Decides a pair, or returns `undefined` to fall through.
53
+ * @returns Whether `a` and `b` are equal under `customizer`.
54
+ * @example
55
+ * ```ts
56
+ * class Point {
57
+ * constructor(public x: number, public y: number) {}
58
+ * }
59
+ * const byFields = (a: unknown, b: unknown) =>
60
+ * a instanceof Point && b instanceof Point ? a.x === b.x && a.y === b.y : undefined
61
+ * isEqualWith([new Point(1, 2)], [new Point(1, 2)], byFields) // true
62
+ * ```
63
+ */
64
+ export declare function isEqualWith(a: unknown, b: unknown, customizer: EqualityCustomizer): boolean;
@@ -0,0 +1,289 @@
1
+ import { sameValueZero } from '../internal/compare.js';
2
+ import { ERROR_LOCATION_KEYS, enumerableKeys, isEnumerable } from '../internal/keys.js';
3
+ import { bytesOf, contentKindOf, isFloatView, sameClass, unbox } from '../internal/kind.js';
4
+ import { walkArrayIndices } from '../internal/sparse.js';
5
+ import { enterDepth, exitDepth, guardDepth } from '../internal/walk.js';
6
+ /** Past this many tracked objects, or pairs with a customizer, a comparison throws `RangeError`. */
7
+ const MAX_TRACKED = 2 ** 24;
8
+ const getTime = Date.prototype.getTime;
9
+ /**
10
+ * Equal pairs as a union-find over the objects met. `isEqual`'s own rules are an equivalence, so a
11
+ * pair in one class is equal without a walk, and each object is walked once.
12
+ */
13
+ class EqualClasses {
14
+ #ids = new Map();
15
+ #parent = [];
16
+ assumed(a, b) {
17
+ const [rx, ry] = [this.#root(this.#id(a)), this.#root(this.#id(b))];
18
+ if (rx === ry)
19
+ return true;
20
+ this.#parent[rx] = ry;
21
+ return false;
22
+ }
23
+ #id(value) {
24
+ let id = this.#ids.get(value);
25
+ if (id === undefined) {
26
+ if (this.#ids.size >= MAX_TRACKED) {
27
+ throw new RangeError(`comparing more than ${String(MAX_TRACKED)} objects`);
28
+ }
29
+ id = this.#parent.length;
30
+ this.#ids.set(value, id);
31
+ this.#parent.push(id);
32
+ }
33
+ return id;
34
+ }
35
+ #root(id) {
36
+ let root = id;
37
+ while (this.#parent[root] !== root)
38
+ root = this.#parent[root];
39
+ while (this.#parent[id] !== root)
40
+ [this.#parent[id], id] = [root, this.#parent[id]];
41
+ return root;
42
+ }
43
+ }
44
+ /**
45
+ * Equal pairs exactly as walked. A customizer need not be transitive (`a` near `b` and `b` near `c`
46
+ * says nothing of `a` and `c`), so only a pair already walked is equal without a walk.
47
+ */
48
+ class EqualPairs {
49
+ #partners = new Map();
50
+ #size = 0;
51
+ assumed(a, b) {
52
+ const partners = this.#partners.get(a);
53
+ if (partners?.has(b))
54
+ return true;
55
+ if (this.#size >= MAX_TRACKED) {
56
+ throw new RangeError(`comparing more than ${String(MAX_TRACKED)} pairs`);
57
+ }
58
+ this.#size++;
59
+ if (partners === undefined)
60
+ this.#partners.set(a, new Set([b]));
61
+ else
62
+ partners.add(b);
63
+ return false;
64
+ }
65
+ }
66
+ /** One comparison: its customizer, if any, and the pairs it has taken to be equal. */
67
+ class Session {
68
+ customizer;
69
+ #assumptions;
70
+ constructor(customizer) {
71
+ this.customizer = customizer;
72
+ this.#assumptions = customizer === undefined ? new EqualClasses() : new EqualPairs();
73
+ }
74
+ /** Whether `a` and `b` were already taken to be equal; if not, takes them to be from now on. */
75
+ assumed(a, b) {
76
+ return this.#assumptions.assumed(a, b);
77
+ }
78
+ }
79
+ function bytesEqual(a, b) {
80
+ if (a.length !== b.length)
81
+ return false;
82
+ for (let i = 0; i < a.length; i++)
83
+ if (a[i] !== b[i])
84
+ return false;
85
+ return true;
86
+ }
87
+ function viewsEqual(a, b) {
88
+ if (!isFloatView(a))
89
+ return bytesEqual(bytesOf(a), bytesOf(b));
90
+ const other = b;
91
+ const length = a.length;
92
+ if (length !== other.length)
93
+ return false;
94
+ for (let i = 0; i < length; i++)
95
+ if (!sameValueZero(a[i], other[i]))
96
+ return false;
97
+ return true;
98
+ }
99
+ function recordsEqual(a, b, session, ignored) {
100
+ const keysOf = (value) => {
101
+ const keys = enumerableKeys(value);
102
+ return ignored === undefined ? keys : keys.filter((key) => !ignored.has(key));
103
+ };
104
+ const keys = keysOf(a);
105
+ if (keys.length !== keysOf(b).length)
106
+ return false;
107
+ const [x, y] = [a, b];
108
+ return keys.every((key) => isEnumerable(b, key) && equalValues(x[key], y[key], key, session));
109
+ }
110
+ /** Own elements from `from` on, so holes cost nothing and read as `undefined`. */
111
+ function sparseArraysEqual(a, b, from, session) {
112
+ const ownEqual = (array, skip) => {
113
+ let equal = true;
114
+ walkArrayIndices(array, (ev) => {
115
+ if (ev.kind !== 'index' ||
116
+ ev.index < from ||
117
+ (skip !== undefined && isEnumerable(skip, ev.index)))
118
+ return;
119
+ equal = equalValues(isEnumerable(a, ev.index) ? a[ev.index] : undefined, isEnumerable(b, ev.index) ? b[ev.index] : undefined, ev.index, session);
120
+ return equal ? undefined : false;
121
+ });
122
+ return equal;
123
+ };
124
+ return ownEqual(a) && ownEqual(b, a);
125
+ }
126
+ function arraysEqual(a, b, session) {
127
+ if (a.length !== b.length)
128
+ return false;
129
+ let i = 0;
130
+ for (; i < a.length && i in a && i in b; i++) {
131
+ if (!equalValues(a[i], b[i], i, session))
132
+ return false;
133
+ }
134
+ return i === a.length || sparseArraysEqual(a, b, i, session);
135
+ }
136
+ function mapsEqual(a, b, session) {
137
+ if (a.size !== b.size)
138
+ return false;
139
+ for (const [key, value] of Map.prototype.entries.call(a)) {
140
+ if (!Map.prototype.has.call(b, key))
141
+ return false;
142
+ if (!equalValues(value, Map.prototype.get.call(b, key), key, session))
143
+ return false;
144
+ }
145
+ return true;
146
+ }
147
+ function setsEqual(a, b) {
148
+ if (a.size !== b.size)
149
+ return false;
150
+ for (const value of Set.prototype.values.call(a)) {
151
+ if (!Set.prototype.has.call(b, value))
152
+ return false;
153
+ }
154
+ return true;
155
+ }
156
+ /**
157
+ * Name, message, an own `cause` and `errors`, and own enumerable properties but the location keys
158
+ * an engine adds, as `isDeepStrictEqual` reads them.
159
+ */
160
+ function errorsEqual(a, b, session) {
161
+ if (!equalValues(a.name, b.name, 'name', session))
162
+ return false;
163
+ if (!equalValues(a.message, b.message, 'message', session))
164
+ return false;
165
+ const [x, y] = [a, b];
166
+ for (const key of ['cause', 'errors']) {
167
+ const has = Object.hasOwn(a, key);
168
+ if (has !== Object.hasOwn(b, key))
169
+ return false;
170
+ if (has && !equalValues(x[key], y[key], key, session))
171
+ return false;
172
+ }
173
+ return recordsEqual(a, b, session, ERROR_LOCATION_KEYS);
174
+ }
175
+ function regExpsEqual(a, b) {
176
+ return a.source === b.source && a.flags === b.flags && sameValueZero(a.lastIndex, b.lastIndex);
177
+ }
178
+ function contentEqual(a, b, kind, session) {
179
+ switch (kind) {
180
+ case 'boxed':
181
+ return sameValueZero(unbox(a), unbox(b));
182
+ case 'date':
183
+ return sameValueZero(getTime.call(a), getTime.call(b));
184
+ case 'regexp':
185
+ return regExpsEqual(a, b);
186
+ case 'buffer':
187
+ return bytesEqual(bytesOf(a), bytesOf(b));
188
+ case 'view':
189
+ return viewsEqual(a, b);
190
+ case 'array':
191
+ case 'arguments':
192
+ return arraysEqual(a, b, session);
193
+ case 'error':
194
+ return errorsEqual(a, b, session);
195
+ case 'map':
196
+ return mapsEqual(a, b, session);
197
+ case 'set':
198
+ return setsEqual(a, b);
199
+ default:
200
+ return recordsEqual(a, b, session);
201
+ }
202
+ }
203
+ function equalValues(a, b, key, session) {
204
+ if (session.customizer !== undefined) {
205
+ const answer = session.customizer(a, b, key);
206
+ if (answer !== undefined)
207
+ return Boolean(answer);
208
+ }
209
+ if (sameValueZero(a, b))
210
+ return true;
211
+ if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
212
+ return false;
213
+ const kind = contentKindOf(a);
214
+ if (kind === 'other' || kind !== contentKindOf(b) || !sameClass(a, b))
215
+ return false;
216
+ if (session.assumed(a, b))
217
+ return true;
218
+ enterDepth();
219
+ try {
220
+ return contentEqual(a, b, kind, session);
221
+ }
222
+ finally {
223
+ exitDepth();
224
+ }
225
+ }
226
+ /**
227
+ * Deep structural equality, lodash's `isEqual` with the platform's rules. Primitives compare by
228
+ * SameValueZero, so `NaN` equals `NaN`, `0` equals `-0`, and `1` does not equal `1n`. Plain objects
229
+ * compare by own enumerable keys (symbols included), arrays by index (a hole equals `undefined`;
230
+ * other keys are ignored), `Map` by key membership and then value, `Set` by membership, Dates by
231
+ * time, RegExps by source, flags and `lastIndex` (SameValueZero), typed arrays, `DataView` and
232
+ * `ArrayBuffer` by content, boxed primitives by their primitive, `arguments` like an array, and
233
+ * errors by name, message, own `cause` and `errors` and own enumerable properties (not `stack`,
234
+ * nor JavaScriptCore's `line`, `column` and `sourceURL`), as Node's `isDeepStrictEqual` does.
235
+ * Both sides must be of one class,
236
+ * or its twin from another realm. Any other object (a class instance, a function, a promise) equals
237
+ * only itself; use {@link isEqualWith} to compare such types.
238
+ *
239
+ * Cycles and shared objects are compared once each. Nesting past 1000 levels, or more than 2^24
240
+ * objects in one comparison, throws `RangeError`.
241
+ * @param a Any value.
242
+ * @param b Any value.
243
+ * @returns Whether `a` and `b` are structurally equal.
244
+ * @example
245
+ * ```ts
246
+ * class Point {
247
+ * constructor(public x: number, public y: number) {}
248
+ * }
249
+ * isEqual({ a: [1, { b: 2 }] }, { a: [1, { b: 2 }] }) // true
250
+ * isEqual(new Map([[1, NaN]]), new Map([[1, NaN]])) // true
251
+ * isEqual(new Set([{}]), new Set([{}])) // false: members are matched by SameValueZero
252
+ * isEqual(new Point(1, 2), new Point(1, 2)) // false: class instances compare by identity
253
+ * ```
254
+ */
255
+ export function isEqual(a, b) {
256
+ return guardDepth(() => equalValues(a, b, undefined, new Session()));
257
+ }
258
+ /**
259
+ * {@link isEqual} with a `customizer` that may decide any pair first. It sees the two values passed
260
+ * in, then every nested pair with the key it was found under; returning `true` or `false` answers
261
+ * that pair, and `undefined` leaves it to `isEqual`'s rules. This is how to compare class instances
262
+ * by their fields, or values of a type like `Decimal` by its own `equals`. Set members and Map keys
263
+ * still match by SameValueZero and never reach the customizer; to compare those by content, decide
264
+ * the Set or Map pair itself.
265
+ *
266
+ * The customizer need not be transitive (a tolerance such as `Math.abs(a - b) <= 1` works), so each
267
+ * pair of objects is remembered as walked rather than joined into a class: a shared pair is walked
268
+ * once, and two cycles of different lengths are walked until they line up, which counts toward the
269
+ * nesting limit. Nesting past 1000 levels, or more than 2^24 pairs in one comparison, throws
270
+ * `RangeError`.
271
+ * @param a Any value.
272
+ * @param b Any value.
273
+ * @param customizer Decides a pair, or returns `undefined` to fall through.
274
+ * @returns Whether `a` and `b` are equal under `customizer`.
275
+ * @example
276
+ * ```ts
277
+ * class Point {
278
+ * constructor(public x: number, public y: number) {}
279
+ * }
280
+ * const byFields = (a: unknown, b: unknown) =>
281
+ * a instanceof Point && b instanceof Point ? a.x === b.x && a.y === b.y : undefined
282
+ * isEqualWith([new Point(1, 2)], [new Point(1, 2)], byFields) // true
283
+ * ```
284
+ */
285
+ export function isEqualWith(a, b, customizer) {
286
+ if (typeof customizer !== 'function')
287
+ throw new TypeError('customizer must be a function');
288
+ return guardDepth(() => equalValues(a, b, undefined, new Session(customizer)));
289
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Partial deep matching: `isMatch`, `matches`.
3
+ */
4
+ /**
5
+ * True when `obj` has every key of `source`, deeply, with an {@link isEqual} value, as lodash's
6
+ * `isMatch` checks. A plain object in `source` matches an object with at least its own enumerable
7
+ * keys, symbols included, and a key whose source value is `undefined` must be present with the
8
+ * value `undefined`. An array in `source` matches an array that holds a match for each of its
9
+ * elements, each element of `obj` serving one, so arrays match as subsets in any order. A hole is
10
+ * not an element: it wants nothing in `source` and offers nothing in `obj`, as an absent key does.
11
+ * Anything else in `source`, a `Date` or `Map` included, must be {@link isEqual} to the value found.
12
+ * At the top, `obj` may be any value: a primitive is read as its boxed form, and `null` or
13
+ * `undefined` matches only a `source` with no keys.
14
+ *
15
+ * Cycles are assumed to match, and each pair of objects is answered once.
16
+ * @param obj The value to test.
17
+ * @param source The partial shape to look for.
18
+ * @returns Whether `obj` matches.
19
+ * @throws {RangeError} past 1000 levels of nesting, or past 33554432 steps of work.
20
+ * @example
21
+ * ```ts
22
+ * isMatch({ a: 1, b: { c: 2, d: 3 } }, { b: { c: 2 } }) // true
23
+ * isMatch({ tags: ['a', 'b', 'c'] }, { tags: ['c', 'a'] }) // true
24
+ * isMatch({ a: 1 }, { a: undefined }) // false
25
+ * isMatch({}, { a: {} }) // false
26
+ * ```
27
+ */
28
+ export declare function isMatch(obj: unknown, source: unknown): boolean;
29
+ /**
30
+ * A predicate that tells whether a value matches `source`, by the rules of {@link isMatch}; it is
31
+ * lodash's `matches` shorthand as a function to pass to `filter`, `find` and the like.
32
+ * @param source The partial shape to look for.
33
+ * @returns `(obj) => isMatch(obj, source)`.
34
+ * @example
35
+ * ```ts
36
+ * const users = [{ name: 'a', active: true }, { name: 'b', active: false }]
37
+ * users.filter(matches({ active: true })) // [{ name: 'a', active: true }]
38
+ * ```
39
+ */
40
+ export declare function matches(source: unknown): (obj: unknown) => boolean;