@evolu/common 7.4.0 → 8.0.0-next.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 +4 -61
- package/dist/src/Array.d.ts +343 -102
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +181 -85
- package/dist/src/Assert.d.ts +57 -11
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +47 -11
- package/dist/src/BigInt.d.ts +6 -1
- package/dist/src/BigInt.d.ts.map +1 -1
- package/dist/src/BigInt.js +5 -0
- package/dist/src/Brand.d.ts +40 -12
- package/dist/src/Brand.d.ts.map +1 -1
- package/dist/src/Brand.js +5 -0
- package/dist/src/Buffer.d.ts +6 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +7 -2
- package/dist/src/Cache.d.ts +10 -2
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +6 -0
- package/dist/src/Callbacks.d.ts +10 -7
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +23 -13
- package/dist/src/Console.d.ts +361 -69
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +217 -117
- package/dist/src/Crypto.d.ts +70 -21
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +72 -27
- package/dist/src/Eq.d.ts +22 -2
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +21 -1
- package/dist/src/Error.d.ts +23 -12
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +27 -11
- package/dist/src/Function.d.ts +128 -56
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +118 -14
- package/dist/src/Identicon.d.ts +5 -0
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +6 -1
- package/dist/src/Lookup.d.ts +160 -0
- package/dist/src/Lookup.d.ts.map +1 -0
- package/dist/src/Lookup.js +192 -0
- package/dist/src/Microtask.d.ts +21 -0
- package/dist/src/Microtask.d.ts.map +1 -0
- package/dist/src/Microtask.js +37 -0
- package/dist/src/Number.d.ts +18 -4
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +23 -1
- package/dist/src/Object.d.ts +110 -5
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +108 -5
- package/dist/src/Option.d.ts +58 -0
- package/dist/src/Option.d.ts.map +1 -0
- package/dist/src/Option.js +43 -0
- package/dist/src/Order.d.ts +5 -0
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +8 -3
- package/dist/src/Platform.d.ts +36 -2
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +10 -6
- package/dist/src/Polyfills.d.ts +27 -0
- package/dist/src/Polyfills.d.ts.map +1 -0
- package/dist/src/Polyfills.js +299 -0
- package/dist/src/Random.d.ts +18 -7
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +9 -7
- package/dist/src/Redacted.d.ts +7 -4
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +5 -0
- package/dist/src/Ref.d.ts +31 -16
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Ref.js +35 -7
- package/dist/src/RefCount.d.ts +62 -0
- package/dist/src/RefCount.d.ts.map +1 -0
- package/dist/src/RefCount.js +83 -0
- package/dist/src/Relation.d.ts +84 -29
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +83 -105
- package/dist/src/Resource.d.ts +263 -0
- package/dist/src/Resource.d.ts.map +1 -0
- package/dist/src/Resource.js +389 -0
- package/dist/src/Result.d.ts +390 -374
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +142 -70
- package/dist/src/Schedule.d.ts +953 -0
- package/dist/src/Schedule.d.ts.map +1 -0
- package/dist/src/Schedule.js +1199 -0
- package/dist/src/Set.d.ts +181 -0
- package/dist/src/Set.d.ts.map +1 -0
- package/dist/src/Set.js +137 -0
- package/dist/src/Skiplist.d.ts +6 -1
- package/dist/src/Skiplist.d.ts.map +1 -1
- package/dist/src/Skiplist.js +5 -0
- package/dist/src/Sqlite.d.ts +160 -60
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +290 -190
- package/dist/src/Store.d.ts +36 -28
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +55 -15
- package/dist/src/String.d.ts +5 -0
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +5 -0
- package/dist/src/Task.d.ts +2263 -423
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1488 -348
- package/dist/src/Test.d.ts +122 -0
- package/dist/src/Test.d.ts.map +1 -0
- package/dist/src/Test.js +66 -0
- package/dist/src/Time.d.ts +201 -48
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +190 -86
- package/dist/src/Tracer.d.ts +48 -0
- package/dist/src/Tracer.d.ts.map +1 -0
- package/dist/src/Tracer.js +6 -0
- package/dist/src/Type.d.ts +582 -209
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +362 -240
- package/dist/src/Types.d.ts +160 -6
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +22 -2
- package/dist/src/WebSocket.d.ts +113 -58
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +210 -118
- package/dist/src/Worker.d.ts +245 -60
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +220 -64
- package/dist/src/index.d.ts +25 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -3
- package/dist/src/local-first/Db.d.ts +24 -213
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +622 -293
- package/dist/src/local-first/Error.d.ts +12 -0
- package/dist/src/local-first/Error.d.ts.map +1 -0
- package/dist/src/local-first/Error.js +6 -0
- package/dist/src/local-first/Evolu.d.ts +330 -285
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +472 -402
- package/dist/src/local-first/LocalAuth.d.ts +10 -10
- package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
- package/dist/src/local-first/LocalAuth.js +6 -1
- package/dist/src/local-first/Owner.d.ts +70 -27
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +27 -14
- package/dist/src/local-first/Protocol.d.ts +58 -50
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +253 -155
- package/dist/src/local-first/Query.d.ts +133 -43
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +139 -90
- package/dist/src/local-first/Relay.d.ts +18 -38
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +59 -171
- package/dist/src/local-first/Schema.d.ts +139 -144
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +78 -163
- package/dist/src/local-first/Shared.d.ts +125 -0
- package/dist/src/local-first/Shared.d.ts.map +1 -0
- package/dist/src/local-first/Shared.js +569 -0
- package/dist/src/local-first/Storage.d.ts +50 -53
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +121 -173
- package/dist/src/local-first/Timestamp.d.ts +28 -35
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +24 -25
- package/dist/src/local-first/index.d.ts +2 -15
- package/dist/src/local-first/index.d.ts.map +1 -1
- package/dist/src/local-first/index.js +2 -15
- package/package.json +36 -26
- package/src/Array.ts +467 -106
- package/src/Assert.ts +87 -12
- package/src/BigInt.ts +7 -1
- package/src/Brand.ts +41 -12
- package/src/Buffer.ts +10 -4
- package/src/Cache.ts +11 -2
- package/src/Callbacks.ts +33 -23
- package/src/Console.ts +567 -178
- package/src/Crypto.ts +111 -62
- package/src/Eq.ts +30 -3
- package/src/Error.ts +50 -34
- package/src/Function.ts +140 -68
- package/src/Identicon.ts +7 -1
- package/src/Lookup.ts +415 -0
- package/src/Microtask.ts +58 -0
- package/src/Number.ts +40 -7
- package/src/Object.ts +155 -16
- package/src/Option.ts +74 -0
- package/src/Order.ts +11 -3
- package/src/Platform.ts +43 -7
- package/src/Polyfills.ts +465 -0
- package/src/Random.ts +25 -11
- package/src/Redacted.ts +8 -4
- package/src/Ref.ts +72 -21
- package/src/RefCount.ts +170 -0
- package/src/Relation.ts +188 -136
- package/src/Resource.ts +864 -0
- package/src/Result.ts +548 -381
- package/src/Schedule.ts +1471 -0
- package/src/Set.ts +247 -0
- package/src/Skiplist.ts +7 -1
- package/src/Sqlite.ts +409 -304
- package/src/Store.ts +94 -48
- package/src/String.ts +6 -0
- package/src/Task.ts +3685 -740
- package/src/Test.ts +162 -0
- package/src/Time.ts +348 -145
- package/src/Tracer.ts +54 -0
- package/src/Type.ts +1064 -630
- package/src/Types.ts +202 -7
- package/src/WebSocket.ts +311 -178
- package/src/Worker.ts +527 -147
- package/src/index.ts +74 -3
- package/src/local-first/Db.ts +871 -597
- package/src/local-first/Error.ts +17 -0
- package/src/local-first/Evolu.ts +884 -823
- package/src/local-first/LocalAuth.ts +10 -10
- package/src/local-first/Owner.ts +94 -42
- package/src/local-first/Protocol.ts +440 -303
- package/src/local-first/Query.ts +243 -194
- package/src/local-first/Relay.ts +91 -252
- package/src/local-first/Schema.ts +284 -394
- package/src/local-first/Shared.ts +932 -0
- package/src/local-first/Storage.ts +209 -282
- package/src/local-first/Timestamp.ts +38 -45
- package/src/local-first/index.ts +2 -16
- package/LICENSE +0 -21
- package/dist/src/Instances.d.ts +0 -34
- package/dist/src/Instances.d.ts.map +0 -1
- package/dist/src/Instances.js +0 -44
- package/dist/src/Resources.d.ts +0 -118
- package/dist/src/Resources.d.ts.map +0 -1
- package/dist/src/Resources.js +0 -197
- package/dist/src/local-first/Platform.d.ts +0 -25
- package/dist/src/local-first/Platform.d.ts.map +0 -1
- package/dist/src/local-first/Platform.js +0 -1
- package/dist/src/local-first/Public.d.ts +0 -22
- package/dist/src/local-first/Public.d.ts.map +0 -1
- package/dist/src/local-first/Public.js +0 -15
- package/dist/src/local-first/PublicKysely.d.ts +0 -148
- package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
- package/dist/src/local-first/PublicKysely.js +0 -184
- package/dist/src/local-first/Sync.d.ts +0 -112
- package/dist/src/local-first/Sync.d.ts.map +0 -1
- package/dist/src/local-first/Sync.js +0 -529
- package/src/Instances.ts +0 -90
- package/src/Resources.ts +0 -367
- package/src/local-first/Platform.ts +0 -27
- package/src/local-first/Public.ts +0 -42
- package/src/local-first/PublicKysely.ts +0 -239
- package/src/local-first/Sync.ts +0 -960
package/dist/src/Function.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function utilities including exhaustive checks and composition.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
1
6
|
/**
|
|
2
7
|
* Helper function to ensure exhaustive matching in a switch statement. Throws
|
|
3
8
|
* an error if an unhandled case is encountered.
|
|
4
9
|
*
|
|
5
|
-
* Remember, it's useful only when we don't return anything from the switch
|
|
6
|
-
* statement. Otherwise, a return type of a function is enough.
|
|
7
|
-
*
|
|
8
10
|
* ### Example
|
|
9
11
|
*
|
|
10
12
|
* ```ts
|
|
11
13
|
* type Color = "red" | "green" | "blue";
|
|
12
14
|
*
|
|
13
|
-
*
|
|
15
|
+
* const handleColor = (color: Color): void => {
|
|
14
16
|
* switch (color) {
|
|
15
17
|
* case "red":
|
|
16
18
|
* console.log("Handling red");
|
|
@@ -24,14 +26,70 @@
|
|
|
24
26
|
* default:
|
|
25
27
|
* exhaustiveCheck(color); // Ensures all cases are handled
|
|
26
28
|
* }
|
|
27
|
-
* }
|
|
29
|
+
* };
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* Use this primarily in side-effect switches (`void` branches). For
|
|
33
|
+
* value-producing switches, TypeScript can enforce exhaustiveness without a
|
|
34
|
+
* `default` branch.
|
|
35
|
+
*
|
|
36
|
+
* ### Example
|
|
37
|
+
*
|
|
38
|
+
* Return from each case for value-producing switches.
|
|
39
|
+
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* type Color = "red" | "green" | "blue";
|
|
42
|
+
*
|
|
43
|
+
* const colorToHex = (color: Color): string => {
|
|
44
|
+
* switch (color) {
|
|
45
|
+
* case "red":
|
|
46
|
+
* return "#ff0000";
|
|
47
|
+
* case "green":
|
|
48
|
+
* return "#00ff00";
|
|
49
|
+
* case "blue":
|
|
50
|
+
* return "#0000ff";
|
|
51
|
+
* }
|
|
52
|
+
* };
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* ### Example
|
|
56
|
+
*
|
|
57
|
+
* Use assignment + no `default` to get exhaustiveness by definite assignment.
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* type Input =
|
|
61
|
+
* | { readonly type: "Mutate" }
|
|
62
|
+
* | { readonly type: "Query" }
|
|
63
|
+
* | { readonly type: "Export" };
|
|
64
|
+
*
|
|
65
|
+
* const onInput = (input: Input): void => {
|
|
66
|
+
* let result: "A" | "B" | "C";
|
|
67
|
+
*
|
|
68
|
+
* switch (input.type) {
|
|
69
|
+
* case "Mutate":
|
|
70
|
+
* result = "A";
|
|
71
|
+
* break;
|
|
72
|
+
* case "Query":
|
|
73
|
+
* result = "B";
|
|
74
|
+
* break;
|
|
75
|
+
* case "Export":
|
|
76
|
+
* result = "C";
|
|
77
|
+
* break;
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* handleKind(result);
|
|
81
|
+
* };
|
|
82
|
+
*
|
|
83
|
+
* const handleKind = (kind: "A" | "B" | "C"): void => {
|
|
84
|
+
* console.log(kind);
|
|
85
|
+
* };
|
|
28
86
|
* ```
|
|
29
87
|
*/
|
|
30
88
|
export const exhaustiveCheck = (value) => {
|
|
31
89
|
throw new Error(`exhaustiveCheck unhandled case: ${JSON.stringify(value)}`);
|
|
32
90
|
};
|
|
33
91
|
/**
|
|
34
|
-
* Returns the
|
|
92
|
+
* Returns the value unchanged.
|
|
35
93
|
*
|
|
36
94
|
* Useful as a default transformation, placeholder callback, or when a function
|
|
37
95
|
* is required but no transformation is needed.
|
|
@@ -47,11 +105,57 @@ export const exhaustiveCheck = (value) => {
|
|
|
47
105
|
* ```
|
|
48
106
|
*/
|
|
49
107
|
export const identity = (a) => a;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Creates a {@link Lazy} from a precomputed value.
|
|
110
|
+
*
|
|
111
|
+
* Use when the value is expensive to compute and want to compute it once at
|
|
112
|
+
* definition time rather than on every call.
|
|
113
|
+
*
|
|
114
|
+
* ### Example
|
|
115
|
+
*
|
|
116
|
+
* ```ts
|
|
117
|
+
* // Computed once at definition, returned on every call
|
|
118
|
+
* const getConfig = lazy(parseConfig(rawConfig));
|
|
119
|
+
*
|
|
120
|
+
* // vs. computed on every call
|
|
121
|
+
* const getConfig = () => parseConfig(rawConfig);
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
export const lazy = (value) => () => value;
|
|
125
|
+
/** A {@link Lazy} that returns `true`. */
|
|
126
|
+
export const lazyTrue = /*#__PURE__*/ lazy(true);
|
|
127
|
+
/** A {@link Lazy} that returns `false`. */
|
|
128
|
+
export const lazyFalse = /*#__PURE__*/ lazy(false);
|
|
129
|
+
/** A {@link Lazy} that returns `null`. */
|
|
130
|
+
export const lazyNull = /*#__PURE__*/ lazy(null);
|
|
131
|
+
/** A {@link Lazy} that returns `undefined`. */
|
|
132
|
+
export const lazyUndefined = /*#__PURE__*/ lazy(undefined);
|
|
133
|
+
/** A {@link Lazy} that returns `undefined` for void callbacks. */
|
|
134
|
+
export const lazyVoid = lazyUndefined;
|
|
135
|
+
/**
|
|
136
|
+
* Development placeholder that always throws.
|
|
137
|
+
*
|
|
138
|
+
* Use to sketch function bodies before implementing them. TypeScript infers the
|
|
139
|
+
* return type from context, so surrounding code still type-checks. Use an
|
|
140
|
+
* explicit generic when there is no return type annotation.
|
|
141
|
+
*
|
|
142
|
+
* ### Example
|
|
143
|
+
*
|
|
144
|
+
* ```ts
|
|
145
|
+
* // Type inferred from return type annotation
|
|
146
|
+
* const fetchUser = (id: UserId): Result<User, FetchError> => todo();
|
|
147
|
+
*
|
|
148
|
+
* expectTypeOf(fetchUser).returns.toEqualTypeOf<
|
|
149
|
+
* Result<User, FetchError>
|
|
150
|
+
* >();
|
|
151
|
+
*
|
|
152
|
+
* // Explicit generic when no return type
|
|
153
|
+
* const getConfig = () => todo<Config>();
|
|
154
|
+
*
|
|
155
|
+
* expectTypeOf(getConfig).returns.toEqualTypeOf<Config>();
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
159
|
+
export const todo = () => {
|
|
160
|
+
throw new Error("not yet implemented");
|
|
161
|
+
};
|
package/dist/src/Identicon.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Identicon.d.ts","sourceRoot":"","sources":["../../src/Identicon.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,EAAE,EAAe,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"Identicon.d.ts","sourceRoot":"","sources":["../../src/Identicon.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,EAAE,EAAe,MAAM,WAAW,CAAC;AAE5C;;;GAGG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;AAEpD,+BAA+B;AAC/B,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,eAAe,GAC1B,IAAI,EAAE,EACN,QAAO,cAAyB,KAC/B,SA4JF,CAAC"}
|
package/dist/src/Identicon.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Visual identicon generation from IDs.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
2
6
|
import { md5 } from "@noble/hashes/legacy.js";
|
|
7
|
+
import { Id, idToIdBytes } from "./Type.js";
|
|
3
8
|
/**
|
|
4
9
|
* Creates a deterministic identicon SVG from an {@link Id}.
|
|
5
10
|
*
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lookup-key collections and helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Brand } from "./Brand.js";
|
|
7
|
+
/**
|
|
8
|
+
* Derives the native lookup key used by lookup-based collections.
|
|
9
|
+
*
|
|
10
|
+
* Native `Map` and `Set` are suitable for primitive keys and keys where
|
|
11
|
+
* reference identity is the intended key, but they are not useful when
|
|
12
|
+
* different references should represent the same logical key.
|
|
13
|
+
*
|
|
14
|
+
* Lookup-based collections solve that by deriving a stable lookup key from each
|
|
15
|
+
* input key and using that lookup key for the internal native `Map` lookup.
|
|
16
|
+
* Keys that derive the same lookup key are treated as the same logical key.
|
|
17
|
+
*
|
|
18
|
+
* Use this when callers provide keys in one form but logical identity should be
|
|
19
|
+
* based on another stable key, such as a natural id or {@link StructuralKey}.
|
|
20
|
+
*
|
|
21
|
+
* @see {@link createLookupMap}
|
|
22
|
+
* @see {@link createLookupSet}
|
|
23
|
+
*/
|
|
24
|
+
export type Lookup<K, L> = (key: K) => L;
|
|
25
|
+
/** Optional {@link Lookup}. */
|
|
26
|
+
export interface LookupOption<K, L = K> {
|
|
27
|
+
/** Derives the lookup key used for logical equality. */
|
|
28
|
+
readonly lookup?: Lookup<K, L>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* `Map`-like collection keyed by a {@link Lookup derived lookup key}.
|
|
32
|
+
*
|
|
33
|
+
* `set` preserves the first inserted representative for a logical key. `getKey`
|
|
34
|
+
* returns that representative for callers that need stable identity.
|
|
35
|
+
*
|
|
36
|
+
* @see {@link createLookupMap}
|
|
37
|
+
*/
|
|
38
|
+
export interface LookupMap<K, V> extends Iterable<readonly [K, V]> {
|
|
39
|
+
readonly size: number;
|
|
40
|
+
readonly has: (key: K) => boolean;
|
|
41
|
+
readonly get: (key: K) => V | undefined;
|
|
42
|
+
readonly getKey: (key: K) => K | undefined;
|
|
43
|
+
readonly set: (key: K, value: V) => LookupMap<K, V>;
|
|
44
|
+
readonly delete: (key: K) => boolean;
|
|
45
|
+
readonly clear: () => void;
|
|
46
|
+
readonly keys: () => IterableIterator<K>;
|
|
47
|
+
readonly values: () => IterableIterator<V>;
|
|
48
|
+
readonly entries: () => IterableIterator<readonly [K, V]>;
|
|
49
|
+
readonly forEach: (callback: (value: V, key: K, map: LookupMap<K, V>) => void) => void;
|
|
50
|
+
readonly [Symbol.iterator]: () => IterableIterator<readonly [K, V]>;
|
|
51
|
+
}
|
|
52
|
+
/** Options for {@link createLookupMap}. */
|
|
53
|
+
export interface CreateLookupMapOptions<K, V, L> extends Required<LookupOption<K, L>> {
|
|
54
|
+
/** Initial entries for the map. */
|
|
55
|
+
readonly entries?: Iterable<readonly [K, V]>;
|
|
56
|
+
}
|
|
57
|
+
/** Creates {@link LookupMap}. */
|
|
58
|
+
export declare const createLookupMap: <K, V, L>({ lookup, entries, }: CreateLookupMapOptions<K, V, L>) => LookupMap<K, V>;
|
|
59
|
+
/**
|
|
60
|
+
* `Set`-like collection keyed by a {@link Lookup derived lookup key}.
|
|
61
|
+
*
|
|
62
|
+
* `add` preserves the first inserted representative for a logical key. `get`
|
|
63
|
+
* returns that representative for callers that need stable identity.
|
|
64
|
+
*
|
|
65
|
+
* @see {@link createLookupSet}
|
|
66
|
+
*/
|
|
67
|
+
export interface LookupSet<K> extends Iterable<K> {
|
|
68
|
+
readonly size: number;
|
|
69
|
+
readonly has: (key: K) => boolean;
|
|
70
|
+
readonly get: (key: K) => K | undefined;
|
|
71
|
+
readonly add: (key: K) => LookupSet<K>;
|
|
72
|
+
readonly delete: (key: K) => boolean;
|
|
73
|
+
readonly clear: () => void;
|
|
74
|
+
readonly keys: () => IterableIterator<K>;
|
|
75
|
+
readonly values: () => IterableIterator<K>;
|
|
76
|
+
readonly entries: () => IterableIterator<readonly [K, K]>;
|
|
77
|
+
readonly forEach: (callback: (value: K, key: K, set: LookupSet<K>) => void) => void;
|
|
78
|
+
readonly [Symbol.iterator]: () => IterableIterator<K>;
|
|
79
|
+
}
|
|
80
|
+
/** Options for {@link createLookupSet}. */
|
|
81
|
+
export interface CreateLookupSetOptions<K, L> extends Required<LookupOption<K, L>> {
|
|
82
|
+
/** Initial values for the set. */
|
|
83
|
+
readonly values?: Iterable<K>;
|
|
84
|
+
}
|
|
85
|
+
/** Creates {@link LookupSet}. */
|
|
86
|
+
export declare const createLookupSet: <K, L>({ lookup, values, }: CreateLookupSetOptions<K, L>) => LookupSet<K>;
|
|
87
|
+
/** Scalar branch shared by {@link StructuralKey} and {@link Structural}. */
|
|
88
|
+
export type StructuralScalar = string | number | boolean | null | Uint8Array;
|
|
89
|
+
/** Branded native key produced by {@link structuralLookup}. */
|
|
90
|
+
export type StructuralLookupKey = string & Brand<"StructuralLookupKey">;
|
|
91
|
+
/**
|
|
92
|
+
* Immutable structural key.
|
|
93
|
+
*
|
|
94
|
+
* Structural keys are JSON-like values with `NaN` and positive/negative
|
|
95
|
+
* infinity also supported, or `Uint8Array`.
|
|
96
|
+
*
|
|
97
|
+
* @see {@link Structural}
|
|
98
|
+
* @see {@link structuralLookup}
|
|
99
|
+
*/
|
|
100
|
+
export type StructuralKey = StructuralScalar | ReadonlyArray<StructuralKey> | {
|
|
101
|
+
readonly [key: string]: StructuralKey;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Compile-time structural form of `T` for structural lookup APIs.
|
|
105
|
+
*
|
|
106
|
+
* This exists because {@link StructuralKey} is the runtime serialization model,
|
|
107
|
+
* not a good public generic constraint for interface-shaped objects.
|
|
108
|
+
* `StructuralKey` models object values with a string index signature, which is
|
|
109
|
+
* stricter than ordinary interfaces like `{ readonly id: string }` even though
|
|
110
|
+
* the runtime serializer accepts such plain objects.
|
|
111
|
+
*
|
|
112
|
+
* `Structural<T>` checks a concrete type recursively at compile time instead:
|
|
113
|
+
* scalars pass through, arrays recurse, object properties recurse, and
|
|
114
|
+
* function-valued properties are rejected. This keeps public structural APIs
|
|
115
|
+
* ergonomic for interface-based inputs while preserving the same runtime
|
|
116
|
+
* constraints as structural lookup serialization.
|
|
117
|
+
*
|
|
118
|
+
* @see {@link StructuralKey}
|
|
119
|
+
* @see {@link structuralLookup}
|
|
120
|
+
*/
|
|
121
|
+
export type Structural<T> = T extends StructuralScalar ? T : T extends ReadonlyArray<infer Item> ? ReadonlyArray<Structural<Item>> : T extends StructuralFunction ? never : T extends object ? {
|
|
122
|
+
readonly [K in keyof T as Extract<T[K], StructuralFunction> extends never ? K : never]: Structural<Exclude<T[K], StructuralFunction>>;
|
|
123
|
+
} & {
|
|
124
|
+
readonly [K in keyof T as Extract<T[K], StructuralFunction> extends never ? never : K]?: never;
|
|
125
|
+
} : never;
|
|
126
|
+
/** Function branch excluded by {@link Structural}. */
|
|
127
|
+
export type StructuralFunction = (...args: ReadonlyArray<unknown>) => unknown;
|
|
128
|
+
/**
|
|
129
|
+
* Returns the structural lookup key for `key`.
|
|
130
|
+
*
|
|
131
|
+
* Structural lookup keys are derived from JSON-like values plus `Uint8Array`.
|
|
132
|
+
* Equal structures produce the same lookup key even when they are different
|
|
133
|
+
* JavaScript instances.
|
|
134
|
+
*
|
|
135
|
+
* The derived key is memoized by non-null object identity in a module-scoped
|
|
136
|
+
* `WeakMap` shared by all callers, so keys must be immutable.
|
|
137
|
+
*
|
|
138
|
+
* Use this as a {@link Lookup} when logical equality should be based on
|
|
139
|
+
* structural value instead of reference identity.
|
|
140
|
+
*
|
|
141
|
+
* ### Example
|
|
142
|
+
*
|
|
143
|
+
* ```ts
|
|
144
|
+
* const byFilter = createLookupMap<
|
|
145
|
+
* { readonly table: string; readonly where: readonly [string, string] },
|
|
146
|
+
* string,
|
|
147
|
+
* StructuralLookupKey
|
|
148
|
+
* >({
|
|
149
|
+
* lookup: structuralLookup,
|
|
150
|
+
* });
|
|
151
|
+
*
|
|
152
|
+
* byFilter.set({ table: "todo", where: ["owner", "ada"] }, "cached");
|
|
153
|
+
* byFilter.get({ table: "todo", where: ["owner", "ada"] }); // "cached"
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @see {@link StructuralKey}
|
|
157
|
+
* @see {@link Structural}
|
|
158
|
+
*/
|
|
159
|
+
export declare const structuralLookup: <K>(key: Structural<K>) => StructuralLookupKey;
|
|
160
|
+
//# sourceMappingURL=Lookup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Lookup.d.ts","sourceRoot":"","sources":["../../src/Lookup.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAIxC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;AAEzC,+BAA+B;AAC/B,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC;IACpC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,EAAE,CAAC,CAAE,SAAQ,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,OAAO,EAAE,CAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,KACvD,IAAI,CAAC;IACV,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CACrE;AAED,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAE,SAAQ,QAAQ,CAC/D,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CACnB;IACC,mCAAmC;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;CAC9C;AAED,iCAAiC;AACjC,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,sBAGtC,sBAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAuElD,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC,CAAE,SAAQ,QAAQ,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1D,QAAQ,CAAC,OAAO,EAAE,CAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,KACpD,IAAI,CAAC;IACV,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,gBAAgB,CAAC,CAAC,CAAC,CAAC;CACvD;AAED,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAE,SAAQ,QAAQ,CAC5D,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CACnB;IACC,kCAAkC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CAC/B;AAED,iCAAiC;AACjC,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,CAAC,EAAE,qBAGnC,sBAAsB,CAAC,CAAC,EAAE,CAAC,CAAC,KAAG,SAAS,CAAC,CAAC,CAmD5C,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,UAAU,CAAC;AAE7E,+DAA+D;AAC/D,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,CAAC;AAExE;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GACrB,gBAAgB,GAChB,aAAa,CAAC,aAAa,CAAC,GAC5B;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,CAAA;CAAE,CAAC;AAE9C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI,CAAC,SAAS,gBAAgB,GAClD,CAAC,GACD,CAAC,SAAS,aAAa,CAAC,MAAM,IAAI,CAAC,GACjC,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAC/B,CAAC,SAAS,kBAAkB,GAC1B,KAAK,GACL,CAAC,SAAS,MAAM,GACd;IACE,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,OAAO,CAC/B,CAAC,CAAC,CAAC,CAAC,EACJ,kBAAkB,CACnB,SAAS,KAAK,GACX,CAAC,GACD,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;CAC1D,GAAG;IACF,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,IAAI,OAAO,CAC/B,CAAC,CAAC,CAAC,CAAC,EACJ,kBAAkB,CACnB,SAAS,KAAK,GACX,KAAK,GACL,CAAC,CAAC,CAAC,EAAE,KAAK;CACf,GACD,KAAK,CAAC;AAEhB,sDAAsD;AACtD,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,gBAAgB,GAAI,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC,CAAC,KAAG,mBACH,CAAC"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lookup-key collections and helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { assert } from "./Assert.js";
|
|
7
|
+
import { isPlainObject } from "./Object.js";
|
|
8
|
+
import { Uint8Array, uint8ArrayToBase64Url } from "./Type.js";
|
|
9
|
+
/** Creates {@link LookupMap}. */
|
|
10
|
+
export const createLookupMap = ({ lookup, entries, }) => {
|
|
11
|
+
const entriesByLookupKey = new Map();
|
|
12
|
+
const map = {
|
|
13
|
+
get size() {
|
|
14
|
+
return entriesByLookupKey.size;
|
|
15
|
+
},
|
|
16
|
+
has: (key) => entriesByLookupKey.has(lookup(key)),
|
|
17
|
+
get: (key) => entriesByLookupKey.get(lookup(key))?.value,
|
|
18
|
+
getKey: (key) => entriesByLookupKey.get(lookup(key))?.key,
|
|
19
|
+
set: (key, value) => {
|
|
20
|
+
const lookupKey = lookup(key);
|
|
21
|
+
const existingEntry = entriesByLookupKey.get(lookupKey);
|
|
22
|
+
entriesByLookupKey.set(lookupKey, {
|
|
23
|
+
key: existingEntry?.key ?? key,
|
|
24
|
+
value,
|
|
25
|
+
});
|
|
26
|
+
return map;
|
|
27
|
+
},
|
|
28
|
+
delete: (key) => entriesByLookupKey.delete(lookup(key)),
|
|
29
|
+
clear: () => {
|
|
30
|
+
entriesByLookupKey.clear();
|
|
31
|
+
},
|
|
32
|
+
keys: function* () {
|
|
33
|
+
for (const entry of entriesByLookupKey.values()) {
|
|
34
|
+
yield entry.key;
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
values: function* () {
|
|
38
|
+
for (const entry of entriesByLookupKey.values()) {
|
|
39
|
+
yield entry.value;
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
entries: function* () {
|
|
43
|
+
for (const entry of entriesByLookupKey.values()) {
|
|
44
|
+
yield [entry.key, entry.value];
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
forEach: (callback) => {
|
|
48
|
+
for (const entry of entriesByLookupKey.values()) {
|
|
49
|
+
callback(entry.value, entry.key, map);
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
[Symbol.iterator]: function () {
|
|
53
|
+
return map.entries();
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
if (entries) {
|
|
57
|
+
for (const [key, value] of entries) {
|
|
58
|
+
map.set(key, value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return map;
|
|
62
|
+
};
|
|
63
|
+
/** Creates {@link LookupSet}. */
|
|
64
|
+
export const createLookupSet = ({ lookup, values, }) => {
|
|
65
|
+
const map = createLookupMap({ lookup });
|
|
66
|
+
const set = {
|
|
67
|
+
get size() {
|
|
68
|
+
return map.size;
|
|
69
|
+
},
|
|
70
|
+
has: (key) => map.has(key),
|
|
71
|
+
get: (key) => map.getKey(key),
|
|
72
|
+
add: (key) => {
|
|
73
|
+
map.set(key, true);
|
|
74
|
+
return set;
|
|
75
|
+
},
|
|
76
|
+
delete: (key) => map.delete(key),
|
|
77
|
+
clear: () => {
|
|
78
|
+
map.clear();
|
|
79
|
+
},
|
|
80
|
+
keys: () => map.keys(),
|
|
81
|
+
values: () => map.keys(),
|
|
82
|
+
entries: function* () {
|
|
83
|
+
for (const key of map.keys()) {
|
|
84
|
+
yield [key, key];
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
forEach: (callback) => {
|
|
88
|
+
for (const key of map.keys()) {
|
|
89
|
+
callback(key, key, set);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
[Symbol.iterator]: function () {
|
|
93
|
+
return set.keys();
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
if (values) {
|
|
97
|
+
for (const value of values) {
|
|
98
|
+
set.add(value);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return set;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* Returns the structural lookup key for `key`.
|
|
105
|
+
*
|
|
106
|
+
* Structural lookup keys are derived from JSON-like values plus `Uint8Array`.
|
|
107
|
+
* Equal structures produce the same lookup key even when they are different
|
|
108
|
+
* JavaScript instances.
|
|
109
|
+
*
|
|
110
|
+
* The derived key is memoized by non-null object identity in a module-scoped
|
|
111
|
+
* `WeakMap` shared by all callers, so keys must be immutable.
|
|
112
|
+
*
|
|
113
|
+
* Use this as a {@link Lookup} when logical equality should be based on
|
|
114
|
+
* structural value instead of reference identity.
|
|
115
|
+
*
|
|
116
|
+
* ### Example
|
|
117
|
+
*
|
|
118
|
+
* ```ts
|
|
119
|
+
* const byFilter = createLookupMap<
|
|
120
|
+
* { readonly table: string; readonly where: readonly [string, string] },
|
|
121
|
+
* string,
|
|
122
|
+
* StructuralLookupKey
|
|
123
|
+
* >({
|
|
124
|
+
* lookup: structuralLookup,
|
|
125
|
+
* });
|
|
126
|
+
*
|
|
127
|
+
* byFilter.set({ table: "todo", where: ["owner", "ada"] }, "cached");
|
|
128
|
+
* byFilter.get({ table: "todo", where: ["owner", "ada"] }); // "cached"
|
|
129
|
+
* ```
|
|
130
|
+
*
|
|
131
|
+
* @see {@link StructuralKey}
|
|
132
|
+
* @see {@link Structural}
|
|
133
|
+
*/
|
|
134
|
+
export const structuralLookup = (key) => structuralLookupInternal(key);
|
|
135
|
+
const structuralLookupKeyByValue = new WeakMap();
|
|
136
|
+
const structuralLookupInternal = (value, path = new Set()) => {
|
|
137
|
+
switch (typeof value) {
|
|
138
|
+
case "string":
|
|
139
|
+
return `s:${JSON.stringify(value)}`;
|
|
140
|
+
case "number":
|
|
141
|
+
if (Number.isNaN(value))
|
|
142
|
+
return "n:NaN";
|
|
143
|
+
if (value === Number.POSITIVE_INFINITY)
|
|
144
|
+
return "n:Infinity";
|
|
145
|
+
if (value === Number.NEGATIVE_INFINITY)
|
|
146
|
+
return "n:-Infinity";
|
|
147
|
+
return Object.is(value, -0) ? "n:0" : `n:${value}`;
|
|
148
|
+
case "boolean":
|
|
149
|
+
return value ? "b:true" : "b:false";
|
|
150
|
+
case "object": {
|
|
151
|
+
if (value === null)
|
|
152
|
+
return "l:null";
|
|
153
|
+
const cachedLookupKey = structuralLookupKeyByValue.get(value);
|
|
154
|
+
if (cachedLookupKey)
|
|
155
|
+
return cachedLookupKey;
|
|
156
|
+
let lookupKey;
|
|
157
|
+
if (Array.isArray(value)) {
|
|
158
|
+
assert(!path.has(value), "Structural lookup keys must not contain cycles.");
|
|
159
|
+
path.add(value);
|
|
160
|
+
lookupKey = getStructuralArrayLookupKey(value, path);
|
|
161
|
+
path.delete(value);
|
|
162
|
+
}
|
|
163
|
+
else if (isPlainObject(value)) {
|
|
164
|
+
assert(!path.has(value), "Structural lookup keys must not contain cycles.");
|
|
165
|
+
path.add(value);
|
|
166
|
+
lookupKey = getStructuralObjectLookupKey(value, path);
|
|
167
|
+
path.delete(value);
|
|
168
|
+
}
|
|
169
|
+
else if (Uint8Array.is(value)) {
|
|
170
|
+
lookupKey = `u:${uint8ArrayToBase64Url(value)}`;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
assert(false, "Structural lookup keys must be JSON-like values or Uint8Array.");
|
|
174
|
+
}
|
|
175
|
+
structuralLookupKeyByValue.set(value, lookupKey);
|
|
176
|
+
return lookupKey;
|
|
177
|
+
}
|
|
178
|
+
default:
|
|
179
|
+
assert(false, "Structural lookup keys must be JSON-like values or Uint8Array.");
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const getStructuralArrayLookupKey = (value, path) => `a:[${Array.from(value, (item) => structuralLookupInternal(item, path)).join(",")}]`;
|
|
183
|
+
const getStructuralObjectLookupKey = (value, path) => {
|
|
184
|
+
const valueRecord = value;
|
|
185
|
+
const entries = Object.keys(valueRecord)
|
|
186
|
+
.toSorted()
|
|
187
|
+
.map((key) => {
|
|
188
|
+
const item = valueRecord[key];
|
|
189
|
+
return `${JSON.stringify(key)}:${structuralLookupInternal(item, path)}`;
|
|
190
|
+
});
|
|
191
|
+
return `o:{${entries.join(",")}}`;
|
|
192
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microtask queue utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { type NonEmptyReadonlyArray } from "./Array.js";
|
|
7
|
+
/**
|
|
8
|
+
* Batches values and flushes them in a single microtask.
|
|
9
|
+
*
|
|
10
|
+
* Calls to {@link MicrotaskBatch.push} within the same tick are coalesced into
|
|
11
|
+
* one flush.
|
|
12
|
+
*/
|
|
13
|
+
export interface MicrotaskBatch<T> extends Disposable {
|
|
14
|
+
/** Enqueues one item and schedules a microtask flush if needed. */
|
|
15
|
+
readonly push: (item: T) => void;
|
|
16
|
+
/** Flushes queued items immediately. */
|
|
17
|
+
readonly flushNow: () => void;
|
|
18
|
+
}
|
|
19
|
+
/** Creates {@link MicrotaskBatch}. */
|
|
20
|
+
export declare const createMicrotaskBatch: <T>(onFlush: (items: NonEmptyReadonlyArray<T>) => void) => MicrotaskBatch<T>;
|
|
21
|
+
//# sourceMappingURL=Microtask.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Microtask.d.ts","sourceRoot":"","sources":["../../src/Microtask.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAiB,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,CAAE,SAAQ,UAAU;IACnD,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC;IAEjC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,sCAAsC;AACtC,eAAO,MAAM,oBAAoB,GAAI,CAAC,EACpC,SAAS,CAAC,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAAK,IAAI,KACjD,cAAc,CAAC,CAAC,CAgClB,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Microtask queue utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { appendToArray } from "./Array.js";
|
|
7
|
+
/** Creates {@link MicrotaskBatch}. */
|
|
8
|
+
export const createMicrotaskBatch = (onFlush) => {
|
|
9
|
+
let queue = null;
|
|
10
|
+
let disposed = false;
|
|
11
|
+
const flushNow = () => {
|
|
12
|
+
if (disposed || queue == null)
|
|
13
|
+
return;
|
|
14
|
+
const queuedItems = queue;
|
|
15
|
+
queue = null;
|
|
16
|
+
onFlush(queuedItems);
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
push: (item) => {
|
|
20
|
+
if (disposed)
|
|
21
|
+
return;
|
|
22
|
+
if (queue == null) {
|
|
23
|
+
queue = [item];
|
|
24
|
+
queueMicrotask(flushNow);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
queue = appendToArray(queue, item);
|
|
28
|
+
},
|
|
29
|
+
flushNow,
|
|
30
|
+
[Symbol.dispose]: () => {
|
|
31
|
+
if (disposed)
|
|
32
|
+
return;
|
|
33
|
+
disposed = true;
|
|
34
|
+
queue = null;
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
};
|
package/dist/src/Number.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Number arithmetic, comparison, and branded numeric types.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { NonEmptyReadonlyArray } from "./Array.js";
|
|
7
|
+
import type { IsBranded } from "./Brand.js";
|
|
8
|
+
import type { Result } from "./Result.js";
|
|
3
9
|
import { NonNegativeInt, PositiveInt } from "./Type.js";
|
|
4
|
-
import { Predicate, WidenLiteral } from "./Types.js";
|
|
5
|
-
import { IsBranded } from "./Brand.js";
|
|
10
|
+
import type { Predicate, WidenLiteral } from "./Types.js";
|
|
6
11
|
export declare const increment: (n: number) => number;
|
|
7
12
|
export declare const decrement: (n: number) => number;
|
|
8
13
|
/** Clamps a number within a given range. */
|
|
@@ -40,4 +45,13 @@ export declare const computeBalancedBuckets: (numberOfItems: NonNegativeInt,
|
|
|
40
45
|
numberOfBuckets?: number & import("./Brand.js").Brand<"Int"> & import("./Brand.js").Brand<"NonNegative"> & import("./Brand.js").Brand<"Positive">,
|
|
41
46
|
/** Default: 2 */
|
|
42
47
|
minNumberOfItemsPerBucket?: number & import("./Brand.js").Brand<"Int"> & import("./Brand.js").Brand<"NonNegative"> & import("./Brand.js").Brand<"Positive">) => Result<NonEmptyReadonlyArray<PositiveInt>, PositiveInt>;
|
|
48
|
+
/**
|
|
49
|
+
* Valid index for {@link fibonacciAt}, constrained to 1-78.
|
|
50
|
+
*
|
|
51
|
+
* Limited to 78 because F(79) exceeds JavaScript's `MAX_SAFE_INTEGER`.
|
|
52
|
+
*/
|
|
53
|
+
export declare const FibonacciIndex: import("./Type.js").BrandType<import("./Type.js").BrandType<import("./Type.js").Type<"Brand", number & import("./Brand.js").Brand<"Int"> & import("./Brand.js").Brand<"NonNegative"> & import("./Brand.js").Brand<"Positive">, number, import("./Type.js").PositiveError, number & import("./Brand.js").Brand<"Int"> & import("./Brand.js").Brand<"NonNegative">, import("./Type.js").NumberError | import("./Type.js").NonNegativeError | import("./Type.js").IntError>, "LessThanOrEqualTo78", import("./Type.js").LessThanOrEqualToError<78>, import("./Type.js").NumberError | import("./Type.js").NonNegativeError | import("./Type.js").IntError | import("./Type.js").PositiveError>, "FibonacciIndex", import("./Type.js").BrandWithoutRefineError<"FibonacciIndex", import("./Type.js").NumberError | import("./Type.js").NonNegativeError | import("./Type.js").IntError | import("./Type.js").PositiveError | import("./Type.js").LessThanOrEqualToError<78>>, never>;
|
|
54
|
+
export type FibonacciIndex = typeof FibonacciIndex.Type;
|
|
55
|
+
/** Returns the Fibonacci number at the given index (1-indexed: 1,1,2,3,5,8,...). */
|
|
56
|
+
export declare const fibonacciAt: (index: FibonacciIndex) => PositiveInt;
|
|
43
57
|
//# sourceMappingURL=Number.d.ts.map
|
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,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;
|
|
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;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAIL,cAAc,EACd,WAAW,EACZ,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1D,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,KAAG,MAAe,CAAC;AAEtD,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,KAAG,MAAe,CAAC;AAEtD,4CAA4C;AAC5C,eAAO,MAAM,KAAK,GACf,KAAK,MAAM,EAAE,KAAK,MAAM,MACxB,GAAG,MAAM,KAAG,MACoB,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,GACnB,KAAK,MAAM,EAAE,KAAK,MAAM,KAAG,SAAS,CAAC,MAAM,CAEd,CAAC;AAEjC,wEAAwE;AACxE,eAAO,MAAM,GAAG,GAAI,CAAC,SAAS,MAAM,EAClC,GAAG,QAAQ,CAAC,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,KAClC,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,CACE,CAAC;AAEpD,wEAAwE;AACxE,eAAO,MAAM,GAAG,GAAI,CAAC,SAAS,MAAM,EAClC,GAAG,QAAQ,CAAC,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,KAClC,SAAS,CAAC,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,GAAG,YAAY,CAAC,CAAC,CACE,CAAC;AAEpD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,sBAAsB,GACjC,eAAe,cAAc;AAE7B,kBAAkB;AAClB,iJAAyC;AAEzC,iBAAiB;AACjB,2JAAkD,KACjD,MAAM,CAAC,qBAAqB,CAAC,WAAW,CAAC,EAAE,WAAW,CAoBxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,k7BAG1B,CAAC;AACF,MAAM,MAAM,cAAc,GAAG,OAAO,cAAc,CAAC,IAAI,CAAC;AAExD,oFAAoF;AACpF,eAAO,MAAM,WAAW,GAAI,OAAO,cAAc,KAAG,WAMnD,CAAC"}
|