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.
- package/README.md +397 -91
- package/dist/array/index.d.ts +9 -0
- package/dist/array/index.js +9 -0
- package/dist/array/list.d.ts +99 -0
- package/dist/array/list.js +133 -0
- package/dist/array/sets.d.ts +130 -0
- package/dist/array/sets.js +213 -0
- package/dist/async/index.d.ts +6 -0
- package/dist/async/index.js +6 -0
- package/dist/async/retry.d.ts +38 -0
- package/dist/async/retry.js +56 -0
- package/dist/async/sleep.d.ts +42 -0
- package/dist/async/sleep.js +76 -0
- package/dist/collections/bisect.d.ts +103 -0
- package/dist/collections/bisect.js +157 -0
- package/dist/collections/deque.d.ts +67 -97
- package/dist/collections/deque.js +197 -256
- package/dist/collections/entries.d.ts +89 -0
- package/dist/collections/entries.js +131 -0
- package/dist/collections/frozen-set.d.ts +42 -0
- package/dist/collections/frozen-set.js +64 -0
- package/dist/collections/group.d.ts +141 -0
- package/dist/collections/group.js +241 -0
- package/dist/collections/heap.d.ts +64 -0
- package/dist/collections/heap.js +205 -0
- package/dist/collections/index.d.ts +15 -623
- package/dist/collections/index.js +14 -844
- package/dist/collections/internal/arrayKeys.d.ts +19 -0
- package/dist/collections/internal/arrayKeys.js +83 -0
- package/dist/collections/internal/invariants.d.ts +4 -0
- package/dist/collections/internal/invariants.js +12 -0
- package/dist/collections/internal/iterable.d.ts +25 -0
- package/dist/collections/internal/iterable.js +62 -0
- package/dist/collections/iterate.d.ts +162 -0
- package/dist/collections/iterate.js +188 -0
- package/dist/collections/lru-cache.d.ts +58 -0
- package/dist/collections/lru-cache.js +164 -0
- package/dist/collections/order.d.ts +19 -0
- package/dist/collections/order.js +38 -0
- package/dist/collections/shape.d.ts +32 -0
- package/dist/collections/shape.js +86 -0
- package/dist/collections/sorted-map.d.ts +171 -0
- package/dist/collections/sorted-map.js +845 -0
- package/dist/collections/sorted-set.d.ts +103 -0
- package/dist/collections/sorted-set.js +147 -0
- package/dist/collections/splay-tree.d.ts +82 -0
- package/dist/collections/splay-tree.js +354 -0
- package/dist/collections/trie.d.ts +58 -0
- package/dist/collections/trie.js +196 -0
- package/dist/decimal/currency.d.ts +211 -0
- package/dist/decimal/currency.js +321 -0
- package/dist/decimal/decimal.d.ts +299 -0
- package/dist/decimal/decimal.js +660 -0
- package/dist/decimal/index.d.ts +11 -148
- package/dist/decimal/index.js +10 -410
- package/dist/decimal/internal/bits.d.ts +2 -0
- package/dist/decimal/internal/bits.js +7 -0
- package/dist/decimal/internal/echo.d.ts +4 -0
- package/dist/decimal/internal/echo.js +6 -0
- package/dist/decimal/internal/isqrt.d.ts +9 -0
- package/dist/decimal/internal/isqrt.js +34 -0
- package/dist/decimal/internal/locale.d.ts +7 -0
- package/dist/decimal/internal/locale.js +24 -0
- package/dist/decimal/internal/minor-units.d.ts +2 -0
- package/dist/decimal/internal/minor-units.js +33 -0
- package/dist/decimal/internal/pow10.d.ts +24 -0
- package/dist/decimal/internal/pow10.js +96 -0
- package/dist/encoding/base64.d.ts +39 -0
- package/dist/encoding/base64.js +53 -0
- package/dist/encoding/hex.d.ts +23 -0
- package/dist/encoding/hex.js +34 -0
- package/dist/encoding/index.d.ts +6 -0
- package/dist/encoding/index.js +6 -0
- package/dist/function/debounce.d.ts +68 -0
- package/dist/function/debounce.js +203 -0
- package/dist/function/index.d.ts +6 -0
- package/dist/function/index.js +6 -0
- package/dist/function/shared.d.ts +2 -0
- package/dist/function/shared.js +5 -0
- package/dist/function/wrap.d.ts +130 -0
- package/dist/function/wrap.js +113 -0
- package/dist/hash/digest.d.ts +18 -0
- package/dist/hash/digest.js +26 -0
- package/dist/hash/hash.d.ts +22 -0
- package/dist/hash/hash.js +252 -0
- package/dist/hash/hashString.d.ts +13 -0
- package/dist/hash/hashString.js +53 -0
- package/dist/hash/index.d.ts +8 -0
- package/dist/hash/index.js +8 -0
- package/dist/hash/stableStringify.d.ts +19 -0
- package/dist/hash/stableStringify.js +102 -0
- package/dist/id/index.d.ts +7 -0
- package/dist/id/index.js +7 -0
- package/dist/id/nanoid.d.ts +16 -0
- package/dist/id/nanoid.js +65 -0
- package/dist/id/uniqueId.d.ts +14 -0
- package/dist/id/uniqueId.js +20 -0
- package/dist/id/uuid.d.ts +25 -0
- package/dist/id/uuid.js +64 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +15 -8
- package/dist/internal/bytes.d.ts +11 -0
- package/dist/internal/bytes.js +33 -0
- package/dist/internal/codec.d.ts +11 -0
- package/dist/internal/codec.js +84 -0
- package/dist/internal/compare.d.ts +10 -0
- package/dist/internal/compare.js +26 -0
- package/dist/internal/crypto.d.ts +5 -0
- package/dist/internal/crypto.js +11 -0
- package/dist/internal/keys.d.ts +12 -0
- package/dist/internal/keys.js +23 -0
- package/dist/internal/kind.d.ts +44 -0
- package/dist/internal/kind.js +139 -0
- package/dist/internal/sparse.d.ts +51 -0
- package/dist/internal/sparse.js +104 -0
- package/dist/internal/text.d.ts +7 -0
- package/dist/internal/text.js +15 -0
- package/dist/internal/timer.d.ts +10 -0
- package/dist/internal/timer.js +17 -0
- package/dist/internal/truncate.d.ts +10 -0
- package/dist/internal/truncate.js +22 -0
- package/dist/internal/walk.d.ts +47 -0
- package/dist/internal/walk.js +100 -0
- package/dist/is/index.d.ts +8 -0
- package/dist/is/index.js +8 -0
- package/dist/is/isArrayLike.d.ts +18 -0
- package/dist/is/isArrayLike.js +25 -0
- package/dist/is/isError.d.ts +13 -0
- package/dist/is/isError.js +18 -0
- package/dist/is/isNil.d.ts +12 -0
- package/dist/is/isNil.js +14 -0
- package/dist/is/isPlainObject.d.ts +15 -0
- package/dist/is/isPlainObject.js +34 -0
- package/dist/number/index.d.ts +7 -0
- package/dist/number/index.js +7 -0
- package/dist/number/round.d.ts +86 -0
- package/dist/number/round.js +130 -0
- package/dist/number/stats.d.ts +52 -0
- package/dist/number/stats.js +115 -0
- package/dist/object/cloneDeep.d.ts +28 -0
- package/dist/object/cloneDeep.js +200 -0
- package/dist/object/index.d.ts +14 -0
- package/dist/object/index.js +13 -0
- package/dist/object/isEqual.d.ts +64 -0
- package/dist/object/isEqual.js +289 -0
- package/dist/object/matches.d.ts +40 -0
- package/dist/object/matches.js +284 -0
- package/dist/object/merge.d.ts +66 -0
- package/dist/object/merge.js +272 -0
- package/dist/object/parsePath.d.ts +22 -0
- package/dist/object/parsePath.js +111 -0
- package/dist/object/path.d.ts +85 -0
- package/dist/object/path.js +208 -0
- package/dist/object/pick.d.ts +91 -0
- package/dist/object/pick.js +180 -0
- package/dist/object/reshape.d.ts +73 -0
- package/dist/object/reshape.js +144 -0
- package/dist/random/index.d.ts +96 -32
- package/dist/random/index.js +215 -53
- package/dist/string/case.d.ts +71 -0
- package/dist/string/case.js +152 -0
- package/dist/string/fold.d.ts +35 -0
- package/dist/string/fold.js +100 -0
- package/dist/string/index.d.ts +6 -187
- package/dist/string/index.js +6 -224
- package/dist/string/truncate.d.ts +25 -0
- package/dist/string/truncate.js +44 -0
- package/dist/string/words.d.ts +27 -0
- package/dist/string/words.js +241 -0
- package/package.json +99 -51
- package/dist/collections/BTree.d.ts +0 -230
- package/dist/collections/BTree.js +0 -1143
- package/dist/collections/Heap.d.ts +0 -69
- package/dist/collections/Heap.js +0 -181
- package/dist/collections/LRUCache.d.ts +0 -83
- package/dist/collections/LRUCache.js +0 -139
- package/dist/collections/SortedMap.d.ts +0 -92
- package/dist/collections/SortedMap.js +0 -131
- package/dist/collections/SortedSet.d.ts +0 -69
- package/dist/collections/SortedSet.js +0 -99
- package/dist/collections/SortedTree.d.ts +0 -103
- package/dist/collections/SortedTree.js +0 -142
- package/dist/collections/SplayTree.d.ts +0 -107
- package/dist/collections/SplayTree.js +0 -351
- package/dist/collections/Trie.d.ts +0 -42
- package/dist/collections/Trie.js +0 -104
- package/dist/collections/abc.d.ts +0 -152
- package/dist/collections/abc.js +0 -39
- package/dist/collections/frozenset.d.ts +0 -19
- package/dist/collections/frozenset.js +0 -33
- package/dist/functools/index.d.ts +0 -106
- package/dist/functools/index.js +0 -203
- package/dist/globals/index.d.ts +0 -268
- package/dist/globals/index.js +0 -447
- package/dist/i18n/currency.d.ts +0 -27
- package/dist/i18n/currency.js +0 -100
- package/dist/i18n/date/index.d.ts +0 -210
- package/dist/i18n/date/index.js +0 -552
- package/dist/i18n/date/utils.d.ts +0 -64
- package/dist/i18n/date/utils.js +0 -192
- package/dist/i18n/duration.d.ts +0 -113
- package/dist/i18n/duration.js +0 -398
- package/dist/i18n/format.d.ts +0 -34
- package/dist/i18n/format.js +0 -378
- package/dist/i18n/index.d.ts +0 -9
- package/dist/i18n/index.js +0 -8
- package/dist/itertools/index.d.ts +0 -251
- package/dist/itertools/index.js +0 -434
- package/dist/math/index.d.ts +0 -79
- package/dist/math/index.js +0 -81
- package/dist/mod.d.ts +0 -1
- package/dist/mod.js +0 -1
- package/dist/operators/index.d.ts +0 -148
- package/dist/operators/index.js +0 -325
- package/dist/types.d.ts +0 -19
- package/dist/types.js +0 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { unbox } from '../internal/kind.js';
|
|
2
|
+
import { assertNotHugeSparse } from '../internal/sparse.js';
|
|
3
|
+
import { Ancestors, guardDepth } from '../internal/walk.js';
|
|
4
|
+
/**
|
|
5
|
+
* The value JSON writes for `holder[key]`: through `toJSON`, then unboxed. JSON unboxes numbers,
|
|
6
|
+
* strings, booleans and bigints but writes a boxed symbol as an object.
|
|
7
|
+
*/
|
|
8
|
+
function jsonValue(holder, key) {
|
|
9
|
+
let value = holder[key];
|
|
10
|
+
if ((typeof value === 'object' && value !== null) ||
|
|
11
|
+
typeof value === 'function' ||
|
|
12
|
+
typeof value === 'bigint') {
|
|
13
|
+
const toJSON = value.toJSON;
|
|
14
|
+
if (typeof toJSON === 'function')
|
|
15
|
+
value = toJSON.call(value, key);
|
|
16
|
+
}
|
|
17
|
+
if (typeof value !== 'object' || value === null)
|
|
18
|
+
return value;
|
|
19
|
+
const primitive = unbox(value);
|
|
20
|
+
return typeof primitive === 'symbol' ? value : primitive;
|
|
21
|
+
}
|
|
22
|
+
function write(value, path, out) {
|
|
23
|
+
switch (typeof value) {
|
|
24
|
+
case 'string':
|
|
25
|
+
out.push(JSON.stringify(value));
|
|
26
|
+
return true;
|
|
27
|
+
case 'number':
|
|
28
|
+
out.push(Number.isFinite(value) ? String(value) : 'null');
|
|
29
|
+
return true;
|
|
30
|
+
case 'boolean':
|
|
31
|
+
out.push(value ? 'true' : 'false');
|
|
32
|
+
return true;
|
|
33
|
+
case 'bigint':
|
|
34
|
+
throw new TypeError('stableStringify cannot serialize a bigint');
|
|
35
|
+
case 'object':
|
|
36
|
+
if (value === null) {
|
|
37
|
+
out.push('null');
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
if (path.has(value))
|
|
45
|
+
throw new TypeError('stableStringify cannot serialize a cyclic structure');
|
|
46
|
+
path.enter(value);
|
|
47
|
+
try {
|
|
48
|
+
if (Array.isArray(value)) {
|
|
49
|
+
assertNotHugeSparse(value);
|
|
50
|
+
const length = value.length;
|
|
51
|
+
out.push('[');
|
|
52
|
+
for (let i = 0; i < length; i++) {
|
|
53
|
+
if (i > 0)
|
|
54
|
+
out.push(',');
|
|
55
|
+
if (!write(jsonValue(value, String(i)), path, out)) {
|
|
56
|
+
out.push('null');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
out.push(']');
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
const record = value;
|
|
63
|
+
out.push('{');
|
|
64
|
+
let first = true;
|
|
65
|
+
for (const key of Object.keys(record).sort()) {
|
|
66
|
+
const mark = out.length;
|
|
67
|
+
out.push(first ? '' : ',', JSON.stringify(key), ':');
|
|
68
|
+
if (write(jsonValue(record, key), path, out))
|
|
69
|
+
first = false;
|
|
70
|
+
else
|
|
71
|
+
out.length = mark;
|
|
72
|
+
}
|
|
73
|
+
out.push('}');
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
path.leave(value);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* `JSON.stringify` with every object's keys sorted, so equal data always gives the same text (for
|
|
82
|
+
* cache keys, signatures and snapshots). It follows `JSON.stringify` otherwise. A value's own or
|
|
83
|
+
* inherited `toJSON` is called with its key, as JSON's contract has it, so Dates write their ISO
|
|
84
|
+
* string and types such as `Decimal` write their JSON form. Boxed primitives unbox, `undefined`,
|
|
85
|
+
* functions and symbols are dropped from objects and become `null` in arrays, and non-finite
|
|
86
|
+
* numbers become `null`. A cycle or a bigint throws `TypeError`, nesting past 1000 levels throws
|
|
87
|
+
* `RangeError`, and so does a huge sparse array. As in JSON, a `Map`, a `Set` or a class instance
|
|
88
|
+
* without `toJSON` writes only its own enumerable keys, often `'{}'`, so equal text does not imply
|
|
89
|
+
* equal data for those kinds.
|
|
90
|
+
* @param value Any value.
|
|
91
|
+
* @returns The JSON text, or `undefined` for a value JSON cannot write (`undefined`, a function, a
|
|
92
|
+
* symbol).
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* stableStringify({ b: 1, a: [true, { d: 2, c: 3 }] }) // '{"a":[true,{"c":3,"d":2}],"b":1}'
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export function stableStringify(value) {
|
|
99
|
+
const out = [];
|
|
100
|
+
const ok = guardDepth(() => write(jsonValue({ '': value }, ''), new Ancestors(), out));
|
|
101
|
+
return ok ? out.join('') : undefined;
|
|
102
|
+
}
|
package/dist/id/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A random id of `size` characters from `alphabet`, as the `nanoid` package makes them: each
|
|
3
|
+
* character is drawn without bias through `crypto.getRandomValues`. The default is 21 URL-safe
|
|
4
|
+
* characters, about as collision-resistant as a v4 UUID.
|
|
5
|
+
* @param size Characters in the id, an integer from 1 to 1024 (default 21); else `TypeError` for a
|
|
6
|
+
* non-number and `RangeError` for any other value.
|
|
7
|
+
* @param alphabet Characters to draw from: a well-formed string of 2 to 256 distinct code points
|
|
8
|
+
* (default `A-Za-z0-9_-`); else `TypeError` for a non-string and `RangeError` for any other value.
|
|
9
|
+
* @returns The id.
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* nanoid() // 'V1StGXR8_Z5jdHi6B-myT'
|
|
13
|
+
* nanoid(8, '0123456789') // '48105763'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function nanoid(size?: number, alphabet?: string): string;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { randomBytes } from '../internal/crypto.js';
|
|
2
|
+
const URL_ALPHABET = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
|
|
3
|
+
const URL_SYMBOLS = [...URL_ALPHABET];
|
|
4
|
+
/** Longest id {@link nanoid} makes, so a size from input cannot allocate without bound. */
|
|
5
|
+
const MAX_SIZE = 1024;
|
|
6
|
+
/** Most code points an alphabet may hold, since each draw indexes it with one random byte. */
|
|
7
|
+
const MAX_SYMBOLS = 256;
|
|
8
|
+
/** The code points of `alphabet`, or an error for an alphabet {@link nanoid} cannot draw from. */
|
|
9
|
+
function symbolsOf(alphabet) {
|
|
10
|
+
if (typeof alphabet !== 'string')
|
|
11
|
+
throw new TypeError('alphabet must be a string');
|
|
12
|
+
if (alphabet === URL_ALPHABET)
|
|
13
|
+
return URL_SYMBOLS;
|
|
14
|
+
if (!alphabet.isWellFormed())
|
|
15
|
+
throw new RangeError('alphabet must not hold lone surrogates');
|
|
16
|
+
const outOfRange = `alphabet must hold 2 to ${String(MAX_SYMBOLS)} distinct characters`;
|
|
17
|
+
// A code point is one or two UTF-16 units, so a longer string holds too many to spread.
|
|
18
|
+
if (alphabet.length > 2 * MAX_SYMBOLS)
|
|
19
|
+
throw new RangeError(outOfRange);
|
|
20
|
+
const symbols = [...alphabet];
|
|
21
|
+
if (symbols.length < 2 ||
|
|
22
|
+
symbols.length > MAX_SYMBOLS ||
|
|
23
|
+
new Set(symbols).size !== symbols.length) {
|
|
24
|
+
throw new RangeError(outOfRange);
|
|
25
|
+
}
|
|
26
|
+
return symbols;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A random id of `size` characters from `alphabet`, as the `nanoid` package makes them: each
|
|
30
|
+
* character is drawn without bias through `crypto.getRandomValues`. The default is 21 URL-safe
|
|
31
|
+
* characters, about as collision-resistant as a v4 UUID.
|
|
32
|
+
* @param size Characters in the id, an integer from 1 to 1024 (default 21); else `TypeError` for a
|
|
33
|
+
* non-number and `RangeError` for any other value.
|
|
34
|
+
* @param alphabet Characters to draw from: a well-formed string of 2 to 256 distinct code points
|
|
35
|
+
* (default `A-Za-z0-9_-`); else `TypeError` for a non-string and `RangeError` for any other value.
|
|
36
|
+
* @returns The id.
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* nanoid() // 'V1StGXR8_Z5jdHi6B-myT'
|
|
40
|
+
* nanoid(8, '0123456789') // '48105763'
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export function nanoid(size = 21, alphabet = URL_ALPHABET) {
|
|
44
|
+
if (typeof size !== 'number')
|
|
45
|
+
throw new TypeError('size must be a number');
|
|
46
|
+
if (!Number.isInteger(size) || size < 1 || size > MAX_SIZE) {
|
|
47
|
+
throw new RangeError(`size must be an integer from 1 to ${String(MAX_SIZE)}`);
|
|
48
|
+
}
|
|
49
|
+
const symbols = symbolsOf(alphabet);
|
|
50
|
+
const mask = (2 << (31 - Math.clz32((symbols.length - 1) | 1))) - 1;
|
|
51
|
+
const batch = Math.ceil((1.6 * mask * size) / symbols.length);
|
|
52
|
+
let id = '';
|
|
53
|
+
let length = 0;
|
|
54
|
+
while (length < size) {
|
|
55
|
+
for (const byte of randomBytes(batch)) {
|
|
56
|
+
const index = byte & mask;
|
|
57
|
+
if (index < symbols.length) {
|
|
58
|
+
id += symbols[index];
|
|
59
|
+
if (++length === size)
|
|
60
|
+
return id;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return id;
|
|
65
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The next id from one realm-wide counter, as a decimal string: '1', '2', and so on.
|
|
3
|
+
* Every copy of atomic-fns loaded in this realm shares the counter. Each worker and each
|
|
4
|
+
* process counts on its own, so ids repeat across them; use {@link uuid} for that.
|
|
5
|
+
* Takes no parameters. Like `crypto.randomUUID`, it ignores any arguments passed at runtime,
|
|
6
|
+
* including a lodash-style prefix argument. Add a prefix with a template string instead.
|
|
7
|
+
* @returns The next id as a decimal string.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* uniqueId() // '1'
|
|
11
|
+
* `user_${uniqueId()}` // 'user_2'
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export declare function uniqueId(): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const slot = Symbol.for('atomic-fns.uniqueId');
|
|
2
|
+
const realm = globalThis;
|
|
3
|
+
/**
|
|
4
|
+
* The next id from one realm-wide counter, as a decimal string: '1', '2', and so on.
|
|
5
|
+
* Every copy of atomic-fns loaded in this realm shares the counter. Each worker and each
|
|
6
|
+
* process counts on its own, so ids repeat across them; use {@link uuid} for that.
|
|
7
|
+
* Takes no parameters. Like `crypto.randomUUID`, it ignores any arguments passed at runtime,
|
|
8
|
+
* including a lodash-style prefix argument. Add a prefix with a template string instead.
|
|
9
|
+
* @returns The next id as a decimal string.
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* uniqueId() // '1'
|
|
13
|
+
* `user_${uniqueId()}` // 'user_2'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function uniqueId() {
|
|
17
|
+
const state = (realm[slot] ??= { counter: 0 });
|
|
18
|
+
state.counter++;
|
|
19
|
+
return String(state.counter);
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A random (version 4) UUID, from `crypto.randomUUID` where the runtime has it (secure contexts) and
|
|
3
|
+
* from `crypto.getRandomValues` elsewhere. Throws `TypeError` where neither exists.
|
|
4
|
+
* @returns A lowercase UUID string.
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* uuid() // '0b5e1f9c-8a5d-4f8e-9b8a-2a8f6a1c3d4e'
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export declare function uuid(): string;
|
|
11
|
+
/**
|
|
12
|
+
* A time-ordered (version 7) UUID, RFC 9562: 48 bits of Unix milliseconds, then a 12-bit sequence
|
|
13
|
+
* and 62 random bits, so ids sort by creation time as strings and as bytes. Ids made in one
|
|
14
|
+
* millisecond, or while the clock steps back, count up the sequence from a random start, so they
|
|
15
|
+
* still sort in the order this process made them: they keep the last timestamp, and when its
|
|
16
|
+
* sequence runs out they borrow the next millisecond (RFC 9562 section 6.2), so the timestamp can
|
|
17
|
+
* run ahead of the clock. Throws `TypeError` without Web Crypto.
|
|
18
|
+
* @returns A lowercase UUID string.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const [a, b] = [uuidv7(), uuidv7()]
|
|
22
|
+
* a < b // true
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function uuidv7(): string;
|
package/dist/id/uuid.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { bytesToHex } from '../internal/bytes.js';
|
|
2
|
+
import { randomBytes } from '../internal/crypto.js';
|
|
3
|
+
function format(bytes) {
|
|
4
|
+
const hex = bytesToHex(bytes);
|
|
5
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A random (version 4) UUID, from `crypto.randomUUID` where the runtime has it (secure contexts) and
|
|
9
|
+
* from `crypto.getRandomValues` elsewhere. Throws `TypeError` where neither exists.
|
|
10
|
+
* @returns A lowercase UUID string.
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* uuid() // '0b5e1f9c-8a5d-4f8e-9b8a-2a8f6a1c3d4e'
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function uuid() {
|
|
17
|
+
const crypto = globalThis.crypto;
|
|
18
|
+
if (typeof crypto?.randomUUID === 'function')
|
|
19
|
+
return crypto.randomUUID();
|
|
20
|
+
const bytes = randomBytes(16);
|
|
21
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
22
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
23
|
+
return format(bytes);
|
|
24
|
+
}
|
|
25
|
+
let lastTime = -1;
|
|
26
|
+
let sequence = 0;
|
|
27
|
+
/**
|
|
28
|
+
* A time-ordered (version 7) UUID, RFC 9562: 48 bits of Unix milliseconds, then a 12-bit sequence
|
|
29
|
+
* and 62 random bits, so ids sort by creation time as strings and as bytes. Ids made in one
|
|
30
|
+
* millisecond, or while the clock steps back, count up the sequence from a random start, so they
|
|
31
|
+
* still sort in the order this process made them: they keep the last timestamp, and when its
|
|
32
|
+
* sequence runs out they borrow the next millisecond (RFC 9562 section 6.2), so the timestamp can
|
|
33
|
+
* run ahead of the clock. Throws `TypeError` without Web Crypto.
|
|
34
|
+
* @returns A lowercase UUID string.
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const [a, b] = [uuidv7(), uuidv7()]
|
|
38
|
+
* a < b // true
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function uuidv7() {
|
|
42
|
+
const bytes = randomBytes(16);
|
|
43
|
+
let time = Date.now();
|
|
44
|
+
if (time > lastTime) {
|
|
45
|
+
sequence = ((bytes[6] << 8) | bytes[7]) & 0x7ff;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
time = lastTime;
|
|
49
|
+
sequence++;
|
|
50
|
+
if (sequence > 0xfff) {
|
|
51
|
+
time++;
|
|
52
|
+
sequence = 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
lastTime = time;
|
|
56
|
+
for (let i = 5; i >= 0; i--) {
|
|
57
|
+
bytes[i] = time % 256;
|
|
58
|
+
time = Math.floor(time / 256);
|
|
59
|
+
}
|
|
60
|
+
bytes[6] = 0x70 | (sequence >> 8);
|
|
61
|
+
bytes[7] = sequence & 0xff;
|
|
62
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
63
|
+
return format(bytes);
|
|
64
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collections, utilities and exact decimal arithmetic.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
1
5
|
export * from './collections/index.js';
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './itertools/index.js';
|
|
7
|
-
export * from './math/index.js';
|
|
8
|
-
export * from './operators/index.js';
|
|
9
|
-
export * from './random/index.js';
|
|
6
|
+
export * from './object/index.js';
|
|
7
|
+
export * from './array/index.js';
|
|
8
|
+
export * from './function/index.js';
|
|
9
|
+
export * from './async/index.js';
|
|
10
10
|
export * from './string/index.js';
|
|
11
|
+
export * from './number/index.js';
|
|
12
|
+
export * from './random/index.js';
|
|
13
|
+
export * from './id/index.js';
|
|
14
|
+
export * from './hash/index.js';
|
|
15
|
+
export * from './encoding/index.js';
|
|
16
|
+
export * from './is/index.js';
|
|
17
|
+
export * from './decimal/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collections, utilities and exact decimal arithmetic.
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
1
5
|
export * from './collections/index.js';
|
|
2
|
-
export * from './
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './itertools/index.js';
|
|
7
|
-
export * from './math/index.js';
|
|
8
|
-
export * from './operators/index.js';
|
|
9
|
-
export * from './random/index.js';
|
|
6
|
+
export * from './object/index.js';
|
|
7
|
+
export * from './array/index.js';
|
|
8
|
+
export * from './function/index.js';
|
|
9
|
+
export * from './async/index.js';
|
|
10
10
|
export * from './string/index.js';
|
|
11
|
+
export * from './number/index.js';
|
|
12
|
+
export * from './random/index.js';
|
|
13
|
+
export * from './id/index.js';
|
|
14
|
+
export * from './hash/index.js';
|
|
15
|
+
export * from './encoding/index.js';
|
|
16
|
+
export * from './is/index.js';
|
|
17
|
+
export * from './decimal/index.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte and text helpers shared by hashing, ids and encoding.
|
|
3
|
+
*/
|
|
4
|
+
/** Lowercase hex of `bytes`, two digits per byte. */
|
|
5
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
6
|
+
/** UTF-8 bytes of `text`, with lone surrogates as U+FFFD, as `TextEncoder` writes them. */
|
|
7
|
+
export declare function utf8(text: string): Uint8Array;
|
|
8
|
+
/** An `ArrayBuffer`, from any realm. */
|
|
9
|
+
export declare function isArrayBuffer(value: unknown): value is ArrayBuffer;
|
|
10
|
+
/** The bytes of a string (UTF-8), a buffer or a view, without copying a buffer or view. */
|
|
11
|
+
export declare function toBytes(data: string | ArrayBuffer | SharedArrayBuffer | ArrayBufferView): Uint8Array;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Byte and text helpers shared by hashing, ids and encoding.
|
|
3
|
+
*/
|
|
4
|
+
import { viewBytes } from './kind.js';
|
|
5
|
+
const HEX = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
|
|
6
|
+
/** Lowercase hex of `bytes`, two digits per byte. */
|
|
7
|
+
export function bytesToHex(bytes) {
|
|
8
|
+
let out = '';
|
|
9
|
+
for (const byte of bytes)
|
|
10
|
+
out += HEX[byte];
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
/** UTF-8 bytes of `text`, with lone surrogates as U+FFFD, as `TextEncoder` writes them. */
|
|
14
|
+
export function utf8(text) {
|
|
15
|
+
return new TextEncoder().encode(text);
|
|
16
|
+
}
|
|
17
|
+
/** An `ArrayBuffer`, from any realm. */
|
|
18
|
+
export function isArrayBuffer(value) {
|
|
19
|
+
return Object.prototype.toString.call(value) === '[object ArrayBuffer]';
|
|
20
|
+
}
|
|
21
|
+
function isSharedArrayBuffer(value) {
|
|
22
|
+
return Object.prototype.toString.call(value) === '[object SharedArrayBuffer]';
|
|
23
|
+
}
|
|
24
|
+
/** The bytes of a string (UTF-8), a buffer or a view, without copying a buffer or view. */
|
|
25
|
+
export function toBytes(data) {
|
|
26
|
+
if (typeof data === 'string')
|
|
27
|
+
return utf8(data);
|
|
28
|
+
if (ArrayBuffer.isView(data))
|
|
29
|
+
return viewBytes(data);
|
|
30
|
+
if (isArrayBuffer(data) || isSharedArrayBuffer(data))
|
|
31
|
+
return new Uint8Array(data);
|
|
32
|
+
throw new TypeError('expected a string, an ArrayBuffer or a typed array');
|
|
33
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portable base64 and hex codecs, for runtimes without the native `Uint8Array` methods.
|
|
3
|
+
*/
|
|
4
|
+
/** The base64 alphabets, by the names the native methods take. */
|
|
5
|
+
export type Base64Alphabet = 'base64' | 'base64url';
|
|
6
|
+
/** Base64 of `bytes` in `alphabet`. */
|
|
7
|
+
export declare function encodeBase64(bytes: Uint8Array, alphabet: Base64Alphabet, omitPadding: boolean): string;
|
|
8
|
+
/** Bytes of base64 `text` in `alphabet`, read as `Uint8Array.fromBase64` reads it. */
|
|
9
|
+
export declare function decodeBase64(text: string, alphabet: Base64Alphabet): Uint8Array;
|
|
10
|
+
/** Bytes of hex `text`, read as `Uint8Array.fromHex` reads it. */
|
|
11
|
+
export declare function decodeHex(text: string): Uint8Array;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Portable base64 and hex codecs, for runtimes without the native `Uint8Array` methods.
|
|
3
|
+
*/
|
|
4
|
+
const CHARACTERS = {
|
|
5
|
+
base64: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
|
|
6
|
+
base64url: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
|
|
7
|
+
};
|
|
8
|
+
/** For each alphabet, the 6-bit value of every ASCII code unit, or -1 outside the alphabet. */
|
|
9
|
+
const VALUES = {
|
|
10
|
+
base64: valuesOf(CHARACTERS.base64),
|
|
11
|
+
base64url: valuesOf(CHARACTERS.base64url)
|
|
12
|
+
};
|
|
13
|
+
function valuesOf(characters) {
|
|
14
|
+
const values = new Int8Array(128).fill(-1);
|
|
15
|
+
for (let value = 0; value < characters.length; value++) {
|
|
16
|
+
values[characters.charCodeAt(value)] = value;
|
|
17
|
+
}
|
|
18
|
+
return values;
|
|
19
|
+
}
|
|
20
|
+
/** Base64 of `bytes` in `alphabet`. */
|
|
21
|
+
export function encodeBase64(bytes, alphabet, omitPadding) {
|
|
22
|
+
const characters = CHARACTERS[alphabet];
|
|
23
|
+
let out = '';
|
|
24
|
+
let i = 0;
|
|
25
|
+
for (; i + 2 < bytes.length; i += 3) {
|
|
26
|
+
const n = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
|
27
|
+
out +=
|
|
28
|
+
characters[n >> 18] +
|
|
29
|
+
characters[(n >> 12) & 63] +
|
|
30
|
+
characters[(n >> 6) & 63] +
|
|
31
|
+
characters[n & 63];
|
|
32
|
+
}
|
|
33
|
+
const rest = bytes.length - i;
|
|
34
|
+
if (rest === 1) {
|
|
35
|
+
const n = bytes[i] << 16;
|
|
36
|
+
out += characters[n >> 18] + characters[(n >> 12) & 63] + (omitPadding ? '' : '==');
|
|
37
|
+
}
|
|
38
|
+
else if (rest === 2) {
|
|
39
|
+
const n = (bytes[i] << 16) | (bytes[i + 1] << 8);
|
|
40
|
+
out += characters[n >> 18] + characters[(n >> 12) & 63] + characters[(n >> 6) & 63];
|
|
41
|
+
out += omitPadding ? '' : '=';
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
/** Bytes of base64 `text` in `alphabet`, read as `Uint8Array.fromBase64` reads it. */
|
|
46
|
+
export function decodeBase64(text, alphabet) {
|
|
47
|
+
const values = VALUES[alphabet];
|
|
48
|
+
let chars = text.replace(/[\t\n\f\r ]/g, '');
|
|
49
|
+
if (chars.endsWith('=')) {
|
|
50
|
+
if (chars.length % 4 !== 0)
|
|
51
|
+
throw new SyntaxError('invalid base64 padding');
|
|
52
|
+
chars = chars.replace(/={1,2}$/, '');
|
|
53
|
+
}
|
|
54
|
+
if (chars.length % 4 === 1)
|
|
55
|
+
throw new SyntaxError('invalid base64 length');
|
|
56
|
+
const out = new Uint8Array(Math.floor((chars.length * 3) / 4));
|
|
57
|
+
let bits = 0;
|
|
58
|
+
let buffer = 0;
|
|
59
|
+
let written = 0;
|
|
60
|
+
for (let i = 0; i < chars.length; i++) {
|
|
61
|
+
const code = chars.charCodeAt(i);
|
|
62
|
+
const value = code < 128 ? values[code] : -1;
|
|
63
|
+
if (value < 0)
|
|
64
|
+
throw new SyntaxError(`invalid base64 character: ${JSON.stringify(chars[i])}`);
|
|
65
|
+
buffer = (buffer << 6) | value;
|
|
66
|
+
bits += 6;
|
|
67
|
+
if (bits >= 8) {
|
|
68
|
+
bits -= 8;
|
|
69
|
+
out[written++] = (buffer >> bits) & 0xff;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
/** Bytes of hex `text`, read as `Uint8Array.fromHex` reads it. */
|
|
75
|
+
export function decodeHex(text) {
|
|
76
|
+
if (text.length % 2 !== 0)
|
|
77
|
+
throw new SyntaxError('hex text must have an even length');
|
|
78
|
+
if (!/^[0-9a-fA-F]*$/.test(text))
|
|
79
|
+
throw new SyntaxError('invalid hex character');
|
|
80
|
+
const out = new Uint8Array(text.length / 2);
|
|
81
|
+
for (let i = 0; i < out.length; i++)
|
|
82
|
+
out[i] = Number.parseInt(text.slice(2 * i, 2 * i + 2), 16);
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** A comparator `(a, b) => number`: negative when `a` sorts first, 0 for the same key. */
|
|
2
|
+
export type Comparator<T> = (a: T, b: T) => number;
|
|
3
|
+
/**
|
|
4
|
+
* The default order: numbers and bigints by value (compared exactly with each other) and strings
|
|
5
|
+
* by UTF-16 code units, as `<` does. `NaN` throws `RangeError`; mixed strings and numbers, `null`,
|
|
6
|
+
* `undefined` and every other value throw `TypeError` asking for a comparator.
|
|
7
|
+
*/
|
|
8
|
+
export declare function defaultCompare(a: unknown, b: unknown): number;
|
|
9
|
+
/** SameValueZero, as `Map`, `Set` and `includes` use. */
|
|
10
|
+
export declare function sameValueZero(a: unknown, b: unknown): boolean;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
function describe(x) {
|
|
2
|
+
return x === null ? 'null' : typeof x;
|
|
3
|
+
}
|
|
4
|
+
function isNumeric(x) {
|
|
5
|
+
return typeof x === 'number' || typeof x === 'bigint';
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The default order: numbers and bigints by value (compared exactly with each other) and strings
|
|
9
|
+
* by UTF-16 code units, as `<` does. `NaN` throws `RangeError`; mixed strings and numbers, `null`,
|
|
10
|
+
* `undefined` and every other value throw `TypeError` asking for a comparator.
|
|
11
|
+
*/
|
|
12
|
+
export function defaultCompare(a, b) {
|
|
13
|
+
if (isNumeric(a) && isNumeric(b)) {
|
|
14
|
+
if (Number.isNaN(a) || Number.isNaN(b)) {
|
|
15
|
+
throw new RangeError('NaN has no order; pass a comparator');
|
|
16
|
+
}
|
|
17
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
18
|
+
}
|
|
19
|
+
if (typeof a === 'string' && typeof b === 'string')
|
|
20
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
21
|
+
throw new TypeError(`the default comparator orders numbers, bigints and strings; pass a comparator to order ${describe(a)} and ${describe(b)}`);
|
|
22
|
+
}
|
|
23
|
+
/** SameValueZero, as `Map`, `Set` and `includes` use. */
|
|
24
|
+
export function sameValueZero(a, b) {
|
|
25
|
+
return a === b || (a !== a && b !== b);
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Crypto access shared by the random ids.
|
|
3
|
+
*/
|
|
4
|
+
/** `length` bytes from `crypto.getRandomValues`, or a `TypeError` where the runtime has no Web Crypto. */
|
|
5
|
+
export function randomBytes(length) {
|
|
6
|
+
const crypto = globalThis.crypto;
|
|
7
|
+
if (typeof crypto?.getRandomValues !== 'function') {
|
|
8
|
+
throw new TypeError('crypto.getRandomValues is not available');
|
|
9
|
+
}
|
|
10
|
+
return crypto.getRandomValues(new Uint8Array(length));
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key lists shared by the deep walks.
|
|
3
|
+
*/
|
|
4
|
+
/** Whether `key` is an own enumerable property of `value`. */
|
|
5
|
+
export declare function isEnumerable(value: object, key: PropertyKey): boolean;
|
|
6
|
+
/** The own enumerable keys of `value`: its string keys as `Object.keys` lists them, then symbols. */
|
|
7
|
+
export declare function enumerableKeys(value: object): (string | symbol)[];
|
|
8
|
+
/**
|
|
9
|
+
* Location keys JavaScriptCore puts on every error as own enumerable properties, like `stack`, so
|
|
10
|
+
* `isEqual` and `hash` leave them out of an error's content.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ERROR_LOCATION_KEYS: ReadonlySet<PropertyKey>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Key lists shared by the deep walks.
|
|
3
|
+
*/
|
|
4
|
+
/** Whether `key` is an own enumerable property of `value`. */
|
|
5
|
+
export function isEnumerable(value, key) {
|
|
6
|
+
return Object.prototype.propertyIsEnumerable.call(value, key);
|
|
7
|
+
}
|
|
8
|
+
/** The own enumerable keys of `value`: its string keys as `Object.keys` lists them, then symbols. */
|
|
9
|
+
export function enumerableKeys(value) {
|
|
10
|
+
const symbols = Object.getOwnPropertySymbols(value);
|
|
11
|
+
if (symbols.length === 0)
|
|
12
|
+
return Object.keys(value);
|
|
13
|
+
return [...Object.keys(value), ...symbols.filter((key) => isEnumerable(value, key))];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Location keys JavaScriptCore puts on every error as own enumerable properties, like `stack`, so
|
|
17
|
+
* `isEqual` and `hash` leave them out of an error's content.
|
|
18
|
+
*/
|
|
19
|
+
export const ERROR_LOCATION_KEYS = new Set([
|
|
20
|
+
'line',
|
|
21
|
+
'column',
|
|
22
|
+
'sourceURL'
|
|
23
|
+
]);
|