atomic-fns 1.1.7 → 1.2.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 (46) hide show
  1. package/README.md +51 -12
  2. package/dist/collections/BTree.d.ts +11 -10
  3. package/dist/collections/BTree.js +58 -80
  4. package/dist/collections/Heap.js +1 -1
  5. package/dist/collections/LRUCache.d.ts +6 -3
  6. package/dist/collections/LRUCache.js +24 -11
  7. package/dist/collections/SortedMap.js +2 -2
  8. package/dist/collections/SortedTree.d.ts +2 -2
  9. package/dist/collections/SortedTree.js +3 -2
  10. package/dist/collections/SplayTree.d.ts +7 -5
  11. package/dist/collections/SplayTree.js +39 -26
  12. package/dist/collections/Trie.d.ts +1 -1
  13. package/dist/collections/Trie.js +26 -26
  14. package/dist/collections/deque.d.ts +1 -1
  15. package/dist/collections/deque.js +17 -10
  16. package/dist/collections/frozenset.js +4 -1
  17. package/dist/collections/index.d.ts +13 -32
  18. package/dist/collections/index.js +210 -82
  19. package/dist/decimal/index.d.ts +5 -2
  20. package/dist/decimal/index.js +63 -27
  21. package/dist/functools/index.d.ts +6 -30
  22. package/dist/functools/index.js +24 -56
  23. package/dist/globals/index.d.ts +3 -20
  24. package/dist/globals/index.js +23 -39
  25. package/dist/i18n/currency.d.ts +3 -0
  26. package/dist/i18n/currency.js +22 -7
  27. package/dist/i18n/date/index.d.ts +17 -10
  28. package/dist/i18n/date/index.js +79 -58
  29. package/dist/i18n/date/utils.d.ts +4 -5
  30. package/dist/i18n/date/utils.js +15 -113
  31. package/dist/i18n/duration.d.ts +11 -10
  32. package/dist/i18n/duration.js +38 -32
  33. package/dist/i18n/format.d.ts +5 -2
  34. package/dist/i18n/format.js +81 -209
  35. package/dist/i18n/index.d.ts +2 -1
  36. package/dist/itertools/index.d.ts +9 -13
  37. package/dist/itertools/index.js +38 -41
  38. package/dist/math/index.d.ts +10 -27
  39. package/dist/math/index.js +16 -33
  40. package/dist/operators/index.d.ts +1 -5
  41. package/dist/operators/index.js +60 -40
  42. package/dist/random/index.js +9 -6
  43. package/dist/string/index.d.ts +1 -1
  44. package/dist/string/index.js +2 -4
  45. package/dist/types.d.ts +3 -3
  46. package/package.json +16 -21
@@ -5,4 +5,5 @@
5
5
  */
6
6
  export * from './currency.js';
7
7
  export * from './date/index.js';
8
- export { Duration, TDuration, DurationUnit } from './duration.js';
8
+ export { Duration } from './duration.js';
9
+ export type { DurationUnit, TDuration } from './duration.js';
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * @module itertools
5
5
  */
6
- import { add, Comparer } from '../operators/index.js';
7
- import { Function, Iteratee, Predicate } from '../types';
6
+ import { add, type Comparer } from '../operators/index.js';
7
+ import type { Function, Iteratee, Predicate } from '../types.js';
8
8
  /**
9
9
  * Make an iterator that returns accumulated sums, or accumulated results of other binary functions (specified via the optional `func` argument).
10
10
  * @param iterable The iterable to accumulate
@@ -21,7 +21,7 @@ export declare function accumulate<T>(iterable: Iterable<T>, func?: typeof add,
21
21
  * @example
22
22
  ```js
23
23
  all([0])
24
- // true
24
+ // false
25
25
 
26
26
  all([1, 2, 3])
27
27
  // true
@@ -62,9 +62,6 @@ export declare function chain<T>(...iterables: Array<Iterable<T>>): Generator<T,
62
62
  contains([1, 2, 3], 1)
63
63
  // true
64
64
 
65
- contains([1, 2, 3], 1, 2)
66
- // false
67
-
68
65
  contains({ 'a': 1, 'b': 2 }, 1)
69
66
  // true
70
67
 
@@ -83,7 +80,6 @@ export declare function contains(collection: Iterable<any>, value: any): boolean
83
80
  */
84
81
  export declare function dropWhile<T>(iterable: Iterable<T>, predicate: Predicate<T>): Generator<T, T, unknown>;
85
82
  export declare function iforEach<T>(iterable: Iterable<T>, fun: Iteratee<T>): void;
86
- export declare function IterableIterator<T = any>(next: Iterator<T>['next']): Iterable<T> & Iterator<T>;
87
83
  /**
88
84
  * Yields elements like `[index, item]` from an iterable. Index starts at zero by default.
89
85
  * @template T
@@ -109,11 +105,11 @@ export declare function enumerate<T>(iterable: Iterable<T>, start?: number): Gen
109
105
  export declare function first<T>(iterable: Iterable<T>): T;
110
106
  /**
111
107
  * Creates a new generator that filters all falsy and empty values from iterable.
112
- * @param arr The array to compact
113
- * @returns A new array with the filtered values.
108
+ * @param iterable The iterable to compact
109
+ * @returns A generator with the filtered values.
114
110
  * @example
115
111
  ```js
116
- compact([0, 1, false, 2, '', 3])
112
+ [...icompact([0, 1, false, 2, '', 3])]
117
113
  // [1, 2, 3]
118
114
  ```
119
115
  */
@@ -134,7 +130,7 @@ export declare function imap<T, TReturn = any>(iterable: Iterable<T>, mapFn: Pre
134
130
  */
135
131
  export declare function iflatten<T = any>(iterables: Iterable<Iterable<T>>): Generator<T, void, unknown>;
136
132
  export declare function flatMap<T>(iterable: Iterable<T>, mapFn?: (x: T) => any): Generator<T, void, unknown>;
137
- export declare function islice<T>(iterable: Iterable<T>, start: number, stop?: number, step?: number): Generator<T, T, unknown>;
133
+ export declare function islice<T>(iterable: Iterable<T>, start: number, stop?: number, step?: number): Generator<T, void, unknown>;
138
134
  export declare function itake<T>(n: number, iterable: Iterable<T>): Generator<T, void, unknown>;
139
135
  /**
140
136
  * Returns an Iterator from the elements of a collection or the object keys.
@@ -146,7 +142,7 @@ export declare function partition<T>(iterable: Iterable<T>, predicate: Predicate
146
142
  /**
147
143
  * Returns a generator for a sequence of numbers in the given range, starting from `start` (default 0) to `stop` (not-inclusive) in increments of `step` (default 1).
148
144
  *
149
- * `range(x)` is a shorthand for `range(0, x, 1)`.
145
+ * `range(x)` is a shorthand for `range(0, x, 1)`, or `range(0, x, -1)` when `x` is negative.
150
146
  * @param args When called with a single argument, it is assigned to `stop` param. If two arguments are given, it will assign them to `(start, stop)`. When three arguments, it means `(start, stop, step)`.
151
147
  * @example
152
148
  ```js
@@ -163,7 +159,7 @@ range(5, 0, -1)
163
159
  // [5, 4, 3, 2, 1]
164
160
 
165
161
  range(-3)
166
- // []
162
+ // [0, -1, -2]
167
163
  ```
168
164
  */
169
165
  export declare function range(...args: number[]): Generator<number, void, unknown>;
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * @module itertools
5
5
  */
6
- import { call, isEmpty, isObject, notNull, ValueError } from '../globals/index.js';
7
- import { add, bool, compare, eq, id } from '../operators/index.js';
6
+ import { call, isDate, isEmpty, isIterable, isObject, isRegExp, notNull, ValueError } from '../globals/index.js';
7
+ import { add, bool, compare, eq, identity } from '../operators/index.js';
8
8
  /**
9
9
  * Make an iterator that returns accumulated sums, or accumulated results of other binary functions (specified via the optional `func` argument).
10
10
  * @param iterable The iterable to accumulate
@@ -15,12 +15,15 @@ import { add, bool, compare, eq, id } from '../operators/index.js';
15
15
  export function* accumulate(iterable, func = add, initial) {
16
16
  const it = iter(iterable);
17
17
  let total = initial;
18
- let current = it.next();
19
- if (initial == null)
20
- total = current.value;
21
- while (!current.done) {
18
+ if (initial == null) {
19
+ const head = it.next();
20
+ if (head.done)
21
+ return;
22
+ total = head.value;
23
+ }
24
+ while (true) {
22
25
  yield total;
23
- current = it.next();
26
+ const current = it.next();
24
27
  if (current.done)
25
28
  return;
26
29
  total = func(total, current.value);
@@ -34,7 +37,7 @@ export function* accumulate(iterable, func = add, initial) {
34
37
  * @example
35
38
  ```js
36
39
  all([0])
37
- // true
40
+ // false
38
41
 
39
42
  all([1, 2, 3])
40
43
  // true
@@ -89,9 +92,6 @@ export function chain(...iterables) {
89
92
  contains([1, 2, 3], 1)
90
93
  // true
91
94
 
92
- contains([1, 2, 3], 1, 2)
93
- // false
94
-
95
95
  contains({ 'a': 1, 'b': 2 }, 1)
96
96
  // true
97
97
 
@@ -107,7 +107,8 @@ export function contains(collection, value) {
107
107
  const includes = call(collection, 'includes', value);
108
108
  if (includes != null)
109
109
  return includes;
110
- return any(collection, (x) => eq(value, x));
110
+ const items = isIterable(collection) ? collection : Object.values(collection);
111
+ return any(items, (x) => eq(value, x));
111
112
  }
112
113
  /**
113
114
  * Returns a generator that drops elements from the iterable as long as the predicate is `true`; afterwards, returns every remaining element. Note, the generator does not produce any output until the predicate first becomes `false`.
@@ -119,9 +120,9 @@ export function* dropWhile(iterable, predicate) {
119
120
  const it = iter(iterable);
120
121
  while (true) {
121
122
  const head = it.next();
123
+ if (head.done)
124
+ return head.value;
122
125
  if (!predicate(head.value)) {
123
- if (head.done)
124
- return head.value;
125
126
  yield head.value;
126
127
  break;
127
128
  }
@@ -140,14 +141,6 @@ export function iforEach(iterable, fun) {
140
141
  }
141
142
  }
142
143
  }
143
- export function IterableIterator(next) {
144
- return {
145
- next,
146
- [Symbol.iterator]() {
147
- return this;
148
- }
149
- };
150
- }
151
144
  /**
152
145
  * Yields elements like `[index, item]` from an iterable. Index starts at zero by default.
153
146
  * @template T
@@ -180,18 +173,20 @@ export function first(iterable) {
180
173
  }
181
174
  /**
182
175
  * Creates a new generator that filters all falsy and empty values from iterable.
183
- * @param arr The array to compact
184
- * @returns A new array with the filtered values.
176
+ * @param iterable The iterable to compact
177
+ * @returns A generator with the filtered values.
185
178
  * @example
186
179
  ```js
187
- compact([0, 1, false, 2, '', 3])
180
+ [...icompact([0, 1, false, 2, '', 3])]
188
181
  // [1, 2, 3]
189
182
  ```
190
183
  */
191
184
  export function* icompact(iterable) {
192
185
  for (const value of iterable) {
193
- if (!isEmpty(value))
186
+ // `isEmpty` reads arity and keys, which say nothing about these values
187
+ if (!isEmpty(value) || typeof value === 'function' || isDate(value) || isRegExp(value)) {
194
188
  yield value;
189
+ }
195
190
  }
196
191
  }
197
192
  /**
@@ -224,8 +219,12 @@ export function* iflatten(iterables) {
224
219
  }
225
220
  }
226
221
  }
227
- export function flatMap(iterable, mapFn = id) {
228
- return iflatten(imap(iterable, mapFn));
222
+ export function flatMap(iterable, mapFn = identity) {
223
+ const toIterable = (x) => {
224
+ const mapped = mapFn(x);
225
+ return isIterable(mapped) ? mapped : [mapped];
226
+ };
227
+ return iflatten(imap(iterable, toIterable));
229
228
  }
230
229
  export function* islice(iterable, start, stop, step = 1) {
231
230
  if (stop != null && stop < 0)
@@ -237,9 +236,9 @@ export function* islice(iterable, start, stop, step = 1) {
237
236
  if (step < 0)
238
237
  throw new ValueError(`step parameter can't be negative`);
239
238
  for (const [i, value] of enumerate(iterable)) {
239
+ if (stop != null && i >= stop)
240
+ return;
240
241
  if (i === start) {
241
- if (stop && start + step > stop)
242
- return value;
243
242
  yield value;
244
243
  start += step;
245
244
  }
@@ -280,7 +279,7 @@ export function partition(iterable, predicate) {
280
279
  /**
281
280
  * Returns a generator for a sequence of numbers in the given range, starting from `start` (default 0) to `stop` (not-inclusive) in increments of `step` (default 1).
282
281
  *
283
- * `range(x)` is a shorthand for `range(0, x, 1)`.
282
+ * `range(x)` is a shorthand for `range(0, x, 1)`, or `range(0, x, -1)` when `x` is negative.
284
283
  * @param args When called with a single argument, it is assigned to `stop` param. If two arguments are given, it will assign them to `(start, stop)`. When three arguments, it means `(start, stop, step)`.
285
284
  * @example
286
285
  ```js
@@ -297,7 +296,7 @@ range(5, 0, -1)
297
296
  // [5, 4, 3, 2, 1]
298
297
 
299
298
  range(-3)
300
- // []
299
+ // [0, -1, -2]
301
300
  ```
302
301
  */
303
302
  export function* range(...args) {
@@ -338,7 +337,7 @@ reduce([1, 2, 3, 4, 5], (x, y) => x + y, 0)
338
337
  export function reduce(iterable, reducer, initial) {
339
338
  const it = iter(iterable);
340
339
  let output = initial ?? it.next().value;
341
- for (const [index, value] of enumerate(it)) {
340
+ for (const [index, value] of enumerate({ [Symbol.iterator]: () => it })) {
342
341
  output = reducer(output, value, index);
343
342
  }
344
343
  return output;
@@ -357,17 +356,13 @@ export function sorted(args, key, reverse, compareFn) {
357
356
  args = Object.keys(args);
358
357
  }
359
358
  if (typeof key === 'boolean') {
360
- if (typeof reverse === 'function') {
359
+ if (typeof reverse === 'function')
361
360
  compareFn = reverse;
362
- reverse = false;
363
- }
364
- else {
365
- reverse = true;
366
- }
367
- key = id;
361
+ reverse = key || reverse === true;
362
+ key = identity;
368
363
  }
369
364
  const copy = Array.from(args);
370
- const _compare = compKey(compareFn || compare, key || id);
365
+ const _compare = compKey(compareFn || compare, key || identity);
371
366
  copy.sort(_compare);
372
367
  if (reverse)
373
368
  copy.reverse();
@@ -423,6 +418,8 @@ for item of zip([1, 2, 3], ['sugar', 'spice', 'nice'])
423
418
  ```
424
419
  */
425
420
  export function* zip(...args) {
421
+ if (args.length === 0)
422
+ return;
426
423
  const iterables = args.map(iter);
427
424
  while (true) {
428
425
  const items = [];
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @module math
5
5
  */
6
- import { Predicate } from '../types.js';
6
+ import type { Predicate } from '../types.js';
7
7
  /**
8
8
  * Returns the absolute value of a number. The argument may be a number or an object implementing the `abs()`.
9
9
  * @param x The value.
@@ -21,35 +21,18 @@ export declare function abs(x: any): number;
21
21
  */
22
22
  export declare function round(x: number, digits?: number): number;
23
23
  /**
24
- * Rounds down and returns the largest integer less than or equal to a given number.
25
- * @param x A number.
26
- * @returns Nearest integer less than or equal to number.
27
- *
28
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor Math.floor()}
29
- */
30
- export declare function floor(x: number): number;
31
- /**
32
- * Rounds up and returns the largest integer greater than or equal to a given number.
33
- * @param x A number.
34
- * @returns Nearest integer greater than or equal to number.
35
- *
36
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil Math.ceil()}
37
- */
38
- export declare function ceil(x: number): number;
39
- /**
40
- * Returns a tuple like `[x / y, x % y]`.
24
+ * Returns a tuple like `[q, r]` with the floored quotient of `x / y` and a remainder that takes the sign of `y`, so `q * y + r` gives `x`, as in Python.
41
25
  *
42
26
  * @param x
43
27
  * @param y
44
28
  * @returns
45
29
  */
46
30
  export declare function divmod(x: number, y: number): [number, number];
47
- export declare function log2(x: number): number;
48
31
  export declare function logBase(x: number, y: number): number;
49
32
  /**
50
33
  * Returns the smallest element in an iterable. The optional `key` argument specifies a transform on the elements before comparing them. If the elements in the iterable are objects that implement a custom `lt` method, this will be called to compare.
51
34
  * @param iterable The iterable to inspect.
52
- * @param key Optional key function to transform the elements (default `id`).
35
+ * @param key Optional key function to transform the elements (default `identity`).
53
36
  * @returns The smallest element in the iterable.
54
37
  */
55
38
  export declare function min(iterable: number[]): number;
@@ -57,7 +40,7 @@ export declare function min<T>(iterable: Iterable<T>, key?: Predicate<T>): T;
57
40
  /**
58
41
  * Returns the largest element in an iterable. The optional `key` argument specifies a transform on the elements before comparing them. If the elements in the iterable are objects that implement a custom `gt` method, this will be called to compare.
59
42
  * @param iterable The iterable to inspect.
60
- * @param key Optional key function to transform the elements (default `id`).
43
+ * @param key Optional key function to transform the elements (default `identity`).
61
44
  * @returns The largest element in the iterable.
62
45
  */
63
46
  export declare function max(iterable: number[]): number;
@@ -79,17 +62,17 @@ mean(objects, o => o.n)
79
62
  export declare function mean(iterable: number[]): number;
80
63
  export declare function mean<T>(iterable: Iterable<T>, key?: Predicate<T>): number;
81
64
  /**
82
- * Sums `initial` and the items of an iterable and returns the total.
83
- * @param args The elements to add to `initial`.
84
- * @param initial The initial value to add to (default `0`).
85
- * @returns The total sum of initial and iterable elements.
65
+ * Sums the items of an iterable and returns the total. The optional `key` argument specifies a transform on the elements before adding them.
66
+ * @param args The elements to add.
67
+ * @param key Optional key function to transform the elements (default `identity`).
68
+ * @returns The total sum of the iterable elements.
86
69
  * @example
87
70
  ```js
88
71
  sum([1, 2, 3, 4])
89
72
  // 10
90
73
 
91
- sum([1, 2, 3, 4], 5)
92
- // 15
74
+ sum([{ n: 1 }, { n: 2 }], o => o.n)
75
+ // 3
93
76
  ```
94
77
  */
95
78
  export declare function sum(args: number[]): number;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { call } from '../globals/index.js';
7
7
  import { reduce } from '../itertools/index.js';
8
- import { gt, id, lt } from '../operators/index.js';
8
+ import { gt, identity, lt } from '../operators/index.js';
9
9
  /**
10
10
  * Returns the absolute value of a number. The argument may be a number or an object implementing the `abs()`.
11
11
  * @param x The value.
@@ -28,43 +28,26 @@ export function abs(x) {
28
28
  */
29
29
  export function round(x, digits = 0) {
30
30
  const base = 10 ** digits;
31
- return Math.round(x * base) / base;
31
+ const scaled = x * base;
32
+ // A number too large to scale has no digits left to round.
33
+ return Number.isFinite(scaled) ? Math.round(scaled) / base : Number(x);
32
34
  }
33
35
  /**
34
- * Rounds down and returns the largest integer less than or equal to a given number.
35
- * @param x A number.
36
- * @returns Nearest integer less than or equal to number.
37
- *
38
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor Math.floor()}
39
- */
40
- export function floor(x) {
41
- return Math.floor(x);
42
- }
43
- /**
44
- * Rounds up and returns the largest integer greater than or equal to a given number.
45
- * @param x A number.
46
- * @returns Nearest integer greater than or equal to number.
47
- *
48
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil Math.ceil()}
49
- */
50
- export function ceil(x) {
51
- return Math.ceil(x);
52
- }
53
- /**
54
- * Returns a tuple like `[x / y, x % y]`.
36
+ * Returns a tuple like `[q, r]` with the floored quotient of `x / y` and a remainder that takes the sign of `y`, so `q * y + r` gives `x`, as in Python.
55
37
  *
56
38
  * @param x
57
39
  * @param y
58
40
  * @returns
59
41
  */
60
42
  export function divmod(x, y) {
61
- return [Math.floor(x / y), x % y];
62
- }
63
- export function log2(x) {
64
- if (x > 0) {
65
- return Math.log(x) * 1.442695;
43
+ let remainder = x % y;
44
+ let quotient = (x - remainder) / y;
45
+ if (remainder !== 0 && remainder < 0 !== y < 0) {
46
+ remainder += y;
47
+ quotient -= 1;
66
48
  }
67
- return Number.NaN;
49
+ // A zero or NaN quotient keeps the sign of zero and the infinities of `x / y`.
50
+ return [Math.round(quotient) || Math.floor(x / y), remainder];
68
51
  }
69
52
  export function logBase(x, y) {
70
53
  if (x > 0 && y > 0) {
@@ -72,13 +55,13 @@ export function logBase(x, y) {
72
55
  }
73
56
  return Number.NaN;
74
57
  }
75
- export function min(iterable, key = id) {
58
+ export function min(iterable, key = identity) {
76
59
  return reduce(iterable, (x, y) => (lt(key(x), key(y)) ? x : y));
77
60
  }
78
- export function max(iterable, key = id) {
61
+ export function max(iterable, key = identity) {
79
62
  return reduce(iterable, (x, y) => (gt(key(x), key(y)) ? x : y));
80
63
  }
81
- export function mean(iterable, key = id) {
64
+ export function mean(iterable, key = identity) {
82
65
  let total = 0;
83
66
  let count = 0;
84
67
  for (const value of iterable) {
@@ -89,7 +72,7 @@ export function mean(iterable, key = id) {
89
72
  return total / count;
90
73
  return Number.NaN;
91
74
  }
92
- export function sum(args, key = id) {
75
+ export function sum(args, key = identity) {
93
76
  let initial = 0;
94
77
  for (const x of args) {
95
78
  initial += key(x);
@@ -3,10 +3,6 @@
3
3
  *
4
4
  * @module operators
5
5
  */
6
- /** @deprecated Use the `identity` function instead.
7
- * @see {@link identity}
8
- */
9
- export declare function id(x: any): any;
10
6
  /** This is the identity function. It always returns the same value that was passed in. */
11
7
  export declare const identity: <T>(x: T) => T;
12
8
  /**
@@ -31,7 +27,7 @@ export declare function isinstance(x: any, y: any): boolean;
31
27
  *
32
28
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#parameters Array.sort()}
33
29
  */
34
- export declare type Comparer<T = any> = (x: T, y: T) => number;
30
+ export type Comparer<T = any> = (x: T, y: T) => number;
35
31
  /**
36
32
  * Checks whether `x` is a comparable type and returns the result of `x.compare(y)`.
37
33
  * Otherwise the return value of the compare function is equivalent to `obj === other ? 0 : obj < other ? -1 : 1`
@@ -4,12 +4,6 @@
4
4
  * @module operators
5
5
  */
6
6
  import { call, isObject } from '../globals/index.js';
7
- /** @deprecated Use the `identity` function instead.
8
- * @see {@link identity}
9
- */
10
- export function id(x) {
11
- return x;
12
- }
13
7
  /** This is the identity function. It always returns the same value that was passed in. */
14
8
  export const identity = (x) => x;
15
9
  /**
@@ -55,7 +49,9 @@ export function compare(x, y) {
55
49
  const op = call(x, 'compare', y);
56
50
  if (typeof op === 'number')
57
51
  return op;
58
- if (x < y || lt(x, y))
52
+ if (x instanceof Date && y instanceof Date)
53
+ return Math.sign(x.getTime() - y.getTime()) || 0;
54
+ if (lt(x, y))
59
55
  return -1;
60
56
  return 1;
61
57
  }
@@ -67,7 +63,7 @@ export function compare(x, y) {
67
63
  * @returns {boolean} `true` if `x` and `y` are equal or `false` otherwise.
68
64
  */
69
65
  export function eq(x, y) {
70
- return Object.is(x, y) || call(x, 'eq', y) != null;
66
+ return x === y || Object.is(x, y) || !!call(x, 'eq', y);
71
67
  }
72
68
  /**
73
69
  * Compares two values to check if `x` is strictly less than `y`. If `x` is an object with a `lt` method, it returns `x.lt(y)`.
@@ -77,7 +73,8 @@ export function eq(x, y) {
77
73
  * @returns {boolean} `true` if `x` is strictly less than `y` or `false` otherwise.
78
74
  */
79
75
  export function lt(x, y) {
80
- return x < y || call(x, 'lt', y) != null;
76
+ const op = call(x, 'lt', y);
77
+ return op != null ? !!op : x < y;
81
78
  }
82
79
  /**
83
80
  * Compares two values to check if `x <= y`. If `x` is an object with a `lte` method, it returns `x.lte(y)`, also checks `x.eq(y)` and `x.lt(y)`.
@@ -89,13 +86,13 @@ export function lt(x, y) {
89
86
  * @see {@link lt}
90
87
  */
91
88
  export function lte(x, y) {
92
- if (x <= y || call(x, 'lte', y))
93
- return true;
94
- if (x === y || eq(x, y))
95
- return true;
96
- if (x < y || lt(x, y))
97
- return true;
98
- return false;
89
+ const op = call(x, 'lte', y);
90
+ if (op != null)
91
+ return !!op;
92
+ const less = call(x, 'lt', y);
93
+ if (less != null)
94
+ return !!less || eq(x, y) || (call(y, 'lt', x) === false && x <= y);
95
+ return x <= y || eq(x, y);
99
96
  }
100
97
  /**
101
98
  * Compares two values to check if `x` is strictly greater than `y`. If `x` is an object with a `gt` method, it returns `x.gt(y)`.
@@ -105,7 +102,8 @@ export function lte(x, y) {
105
102
  * @returns {boolean} `true` if `x` is strictly greater than `y` or `false` otherwise.
106
103
  */
107
104
  export function gt(x, y) {
108
- return x > y || call(x, 'gt', y);
105
+ const op = call(x, 'gt', y);
106
+ return op != null ? !!op : x > y;
109
107
  }
110
108
  /**
111
109
  * Compares two values to check if `x >= y`. If `x` is an object with a `gte` method, it returns `x.gte(y)`, also checks `x.eq(y)` and `x.gt(y)`.
@@ -117,13 +115,13 @@ export function gt(x, y) {
117
115
  * @see {@link gt}
118
116
  */
119
117
  export function gte(x, y) {
120
- if (x <= y || call(x, 'gte', y))
121
- return true;
122
- if (x === y || eq(x, y))
123
- return true;
124
- if (x > y || gt(x, y))
125
- return true;
126
- return false;
118
+ const op = call(x, 'gte', y);
119
+ if (op != null)
120
+ return !!op;
121
+ const greater = call(x, 'gt', y);
122
+ if (greater != null)
123
+ return !!greater || eq(x, y) || (call(y, 'gt', x) === false && x >= y);
124
+ return x >= y || eq(x, y);
127
125
  }
128
126
  /**
129
127
  * The addition (+) operator. If `x` is an object with an `add` method, it returns `x.add(y)`.
@@ -203,6 +201,26 @@ export function pow(x, y) {
203
201
  return op;
204
202
  return x ** y;
205
203
  }
204
+ /** Class names tell kinds apart across realms, where prototypes differ. */
205
+ function sameKind(x, y) {
206
+ if (!x || !y || typeof x !== 'object' || typeof y !== 'object')
207
+ return false;
208
+ const tag = Object.prototype.toString;
209
+ if (tag.call(x) !== tag.call(y))
210
+ return false;
211
+ return (x.constructor?.name ?? 'Object') === (y.constructor?.name ?? 'Object');
212
+ }
213
+ function isList(x) {
214
+ return Array.isArray(x) || (ArrayBuffer.isView(x) && !(x instanceof DataView));
215
+ }
216
+ function isDateOrRegExp(x) {
217
+ return x instanceof Date || x instanceof RegExp;
218
+ }
219
+ function sameDateOrRegExp(x, y) {
220
+ if (x instanceof Date)
221
+ return Object.is(x.getTime(), y.getTime());
222
+ return String(x) === String(y);
223
+ }
206
224
  /**
207
225
  * Performs a shallow comparison of two objects or arrays to check if they have the same keys, length and values.
208
226
  * @param obj
@@ -213,8 +231,10 @@ export function pow(x, y) {
213
231
  export function shallowEqual(obj, other) {
214
232
  if (obj === other)
215
233
  return true;
216
- if (!obj || !other)
234
+ if (!sameKind(obj, other))
217
235
  return false;
236
+ if (isDateOrRegExp(obj))
237
+ return sameDateOrRegExp(obj, other);
218
238
  if (Array.isArray(obj)) {
219
239
  // compare the arrays
220
240
  if (obj.length !== other.length)
@@ -233,7 +253,7 @@ export function shallowEqual(obj, other) {
233
253
  if (objKeys.length !== otherKeys.length)
234
254
  return false;
235
255
  for (const key of objKeys) {
236
- if (!Object.prototype.hasOwnProperty.call(other, key) || obj[key] !== other[key]) {
256
+ if (!Object.hasOwn(other, key) || obj[key] !== other[key]) {
237
257
  return false;
238
258
  }
239
259
  }
@@ -241,21 +261,26 @@ export function shallowEqual(obj, other) {
241
261
  }
242
262
  return false;
243
263
  }
244
- export function deepEqual(obj, other, checker = eq, seen = new WeakSet()) {
264
+ export function deepEqual(obj, other, checker = eq, seen = new WeakMap()) {
265
+ if (!(seen instanceof WeakMap))
266
+ seen = new WeakMap();
245
267
  if (checker(obj, other))
246
268
  return true;
247
- if (!obj || !other)
248
- return false;
249
- if (obj.prototype !== other.prototype)
269
+ if (!sameKind(obj, other))
250
270
  return false;
251
- if (seen.has(obj) && seen.has(other))
252
- return false;
253
- if (Array.isArray(obj)) {
271
+ if (isDateOrRegExp(obj))
272
+ return sameDateOrRegExp(obj, other);
273
+ // A pair that was compared before needs no second walk: it either held, or the call has returned.
274
+ const partners = seen.get(obj) ?? new WeakSet();
275
+ if (partners.has(other))
276
+ return true;
277
+ seen.set(obj, partners.add(other));
278
+ if (isList(obj)) {
254
279
  // compare the arrays
255
280
  if (obj.length !== other.length)
256
281
  return false;
257
282
  for (let i = 0; i < obj.length; i++) {
258
- if (!deepEqual(obj[i], other[i], checker)) {
283
+ if (!deepEqual(obj[i], other[i], checker, seen)) {
259
284
  return false;
260
285
  }
261
286
  }
@@ -274,8 +299,6 @@ export function deepEqual(obj, other, checker = eq, seen = new WeakSet()) {
274
299
  // compare keys and values
275
300
  if (obj.size !== other.size)
276
301
  return false;
277
- seen.add(obj);
278
- seen.add(other);
279
302
  for (const key of obj.keys()) {
280
303
  if (!other.has(key))
281
304
  return false;
@@ -291,11 +314,8 @@ export function deepEqual(obj, other, checker = eq, seen = new WeakSet()) {
291
314
  const otherKeys = Object.keys(other);
292
315
  if (objKeys.length !== otherKeys.length)
293
316
  return false;
294
- seen.add(obj);
295
- seen.add(other);
296
317
  for (const key of objKeys) {
297
- if (!Object.prototype.hasOwnProperty.call(other, key) ||
298
- !deepEqual(obj[key], other[key], checker, seen)) {
318
+ if (!Object.hasOwn(other, key) || !deepEqual(obj[key], other[key], checker, seen)) {
299
319
  return false;
300
320
  }
301
321
  }