@evolu/common 8.9.0 → 8.11.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/dist/src/Bytes.d.ts +647 -0
- package/dist/src/Bytes.d.ts.map +1 -0
- package/dist/src/{Binary.js → Bytes.js} +266 -16
- package/dist/src/Config.d.ts +142 -0
- package/dist/src/Config.d.ts.map +1 -0
- package/dist/src/Config.js +181 -0
- package/dist/src/Console.d.ts +62 -7
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +20 -4
- package/dist/src/Crypto.d.ts +76 -4
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +55 -4
- package/dist/src/Error.d.ts +45 -0
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +69 -0
- package/dist/src/Fs.d.ts +376 -0
- package/dist/src/Fs.d.ts.map +1 -0
- package/dist/src/Fs.js +113 -0
- package/dist/src/Identicon.d.ts +2 -2
- package/dist/src/Identicon.js +2 -2
- package/dist/src/LeakDetector.d.ts +22 -3
- package/dist/src/LeakDetector.d.ts.map +1 -1
- package/dist/src/LeakDetector.js +12 -2
- package/dist/src/LockManager.d.ts +8 -0
- package/dist/src/LockManager.d.ts.map +1 -1
- package/dist/src/LockManager.js +6 -0
- package/dist/src/Number.d.ts +50 -7
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +47 -8
- package/dist/src/Object.d.ts +32 -0
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +46 -0
- package/dist/src/Platform.d.ts +47 -7
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +24 -5
- package/dist/src/Random.d.ts +25 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +14 -2
- package/dist/src/Resource.d.ts +156 -1
- package/dist/src/Resource.d.ts.map +1 -1
- package/dist/src/Resource.js +201 -72
- package/dist/src/Schedule.d.ts +11 -10
- package/dist/src/Schedule.d.ts.map +1 -1
- package/dist/src/Schedule.js +1 -1
- package/dist/src/Sqlite.d.ts +132 -16
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +64 -10
- package/dist/src/Task.d.ts +15 -4
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +41 -15
- package/dist/src/Test.d.ts +9 -0
- package/dist/src/Test.d.ts.map +1 -1
- package/dist/src/Test.js +4 -0
- package/dist/src/Time.d.ts +179 -20
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +95 -6
- package/dist/src/Type.d.ts +3056 -1539
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +2548 -584
- package/dist/src/WebSocket.d.ts +164 -13
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +133 -24
- package/dist/src/Worker.d.ts +90 -8
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +28 -2
- package/dist/src/index.d.ts +9 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -4
- package/dist/src/intl/_en.d.ts +24 -1
- package/dist/src/intl/_en.d.ts.map +1 -1
- package/dist/src/intl/_en.js +20 -0
- package/dist/src/intl/ar.d.ts +24 -1
- package/dist/src/intl/ar.d.ts.map +1 -1
- package/dist/src/intl/ar.js +20 -0
- package/dist/src/intl/bn.d.ts +24 -1
- package/dist/src/intl/bn.d.ts.map +1 -1
- package/dist/src/intl/bn.js +20 -0
- package/dist/src/intl/ca.d.ts +24 -1
- package/dist/src/intl/ca.d.ts.map +1 -1
- package/dist/src/intl/ca.js +20 -0
- package/dist/src/intl/cs.d.ts +24 -1
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +20 -0
- package/dist/src/intl/da.d.ts +24 -1
- package/dist/src/intl/da.d.ts.map +1 -1
- package/dist/src/intl/da.js +20 -0
- package/dist/src/intl/de.d.ts +24 -1
- package/dist/src/intl/de.d.ts.map +1 -1
- package/dist/src/intl/de.js +20 -0
- package/dist/src/intl/el.d.ts +24 -1
- package/dist/src/intl/el.d.ts.map +1 -1
- package/dist/src/intl/el.js +20 -0
- package/dist/src/intl/es.d.ts +24 -1
- package/dist/src/intl/es.d.ts.map +1 -1
- package/dist/src/intl/es.js +20 -0
- package/dist/src/intl/fa.d.ts +24 -1
- package/dist/src/intl/fa.d.ts.map +1 -1
- package/dist/src/intl/fa.js +20 -0
- package/dist/src/intl/fi.d.ts +24 -1
- package/dist/src/intl/fi.d.ts.map +1 -1
- package/dist/src/intl/fi.js +20 -0
- package/dist/src/intl/fil.d.ts +24 -1
- package/dist/src/intl/fil.d.ts.map +1 -1
- package/dist/src/intl/fil.js +20 -0
- package/dist/src/intl/fr.d.ts +24 -1
- package/dist/src/intl/fr.d.ts.map +1 -1
- package/dist/src/intl/fr.js +20 -0
- package/dist/src/intl/he.d.ts +24 -1
- package/dist/src/intl/he.d.ts.map +1 -1
- package/dist/src/intl/he.js +20 -0
- package/dist/src/intl/hi.d.ts +24 -1
- package/dist/src/intl/hi.d.ts.map +1 -1
- package/dist/src/intl/hi.js +20 -0
- package/dist/src/intl/hr.d.ts +24 -1
- package/dist/src/intl/hr.d.ts.map +1 -1
- package/dist/src/intl/hr.js +20 -0
- package/dist/src/intl/hu.d.ts +22 -1
- package/dist/src/intl/hu.d.ts.map +1 -1
- package/dist/src/intl/hu.js +18 -0
- package/dist/src/intl/id.d.ts +24 -1
- package/dist/src/intl/id.d.ts.map +1 -1
- package/dist/src/intl/id.js +20 -0
- package/dist/src/intl/it.d.ts +24 -1
- package/dist/src/intl/it.d.ts.map +1 -1
- package/dist/src/intl/it.js +20 -0
- package/dist/src/intl/ja.d.ts +24 -1
- package/dist/src/intl/ja.d.ts.map +1 -1
- package/dist/src/intl/ja.js +20 -0
- package/dist/src/intl/ko.d.ts +24 -1
- package/dist/src/intl/ko.d.ts.map +1 -1
- package/dist/src/intl/ko.js +20 -0
- package/dist/src/intl/ml.d.ts +24 -1
- package/dist/src/intl/ml.d.ts.map +1 -1
- package/dist/src/intl/ml.js +20 -0
- package/dist/src/intl/mr.d.ts +24 -1
- package/dist/src/intl/mr.d.ts.map +1 -1
- package/dist/src/intl/mr.js +20 -0
- package/dist/src/intl/ms.d.ts +24 -1
- package/dist/src/intl/ms.d.ts.map +1 -1
- package/dist/src/intl/ms.js +20 -0
- package/dist/src/intl/nb.d.ts +22 -1
- package/dist/src/intl/nb.d.ts.map +1 -1
- package/dist/src/intl/nb.js +18 -0
- package/dist/src/intl/nl.d.ts +24 -1
- package/dist/src/intl/nl.d.ts.map +1 -1
- package/dist/src/intl/nl.js +20 -0
- package/dist/src/intl/pa.d.ts +24 -1
- package/dist/src/intl/pa.d.ts.map +1 -1
- package/dist/src/intl/pa.js +20 -0
- package/dist/src/intl/pl.d.ts +23 -0
- package/dist/src/intl/pl.d.ts.map +1 -1
- package/dist/src/intl/pl.js +20 -0
- package/dist/src/intl/pt-BR.d.ts +24 -1
- package/dist/src/intl/pt-BR.d.ts.map +1 -1
- package/dist/src/intl/pt-BR.js +20 -0
- package/dist/src/intl/pt.d.ts +24 -1
- package/dist/src/intl/pt.d.ts.map +1 -1
- package/dist/src/intl/pt.js +20 -0
- package/dist/src/intl/ro.d.ts +24 -1
- package/dist/src/intl/ro.d.ts.map +1 -1
- package/dist/src/intl/ro.js +20 -0
- package/dist/src/intl/sk.d.ts +24 -1
- package/dist/src/intl/sk.d.ts.map +1 -1
- package/dist/src/intl/sk.js +20 -0
- package/dist/src/intl/sl.d.ts +24 -1
- package/dist/src/intl/sl.d.ts.map +1 -1
- package/dist/src/intl/sl.js +20 -0
- package/dist/src/intl/sv.d.ts +24 -1
- package/dist/src/intl/sv.d.ts.map +1 -1
- package/dist/src/intl/sv.js +20 -0
- package/dist/src/intl/sw.d.ts +21 -0
- package/dist/src/intl/sw.d.ts.map +1 -1
- package/dist/src/intl/sw.js +18 -0
- package/dist/src/intl/ta.d.ts +24 -1
- package/dist/src/intl/ta.d.ts.map +1 -1
- package/dist/src/intl/ta.js +20 -0
- package/dist/src/intl/te.d.ts +24 -1
- package/dist/src/intl/te.d.ts.map +1 -1
- package/dist/src/intl/te.js +20 -0
- package/dist/src/intl/th.d.ts +24 -1
- package/dist/src/intl/th.d.ts.map +1 -1
- package/dist/src/intl/th.js +20 -0
- package/dist/src/intl/tr.d.ts +24 -1
- package/dist/src/intl/tr.d.ts.map +1 -1
- package/dist/src/intl/tr.js +20 -0
- package/dist/src/intl/uk.d.ts +80 -57
- package/dist/src/intl/uk.d.ts.map +1 -1
- package/dist/src/intl/uk.js +174 -149
- package/dist/src/intl/ur.d.ts +24 -1
- package/dist/src/intl/ur.d.ts.map +1 -1
- package/dist/src/intl/ur.js +20 -0
- package/dist/src/intl/vi.d.ts +24 -1
- package/dist/src/intl/vi.d.ts.map +1 -1
- package/dist/src/intl/vi.js +20 -0
- package/dist/src/intl/zh-CN.d.ts +24 -1
- package/dist/src/intl/zh-CN.d.ts.map +1 -1
- package/dist/src/intl/zh-CN.js +20 -0
- package/dist/src/intl/zh-TW.d.ts +24 -1
- package/dist/src/intl/zh-TW.d.ts.map +1 -1
- package/dist/src/intl/zh-TW.js +20 -0
- package/dist/src/local-first/Db.d.ts +52 -3
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +412 -137
- package/dist/src/local-first/Evolu.d.ts +336 -211
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +102 -15
- package/dist/src/local-first/Owner.d.ts +13 -30
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +13 -30
- package/dist/src/local-first/Protocol.d.ts +95 -17
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +119 -39
- package/dist/src/local-first/Query.d.ts +8 -15
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Schema.d.ts +345 -21
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +214 -17
- package/dist/src/local-first/Shared.d.ts +537 -22
- package/dist/src/local-first/Shared.d.ts.map +1 -1
- package/dist/src/local-first/Shared.js +1437 -234
- package/dist/src/local-first/Storage.d.ts +192 -14
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +82 -21
- package/dist/src/local-first/Timestamp.d.ts +392 -41
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +404 -82
- package/dist/src/local-first/index.d.ts +0 -1
- package/dist/src/local-first/index.d.ts.map +1 -1
- package/dist/src/local-first/index.js +0 -1
- package/package.json +1 -1
- package/src/Assert.test.ts +2 -5
- package/src/{Binary.test.ts → Bytes.test.ts} +286 -1
- package/src/{Binary.ts → Bytes.ts} +652 -21
- package/src/Config.test.ts +668 -0
- package/src/Config.ts +410 -0
- package/src/Console.ts +62 -7
- package/src/Crypto.ts +76 -4
- package/src/Eq.test.ts +2 -3
- package/src/Error.test.ts +76 -3
- package/src/Error.ts +71 -0
- package/src/Fs.test.ts +105 -0
- package/src/Fs.ts +488 -0
- package/src/Identicon.ts +2 -2
- package/src/LeakDetector.ts +22 -3
- package/src/LockManager.ts +8 -0
- package/src/Number.test.ts +82 -18
- package/src/Number.ts +76 -8
- package/src/Object.test.ts +139 -10
- package/src/Object.ts +49 -0
- package/src/Platform.ts +50 -8
- package/src/Random.ts +25 -2
- package/src/Resource.test.ts +837 -0
- package/src/Resource.ts +235 -15
- package/src/Schedule.test.ts +50 -12
- package/src/Schedule.ts +24 -14
- package/src/Sqlite.ts +138 -18
- package/src/Task.test.ts +189 -8
- package/src/Task.ts +56 -17
- package/src/Test.ts +9 -0
- package/src/Time.test.ts +82 -11
- package/src/Time.ts +246 -24
- package/src/Type.test.ts +3994 -1119
- package/src/Type.ts +7258 -3842
- package/src/Types.test.ts +4 -14
- package/src/WebSocket.ts +313 -40
- package/src/Worker.ts +90 -8
- package/src/index.ts +18 -7
- package/src/intl/_en.ts +70 -0
- package/src/intl/ar.ts +71 -0
- package/src/intl/bn.ts +70 -0
- package/src/intl/ca.ts +70 -0
- package/src/intl/cs.ts +70 -0
- package/src/intl/da.ts +70 -0
- package/src/intl/de.ts +70 -0
- package/src/intl/el.ts +70 -0
- package/src/intl/es.ts +70 -0
- package/src/intl/fa.ts +70 -0
- package/src/intl/fi.ts +70 -0
- package/src/intl/fil.ts +70 -0
- package/src/intl/fr.ts +70 -0
- package/src/intl/he.ts +70 -0
- package/src/intl/hi.ts +70 -0
- package/src/intl/hr.ts +70 -0
- package/src/intl/hu.ts +69 -0
- package/src/intl/id.ts +70 -0
- package/src/intl/intl.test.ts +819 -1
- package/src/intl/it.ts +70 -0
- package/src/intl/ja.ts +70 -0
- package/src/intl/ko.ts +68 -0
- package/src/intl/ml.ts +70 -0
- package/src/intl/mr.ts +70 -0
- package/src/intl/ms.ts +71 -0
- package/src/intl/nb.ts +69 -0
- package/src/intl/nl.ts +70 -0
- package/src/intl/pa.ts +70 -0
- package/src/intl/pl.ts +63 -0
- package/src/intl/pt-BR.ts +70 -0
- package/src/intl/pt.ts +71 -0
- package/src/intl/ro.ts +70 -0
- package/src/intl/sk.ts +71 -0
- package/src/intl/sl.ts +70 -0
- package/src/intl/sv.ts +70 -0
- package/src/intl/sw.ts +62 -0
- package/src/intl/ta.ts +70 -0
- package/src/intl/te.ts +70 -0
- package/src/intl/th.ts +68 -0
- package/src/intl/tr.ts +70 -0
- package/src/intl/uk.ts +228 -155
- package/src/intl/ur.ts +70 -0
- package/src/intl/vi.ts +70 -0
- package/src/intl/zh-CN.ts +68 -0
- package/src/intl/zh-TW.ts +68 -0
- package/src/local-first/Db.ts +644 -339
- package/src/local-first/Evolu.test.ts +686 -21
- package/src/local-first/Evolu.ts +450 -228
- package/src/local-first/Owner.ts +13 -30
- package/src/local-first/Protocol.test.ts +618 -11
- package/src/local-first/Protocol.ts +197 -73
- package/src/local-first/Query.ts +8 -15
- package/src/local-first/Schema.test.ts +143 -0
- package/src/local-first/Schema.ts +374 -24
- package/src/local-first/Shared.test.ts +7731 -559
- package/src/local-first/Shared.ts +2036 -267
- package/src/local-first/Storage.ts +219 -33
- package/src/local-first/Timestamp.test.ts +344 -70
- package/src/local-first/Timestamp.ts +435 -119
- package/src/local-first/index.ts +0 -1
- package/dist/src/Binary.d.ts +0 -254
- package/dist/src/Binary.d.ts.map +0 -1
- package/dist/src/local-first/Error.d.ts +0 -12
- package/dist/src/local-first/Error.d.ts.map +0 -1
- package/dist/src/local-first/Error.js +0 -6
- package/dist/src/local-first/LocalAuth.d.ts +0 -150
- package/dist/src/local-first/LocalAuth.d.ts.map +0 -1
- package/dist/src/local-first/LocalAuth.js +0 -179
- package/src/local-first/Error.ts +0 -17
- package/src/local-first/LocalAuth.ts +0 -457
package/dist/src/Fs.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File system operations for {@link Task}s.
|
|
3
|
+
*
|
|
4
|
+
* {@link Fs} reads, writes, copies, and renames files; lists and manages
|
|
5
|
+
* directories; and provides metadata and existence checks. Each operation
|
|
6
|
+
* returns a Task.
|
|
7
|
+
*
|
|
8
|
+
* Tasks can sequence file operations without synchronous I/O. Node.js's
|
|
9
|
+
* synchronous methods are intentionally omitted to avoid accidentally blocking
|
|
10
|
+
* the event loop.
|
|
11
|
+
*
|
|
12
|
+
* Inject {@link @evolu/nodejs!createNodeFs | createNodeFs} through
|
|
13
|
+
* {@link @evolu/nodejs!runMain | runMain} or {@link createRun}. Tasks declare
|
|
14
|
+
* {@link FsDep} and access the file system through `run.deps.fs`.
|
|
15
|
+
*
|
|
16
|
+
* {@link FsError} includes the path, a diagnostic message, and a
|
|
17
|
+
* {@link FsErrorReason} such as `NotFound` or `PermissionDenied`.
|
|
18
|
+
* {@link Fs.exists} returns `false` for `NotFound` and preserves other errors.
|
|
19
|
+
*
|
|
20
|
+
* ### Example
|
|
21
|
+
*
|
|
22
|
+
* ```ts
|
|
23
|
+
* import {
|
|
24
|
+
* assertEqual,
|
|
25
|
+
* ok,
|
|
26
|
+
* type FsDep,
|
|
27
|
+
* type FsError,
|
|
28
|
+
* type Task,
|
|
29
|
+
* } from "@evolu/common";
|
|
30
|
+
* import { createNodeFs, runMain } from "@evolu/nodejs";
|
|
31
|
+
* import { join } from "node:path";
|
|
32
|
+
*
|
|
33
|
+
* const main: Task<void, FsError, FsDep> = async (run) => {
|
|
34
|
+
* const { fs } = run.deps;
|
|
35
|
+
* const temp = await run(
|
|
36
|
+
* fs.createTempDirectory({ prefix: "evolu-fs-" }),
|
|
37
|
+
* );
|
|
38
|
+
* if (!temp.ok) return temp;
|
|
39
|
+
*
|
|
40
|
+
* await using directory = temp.value;
|
|
41
|
+
* const path = join(directory.path, "message.txt");
|
|
42
|
+
*
|
|
43
|
+
* const result = await run(fs.writeFile(path, "hello"));
|
|
44
|
+
* if (!result.ok) return result;
|
|
45
|
+
*
|
|
46
|
+
* const text = await run(fs.readFile(path, "utf8"));
|
|
47
|
+
* if (!text.ok) return text;
|
|
48
|
+
* assertEqual(text.value, "hello");
|
|
49
|
+
*
|
|
50
|
+
* return ok();
|
|
51
|
+
* };
|
|
52
|
+
*
|
|
53
|
+
* await runMain({ fs: createNodeFs() }, { mode: "command" })(main);
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @module
|
|
57
|
+
*/
|
|
58
|
+
/**
|
|
59
|
+
* Creates a test {@link Fs} with the supplied operation overrides.
|
|
60
|
+
*
|
|
61
|
+
* Unconfigured operations throw a defect naming the method when their Task
|
|
62
|
+
* runs. Constructing a Task does not execute it. This helper performs no file
|
|
63
|
+
* system I/O; overrides provide the behavior needed by each test.
|
|
64
|
+
*
|
|
65
|
+
* ### Example
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* import {
|
|
69
|
+
* assertEqual,
|
|
70
|
+
* assertOk,
|
|
71
|
+
* ok,
|
|
72
|
+
* testCreateFs,
|
|
73
|
+
* testCreateRun,
|
|
74
|
+
* type FsDep,
|
|
75
|
+
* type FsError,
|
|
76
|
+
* type Task,
|
|
77
|
+
* } from "@evolu/common";
|
|
78
|
+
*
|
|
79
|
+
* const saveMessage: Task<void, FsError, FsDep> = (run) =>
|
|
80
|
+
* run(run.deps.fs.writeFile("message.txt", "hello"));
|
|
81
|
+
*
|
|
82
|
+
* await using run = testCreateRun({
|
|
83
|
+
* fs: testCreateFs({
|
|
84
|
+
* writeFile: (path, data) => () => {
|
|
85
|
+
* assertEqual(path, "message.txt");
|
|
86
|
+
* assertEqual(data, "hello");
|
|
87
|
+
* return ok();
|
|
88
|
+
* },
|
|
89
|
+
* }),
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* assertOk(await run(saveMessage));
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @group Testing
|
|
96
|
+
*/
|
|
97
|
+
export const testCreateFs = (overrides = {}) => ({
|
|
98
|
+
readFile: createUnexpectedFsOperation("readFile"),
|
|
99
|
+
writeFile: createUnexpectedFsOperation("writeFile"),
|
|
100
|
+
readDirectory: createUnexpectedFsOperation("readDirectory"),
|
|
101
|
+
createDirectory: createUnexpectedFsOperation("createDirectory"),
|
|
102
|
+
copy: createUnexpectedFsOperation("copy"),
|
|
103
|
+
copyFile: createUnexpectedFsOperation("copyFile"),
|
|
104
|
+
rename: createUnexpectedFsOperation("rename"),
|
|
105
|
+
remove: createUnexpectedFsOperation("remove"),
|
|
106
|
+
getMetadata: createUnexpectedFsOperation("getMetadata"),
|
|
107
|
+
exists: createUnexpectedFsOperation("exists"),
|
|
108
|
+
createTempDirectory: createUnexpectedFsOperation("createTempDirectory"),
|
|
109
|
+
...overrides,
|
|
110
|
+
});
|
|
111
|
+
const createUnexpectedFsOperation = (method) => () => () => {
|
|
112
|
+
throw new Error(`Unexpected Fs.${method} call`);
|
|
113
|
+
};
|
package/dist/src/Identicon.d.ts
CHANGED
|
@@ -32,6 +32,7 @@ export type IdenticonStyle = "github" | "quadrant" | "gradient" | "sutnar";
|
|
|
32
32
|
* assertTrue,
|
|
33
33
|
* createIdFromString,
|
|
34
34
|
* createIdenticon,
|
|
35
|
+
* testTodoId,
|
|
35
36
|
* } from "@evolu/common";
|
|
36
37
|
*
|
|
37
38
|
* const id = createIdFromString("identicon-example");
|
|
@@ -42,8 +43,7 @@ export type IdenticonStyle = "github" | "quadrant" | "gradient" | "sutnar";
|
|
|
42
43
|
* );
|
|
43
44
|
*
|
|
44
45
|
* // Branded IDs work too.
|
|
45
|
-
* const
|
|
46
|
-
* const todoSvg = createIdenticon(todoId);
|
|
46
|
+
* const todoSvg = createIdenticon(testTodoId);
|
|
47
47
|
*
|
|
48
48
|
* assertTrue(svg.startsWith("<svg"));
|
|
49
49
|
* assertEqual(new Set([svg, ...alternativeSvgs]).size, 4);
|
package/dist/src/Identicon.js
CHANGED
|
@@ -25,6 +25,7 @@ import { Id, idToIdBytes } from "./Type.js";
|
|
|
25
25
|
* assertTrue,
|
|
26
26
|
* createIdFromString,
|
|
27
27
|
* createIdenticon,
|
|
28
|
+
* testTodoId,
|
|
28
29
|
* } from "@evolu/common";
|
|
29
30
|
*
|
|
30
31
|
* const id = createIdFromString("identicon-example");
|
|
@@ -35,8 +36,7 @@ import { Id, idToIdBytes } from "./Type.js";
|
|
|
35
36
|
* );
|
|
36
37
|
*
|
|
37
38
|
* // Branded IDs work too.
|
|
38
|
-
* const
|
|
39
|
-
* const todoSvg = createIdenticon(todoId);
|
|
39
|
+
* const todoSvg = createIdenticon(testTodoId);
|
|
40
40
|
*
|
|
41
41
|
* assertTrue(svg.startsWith("<svg"));
|
|
42
42
|
* assertEqual(new Set([svg, ...alternativeSvgs]).size, 4);
|
|
@@ -19,6 +19,8 @@ import { type ConsoleDep } from "./Console.ts";
|
|
|
19
19
|
* a warning may come late or, in short-lived processes, never. It is a
|
|
20
20
|
* development canary, not a guarantee. Production uses
|
|
21
21
|
* {@link noopLeakDetector}.
|
|
22
|
+
*
|
|
23
|
+
* @group Core
|
|
22
24
|
*/
|
|
23
25
|
export interface LeakDetector {
|
|
24
26
|
/**
|
|
@@ -33,7 +35,11 @@ export interface LeakDetector {
|
|
|
33
35
|
/** Stops tracking the target registered with `unregisterToken`. */
|
|
34
36
|
readonly untrack: (unregisterToken: object) => void;
|
|
35
37
|
}
|
|
36
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* Describes a tracked handle for {@link LeakDetector.track}.
|
|
40
|
+
*
|
|
41
|
+
* @group Core
|
|
42
|
+
*/
|
|
37
43
|
export interface Leak {
|
|
38
44
|
/** Handle name used in the warning, for example `"Lease"`. */
|
|
39
45
|
readonly name: string;
|
|
@@ -43,6 +49,7 @@ export interface Leak {
|
|
|
43
49
|
/**
|
|
44
50
|
* Dependency wrapper for {@link LeakDetector}.
|
|
45
51
|
*
|
|
52
|
+
* @group Core
|
|
46
53
|
* @see {@link LeakDetector}
|
|
47
54
|
*/
|
|
48
55
|
export interface LeakDetectorDep {
|
|
@@ -53,13 +60,20 @@ export interface LeakDetectorDep {
|
|
|
53
60
|
*
|
|
54
61
|
* Capturing a stack per track call is too expensive for production; use
|
|
55
62
|
* {@link noopLeakDetector} there.
|
|
63
|
+
*
|
|
64
|
+
* @group Core
|
|
56
65
|
*/
|
|
57
66
|
export declare const createLeakDetector: (deps: ConsoleDep) => LeakDetector;
|
|
58
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* No-op {@link LeakDetector} for production.
|
|
69
|
+
*
|
|
70
|
+
* @group Core
|
|
71
|
+
*/
|
|
59
72
|
export declare const noopLeakDetector: LeakDetector;
|
|
60
73
|
/**
|
|
61
74
|
* Test {@link LeakDetector} with deterministic collection.
|
|
62
75
|
*
|
|
76
|
+
* @group Testing
|
|
63
77
|
* @see {@link testCreateLeakDetector}
|
|
64
78
|
*/
|
|
65
79
|
export interface TestLeakDetector extends LeakDetector {
|
|
@@ -78,11 +92,16 @@ export interface TestLeakDetector extends LeakDetector {
|
|
|
78
92
|
/**
|
|
79
93
|
* Dependency wrapper for {@link TestLeakDetector}.
|
|
80
94
|
*
|
|
95
|
+
* @group Testing
|
|
81
96
|
* @see {@link TestLeakDetector}
|
|
82
97
|
*/
|
|
83
98
|
export interface TestLeakDetectorDep extends LeakDetectorDep {
|
|
84
99
|
readonly leakDetector: TestLeakDetector;
|
|
85
100
|
}
|
|
86
|
-
/**
|
|
101
|
+
/**
|
|
102
|
+
* Creates {@link TestLeakDetector}.
|
|
103
|
+
*
|
|
104
|
+
* @group Testing
|
|
105
|
+
*/
|
|
87
106
|
export declare const testCreateLeakDetector: (deps: ConsoleDep) => TestLeakDetector;
|
|
88
107
|
//# sourceMappingURL=LeakDetector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LeakDetector.d.ts","sourceRoot":"","sources":["../../src/LeakDetector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C
|
|
1
|
+
{"version":3,"file":"LeakDetector.d.ts","sourceRoot":"","sources":["../../src/LeakDetector.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;IAE9E,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,CAAC,eAAe,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD;AAED;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACnB,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC;CAClC;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,SAAU,UAAU,KAAG,YAsBrD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAG9B,CAAC;AAyBF;;;;;GAKG;AACH,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC;IAE/B,uDAAuD;IACvD,QAAQ,CAAC,eAAe,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CACnE;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAoB,SAAQ,eAAe;IAC1D,QAAQ,CAAC,YAAY,EAAE,gBAAgB,CAAC;CACzC;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,SAAU,UAAU,KAAG,gBAsCzD,CAAC"}
|
package/dist/src/LeakDetector.js
CHANGED
|
@@ -10,6 +10,8 @@ import { constVoid } from "./Function.js";
|
|
|
10
10
|
*
|
|
11
11
|
* Capturing a stack per track call is too expensive for production; use
|
|
12
12
|
* {@link noopLeakDetector} there.
|
|
13
|
+
*
|
|
14
|
+
* @group Core
|
|
13
15
|
*/
|
|
14
16
|
export const createLeakDetector = (deps) => {
|
|
15
17
|
if (typeof globalThis.FinalizationRegistry !== "function")
|
|
@@ -28,7 +30,11 @@ export const createLeakDetector = (deps) => {
|
|
|
28
30
|
},
|
|
29
31
|
};
|
|
30
32
|
};
|
|
31
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* No-op {@link LeakDetector} for production.
|
|
35
|
+
*
|
|
36
|
+
* @group Core
|
|
37
|
+
*/
|
|
32
38
|
export const noopLeakDetector = {
|
|
33
39
|
track: constVoid,
|
|
34
40
|
untrack: constVoid,
|
|
@@ -47,7 +53,11 @@ const reportLeak = (deps) => (leak) => {
|
|
|
47
53
|
deps.console.warn(`${leak.name} was garbage-collected without cleanup. Tracked at:`, leak.stack);
|
|
48
54
|
return true;
|
|
49
55
|
};
|
|
50
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Creates {@link TestLeakDetector}.
|
|
58
|
+
*
|
|
59
|
+
* @group Testing
|
|
60
|
+
*/
|
|
51
61
|
export const testCreateLeakDetector = (deps) => {
|
|
52
62
|
const trackedLeaksByToken = new Map();
|
|
53
63
|
const report = reportLeak(deps);
|
|
@@ -41,6 +41,8 @@ import type { Callback } from "./Types.ts";
|
|
|
41
41
|
* );
|
|
42
42
|
* assertEqual(result, "example");
|
|
43
43
|
* ```
|
|
44
|
+
*
|
|
45
|
+
* @group Core
|
|
44
46
|
*/
|
|
45
47
|
export interface LockManagerDep {
|
|
46
48
|
readonly lockManager: LockManager;
|
|
@@ -57,6 +59,8 @@ export interface LockManagerDep {
|
|
|
57
59
|
* via internal namespacing, so tests can reuse the same lock names without
|
|
58
60
|
* contending through the global Web Locks. Query results are filtered to that
|
|
59
61
|
* private namespace and returned with the original visible names.
|
|
62
|
+
*
|
|
63
|
+
* @group Testing
|
|
60
64
|
*/
|
|
61
65
|
export declare const testCreateLockManager: (nativeLockManager?: LockManager) => LockManager;
|
|
62
66
|
/**
|
|
@@ -68,6 +72,8 @@ export declare const testCreateLockManager: (nativeLockManager?: LockManager) =>
|
|
|
68
72
|
* Leadership is held until the returned handle is disposed. Once released,
|
|
69
73
|
* another waiting caller may become the next leader. Waiting for leadership is
|
|
70
74
|
* abortable via the calling {@link Task}'s signal.
|
|
75
|
+
*
|
|
76
|
+
* @group Leader election
|
|
71
77
|
*/
|
|
72
78
|
export declare const acquireLeaderLock: (name: string) => Task<AsyncDisposable, never, LockManagerDep>;
|
|
73
79
|
/**
|
|
@@ -80,6 +86,8 @@ export declare const acquireLeaderLock: (name: string) => Task<AsyncDisposable,
|
|
|
80
86
|
* Leadership is held until the returned handle is disposed. Once released,
|
|
81
87
|
* another waiting caller may become the next leader. Waiting for leadership is
|
|
82
88
|
* abortable by disposing the returned handle.
|
|
89
|
+
*
|
|
90
|
+
* @group Leader election
|
|
83
91
|
*/
|
|
84
92
|
export declare const acquireLeaderLockCallback: (deps: LockManagerDep) => (name: string, callback: Callback<void>) => Disposable;
|
|
85
93
|
//# sourceMappingURL=LockManager.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LockManager.d.ts","sourceRoot":"","sources":["../../src/LockManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C
|
|
1
|
+
{"version":3,"file":"LockManager.d.ts","sourceRoot":"","sources":["../../src/LockManager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;CACnC;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,qBAAqB,uBACb,WAAW,KAC7B,WAwCF,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iBAAiB,SACrB,MAAM,KAAG,IAAI,CAAC,eAAe,EAAE,KAAK,EAAE,cAAc,CAuB1D,CAAC;AAEJ;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,yBAAyB,SAC7B,cAAc,YACd,MAAM,YAAY,QAAQ,CAAC,IAAI,CAAC,KAAG,UAsBzC,CAAC"}
|
package/dist/src/LockManager.js
CHANGED
|
@@ -19,6 +19,8 @@ import { createId } from "./Type.js";
|
|
|
19
19
|
* via internal namespacing, so tests can reuse the same lock names without
|
|
20
20
|
* contending through the global Web Locks. Query results are filtered to that
|
|
21
21
|
* private namespace and returned with the original visible names.
|
|
22
|
+
*
|
|
23
|
+
* @group Testing
|
|
22
24
|
*/
|
|
23
25
|
export const testCreateLockManager = (nativeLockManager = navigator.locks) => {
|
|
24
26
|
const namespace = createId({ randomBytes: createRandomBytes() });
|
|
@@ -54,6 +56,8 @@ export const testCreateLockManager = (nativeLockManager = navigator.locks) => {
|
|
|
54
56
|
* Leadership is held until the returned handle is disposed. Once released,
|
|
55
57
|
* another waiting caller may become the next leader. Waiting for leadership is
|
|
56
58
|
* abortable via the calling {@link Task}'s signal.
|
|
59
|
+
*
|
|
60
|
+
* @group Leader election
|
|
57
61
|
*/
|
|
58
62
|
export const acquireLeaderLock = (name) => async (run) => {
|
|
59
63
|
const acquisition = Promise.withResolvers();
|
|
@@ -81,6 +85,8 @@ export const acquireLeaderLock = (name) => async (run) => {
|
|
|
81
85
|
* Leadership is held until the returned handle is disposed. Once released,
|
|
82
86
|
* another waiting caller may become the next leader. Waiting for leadership is
|
|
83
87
|
* abortable by disposing the returned handle.
|
|
88
|
+
*
|
|
89
|
+
* @group Leader election
|
|
84
90
|
*/
|
|
85
91
|
export const acquireLeaderLockCallback = (deps) => (name, callback) => {
|
|
86
92
|
const abortController = new AbortController();
|
package/dist/src/Number.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import type { NonEmptyReadonlyArray } from "./Array.ts";
|
|
7
7
|
import type { IsBranded } from "./Brand.ts";
|
|
8
8
|
import type { Result } from "./Result.ts";
|
|
9
|
-
import { Digit1To99, NonNegativeInt, PositiveInt, Ratio } from "./Type.ts";
|
|
9
|
+
import { type Type, type TypeError, type UnionError, Digit1To9, Digit1To99, NonNegativeInt, PositiveInt, Ratio } from "./Type.ts";
|
|
10
10
|
import type { Predicate, WidenLiteral } from "./Types.ts";
|
|
11
11
|
/** Integer literal from `1` to `99`. */
|
|
12
12
|
export type Int1To99 = Digit1To99 extends `${infer Value extends number}` ? Value : never;
|
|
@@ -76,14 +76,57 @@ export type Int1To100OrPositiveInt = Int1To100 | PositiveInt;
|
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
78
|
export type Percentage = PercentageLiteral | Ratio;
|
|
79
|
+
export type PercentageLiteral = "0%" | "100%" | `${Digit1To99}%` | `${"0" | Digit1To99}.${Digit1To9}%`;
|
|
79
80
|
/**
|
|
80
|
-
* Percentage literal
|
|
81
|
+
* Percentage literal Type with compile-time and runtime validation.
|
|
81
82
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
83
|
+
* Supported formats:
|
|
84
|
+
*
|
|
85
|
+
* - Integers: `0%`, `50%`, `100%` (0-100)
|
|
86
|
+
* - One decimal place: `0.1%`, `12.5%`, `99.9%` (0.1-99.9)
|
|
87
|
+
*
|
|
88
|
+
* The decimal digit is never zero, so `12.0%` must be written as `"12%"`, and
|
|
89
|
+
* `100%` has no decimal form. For computed values or more precision, use
|
|
90
|
+
* {@link Ratio} directly.
|
|
91
|
+
*
|
|
92
|
+
* See {@link Percentage} for a type that also accepts {@link Ratio}. Use
|
|
93
|
+
* {@link percentageToRatio} to convert.
|
|
94
|
+
*
|
|
95
|
+
* Invalid values produce a {@link PercentageLiteralError}.
|
|
96
|
+
*
|
|
97
|
+
* ### Example
|
|
98
|
+
*
|
|
99
|
+
* ```ts
|
|
100
|
+
* import {
|
|
101
|
+
* assertFalse,
|
|
102
|
+
* assertOk,
|
|
103
|
+
* assertType,
|
|
104
|
+
* PercentageLiteral,
|
|
105
|
+
* } from "@evolu/common";
|
|
106
|
+
*
|
|
107
|
+
* // The TypeScript type accepts valid spellings and rejects the rest.
|
|
108
|
+
* const literal: PercentageLiteral = "12.5%";
|
|
109
|
+
* assertType<
|
|
110
|
+
* Extract<PercentageLiteral, "101%" | "12.0%" | "12.55%">,
|
|
111
|
+
* never
|
|
112
|
+
* >();
|
|
113
|
+
*
|
|
114
|
+
* // The runtime Type validates the same grammar.
|
|
115
|
+
* assertOk(PercentageLiteral.fromUnknown(literal), "12.5%");
|
|
116
|
+
* assertFalse(PercentageLiteral.is("101%"));
|
|
117
|
+
* ```
|
|
84
118
|
*/
|
|
85
|
-
export declare const PercentageLiteral:
|
|
86
|
-
|
|
119
|
+
export declare const PercentageLiteral: Type<"PercentageLiteral", PercentageLiteral, PercentageLiteral, PercentageLiteralError>;
|
|
120
|
+
/** Error returned when {@link PercentageLiteral} rejects a value. */
|
|
121
|
+
export interface PercentageLiteralError extends TypeError<"PercentageLiteral"> {
|
|
122
|
+
readonly value: unknown;
|
|
123
|
+
/**
|
|
124
|
+
* The underlying union failure, retained for diagnostics.
|
|
125
|
+
*
|
|
126
|
+
* With `{ errors: "all" }`, includes every failed alternative.
|
|
127
|
+
*/
|
|
128
|
+
readonly cause: UnionError;
|
|
129
|
+
}
|
|
87
130
|
/** Converts a {@link Percentage} to its numeric {@link Ratio}. */
|
|
88
131
|
export declare const percentageToRatio: (percentage: Percentage) => Ratio;
|
|
89
132
|
export declare const increment: (n: number) => number;
|
|
@@ -150,7 +193,7 @@ minNumberOfItemsPerBucket?: number & import("./Brand.ts").Brand<"NonNaN"> & impo
|
|
|
150
193
|
*
|
|
151
194
|
* Limited to 78 because F(79) exceeds JavaScript's `MAX_SAFE_INTEGER`.
|
|
152
195
|
*/
|
|
153
|
-
export declare const FibonacciIndex: import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<
|
|
196
|
+
export declare const FibonacciIndex: import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<import("./Type.ts").BrandType<Type<"Number", number, number, import("./Type.ts").TypeOfError<"Number">, null, import("./Type.ts").TypeOfError<"Number">, never, number, true>, "NonNaN", import("./Type.ts").NonNaNError>, "Finite", import("./Type.ts").FiniteError>, "Int", import("./Type.ts").IntError>, "NonNegative", import("./Type.ts").NonNegativeError>, "Positive", import("./Type.ts").PositiveError>, "LessThanOrEqualTo78", import("./Type.ts").LessThanOrEqualToError<78>>, "FibonacciIndex", never>;
|
|
154
197
|
export type FibonacciIndex = typeof FibonacciIndex.Output;
|
|
155
198
|
/** Returns the Fibonacci number at the given index (1-indexed: 1,1,2,3,5,8,...). */
|
|
156
199
|
export declare const fibonacciAt: (index: FibonacciIndex) => PositiveInt;
|
package/dist/src/Number.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Number.d.ts","sourceRoot":"","sources":["../../src/Number.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAExD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"Number.d.ts","sourceRoot":"","sources":["../../src/Number.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Number.js
CHANGED
|
@@ -4,18 +4,57 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { assertNonEmptyReadonlyArray } from "./Assert.js";
|
|
7
|
+
import { safelyStringifyUnknownValue } from "./String.js";
|
|
7
8
|
import { err, ok } from "./Result.js";
|
|
8
|
-
import { brand, Digit1To9, Digit1To99, lessThanOrEqualTo, onePositiveInt, NonNegativeInt, PositiveInt, Ratio, templateLiteral, union, } from "./Type.js";
|
|
9
|
-
|
|
10
|
-
* Percentage literal from `"0%"` to `"100%"`.
|
|
11
|
-
*
|
|
12
|
-
* Decimal literals support one decimal place. Use {@link Ratio} for computed
|
|
13
|
-
* values or greater precision.
|
|
14
|
-
*/
|
|
15
|
-
export const PercentageLiteral = /*#__PURE__*/ union("0%", "100%",
|
|
9
|
+
import { brand, createTypeWithError, Digit1To9, Digit1To99, lessThanOrEqualTo, onePositiveInt, NonNegativeInt, PositiveInt, Ratio, templateLiteral, union, } from "./Type.js";
|
|
10
|
+
const percentageLiteralSyntax = /*#__PURE__*/ union("0%", "100%",
|
|
16
11
|
/*#__PURE__*/ templateLiteral(Digit1To99, "%"),
|
|
17
12
|
/*#__PURE__*/ templateLiteral(
|
|
18
13
|
/*#__PURE__*/ union("0", Digit1To99), ".", Digit1To9, "%"));
|
|
14
|
+
/**
|
|
15
|
+
* Percentage literal Type with compile-time and runtime validation.
|
|
16
|
+
*
|
|
17
|
+
* Supported formats:
|
|
18
|
+
*
|
|
19
|
+
* - Integers: `0%`, `50%`, `100%` (0-100)
|
|
20
|
+
* - One decimal place: `0.1%`, `12.5%`, `99.9%` (0.1-99.9)
|
|
21
|
+
*
|
|
22
|
+
* The decimal digit is never zero, so `12.0%` must be written as `"12%"`, and
|
|
23
|
+
* `100%` has no decimal form. For computed values or more precision, use
|
|
24
|
+
* {@link Ratio} directly.
|
|
25
|
+
*
|
|
26
|
+
* See {@link Percentage} for a type that also accepts {@link Ratio}. Use
|
|
27
|
+
* {@link percentageToRatio} to convert.
|
|
28
|
+
*
|
|
29
|
+
* Invalid values produce a {@link PercentageLiteralError}.
|
|
30
|
+
*
|
|
31
|
+
* ### Example
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* import {
|
|
35
|
+
* assertFalse,
|
|
36
|
+
* assertOk,
|
|
37
|
+
* assertType,
|
|
38
|
+
* PercentageLiteral,
|
|
39
|
+
* } from "@evolu/common";
|
|
40
|
+
*
|
|
41
|
+
* // The TypeScript type accepts valid spellings and rejects the rest.
|
|
42
|
+
* const literal: PercentageLiteral = "12.5%";
|
|
43
|
+
* assertType<
|
|
44
|
+
* Extract<PercentageLiteral, "101%" | "12.0%" | "12.55%">,
|
|
45
|
+
* never
|
|
46
|
+
* >();
|
|
47
|
+
*
|
|
48
|
+
* // The runtime Type validates the same grammar.
|
|
49
|
+
* assertOk(PercentageLiteral.fromUnknown(literal), "12.5%");
|
|
50
|
+
* assertFalse(PercentageLiteral.is("101%"));
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export const PercentageLiteral = /*#__PURE__*/ createTypeWithError("PercentageLiteral", percentageLiteralSyntax, (cause, value) => ({
|
|
54
|
+
type: "PercentageLiteral",
|
|
55
|
+
value,
|
|
56
|
+
cause,
|
|
57
|
+
}), (error) => `The value ${safelyStringifyUnknownValue(error.value)} is not a percentage literal. Use a value such as "50%" or "12.5%".`);
|
|
19
58
|
/** Converts a {@link Percentage} to its numeric {@link Ratio}. */
|
|
20
59
|
export const percentageToRatio = (percentage) => typeof percentage === "number"
|
|
21
60
|
? percentage
|
package/dist/src/Object.d.ts
CHANGED
|
@@ -175,6 +175,38 @@ export declare const objectFrom: <K extends string, V>(keys: ReadonlyArray<K>, g
|
|
|
175
175
|
* Uses `K extends string` for precision.
|
|
176
176
|
*/
|
|
177
177
|
export declare const mapObject: <K extends string, V, U>(record: ReadonlyRecord<K, V>, fn: (value: V, key: K) => U) => ReadonlyRecord<K, U>;
|
|
178
|
+
/**
|
|
179
|
+
* Selects own string-keyed properties while preserving their descriptors.
|
|
180
|
+
*
|
|
181
|
+
* Visits enumerable and non-enumerable properties, ignoring inherited and
|
|
182
|
+
* symbol properties. The predicate receives only the key; property values and
|
|
183
|
+
* getters are never read. The result is a new ordinary object with matching
|
|
184
|
+
* descriptors, including accessor functions and property flags. Declared
|
|
185
|
+
* properties are optional because the predicate may exclude any of them.
|
|
186
|
+
* Numeric property names are visited as strings.
|
|
187
|
+
*
|
|
188
|
+
* ### Example
|
|
189
|
+
*
|
|
190
|
+
* ```ts
|
|
191
|
+
* import {
|
|
192
|
+
* assertEqual,
|
|
193
|
+
* assertType,
|
|
194
|
+
* filterObjectKeys,
|
|
195
|
+
* } from "@evolu/common";
|
|
196
|
+
*
|
|
197
|
+
* const source = { APP_PORT: "4000", HOME: "/home/evolu" };
|
|
198
|
+
* const selected = filterObjectKeys(source, (key) =>
|
|
199
|
+
* key.startsWith("APP_"),
|
|
200
|
+
* );
|
|
201
|
+
*
|
|
202
|
+
* assertEqual(selected, { APP_PORT: "4000" });
|
|
203
|
+
* assertType<
|
|
204
|
+
* typeof selected,
|
|
205
|
+
* { readonly APP_PORT?: string; readonly HOME?: string }
|
|
206
|
+
* >();
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
export declare const filterObjectKeys: <T extends object>(source: T, predicate: (key: string) => boolean) => Readonly<Partial<Pick<T, Exclude<keyof T, symbol>>>>;
|
|
178
210
|
/** Conditionally excludes a property from an object. */
|
|
179
211
|
export declare const excludeProp: <T extends object, K extends keyof T>(obj: T, prop: K, condition?: boolean) => typeof condition extends true ? T : Omit<T, K>;
|
|
180
212
|
/**
|
package/dist/src/Object.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Object.d.ts","sourceRoot":"","sources":["../../src/Object.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,EAAE,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAE5E,oEAAoE;AACpE,MAAM,MAAM,UAAU,GACpB,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,YAAY,GAAG,aAAa,CAAC;AAE7E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,UAAW,MAAM,KAAG,UAgB7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,aAAa,UACjB,OAAO,KACb,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,
|
|
1
|
+
{"version":3,"file":"Object.d.ts","sourceRoot":"","sources":["../../src/Object.ts"],"names":[],"mappings":"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"}
|
package/dist/src/Object.js
CHANGED
|
@@ -74,6 +74,11 @@ export const isPlainObject = (value) => {
|
|
|
74
74
|
const prototype = Object.getPrototypeOf(value);
|
|
75
75
|
if (prototype === null)
|
|
76
76
|
return true;
|
|
77
|
+
// This realm's Object.prototype has an immutable null prototype, so `in`
|
|
78
|
+
// checks the same own properties as the structural test below, faster.
|
|
79
|
+
if (prototype === Object.prototype) {
|
|
80
|
+
return "hasOwnProperty" in prototype && "isPrototypeOf" in prototype;
|
|
81
|
+
}
|
|
77
82
|
return (Object.getPrototypeOf(prototype) === null &&
|
|
78
83
|
Object.hasOwn(prototype, "hasOwnProperty") &&
|
|
79
84
|
Object.hasOwn(prototype, "isPrototypeOf"));
|
|
@@ -202,6 +207,47 @@ export const mapObject = (record, fn) => {
|
|
|
202
207
|
}
|
|
203
208
|
return out;
|
|
204
209
|
};
|
|
210
|
+
/**
|
|
211
|
+
* Selects own string-keyed properties while preserving their descriptors.
|
|
212
|
+
*
|
|
213
|
+
* Visits enumerable and non-enumerable properties, ignoring inherited and
|
|
214
|
+
* symbol properties. The predicate receives only the key; property values and
|
|
215
|
+
* getters are never read. The result is a new ordinary object with matching
|
|
216
|
+
* descriptors, including accessor functions and property flags. Declared
|
|
217
|
+
* properties are optional because the predicate may exclude any of them.
|
|
218
|
+
* Numeric property names are visited as strings.
|
|
219
|
+
*
|
|
220
|
+
* ### Example
|
|
221
|
+
*
|
|
222
|
+
* ```ts
|
|
223
|
+
* import {
|
|
224
|
+
* assertEqual,
|
|
225
|
+
* assertType,
|
|
226
|
+
* filterObjectKeys,
|
|
227
|
+
* } from "@evolu/common";
|
|
228
|
+
*
|
|
229
|
+
* const source = { APP_PORT: "4000", HOME: "/home/evolu" };
|
|
230
|
+
* const selected = filterObjectKeys(source, (key) =>
|
|
231
|
+
* key.startsWith("APP_"),
|
|
232
|
+
* );
|
|
233
|
+
*
|
|
234
|
+
* assertEqual(selected, { APP_PORT: "4000" });
|
|
235
|
+
* assertType<
|
|
236
|
+
* typeof selected,
|
|
237
|
+
* { readonly APP_PORT?: string; readonly HOME?: string }
|
|
238
|
+
* >();
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
export const filterObjectKeys = (source, predicate) => {
|
|
242
|
+
const selected = {};
|
|
243
|
+
for (const key of Object.getOwnPropertyNames(source)) {
|
|
244
|
+
if (!predicate(key))
|
|
245
|
+
continue;
|
|
246
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
247
|
+
Object.defineProperty(selected, key, descriptor);
|
|
248
|
+
}
|
|
249
|
+
return selected;
|
|
250
|
+
};
|
|
205
251
|
/** Conditionally excludes a property from an object. */
|
|
206
252
|
export const excludeProp = (obj, prop, condition) => {
|
|
207
253
|
if (condition) {
|