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,130 @@
1
+ /**
2
+ * A curried function over the parameters `A`: each call takes any leading slice of the parameters
3
+ * still missing and returns the result once no required parameter is left, else another `Curried`.
4
+ */
5
+ export type Curried<A extends unknown[], R> = <P extends Partial<A>>(...args: P) => A extends [...Extract<{
6
+ [K in keyof P]: unknown;
7
+ }, unknown[]>, ...infer Rest] ? [] extends Rest ? R : Curried<Rest, R> : R;
8
+ /**
9
+ * A function curried to an explicit arity, which the type system does not track: every call is
10
+ * typed as returning another `LooseFunction`, so narrow the final result yourself.
11
+ */
12
+ export type LooseFunction = (...args: unknown[]) => LooseFunction;
13
+ /**
14
+ * Creates a function that collects arguments until it has `arity` of them (default `fn.length`),
15
+ * then calls `fn` with them and the `this` of the latest call. Each partial application can be
16
+ * reused. Throws `RangeError` unless `arity` is a non-negative safe integer.
17
+ * @param fn The function to curry.
18
+ * @param arity How many arguments to wait for.
19
+ * @returns The curried function.
20
+ * @example
21
+ * ```ts
22
+ * const add = curry((a: number, b: number, c: number) => a + b + c)
23
+ * add(1)(2)(3) // 6
24
+ * add(1, 2, 3) // 6
25
+ * ```
26
+ */
27
+ export declare function curry<A extends unknown[], R>(fn: (...args: A) => R, arity?: undefined): Curried<A, R>;
28
+ /** Curries to an explicit arity, typed loosely. */
29
+ export declare function curry(fn: (...args: never[]) => unknown, arity: number): LooseFunction;
30
+ /**
31
+ * Composes functions left to right: the first receives every argument, each later one the
32
+ * previous result, and all run with the caller's `this`. With no functions it returns its first
33
+ * argument. Arrays of functions flatten one level, as in lodash.
34
+ * @returns The composed function.
35
+ * @example
36
+ * ```ts
37
+ * const shout = flow((s: string) => s.trim(), (s: string) => s.toUpperCase())
38
+ * shout(' hi ') // 'HI'
39
+ * ```
40
+ */
41
+ export declare function flow(): <T>(value: T) => T;
42
+ /** Flow over these functions, typed from first to last. */
43
+ export declare function flow<A extends unknown[], R>(fn: (...a: A) => R): (...a: A) => R;
44
+ /** Flow over these functions, typed from first to last. */
45
+ export declare function flow<A extends unknown[], B, C>(f1: (...a: A) => B, f2: (b: B) => C): (...a: A) => C;
46
+ /** Flow over these functions, typed from first to last. */
47
+ export declare function flow<A extends unknown[], B, C, D>(f1: (...a: A) => B, f2: (b: B) => C, f3: (c: C) => D): (...a: A) => D;
48
+ /** Flow over these functions, typed from first to last. */
49
+ export declare function flow<A extends unknown[], B, C, D, E>(f1: (...a: A) => B, f2: (b: B) => C, f3: (c: C) => D, f4: (d: D) => E): (...a: A) => E;
50
+ /** Flow over these functions, typed from first to last. */
51
+ export declare function flow<A extends unknown[], B, C, D, E, F>(f1: (...a: A) => B, f2: (b: B) => C, f3: (c: C) => D, f4: (d: D) => E, f5: (e: E) => F): (...a: A) => F;
52
+ /** Flow over these functions, typed from first to last. */
53
+ export declare function flow<A extends unknown[], B, C, D, E, F, G>(f1: (...a: A) => B, f2: (b: B) => C, f3: (c: C) => D, f4: (d: D) => E, f5: (e: E) => F, f6: (f: F) => G): (...a: A) => G;
54
+ /** Flow over any number of functions of one type, or arrays of them. */
55
+ export declare function flow<T>(...fns: (((value: T) => T) | readonly ((value: T) => T)[])[]): (value: T) => T;
56
+ /**
57
+ * Composes functions right to left, as {@link flow} does left to right. Does not reverse an array
58
+ * passed to it.
59
+ * @returns The composed function.
60
+ * @example
61
+ * ```ts
62
+ * const shout = compose((s: string) => s.toUpperCase(), (s: string) => s.trim())
63
+ * shout(' hi ') // 'HI'
64
+ * ```
65
+ */
66
+ export declare function compose(): <T>(value: T) => T;
67
+ /** Compose these functions, typed from last to first. */
68
+ export declare function compose<A extends unknown[], R>(fn: (...a: A) => R): (...a: A) => R;
69
+ /** Compose these functions, typed from last to first. */
70
+ export declare function compose<A extends unknown[], B, C>(f2: (b: B) => C, f1: (...a: A) => B): (...a: A) => C;
71
+ /** Compose these functions, typed from last to first. */
72
+ export declare function compose<A extends unknown[], B, C, D>(f3: (c: C) => D, f2: (b: B) => C, f1: (...a: A) => B): (...a: A) => D;
73
+ /** Compose these functions, typed from last to first. */
74
+ export declare function compose<A extends unknown[], B, C, D, E>(f4: (d: D) => E, f3: (c: C) => D, f2: (b: B) => C, f1: (...a: A) => B): (...a: A) => E;
75
+ /** Compose these functions, typed from last to first. */
76
+ export declare function compose<A extends unknown[], B, C, D, E, F>(f5: (e: E) => F, f4: (d: D) => E, f3: (c: C) => D, f2: (b: B) => C, f1: (...a: A) => B): (...a: A) => F;
77
+ /** Compose these functions, typed from last to first. */
78
+ export declare function compose<A extends unknown[], B, C, D, E, F, G>(f6: (f: F) => G, f5: (e: E) => F, f4: (d: D) => E, f3: (c: C) => D, f2: (b: B) => C, f1: (...a: A) => B): (...a: A) => G;
79
+ /** Compose any number of functions of one type, or arrays of them. */
80
+ export declare function compose<T>(...fns: (((value: T) => T) | readonly ((value: T) => T)[])[]): (value: T) => T;
81
+ /** The store a memoized function reads and writes; a `Map` or anything with its interface. */
82
+ export interface MemoizeCache<K, V> {
83
+ /** Returns the stored value for `key`. */
84
+ get(key: K): V | undefined;
85
+ /** Stores `value` under `key`. */
86
+ set(key: K, value: V): unknown;
87
+ /** Whether `key` is stored. */
88
+ has(key: K): boolean;
89
+ /** Removes `key`. */
90
+ delete(key: K): boolean;
91
+ /** Removes every key. */
92
+ clear(): void;
93
+ /** How many keys are stored. */
94
+ readonly size: number;
95
+ }
96
+ /** A memoized function and its replaceable `cache`. */
97
+ export type Memoized<F extends (...args: never[]) => unknown> = ((this: ThisParameterType<F>, ...args: Parameters<F>) => ReturnType<F>) & {
98
+ /** The store lookups read; assign another `Map`-like store to replace it. */
99
+ cache: MemoizeCache<unknown, ReturnType<F>>;
100
+ };
101
+ /**
102
+ * Creates a function that caches the result of `fn` per key. The key is the first argument, or
103
+ * what `resolver` returns for the arguments. Both run with the caller's `this`. Lookups use `has`,
104
+ * so `undefined` results are cached too. The cache never evicts: clear it with
105
+ * `memoized.cache.clear()` or assign a bounded store to `memoized.cache`.
106
+ * @param fn The function to memoize.
107
+ * @param resolver Computes the cache key from the arguments.
108
+ * @returns The memoized function.
109
+ * @example
110
+ * ```ts
111
+ * const square = memoize((n: number) => n * n)
112
+ * square(4) // 16, computed
113
+ * square(4) // 16, from square.cache
114
+ * ```
115
+ */
116
+ export declare function memoize<F extends (...args: never[]) => unknown>(fn: F, resolver?: (...args: Parameters<F>) => unknown): Memoized<F>;
117
+ /**
118
+ * Creates a function that calls `fn` once and returns that result on every later call. A call
119
+ * made while `fn` is still running, or after it threw, returns `undefined` without calling it.
120
+ * `fn` is released after its call.
121
+ * @param fn The function to restrict.
122
+ * @returns The restricted function.
123
+ * @example
124
+ * ```ts
125
+ * const init = once(() => console.log('ready'))
126
+ * init() // logs 'ready'
127
+ * init() // does nothing
128
+ * ```
129
+ */
130
+ export declare function once<A extends unknown[], R>(fn: (...args: A) => R): (...args: A) => R | undefined;
@@ -0,0 +1,113 @@
1
+ import { assertFunction } from './shared.js';
2
+ export function curry(fn, arity) {
3
+ assertFunction(fn, 'fn');
4
+ const required = arity ?? fn.length;
5
+ if (!Number.isSafeInteger(required) || required < 0) {
6
+ throw new RangeError('arity must be a non-negative safe integer');
7
+ }
8
+ const curried = function (...args) {
9
+ if (args.length >= required)
10
+ return Reflect.apply(fn, this, args);
11
+ return function (...more) {
12
+ return Reflect.apply(curried, this, args.concat(more));
13
+ };
14
+ };
15
+ return curried;
16
+ }
17
+ /**
18
+ * Flattens one level, as lodash `flow` does, and refuses anything but functions. Holes in a nested
19
+ * array count as `undefined`, so they are refused too.
20
+ */
21
+ function pipelineOf(fns) {
22
+ const pipeline = [];
23
+ for (const entry of fns) {
24
+ if (Array.isArray(entry))
25
+ pipeline.push(...Array.from(entry));
26
+ // `Array.isArray` does not narrow a readonly array out of the union
27
+ else
28
+ pipeline.push(entry);
29
+ }
30
+ for (const fn of pipeline)
31
+ assertFunction(fn, 'each argument');
32
+ return pipeline;
33
+ }
34
+ function pipeThrough(thisArg, fns, args) {
35
+ if (fns.length === 0)
36
+ return args[0];
37
+ let result = Reflect.apply(fns[0], thisArg, args);
38
+ for (let i = 1; i < fns.length; i++)
39
+ result = Reflect.apply(fns[i], thisArg, [result]);
40
+ return result;
41
+ }
42
+ /** @param fns The functions to apply, left to right. */
43
+ export function flow(...fns) {
44
+ const pipeline = pipelineOf(fns);
45
+ return function (...args) {
46
+ return pipeThrough(this, pipeline, args);
47
+ };
48
+ }
49
+ /** @param fns The functions to apply, right to left. */
50
+ export function compose(...fns) {
51
+ const reversed = pipelineOf(fns).reverse();
52
+ return function (...args) {
53
+ return pipeThrough(this, reversed, args);
54
+ };
55
+ }
56
+ /**
57
+ * Creates a function that caches the result of `fn` per key. The key is the first argument, or
58
+ * what `resolver` returns for the arguments. Both run with the caller's `this`. Lookups use `has`,
59
+ * so `undefined` results are cached too. The cache never evicts: clear it with
60
+ * `memoized.cache.clear()` or assign a bounded store to `memoized.cache`.
61
+ * @param fn The function to memoize.
62
+ * @param resolver Computes the cache key from the arguments.
63
+ * @returns The memoized function.
64
+ * @example
65
+ * ```ts
66
+ * const square = memoize((n: number) => n * n)
67
+ * square(4) // 16, computed
68
+ * square(4) // 16, from square.cache
69
+ * ```
70
+ */
71
+ export function memoize(fn, resolver) {
72
+ assertFunction(fn, 'fn');
73
+ if (resolver != null)
74
+ assertFunction(resolver, 'resolver');
75
+ const cache = new Map();
76
+ const memoized = Object.assign(function (...args) {
77
+ const key = resolver ? Reflect.apply(resolver, this, args) : args[0];
78
+ const store = memoized.cache;
79
+ // `has` said the key is stored, so `get` returns a stored `ReturnType<F>`
80
+ if (store.has(key))
81
+ return store.get(key);
82
+ const value = Reflect.apply(fn, this, args);
83
+ store.set(key, value);
84
+ return value;
85
+ }, { cache });
86
+ return memoized;
87
+ }
88
+ /**
89
+ * Creates a function that calls `fn` once and returns that result on every later call. A call
90
+ * made while `fn` is still running, or after it threw, returns `undefined` without calling it.
91
+ * `fn` is released after its call.
92
+ * @param fn The function to restrict.
93
+ * @returns The restricted function.
94
+ * @example
95
+ * ```ts
96
+ * const init = once(() => console.log('ready'))
97
+ * init() // logs 'ready'
98
+ * init() // does nothing
99
+ * ```
100
+ */
101
+ export function once(fn) {
102
+ assertFunction(fn, 'fn');
103
+ let pending = fn;
104
+ let value;
105
+ return function (...args) {
106
+ if (pending) {
107
+ const target = pending;
108
+ pending = undefined;
109
+ value = Reflect.apply(target, this, args);
110
+ }
111
+ return value;
112
+ };
113
+ }
@@ -0,0 +1,18 @@
1
+ /** The digest algorithms every `crypto.subtle` implementation supports. */
2
+ export type DigestAlgorithm = 'SHA-1' | 'SHA-256' | 'SHA-384' | 'SHA-512';
3
+ /**
4
+ * Cryptographic digest of `data` as a lowercase hex string, through `crypto.subtle.digest`. A
5
+ * string is hashed as UTF-8, with each lone surrogate as U+FFFD as `TextEncoder` writes it, so
6
+ * `'\uD800'` and `'\uDFFF'` hash alike; bytes on shared memory are copied first, since
7
+ * `crypto.subtle` refuses them. Rejects with `TypeError` where `crypto.subtle` is missing (insecure
8
+ * browser contexts) and for data that is neither a string nor bytes.
9
+ * @param algorithm `'SHA-1'`, `'SHA-256'`, `'SHA-384'` or `'SHA-512'`.
10
+ * @param data A string, an `ArrayBuffer` or `SharedArrayBuffer`, or a typed array or `DataView`.
11
+ * @returns A promise of the hex digest.
12
+ * @example
13
+ * ```ts
14
+ * await digest('SHA-256', 'abc')
15
+ * // 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'
16
+ * ```
17
+ */
18
+ export declare function digest(algorithm: DigestAlgorithm, data: string | ArrayBuffer | SharedArrayBuffer | ArrayBufferView): Promise<string>;
@@ -0,0 +1,26 @@
1
+ import { bytesToHex, isArrayBuffer, toBytes } from '../internal/bytes.js';
2
+ /**
3
+ * Cryptographic digest of `data` as a lowercase hex string, through `crypto.subtle.digest`. A
4
+ * string is hashed as UTF-8, with each lone surrogate as U+FFFD as `TextEncoder` writes it, so
5
+ * `'\uD800'` and `'\uDFFF'` hash alike; bytes on shared memory are copied first, since
6
+ * `crypto.subtle` refuses them. Rejects with `TypeError` where `crypto.subtle` is missing (insecure
7
+ * browser contexts) and for data that is neither a string nor bytes.
8
+ * @param algorithm `'SHA-1'`, `'SHA-256'`, `'SHA-384'` or `'SHA-512'`.
9
+ * @param data A string, an `ArrayBuffer` or `SharedArrayBuffer`, or a typed array or `DataView`.
10
+ * @returns A promise of the hex digest.
11
+ * @example
12
+ * ```ts
13
+ * await digest('SHA-256', 'abc')
14
+ * // 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'
15
+ * ```
16
+ */
17
+ export async function digest(algorithm, data) {
18
+ const subtle = globalThis.crypto?.subtle;
19
+ if (subtle === undefined)
20
+ throw new TypeError('crypto.subtle is not available');
21
+ const view = toBytes(data);
22
+ const bytes = isArrayBuffer(view.buffer)
23
+ ? new Uint8Array(view.buffer, view.byteOffset, view.byteLength)
24
+ : view.slice();
25
+ return bytesToHex(new Uint8Array(await subtle.digest(algorithm, bytes)));
26
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Structural hash, consistent with `isEqual`: whenever `isEqual(a, b)` is true, `hash(a)` equals
3
+ * `hash(b)`, so values can be bucketed before they are compared. It reads the kinds `isEqual`
4
+ * compares by content (plain objects, arrays, `Map`, `Set`, Dates, RegExps, buffers, typed arrays,
5
+ * boxed primitives, errors, `arguments`), key order aside; class instances, functions,
6
+ * unregistered symbols and `Map` keys or `Set` members that are objects hash by identity, which
7
+ * holds only for the life of the process. Not cryptographic, and not resistant to keys crafted to
8
+ * collide.
9
+ *
10
+ * It reads at most 8 levels below the root, and structure deeper than that counts only by its
11
+ * kind. So cyclic values that `isEqual` equates hash alike, and `hash`, unlike the other deep walks,
12
+ * never throws on deep input.
13
+ * @param value Any value.
14
+ * @returns An unsigned 32-bit integer.
15
+ * @example
16
+ * ```ts
17
+ * hash({ a: [1, 2], b: 'x' }) === hash({ b: 'x', a: [1, 2] }) // true
18
+ * hash(new Map([[1, NaN]])) === hash(new Map([[1, NaN]])) // true
19
+ * hash(0) === hash(-0) // true
20
+ * ```
21
+ */
22
+ export declare function hash(value: unknown): number;
@@ -0,0 +1,252 @@
1
+ import { enumerableKeys, ERROR_LOCATION_KEYS } from '../internal/keys.js';
2
+ import { bytesOf, contentKindOf, isFloatView, typedArrayName, unbox } from '../internal/kind.js';
3
+ import { walkArrayIndices } from '../internal/sparse.js';
4
+ import { hashString } from './hashString.js';
5
+ /** Levels below the root a hash reads; deeper structure counts only by its kind. */
6
+ const UNFOLD_DEPTH = 8;
7
+ /** Past this many objects a hash stops remembering them; only time grows, not memory. */
8
+ const MAX_TRACKED_OBJECTS = 2 ** 24;
9
+ /** Seeds that keep the hash of one kind apart from another's. */
10
+ const Tag = {
11
+ Undefined: 4097,
12
+ Null: 4098,
13
+ True: 4099,
14
+ False: 4100,
15
+ NaN: 4101,
16
+ Number: 4102,
17
+ BigInt: 4103,
18
+ String: 4104,
19
+ Symbol: 4105,
20
+ Plain: 4106,
21
+ Array: 4107,
22
+ Map: 4108,
23
+ Set: 4109,
24
+ Date: 4110,
25
+ RegExp: 4111,
26
+ Buffer: 4112,
27
+ View: 4113,
28
+ Boxed: 4114,
29
+ Error: 4115,
30
+ Arguments: 4116,
31
+ NoCause: 4117
32
+ };
33
+ function mix(state, value) {
34
+ const h = Math.imul(state ^ value, 0x5bd1e995);
35
+ return h ^ (h >>> 15);
36
+ }
37
+ function finish(state) {
38
+ let h = state ^ (state >>> 16);
39
+ h = Math.imul(h, 0x85ebca6b);
40
+ h ^= h >>> 13;
41
+ h = Math.imul(h, 0xc2b2ae35);
42
+ return (h ^ (h >>> 16)) >>> 0;
43
+ }
44
+ function canHoldSymbols() {
45
+ try {
46
+ new WeakMap().set(Symbol(), 0);
47
+ return true;
48
+ }
49
+ catch {
50
+ return false;
51
+ }
52
+ }
53
+ const ids = new WeakMap();
54
+ const symbolsAreWeakKeys = canHoldSymbols();
55
+ let nextId = 1;
56
+ function identityOf(value) {
57
+ let id = ids.get(value);
58
+ if (id === undefined)
59
+ ids.set(value, (id = nextId++));
60
+ return id;
61
+ }
62
+ /**
63
+ * A registered symbol by its key; any other by identity where the runtime can hold it weakly, and
64
+ * by its description where it cannot, so that hashing never keeps a symbol alive.
65
+ */
66
+ function symbolHash(value) {
67
+ const key = Symbol.keyFor(value);
68
+ if (key !== undefined)
69
+ return mix(Tag.Symbol, hashString(key));
70
+ if (!symbolsAreWeakKeys)
71
+ return mix(Tag.Symbol, hashString(value.description ?? ''));
72
+ return mix(Tag.Symbol, identityOf(value));
73
+ }
74
+ /** By SameValueZero: `0` and `-0` share a hash, and so do all NaNs. */
75
+ function numberHash(value) {
76
+ if (value !== value)
77
+ return Tag.NaN;
78
+ return mix(Tag.Number, hashString(String(value === 0 ? 0 : value)));
79
+ }
80
+ /** Hash of a value compared by SameValueZero: a primitive by value, an object by identity. */
81
+ function memberHash(value) {
82
+ switch (typeof value) {
83
+ case 'undefined':
84
+ return Tag.Undefined;
85
+ case 'boolean':
86
+ return value ? Tag.True : Tag.False;
87
+ case 'number':
88
+ return numberHash(value);
89
+ case 'bigint':
90
+ return mix(Tag.BigInt, hashString(value.toString(16)));
91
+ case 'string':
92
+ return mix(Tag.String, hashString(value));
93
+ case 'symbol':
94
+ return symbolHash(value);
95
+ default:
96
+ return value === null ? Tag.Null : identityOf(value);
97
+ }
98
+ }
99
+ function bytesHash(bytes) {
100
+ let state = bytes.length;
101
+ for (const byte of bytes)
102
+ state = mix(state, byte);
103
+ return state;
104
+ }
105
+ /** What a container hashes to once the levels a hash reads run out. */
106
+ const CONTAINER_TAGS = {
107
+ plain: Tag.Plain,
108
+ array: Tag.Array,
109
+ arguments: Tag.Arguments,
110
+ map: Tag.Map,
111
+ error: Tag.Error
112
+ };
113
+ /** One `hash` call: hashes of shared objects, by how many levels were left below them. */
114
+ class Unfolding {
115
+ #memo = new Map();
116
+ of(value, levels) {
117
+ if (typeof value !== 'object' || value === null)
118
+ return memberHash(value);
119
+ let byLevel = this.#memo.get(value);
120
+ const known = byLevel?.[levels];
121
+ if (known !== undefined)
122
+ return known;
123
+ const hashed = this.#object(value, levels);
124
+ if (byLevel === undefined && this.#memo.size < MAX_TRACKED_OBJECTS) {
125
+ this.#memo.set(value, (byLevel = []));
126
+ }
127
+ if (byLevel !== undefined)
128
+ byLevel[levels] = hashed;
129
+ return hashed;
130
+ }
131
+ #object(value, levels) {
132
+ const kind = contentKindOf(value);
133
+ switch (kind) {
134
+ case 'other':
135
+ return identityOf(value);
136
+ case 'set': {
137
+ let sum = 0;
138
+ for (const v of Set.prototype.values.call(value))
139
+ sum = (sum + finish(memberHash(v))) | 0;
140
+ return mix(mix(Tag.Set, value.size), sum);
141
+ }
142
+ case 'date':
143
+ return mix(Tag.Date, numberHash(Date.prototype.getTime.call(value)));
144
+ case 'regexp':
145
+ return mix(mix(Tag.RegExp, hashString(value.source)), hashString(value.flags));
146
+ case 'buffer':
147
+ return mix(Tag.Buffer, bytesHash(bytesOf(value)));
148
+ case 'view':
149
+ return this.#view(value);
150
+ case 'boxed':
151
+ return mix(Tag.Boxed, memberHash(unbox(value)));
152
+ default:
153
+ return levels === 0 ? CONTAINER_TAGS[kind] : this.#container(value, kind, levels - 1);
154
+ }
155
+ }
156
+ /** The kinds that hold other values, read one level further down. */
157
+ #container(value, kind, below) {
158
+ switch (kind) {
159
+ case 'plain':
160
+ return this.#record(value, below);
161
+ case 'array':
162
+ return this.#array(value, below, Tag.Array);
163
+ case 'arguments':
164
+ return this.#array(value, below, Tag.Arguments);
165
+ case 'map': {
166
+ let sum = 0;
167
+ for (const [k, v] of Map.prototype.entries.call(value)) {
168
+ sum = (sum + finish(mix(memberHash(k), this.of(v, below)))) | 0;
169
+ }
170
+ return mix(mix(Tag.Map, value.size), sum);
171
+ }
172
+ case 'error':
173
+ return this.#error(value, below);
174
+ }
175
+ }
176
+ /** Name, message, an own `cause` and own enumerable properties, as `isEqual` compares errors. */
177
+ #error(value, below) {
178
+ const cause = Object.hasOwn(value, 'cause') ? this.of(value.cause, below) : Tag.NoCause;
179
+ let state = mix(Tag.Error, this.of(value.name, below));
180
+ state = mix(mix(state, this.of(value.message, below)), cause);
181
+ return mix(state, this.#record(value, below, ERROR_LOCATION_KEYS));
182
+ }
183
+ #record(value, below, ignored) {
184
+ const record = value;
185
+ let sum = 0;
186
+ let count = 0;
187
+ for (const key of enumerableKeys(value)) {
188
+ if (ignored?.has(key))
189
+ continue;
190
+ sum = (sum + finish(mix(memberHash(key), this.of(record[key], below)))) | 0;
191
+ count++;
192
+ }
193
+ return mix(mix(Tag.Plain, count), sum);
194
+ }
195
+ /** `undefined` and holes add nothing, since `isEqual` takes a hole to equal `undefined`. */
196
+ #array(value, below, tag) {
197
+ let sum = 0;
198
+ let i = 0;
199
+ for (; i < value.length && i in value; i++) {
200
+ const item = value[i];
201
+ if (item !== undefined)
202
+ sum = (sum + finish(mix(i, this.of(item, below)))) | 0;
203
+ }
204
+ if (i === value.length)
205
+ return mix(mix(tag, value.length), sum);
206
+ walkArrayIndices(value, (ev) => {
207
+ if (ev.kind !== 'index' || ev.index < i)
208
+ return;
209
+ const item = value[ev.index];
210
+ if (item !== undefined)
211
+ sum = (sum + finish(mix(ev.index, this.of(item, below)))) | 0;
212
+ });
213
+ return mix(mix(tag, value.length), sum);
214
+ }
215
+ #view(value) {
216
+ const tag = mix(Tag.View, hashString(typedArrayName(value) ?? 'DataView'));
217
+ if (!isFloatView(value))
218
+ return mix(tag, bytesHash(bytesOf(value)));
219
+ const floats = value;
220
+ const length = floats.length;
221
+ let state = mix(tag, length);
222
+ for (let i = 0; i < length; i++)
223
+ state = mix(state, numberHash(floats[i]));
224
+ return state;
225
+ }
226
+ }
227
+ /**
228
+ * Structural hash, consistent with `isEqual`: whenever `isEqual(a, b)` is true, `hash(a)` equals
229
+ * `hash(b)`, so values can be bucketed before they are compared. It reads the kinds `isEqual`
230
+ * compares by content (plain objects, arrays, `Map`, `Set`, Dates, RegExps, buffers, typed arrays,
231
+ * boxed primitives, errors, `arguments`), key order aside; class instances, functions,
232
+ * unregistered symbols and `Map` keys or `Set` members that are objects hash by identity, which
233
+ * holds only for the life of the process. Not cryptographic, and not resistant to keys crafted to
234
+ * collide.
235
+ *
236
+ * It reads at most 8 levels below the root, and structure deeper than that counts only by its
237
+ * kind. So cyclic values that `isEqual` equates hash alike, and `hash`, unlike the other deep walks,
238
+ * never throws on deep input.
239
+ * @param value Any value.
240
+ * @returns An unsigned 32-bit integer.
241
+ * @example
242
+ * ```ts
243
+ * hash({ a: [1, 2], b: 'x' }) === hash({ b: 'x', a: [1, 2] }) // true
244
+ * hash(new Map([[1, NaN]])) === hash(new Map([[1, NaN]])) // true
245
+ * hash(0) === hash(-0) // true
246
+ * ```
247
+ */
248
+ export function hash(value) {
249
+ if (typeof value !== 'object' || value === null)
250
+ return finish(memberHash(value));
251
+ return finish(new Unfolding().of(value, UNFOLD_DEPTH));
252
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 32-bit FNV-1a hash of the UTF-8 bytes of `str`, so it matches FNV-1a in other languages. Lone
3
+ * surrogates count as U+FFFD, as `TextEncoder` writes them. Fast and well spread, but not
4
+ * cryptographic.
5
+ * @param str The string to hash.
6
+ * @returns An unsigned 32-bit integer.
7
+ * @example
8
+ * ```ts
9
+ * hashString('') // 2166136261
10
+ * hashString('a') // 3826002220
11
+ * ```
12
+ */
13
+ export declare function hashString(str: string): number;
@@ -0,0 +1,53 @@
1
+ const FNV_OFFSET = 0x811c9dc5;
2
+ const FNV_PRIME = 0x01000193;
3
+ /** One byte into an FNV-1a state. */
4
+ function step(state, byte) {
5
+ return Math.imul(state ^ byte, FNV_PRIME);
6
+ }
7
+ /**
8
+ * 32-bit FNV-1a hash of the UTF-8 bytes of `str`, so it matches FNV-1a in other languages. Lone
9
+ * surrogates count as U+FFFD, as `TextEncoder` writes them. Fast and well spread, but not
10
+ * cryptographic.
11
+ * @param str The string to hash.
12
+ * @returns An unsigned 32-bit integer.
13
+ * @example
14
+ * ```ts
15
+ * hashString('') // 2166136261
16
+ * hashString('a') // 3826002220
17
+ * ```
18
+ */
19
+ export function hashString(str) {
20
+ if (typeof str !== 'string')
21
+ throw new TypeError('hashString expects a string');
22
+ let state = FNV_OFFSET;
23
+ // Encodes in place rather than through `TextEncoder`: `hash` calls this for every string and
24
+ // number it meets, and an allocation per call made it about five times slower.
25
+ for (let i = 0; i < str.length; i++) {
26
+ let code = str.charCodeAt(i);
27
+ if (code >= 0xd800 && code <= 0xdbff && i + 1 < str.length) {
28
+ const low = str.charCodeAt(i + 1);
29
+ if (low >= 0xdc00 && low <= 0xdfff) {
30
+ code = 0x10000 + ((code - 0xd800) << 10) + (low - 0xdc00);
31
+ i++;
32
+ }
33
+ }
34
+ if (code >= 0xd800 && code <= 0xdfff)
35
+ code = 0xfffd;
36
+ if (code < 0x80) {
37
+ state = step(state, code);
38
+ }
39
+ else if (code < 0x800) {
40
+ state = step(step(state, 0xc0 | (code >> 6)), 0x80 | (code & 0x3f));
41
+ }
42
+ else if (code < 0x10000) {
43
+ state = step(step(step(state, 0xe0 | (code >> 12)), 0x80 | ((code >> 6) & 0x3f)), 0x80 | (code & 0x3f));
44
+ }
45
+ else {
46
+ state = step(state, 0xf0 | (code >> 18));
47
+ state = step(state, 0x80 | ((code >> 12) & 0x3f));
48
+ state = step(state, 0x80 | ((code >> 6) & 0x3f));
49
+ state = step(state, 0x80 | (code & 0x3f));
50
+ }
51
+ }
52
+ return state >>> 0;
53
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * String, structural and cryptographic hashes, and a stable JSON form.
3
+ * @module hash
4
+ */
5
+ export { type DigestAlgorithm, digest } from './digest.js';
6
+ export { hash } from './hash.js';
7
+ export { hashString } from './hashString.js';
8
+ export { stableStringify } from './stableStringify.js';
@@ -0,0 +1,8 @@
1
+ /**
2
+ * String, structural and cryptographic hashes, and a stable JSON form.
3
+ * @module hash
4
+ */
5
+ export { digest } from './digest.js';
6
+ export { hash } from './hash.js';
7
+ export { hashString } from './hashString.js';
8
+ export { stableStringify } from './stableStringify.js';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `JSON.stringify` with every object's keys sorted, so equal data always gives the same text (for
3
+ * cache keys, signatures and snapshots). It follows `JSON.stringify` otherwise. A value's own or
4
+ * inherited `toJSON` is called with its key, as JSON's contract has it, so Dates write their ISO
5
+ * string and types such as `Decimal` write their JSON form. Boxed primitives unbox, `undefined`,
6
+ * functions and symbols are dropped from objects and become `null` in arrays, and non-finite
7
+ * numbers become `null`. A cycle or a bigint throws `TypeError`, nesting past 1000 levels throws
8
+ * `RangeError`, and so does a huge sparse array. As in JSON, a `Map`, a `Set` or a class instance
9
+ * without `toJSON` writes only its own enumerable keys, often `'{}'`, so equal text does not imply
10
+ * equal data for those kinds.
11
+ * @param value Any value.
12
+ * @returns The JSON text, or `undefined` for a value JSON cannot write (`undefined`, a function, a
13
+ * symbol).
14
+ * @example
15
+ * ```ts
16
+ * stableStringify({ b: 1, a: [true, { d: 2, c: 3 }] }) // '{"a":[true,{"c":3,"d":2}],"b":1}'
17
+ * ```
18
+ */
19
+ export declare function stableStringify(value: unknown): string | undefined;