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,44 @@
1
+ /**
2
+ * The built-in kinds a deep walk handles, including values from other realms.
3
+ */
4
+ /** A native `Map`, from any realm. */
5
+ export declare function isMap(x: unknown): x is Map<unknown, unknown>;
6
+ /** A native `Set`, from any realm. */
7
+ export declare function isSet(x: unknown): x is Set<unknown>;
8
+ /** An `arguments` object, from any realm. `kindOf` calls it `other`; `isEqual` reads it like an array. */
9
+ export declare function isArguments(x: unknown): x is IArguments;
10
+ /** The primitive inside a wrapper object such as `new Number(1)`; ordinary non-wrappers unchanged. */
11
+ export declare function unbox(x: unknown): unknown;
12
+ /**
13
+ * The kinds a deep walk copies, compares or hashes by content. `other` covers class instances,
14
+ * functions, errors, `arguments`, promises, weak collections and every other object: walks keep
15
+ * those by reference. `isEqual` and `hash` also read errors and `arguments` by content; see
16
+ * {@link isError} and {@link isArguments}.
17
+ */
18
+ export type Kind = 'plain' | 'array' | 'map' | 'set' | 'date' | 'regexp' | 'view' | 'buffer' | 'boxed' | 'other';
19
+ /** The {@link Kind} of `value`. */
20
+ export declare function kindOf(value: object): Kind;
21
+ /** {@link Kind}, with the two `other` kinds `isEqual` and `hash` also read by content. */
22
+ export type ContentKind = Kind | 'error' | 'arguments';
23
+ /** The {@link ContentKind} of `value`: what `isEqual` compares and `hash` hashes it by. */
24
+ export declare function contentKindOf(value: object): ContentKind;
25
+ /** The bytes a view covers, without copying. Throws for a detached or out-of-bounds view. */
26
+ export declare function viewBytes(view: ArrayBufferView): Uint8Array;
27
+ /** The bytes of a buffer or view. A detached or out-of-bounds one has none. */
28
+ export declare function bytesOf(value: ArrayBuffer | SharedArrayBuffer | ArrayBufferView): Uint8Array;
29
+ /** Whether `view` holds floats, which compare by element (`0` equals `-0`) and not by byte. */
30
+ export declare function isFloatView(view: ArrayBufferView): view is Float16Array | Float32Array | Float64Array;
31
+ /**
32
+ * A typed array's type name, such as `'Float64Array'`, from any realm, or `undefined` for anything
33
+ * else, a `DataView` included. It never throws.
34
+ */
35
+ export declare function typedArrayName(x: object): string | undefined;
36
+ /** A typed array's element count (0 when detached), or `undefined` for other objects. */
37
+ export declare function typedArrayLength(x: object): number | undefined;
38
+ export declare function mapSize(map: Map<unknown, unknown>): number;
39
+ export declare function setSize(set: Set<unknown>): number;
40
+ /**
41
+ * Whether `a` and `b` share one prototype chain, or twin chains from two realms (each prototype
42
+ * named like its counterpart). Null-prototype objects count as `Object.prototype`.
43
+ */
44
+ export declare function sameClass(a: object, b: object): boolean;
@@ -0,0 +1,139 @@
1
+ /**
2
+ * The built-in kinds a deep walk handles, including values from other realms.
3
+ */
4
+ import { isError } from '../is/isError.js';
5
+ import { isPlainObject } from '../is/isPlainObject.js';
6
+ function getterOf(prototype, key) {
7
+ const get = Object.getOwnPropertyDescriptor(prototype, key)?.get;
8
+ if (get === undefined)
9
+ throw new TypeError(`no getter for ${String(key)}`);
10
+ return get;
11
+ }
12
+ /** A native `Map`, from any realm. */
13
+ export function isMap(x) {
14
+ return Object.prototype.toString.call(x) === '[object Map]';
15
+ }
16
+ /** A native `Set`, from any realm. */
17
+ export function isSet(x) {
18
+ return Object.prototype.toString.call(x) === '[object Set]';
19
+ }
20
+ /** An `arguments` object, from any realm. `kindOf` calls it `other`; `isEqual` reads it like an array. */
21
+ export function isArguments(x) {
22
+ return Object.prototype.toString.call(x) === '[object Arguments]';
23
+ }
24
+ const UNBOXERS = new Map([
25
+ ['[object Number]', (box) => Reflect.apply(Number.prototype.valueOf, box, [])],
26
+ ['[object String]', (box) => Reflect.apply(String.prototype.valueOf, box, [])],
27
+ ['[object Boolean]', (box) => Reflect.apply(Boolean.prototype.valueOf, box, [])],
28
+ ['[object BigInt]', (box) => Reflect.apply(BigInt.prototype.valueOf, box, [])],
29
+ ['[object Symbol]', (box) => Reflect.apply(Symbol.prototype.valueOf, box, [])]
30
+ ]);
31
+ /** The primitive inside a wrapper object such as `new Number(1)`; ordinary non-wrappers unchanged. */
32
+ export function unbox(x) {
33
+ if (typeof x !== 'object' || x === null)
34
+ return x;
35
+ return UNBOXERS.get(Object.prototype.toString.call(x))?.(x) ?? x;
36
+ }
37
+ /** The {@link Kind} of `value`. */
38
+ export function kindOf(value) {
39
+ if (Array.isArray(value))
40
+ return 'array';
41
+ if (isPlainObject(value))
42
+ return 'plain';
43
+ if (ArrayBuffer.isView(value))
44
+ return 'view';
45
+ const tag = Object.prototype.toString.call(value);
46
+ switch (tag) {
47
+ case '[object Date]':
48
+ return 'date';
49
+ case '[object RegExp]':
50
+ return 'regexp';
51
+ case '[object Map]':
52
+ return 'map';
53
+ case '[object Set]':
54
+ return 'set';
55
+ case '[object ArrayBuffer]':
56
+ case '[object SharedArrayBuffer]':
57
+ return 'buffer';
58
+ }
59
+ if (UNBOXERS.has(tag))
60
+ return 'boxed';
61
+ return 'other';
62
+ }
63
+ /** The {@link ContentKind} of `value`: what `isEqual` compares and `hash` hashes it by. */
64
+ export function contentKindOf(value) {
65
+ const kind = kindOf(value);
66
+ if (kind !== 'other')
67
+ return kind;
68
+ if (isError(value))
69
+ return 'error';
70
+ return isArguments(value) ? 'arguments' : 'other';
71
+ }
72
+ /** `%TypedArray%.prototype`, which holds the getters every typed array shares. */
73
+ const TYPED_ARRAY_PROTOTYPE = Object.getPrototypeOf(Uint8Array.prototype);
74
+ /** `%TypedArray%.prototype[Symbol.toStringTag]`: a typed array's type name, else `undefined`. */
75
+ const TYPED_ARRAY_NAME = getterOf(TYPED_ARRAY_PROTOTYPE, Symbol.toStringTag);
76
+ /** The bytes a view covers, without copying. Throws for a detached or out-of-bounds view. */
77
+ export function viewBytes(view) {
78
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
79
+ }
80
+ /** The bytes of a buffer or view. A detached or out-of-bounds one has none. */
81
+ export function bytesOf(value) {
82
+ try {
83
+ return ArrayBuffer.isView(value) ? viewBytes(value) : new Uint8Array(value);
84
+ }
85
+ catch {
86
+ return new Uint8Array(0);
87
+ }
88
+ }
89
+ const FLOAT_ARRAY_NAMES = new Set([
90
+ 'Float16Array',
91
+ 'Float32Array',
92
+ 'Float64Array'
93
+ ]);
94
+ /** Whether `view` holds floats, which compare by element (`0` equals `-0`) and not by byte. */
95
+ export function isFloatView(view) {
96
+ return FLOAT_ARRAY_NAMES.has(Reflect.apply(TYPED_ARRAY_NAME, view, []));
97
+ }
98
+ /**
99
+ * A typed array's type name, such as `'Float64Array'`, from any realm, or `undefined` for anything
100
+ * else, a `DataView` included. It never throws.
101
+ */
102
+ export function typedArrayName(x) {
103
+ return Reflect.apply(TYPED_ARRAY_NAME, x, []);
104
+ }
105
+ /** A typed array's element count (0 when detached), or `undefined` for other objects. */
106
+ export function typedArrayLength(x) {
107
+ if (typedArrayName(x) === undefined)
108
+ return undefined;
109
+ return x.length;
110
+ }
111
+ export function mapSize(map) {
112
+ return map.size;
113
+ }
114
+ export function setSize(set) {
115
+ return set.size;
116
+ }
117
+ function classNameOf(prototype) {
118
+ const name = prototype.constructor?.name;
119
+ return typeof name === 'string' ? name : undefined;
120
+ }
121
+ function areTwins(x, y) {
122
+ const name = classNameOf(x);
123
+ return x !== y && name !== undefined && name === classNameOf(y);
124
+ }
125
+ /**
126
+ * Whether `a` and `b` share one prototype chain, or twin chains from two realms (each prototype
127
+ * named like its counterpart). Null-prototype objects count as `Object.prototype`.
128
+ */
129
+ export function sameClass(a, b) {
130
+ let x = Object.getPrototypeOf(a) ?? Object.prototype;
131
+ let y = Object.getPrototypeOf(b) ?? Object.prototype;
132
+ if (x === y)
133
+ return true;
134
+ while (x !== null && y !== null && areTwins(x, y)) {
135
+ x = Object.getPrototypeOf(x);
136
+ y = Object.getPrototypeOf(y);
137
+ }
138
+ return x === null && y === null;
139
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Sparse-array helpers for own enumerable indices, with hole-run events.
3
+ */
4
+ /** ECMAScript canonical array index name (0 .. 2^32-2). */
5
+ export declare function isCanonicalArrayIndex(key: string): boolean;
6
+ /** Own enumerable array indices at or after `start`, in `Object.keys` order. */
7
+ export declare function arrayIndicesFrom(arr: readonly unknown[], start: number): number[];
8
+ /** A present index, or a contiguous hole run `[start, end)`. */
9
+ export type ArrayWalkEvent = {
10
+ readonly kind: 'value';
11
+ readonly index: number;
12
+ readonly value: unknown;
13
+ } | {
14
+ readonly kind: 'holeRun';
15
+ readonly start: number;
16
+ readonly end: number;
17
+ };
18
+ export type ArrayIndexWalkEvent = {
19
+ readonly kind: 'index';
20
+ readonly index: number;
21
+ } | {
22
+ readonly kind: 'holeRun';
23
+ readonly start: number;
24
+ readonly end: number;
25
+ };
26
+ /** Holes a walk may visit one by one, beyond one per element seen, before it takes Object.keys. */
27
+ export declare const HOLE_STREAK_BEFORE_KEYS = 256;
28
+ /**
29
+ * Walk the own enumerable indices of `arr` (the set `Object.keys` lists) without expanding huge
30
+ * hole runs index-by-index. Inherited and non-enumerable indices are holes.
31
+ * Dense indices are checked one by one. Once holes pass {@link HOLE_STREAK_BEFORE_KEYS} plus the
32
+ * elements seen so far, take `Object.keys` once and continue over remaining canonical indices only,
33
+ * so cost stays proportional to the elements however they are spaced.
34
+ * Holes are reported as a single `holeRun` event (`end` exclusive).
35
+ * Return `false` from `visit` to stop.
36
+ */
37
+ export declare function walkArrayIndices(arr: readonly unknown[], visit: (event: ArrayIndexWalkEvent) => false | undefined): void;
38
+ /** Like {@link walkArrayIndices}, with the value at each index. */
39
+ export declare function walkArray(arr: readonly unknown[], visit: (event: ArrayWalkEvent) => false | undefined): void;
40
+ /** Absolute length below which per-index consumers never treat an array as huge-sparse. */
41
+ export declare const HUGE_SPARSE_MIN_LENGTH: number;
42
+ /**
43
+ * True when `arr.length` is above {@link HUGE_SPARSE_MIN_LENGTH} and also exceeds
44
+ * `2 * ownIndexCount + 1024`, so a dense `0..length` walk would spend most of its time on holes.
45
+ * Below {@link HUGE_SPARSE_MIN_LENGTH}, consumers walk with their existing hole semantics.
46
+ * Counts through {@link walkArrayIndices}; a dense array stops as soon as its own indices prove
47
+ * it cannot qualify.
48
+ */
49
+ export declare function isHugeSparse(arr: readonly unknown[]): boolean;
50
+ /** Throw when `arr` is a huge sparse array that must not be expanded per-index. */
51
+ export declare function assertNotHugeSparse(arr: readonly unknown[]): void;
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Sparse-array helpers for own enumerable indices, with hole-run events.
3
+ */
4
+ /** ECMAScript canonical array index name (0 .. 2^32-2). */
5
+ export function isCanonicalArrayIndex(key) {
6
+ return /^(0|[1-9]\d*)$/.test(key) && Number(key) <= 0xffff_fffe;
7
+ }
8
+ /** Own enumerable array indices at or after `start`, in `Object.keys` order. */
9
+ export function arrayIndicesFrom(arr, start) {
10
+ const indices = [];
11
+ for (const key of Object.keys(arr)) {
12
+ if (!isCanonicalArrayIndex(key))
13
+ continue;
14
+ const index = Number(key);
15
+ if (index >= start)
16
+ indices.push(index);
17
+ }
18
+ return indices;
19
+ }
20
+ /** Holes a walk may visit one by one, beyond one per element seen, before it takes Object.keys. */
21
+ export const HOLE_STREAK_BEFORE_KEYS = 256;
22
+ const isOwnEnumerable = Object.prototype.propertyIsEnumerable;
23
+ /**
24
+ * Walk the own enumerable indices of `arr` (the set `Object.keys` lists) without expanding huge
25
+ * hole runs index-by-index. Inherited and non-enumerable indices are holes.
26
+ * Dense indices are checked one by one. Once holes pass {@link HOLE_STREAK_BEFORE_KEYS} plus the
27
+ * elements seen so far, take `Object.keys` once and continue over remaining canonical indices only,
28
+ * so cost stays proportional to the elements however they are spaced.
29
+ * Holes are reported as a single `holeRun` event (`end` exclusive).
30
+ * Return `false` from `visit` to stop.
31
+ */
32
+ export function walkArrayIndices(arr, visit) {
33
+ const len = arr.length;
34
+ let i = 0;
35
+ let elements = 0;
36
+ let holes = 0;
37
+ while (i < len) {
38
+ if (isOwnEnumerable.call(arr, i)) {
39
+ if (visit({ kind: 'index', index: i }) === false)
40
+ return;
41
+ i++;
42
+ elements++;
43
+ continue;
44
+ }
45
+ const holeStart = i;
46
+ while (i < len && !isOwnEnumerable.call(arr, i) && holes < HOLE_STREAK_BEFORE_KEYS + elements) {
47
+ i++;
48
+ holes++;
49
+ }
50
+ if (holes >= HOLE_STREAK_BEFORE_KEYS + elements && i < len) {
51
+ const rest = arrayIndicesFrom(arr, i);
52
+ let cursor = holeStart;
53
+ for (const idx of rest) {
54
+ if (idx > cursor && visit({ kind: 'holeRun', start: cursor, end: idx }) === false)
55
+ return;
56
+ if (visit({ kind: 'index', index: idx }) === false)
57
+ return;
58
+ cursor = idx + 1;
59
+ }
60
+ if (cursor < len)
61
+ visit({ kind: 'holeRun', start: cursor, end: len });
62
+ return;
63
+ }
64
+ if (visit({ kind: 'holeRun', start: holeStart, end: i }) === false)
65
+ return;
66
+ }
67
+ }
68
+ /** Like {@link walkArrayIndices}, with the value at each index. */
69
+ export function walkArray(arr, visit) {
70
+ walkArrayIndices(arr, (event) => visit(event.kind === 'index'
71
+ ? { kind: 'value', index: event.index, value: arr[event.index] }
72
+ : event));
73
+ }
74
+ /** Absolute length below which per-index consumers never treat an array as huge-sparse. */
75
+ export const HUGE_SPARSE_MIN_LENGTH = 2 ** 24;
76
+ /**
77
+ * True when `arr.length` is above {@link HUGE_SPARSE_MIN_LENGTH} and also exceeds
78
+ * `2 * ownIndexCount + 1024`, so a dense `0..length` walk would spend most of its time on holes.
79
+ * Below {@link HUGE_SPARSE_MIN_LENGTH}, consumers walk with their existing hole semantics.
80
+ * Counts through {@link walkArrayIndices}; a dense array stops as soon as its own indices prove
81
+ * it cannot qualify.
82
+ */
83
+ export function isHugeSparse(arr) {
84
+ const len = arr.length;
85
+ if (len <= HUGE_SPARSE_MIN_LENGTH)
86
+ return false;
87
+ // own > (len - 1024) / 2 => len < 2 * own + 1024, so the final test is false: stop there.
88
+ const denseOwn = (len - 1024) / 2;
89
+ let own = 0;
90
+ walkArrayIndices(arr, (ev) => {
91
+ if (ev.kind !== 'index')
92
+ return;
93
+ own++;
94
+ if (own > denseOwn)
95
+ return false;
96
+ });
97
+ return len > 2 * own + 1024;
98
+ }
99
+ /** Throw when `arr` is a huge sparse array that must not be expanded per-index. */
100
+ export function assertNotHugeSparse(arr) {
101
+ if (isHugeSparse(arr)) {
102
+ throw new RangeError('sparse array too large');
103
+ }
104
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Text helpers shared by the `fns/string` modules.
3
+ */
4
+ /** Lodash `toString`: `null` and `undefined` become `''`, anything else goes through `String`. */
5
+ export declare function toText(value: unknown): string;
6
+ /** Whether every UTF-16 code unit of `s` is ASCII. */
7
+ export declare function isAsciiString(s: string): boolean;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Text helpers shared by the `fns/string` modules.
3
+ */
4
+ /** Lodash `toString`: `null` and `undefined` become `''`, anything else goes through `String`. */
5
+ export function toText(value) {
6
+ return value == null ? '' : String(value);
7
+ }
8
+ /** Whether every UTF-16 code unit of `s` is ASCII. */
9
+ export function isAsciiString(s) {
10
+ for (let i = 0; i < s.length; i++) {
11
+ if (s.charCodeAt(i) > 0x7f)
12
+ return false;
13
+ }
14
+ return true;
15
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Timer waits shared by `fns/function` and `fns/async`.
3
+ */
4
+ /** Inclusive max for `setTimeout` delays (signed 32-bit). */
5
+ export declare const MAX_TIMER_WAIT_MS = 2147483647;
6
+ /**
7
+ * Checks a timer wait: throws `TypeError` for a non-number, `RangeError` for NaN, infinity or
8
+ * values past the timer range, and clamps a negative wait to 0.
9
+ */
10
+ export declare function timerWait(wait: number, name: string): number;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Timer waits shared by `fns/function` and `fns/async`.
3
+ */
4
+ /** Inclusive max for `setTimeout` delays (signed 32-bit). */
5
+ export const MAX_TIMER_WAIT_MS = 2_147_483_647;
6
+ /**
7
+ * Checks a timer wait: throws `TypeError` for a non-number, `RangeError` for NaN, infinity or
8
+ * values past the timer range, and clamps a negative wait to 0.
9
+ */
10
+ export function timerWait(wait, name) {
11
+ if (typeof wait !== 'number')
12
+ throw new TypeError(`${name} must be a number, got ${typeof wait}`);
13
+ if (!Number.isFinite(wait) || wait > MAX_TIMER_WAIT_MS) {
14
+ throw new RangeError(`${name} must be between 0 and ${MAX_TIMER_WAIT_MS} ms`);
15
+ }
16
+ return Math.max(wait, 0);
17
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Short, bounded echoes of caller strings for error messages.
3
+ */
4
+ /**
5
+ * `value` for an error message: its first {@link MAX_ECHO} UTF-16 code units, cut on a code point
6
+ * boundary, then JSON-encoded, plus `...` when cut. Only the kept prefix is encoded, so a huge
7
+ * string never pays a full encode. Encoding escapes control characters, so a message never embeds
8
+ * a raw newline from caller input; an escape takes more than one unit of the result.
9
+ */
10
+ export declare function truncateForError(value: string): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Short, bounded echoes of caller strings for error messages.
3
+ */
4
+ /** UTF-16 units of caller input an error message repeats. */
5
+ const MAX_ECHO = 40;
6
+ /**
7
+ * `value` for an error message: its first {@link MAX_ECHO} UTF-16 code units, cut on a code point
8
+ * boundary, then JSON-encoded, plus `...` when cut. Only the kept prefix is encoded, so a huge
9
+ * string never pays a full encode. Encoding escapes control characters, so a message never embeds
10
+ * a raw newline from caller input; an escape takes more than one unit of the result.
11
+ */
12
+ export function truncateForError(value) {
13
+ if (value.length <= MAX_ECHO)
14
+ return JSON.stringify(value);
15
+ let end = 0;
16
+ for (const ch of value) {
17
+ if (end + ch.length > MAX_ECHO)
18
+ break;
19
+ end += ch.length;
20
+ }
21
+ return `${JSON.stringify(value.slice(0, end))}...`;
22
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Depth and cycle guards shared by the deep walks (`isEqual`, `cloneDeep`, `merge`, `defaultsDeep`,
3
+ * `omit`, `flattenObject`, `stableStringify`, `isMatch`, `matches`).
4
+ */
5
+ /** Deepest nesting a walk follows before it throws. */
6
+ export declare const MAX_DEPTH = 1000;
7
+ /** Message of the `RangeError` a walk throws past {@link MAX_DEPTH}. */
8
+ export declare const DEPTH_ERROR: string;
9
+ /**
10
+ * Go one level deeper. Throws `RangeError` past {@link MAX_DEPTH}. Pair it with {@link exitDepth}
11
+ * in a `finally` at the recursion site.
12
+ */
13
+ export declare function enterDepth(): void;
14
+ /** Come back up one level. Must follow its {@link enterDepth}. */
15
+ export declare function exitDepth(): void;
16
+ /**
17
+ * Run the outermost call of a walk. An engine stack overflow inside it, which a deep walk can still
18
+ * hit on a small stack, becomes the same `RangeError` as {@link enterDepth} throws, and the depth
19
+ * count is reset. A call made while another walk runs (a customizer that calls `isEqual`) just
20
+ * runs `fn`.
21
+ */
22
+ export declare function guardDepth<T>(fn: () => T): T;
23
+ /**
24
+ * The objects on the path from the root of a walk to where it is now, so a walk can tell a cycle
25
+ * from an object that is merely shared.
26
+ */
27
+ export declare class Ancestors {
28
+ #private;
29
+ /** Whether `obj` is on the current path. */
30
+ has(obj: object): boolean;
31
+ /** Step into `obj`, one level deeper; throws `RangeError` past {@link MAX_DEPTH}. */
32
+ enter(obj: object): void;
33
+ /** Step back out of `obj`. */
34
+ leave(obj: object): void;
35
+ }
36
+ /**
37
+ * A budget for walks that expand shared containers again (`merge` copies a shared row once per
38
+ * place it appears). A first expansion of a container is free; each later one costs one unit per
39
+ * 16 keys, rounded up, with a minimum of one unit even for an empty container. The walk throws
40
+ * `RangeError(message)` once it has spent more than `limit` units.
41
+ */
42
+ export declare class RevisitBudget {
43
+ #private;
44
+ constructor(limit: number, message: string);
45
+ /** Record that `obj`, holding `keys` own keys, is being expanded. */
46
+ note(obj: object, keys: number): void;
47
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Depth and cycle guards shared by the deep walks (`isEqual`, `cloneDeep`, `merge`, `defaultsDeep`,
3
+ * `omit`, `flattenObject`, `stableStringify`, `isMatch`, `matches`).
4
+ */
5
+ /** Deepest nesting a walk follows before it throws. */
6
+ export const MAX_DEPTH = 1000;
7
+ /** Message of the `RangeError` a walk throws past {@link MAX_DEPTH}. */
8
+ export const DEPTH_ERROR = `nesting deeper than ${String(MAX_DEPTH)} levels`;
9
+ /** Shared by every running walk, so a walk that re-enters another one keeps counting. */
10
+ let depth = 0;
11
+ /**
12
+ * Go one level deeper. Throws `RangeError` past {@link MAX_DEPTH}. Pair it with {@link exitDepth}
13
+ * in a `finally` at the recursion site.
14
+ */
15
+ export function enterDepth() {
16
+ if (depth >= MAX_DEPTH)
17
+ throw new RangeError(DEPTH_ERROR);
18
+ depth++;
19
+ }
20
+ /** Come back up one level. Must follow its {@link enterDepth}. */
21
+ export function exitDepth() {
22
+ depth--;
23
+ }
24
+ function isStackOverflow(e) {
25
+ if (!(e instanceof Error))
26
+ return false;
27
+ if (e instanceof RangeError)
28
+ return e.message.includes('Maximum call stack size exceeded');
29
+ return e.name === 'InternalError' && e.message.includes('too much recursion');
30
+ }
31
+ /**
32
+ * Run the outermost call of a walk. An engine stack overflow inside it, which a deep walk can still
33
+ * hit on a small stack, becomes the same `RangeError` as {@link enterDepth} throws, and the depth
34
+ * count is reset. A call made while another walk runs (a customizer that calls `isEqual`) just
35
+ * runs `fn`.
36
+ */
37
+ export function guardDepth(fn) {
38
+ if (depth !== 0)
39
+ return fn();
40
+ try {
41
+ return fn();
42
+ }
43
+ catch (e) {
44
+ if (isStackOverflow(e))
45
+ throw new RangeError(DEPTH_ERROR, { cause: e });
46
+ throw e;
47
+ }
48
+ finally {
49
+ depth = 0;
50
+ }
51
+ }
52
+ /**
53
+ * The objects on the path from the root of a walk to where it is now, so a walk can tell a cycle
54
+ * from an object that is merely shared.
55
+ */
56
+ export class Ancestors {
57
+ #open = new Set();
58
+ /** Whether `obj` is on the current path. */
59
+ has(obj) {
60
+ return this.#open.has(obj);
61
+ }
62
+ /** Step into `obj`, one level deeper; throws `RangeError` past {@link MAX_DEPTH}. */
63
+ enter(obj) {
64
+ enterDepth();
65
+ this.#open.add(obj);
66
+ }
67
+ /** Step back out of `obj`. */
68
+ leave(obj) {
69
+ exitDepth();
70
+ this.#open.delete(obj);
71
+ }
72
+ }
73
+ /** Keys one work unit covers, so a wide container weighs what it copies. */
74
+ const KEYS_PER_WORK_UNIT = 16;
75
+ /**
76
+ * A budget for walks that expand shared containers again (`merge` copies a shared row once per
77
+ * place it appears). A first expansion of a container is free; each later one costs one unit per
78
+ * 16 keys, rounded up, with a minimum of one unit even for an empty container. The walk throws
79
+ * `RangeError(message)` once it has spent more than `limit` units.
80
+ */
81
+ export class RevisitBudget {
82
+ #limit;
83
+ #message;
84
+ #seen = new WeakSet();
85
+ #spent = 0;
86
+ constructor(limit, message) {
87
+ this.#limit = limit;
88
+ this.#message = message;
89
+ }
90
+ /** Record that `obj`, holding `keys` own keys, is being expanded. */
91
+ note(obj, keys) {
92
+ if (!this.#seen.has(obj)) {
93
+ this.#seen.add(obj);
94
+ return;
95
+ }
96
+ this.#spent += Math.max(1, Math.ceil(keys / KEYS_PER_WORK_UNIT));
97
+ if (this.#spent > this.#limit)
98
+ throw new RangeError(this.#message);
99
+ }
100
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Type checks the platform does not have in one call.
3
+ * @module is
4
+ */
5
+ export { isArrayLike } from './isArrayLike.js';
6
+ export { isError } from './isError.js';
7
+ export { isNil } from './isNil.js';
8
+ export { isPlainObject } from './isPlainObject.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Type checks the platform does not have in one call.
3
+ * @module is
4
+ */
5
+ export { isArrayLike } from './isArrayLike.js';
6
+ export { isError } from './isError.js';
7
+ export { isNil } from './isNil.js';
8
+ export { isPlainObject } from './isPlainObject.js';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * True for a value with a `length` that is a non-negative safe integer, as lodash's `isArrayLike`
3
+ * decides and the generic `Array.prototype` methods (`Array.prototype.slice.call`) read by index:
4
+ * arrays, strings, typed arrays, `arguments` and objects like `{ length: 2 }`. Functions are not
5
+ * array-like, though they have a `length`.
6
+ * The guard is one-sided: `false` does not rule out a `{ length: number }` type.
7
+ * @param value Any value.
8
+ * @returns Whether `value` is array-like.
9
+ * @example
10
+ * ```ts
11
+ * isArrayLike([1, 2]) // true
12
+ * isArrayLike('abc') // true
13
+ * isArrayLike({ length: 1, 0: 'a' }) // true
14
+ * isArrayLike({ length: -1 }) // false
15
+ * isArrayLike(() => {}) // false
16
+ * ```
17
+ */
18
+ export declare function isArrayLike(value: unknown): value is ArrayLike<unknown>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * True for a value with a `length` that is a non-negative safe integer, as lodash's `isArrayLike`
3
+ * decides and the generic `Array.prototype` methods (`Array.prototype.slice.call`) read by index:
4
+ * arrays, strings, typed arrays, `arguments` and objects like `{ length: 2 }`. Functions are not
5
+ * array-like, though they have a `length`.
6
+ * The guard is one-sided: `false` does not rule out a `{ length: number }` type.
7
+ * @param value Any value.
8
+ * @returns Whether `value` is array-like.
9
+ * @example
10
+ * ```ts
11
+ * isArrayLike([1, 2]) // true
12
+ * isArrayLike('abc') // true
13
+ * isArrayLike({ length: 1, 0: 'a' }) // true
14
+ * isArrayLike({ length: -1 }) // false
15
+ * isArrayLike(() => {}) // false
16
+ * ```
17
+ */
18
+ export function isArrayLike(value) {
19
+ if (typeof value === 'string')
20
+ return true;
21
+ if (value === null || typeof value !== 'object' || !('length' in value))
22
+ return false;
23
+ const { length } = value;
24
+ return typeof length === 'number' && Number.isSafeInteger(length) && length >= 0;
25
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * True for an error from any realm, as `Error.isError` decides. Where the runtime lacks
3
+ * `Error.isError`, the object tag decides; `DOMException` is not recognized by this fallback.
4
+ * Removed once `Error.isError` is Baseline.
5
+ * @param value Any value.
6
+ * @returns Whether `value` is an error.
7
+ * @example
8
+ * ```ts
9
+ * isError(new TypeError('x')) // true
10
+ * isError({ name: 'Error', message: 'x' }) // false
11
+ * ```
12
+ */
13
+ export declare function isError(value: unknown): value is Error;