atomic-fns 1.1.6 → 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 (51) 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.d.ts +2 -2
  5. package/dist/collections/Heap.js +1 -1
  6. package/dist/collections/LRUCache.d.ts +8 -5
  7. package/dist/collections/LRUCache.js +24 -11
  8. package/dist/collections/SortedMap.d.ts +4 -4
  9. package/dist/collections/SortedMap.js +4 -3
  10. package/dist/collections/SortedSet.d.ts +2 -2
  11. package/dist/collections/SortedTree.d.ts +9 -9
  12. package/dist/collections/SortedTree.js +7 -6
  13. package/dist/collections/SplayTree.d.ts +17 -15
  14. package/dist/collections/SplayTree.js +42 -29
  15. package/dist/collections/Trie.d.ts +2 -2
  16. package/dist/collections/Trie.js +26 -26
  17. package/dist/collections/deque.d.ts +11 -11
  18. package/dist/collections/deque.js +17 -10
  19. package/dist/collections/frozenset.js +4 -1
  20. package/dist/collections/index.d.ts +30 -48
  21. package/dist/collections/index.js +210 -82
  22. package/dist/decimal/index.d.ts +7 -5
  23. package/dist/decimal/index.js +63 -28
  24. package/dist/functools/index.d.ts +10 -34
  25. package/dist/functools/index.js +25 -57
  26. package/dist/globals/index.d.ts +5 -22
  27. package/dist/globals/index.js +24 -40
  28. package/dist/i18n/currency.d.ts +10 -7
  29. package/dist/i18n/currency.js +22 -7
  30. package/dist/i18n/date/index.d.ts +22 -16
  31. package/dist/i18n/date/index.js +89 -67
  32. package/dist/i18n/date/utils.d.ts +6 -7
  33. package/dist/i18n/date/utils.js +15 -113
  34. package/dist/i18n/duration.d.ts +13 -12
  35. package/dist/i18n/duration.js +38 -32
  36. package/dist/i18n/format.d.ts +10 -2
  37. package/dist/i18n/format.js +100 -217
  38. package/dist/i18n/index.d.ts +2 -1
  39. package/dist/itertools/index.d.ts +21 -25
  40. package/dist/itertools/index.js +41 -44
  41. package/dist/math/index.d.ts +12 -29
  42. package/dist/math/index.js +16 -33
  43. package/dist/mod.d.ts +1 -0
  44. package/dist/mod.js +1 -0
  45. package/dist/operators/index.d.ts +3 -3
  46. package/dist/operators/index.js +62 -38
  47. package/dist/random/index.js +9 -6
  48. package/dist/string/index.d.ts +1 -1
  49. package/dist/string/index.js +2 -4
  50. package/dist/types.d.ts +3 -3
  51. package/package.json +16 -21
@@ -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,15 +15,18 @@ 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 head = it.next();
19
- if (initial == null)
18
+ if (initial == null) {
19
+ const head = it.next();
20
+ if (head.done)
21
+ return;
20
22
  total = head.value;
21
- while (!head.done) {
23
+ }
24
+ while (true) {
22
25
  yield total;
23
- head = it.next();
24
- if (head.done)
26
+ const current = it.next();
27
+ if (current.done)
25
28
  return;
26
- total = func(total, head.value);
29
+ total = func(total, current.value);
27
30
  }
28
31
  }
29
32
  /**
@@ -34,12 +37,12 @@ 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
41
44
 
42
- all([2, 4, 6] => (n) => n > 1)
45
+ all([2, 4, 6], n => n > 1)
43
46
  // true
44
47
  ```
45
48
  @see {@link any}
@@ -64,7 +67,7 @@ any([0])
64
67
  any([0, 1, null, undefined])
65
68
  // true
66
69
 
67
- any([1, 4, 5] => (n) => n % 2 === 0)
70
+ any([1, 4, 5], n => n % 2 === 0)
68
71
  // true
69
72
  ```
70
73
  @see {@link all}
@@ -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: any): number;
48
- export declare function logBase(x: any, y: any): number;
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;
@@ -72,24 +55,24 @@ export declare function max<T>(iterable: Iterable<T>, key?: Predicate<T>): T;
72
55
  ```js
73
56
  let objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }]
74
57
 
75
- mean(objects, (o) => o.n)
58
+ mean(objects, o => o.n)
76
59
  // 5
77
60
  ```
78
61
  */
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);
package/dist/mod.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './index.js';
package/dist/mod.js ADDED
@@ -0,0 +1 @@
1
+ export * from './index.js';
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * @module operators
5
5
  */
6
- /** This is the identity function. It always returns the same value that was passed in */
7
- export declare function id(x: any): any;
6
+ /** This is the identity function. It always returns the same value that was passed in. */
7
+ export declare const identity: <T>(x: T) => T;
8
8
  /**
9
9
  * Called to implement truth value testing.
10
10
  * @param x
@@ -27,7 +27,7 @@ export declare function isinstance(x: any, y: any): boolean;
27
27
  *
28
28
  * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#parameters Array.sort()}
29
29
  */
30
- export declare type Comparer<T = any> = (x: T, y: T) => number;
30
+ export type Comparer<T = any> = (x: T, y: T) => number;
31
31
  /**
32
32
  * Checks whether `x` is a comparable type and returns the result of `x.compare(y)`.
33
33
  * Otherwise the return value of the compare function is equivalent to `obj === other ? 0 : obj < other ? -1 : 1`
@@ -4,10 +4,8 @@
4
4
  * @module operators
5
5
  */
6
6
  import { call, isObject } from '../globals/index.js';
7
- /** This is the identity function. It always returns the same value that was passed in */
8
- export function id(x) {
9
- return x;
10
- }
7
+ /** This is the identity function. It always returns the same value that was passed in. */
8
+ export const identity = (x) => x;
11
9
  /**
12
10
  * Called to implement truth value testing.
13
11
  * @param x
@@ -51,7 +49,9 @@ export function compare(x, y) {
51
49
  const op = call(x, 'compare', y);
52
50
  if (typeof op === 'number')
53
51
  return op;
54
- 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))
55
55
  return -1;
56
56
  return 1;
57
57
  }
@@ -63,7 +63,7 @@ export function compare(x, y) {
63
63
  * @returns {boolean} `true` if `x` and `y` are equal or `false` otherwise.
64
64
  */
65
65
  export function eq(x, y) {
66
- return Object.is(x, y) || call(x, 'eq', y) != null;
66
+ return x === y || Object.is(x, y) || !!call(x, 'eq', y);
67
67
  }
68
68
  /**
69
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)`.
@@ -73,7 +73,8 @@ export function eq(x, y) {
73
73
  * @returns {boolean} `true` if `x` is strictly less than `y` or `false` otherwise.
74
74
  */
75
75
  export function lt(x, y) {
76
- return x < y || call(x, 'lt', y) != null;
76
+ const op = call(x, 'lt', y);
77
+ return op != null ? !!op : x < y;
77
78
  }
78
79
  /**
79
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)`.
@@ -85,13 +86,13 @@ export function lt(x, y) {
85
86
  * @see {@link lt}
86
87
  */
87
88
  export function lte(x, y) {
88
- if (x <= y || call(x, 'lte', y))
89
- return true;
90
- if (x === y || eq(x, y))
91
- return true;
92
- if (x < y || lt(x, y))
93
- return true;
94
- 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);
95
96
  }
96
97
  /**
97
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)`.
@@ -101,7 +102,8 @@ export function lte(x, y) {
101
102
  * @returns {boolean} `true` if `x` is strictly greater than `y` or `false` otherwise.
102
103
  */
103
104
  export function gt(x, y) {
104
- return x > y || call(x, 'gt', y);
105
+ const op = call(x, 'gt', y);
106
+ return op != null ? !!op : x > y;
105
107
  }
106
108
  /**
107
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)`.
@@ -113,13 +115,13 @@ export function gt(x, y) {
113
115
  * @see {@link gt}
114
116
  */
115
117
  export function gte(x, y) {
116
- if (x <= y || call(x, 'gte', y))
117
- return true;
118
- if (x === y || eq(x, y))
119
- return true;
120
- if (x > y || gt(x, y))
121
- return true;
122
- 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);
123
125
  }
124
126
  /**
125
127
  * The addition (+) operator. If `x` is an object with an `add` method, it returns `x.add(y)`.
@@ -199,6 +201,26 @@ export function pow(x, y) {
199
201
  return op;
200
202
  return x ** y;
201
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
+ }
202
224
  /**
203
225
  * Performs a shallow comparison of two objects or arrays to check if they have the same keys, length and values.
204
226
  * @param obj
@@ -209,8 +231,10 @@ export function pow(x, y) {
209
231
  export function shallowEqual(obj, other) {
210
232
  if (obj === other)
211
233
  return true;
212
- if (!obj || !other)
234
+ if (!sameKind(obj, other))
213
235
  return false;
236
+ if (isDateOrRegExp(obj))
237
+ return sameDateOrRegExp(obj, other);
214
238
  if (Array.isArray(obj)) {
215
239
  // compare the arrays
216
240
  if (obj.length !== other.length)
@@ -229,7 +253,7 @@ export function shallowEqual(obj, other) {
229
253
  if (objKeys.length !== otherKeys.length)
230
254
  return false;
231
255
  for (const key of objKeys) {
232
- if (!Object.prototype.hasOwnProperty.call(other, key) || obj[key] !== other[key]) {
256
+ if (!Object.hasOwn(other, key) || obj[key] !== other[key]) {
233
257
  return false;
234
258
  }
235
259
  }
@@ -237,21 +261,26 @@ export function shallowEqual(obj, other) {
237
261
  }
238
262
  return false;
239
263
  }
240
- 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();
241
267
  if (checker(obj, other))
242
268
  return true;
243
- if (!obj || !other)
244
- return false;
245
- if (obj.prototype !== other.prototype)
246
- return false;
247
- if (seen.has(obj) && seen.has(other))
269
+ if (!sameKind(obj, other))
248
270
  return false;
249
- 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)) {
250
279
  // compare the arrays
251
280
  if (obj.length !== other.length)
252
281
  return false;
253
282
  for (let i = 0; i < obj.length; i++) {
254
- if (!deepEqual(obj[i], other[i], checker)) {
283
+ if (!deepEqual(obj[i], other[i], checker, seen)) {
255
284
  return false;
256
285
  }
257
286
  }
@@ -270,8 +299,6 @@ export function deepEqual(obj, other, checker = eq, seen = new WeakSet()) {
270
299
  // compare keys and values
271
300
  if (obj.size !== other.size)
272
301
  return false;
273
- seen.add(obj);
274
- seen.add(other);
275
302
  for (const key of obj.keys()) {
276
303
  if (!other.has(key))
277
304
  return false;
@@ -287,11 +314,8 @@ export function deepEqual(obj, other, checker = eq, seen = new WeakSet()) {
287
314
  const otherKeys = Object.keys(other);
288
315
  if (objKeys.length !== otherKeys.length)
289
316
  return false;
290
- seen.add(obj);
291
- seen.add(other);
292
317
  for (const key of objKeys) {
293
- if (!Object.prototype.hasOwnProperty.call(other, key) ||
294
- !deepEqual(obj[key], other[key], checker, seen)) {
318
+ if (!Object.hasOwn(other, key) || !deepEqual(obj[key], other[key], checker, seen)) {
295
319
  return false;
296
320
  }
297
321
  }
@@ -11,7 +11,8 @@ import { isObject } from '../globals/index.js';
11
11
  * @returns {number}
12
12
  */
13
13
  export function random(min = 0, max = 1) {
14
- return Math.random() * (max - min) + min;
14
+ const value = Math.random() * (max - min) + min;
15
+ return value === max ? min : value;
15
16
  }
16
17
  /**
17
18
  * Returns a random integer between a [min, max] value (inclusive).
@@ -20,7 +21,9 @@ export function random(min = 0, max = 1) {
20
21
  * @returns {number}
21
22
  */
22
23
  export function randomInt(min = 0, max = 1) {
23
- return Math.round(random(min, max));
24
+ const low = Math.ceil(Math.min(min, max));
25
+ const high = Math.floor(Math.max(min, max));
26
+ return low + Math.floor(random(0, high - low + 1));
24
27
  }
25
28
  /**
26
29
  * Returns the item at some random index in a sequence.
@@ -42,7 +45,7 @@ export function choice(arr) {
42
45
  export function sample(arr, size) {
43
46
  if (!arr?.length || arr.length < size)
44
47
  return [];
45
- return shuffle(arr.slice()).slice(-size);
48
+ return shuffle(arr.slice()).slice(0, size);
46
49
  }
47
50
  /**
48
51
  * Shuffles a collection elements in-place. Uses the Fisher-Yates algorithm for uniform shuffling. If collection is an Object it returns shuffled `Object.values()`.
@@ -53,11 +56,11 @@ export function sample(arr, size) {
53
56
  * @template T
54
57
  */
55
58
  export function shuffle(arr, size) {
56
- if (!arr?.length)
57
- return arr;
58
59
  if (isObject(arr))
59
60
  arr = Object.values(arr);
60
- if (size == null)
61
+ if (!arr?.length)
62
+ return arr;
63
+ if (size == null || size >= arr.length)
61
64
  size = arr.length - 1;
62
65
  for (let i = 0; i <= size; i++) {
63
66
  const j = randomInt(i, size);
@@ -33,7 +33,7 @@ export declare function capitalize(s: string): string;
33
33
  /**
34
34
  * Split a string into an array of its words.
35
35
  * @param {string} s The string to split
36
- * @param {RegExp | string} [pattern] The pattern to match words
36
+ * @param {RegExp | string} [pattern] The separator to split on, instead of matching words
37
37
  * @returns {string[]} Returns the words array.
38
38
  * @example
39
39
  ```js