@evolu/common 8.0.0-next.4 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/dist/src/Array.d.ts +279 -173
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +105 -101
  4. package/dist/src/Assert.d.ts +44 -44
  5. package/dist/src/Assert.d.ts.map +1 -1
  6. package/dist/src/Assert.js +44 -32
  7. package/dist/src/BigInt.d.ts +6 -3
  8. package/dist/src/BigInt.d.ts.map +1 -1
  9. package/dist/src/BigInt.js +5 -2
  10. package/dist/src/Brand.d.ts +27 -40
  11. package/dist/src/Brand.d.ts.map +1 -1
  12. package/dist/src/Buffer.d.ts +27 -11
  13. package/dist/src/Buffer.d.ts.map +1 -1
  14. package/dist/src/Cache.d.ts +9 -4
  15. package/dist/src/Cache.d.ts.map +1 -1
  16. package/dist/src/Cache.js +8 -3
  17. package/dist/src/Callbacks.d.ts +30 -19
  18. package/dist/src/Callbacks.d.ts.map +1 -1
  19. package/dist/src/Console.d.ts +145 -66
  20. package/dist/src/Console.d.ts.map +1 -1
  21. package/dist/src/Console.js +91 -43
  22. package/dist/src/Crypto.d.ts +85 -42
  23. package/dist/src/Crypto.d.ts.map +1 -1
  24. package/dist/src/Crypto.js +44 -20
  25. package/dist/src/Eq.d.ts +87 -21
  26. package/dist/src/Eq.d.ts.map +1 -1
  27. package/dist/src/Eq.js +67 -19
  28. package/dist/src/Error.d.ts +5 -3
  29. package/dist/src/Error.d.ts.map +1 -1
  30. package/dist/src/Error.js +16 -0
  31. package/dist/src/Function.d.ts +119 -58
  32. package/dist/src/Function.d.ts.map +1 -1
  33. package/dist/src/Function.js +86 -43
  34. package/dist/src/Http.d.ts +394 -0
  35. package/dist/src/Http.d.ts.map +1 -0
  36. package/dist/src/Http.js +102 -0
  37. package/dist/src/Identicon.d.ts +16 -7
  38. package/dist/src/Identicon.d.ts.map +1 -1
  39. package/dist/src/Identicon.js +14 -5
  40. package/dist/src/LeakDetector.d.ts +88 -0
  41. package/dist/src/LeakDetector.d.ts.map +1 -0
  42. package/dist/src/LeakDetector.js +86 -0
  43. package/dist/src/LockManager.d.ts +18 -9
  44. package/dist/src/LockManager.d.ts.map +1 -1
  45. package/dist/src/LockManager.js +7 -8
  46. package/dist/src/Lookup.d.ts +43 -13
  47. package/dist/src/Lookup.d.ts.map +1 -1
  48. package/dist/src/Lookup.js +28 -8
  49. package/dist/src/Microtask.d.ts +1 -1
  50. package/dist/src/Microtask.d.ts.map +1 -1
  51. package/dist/src/Microtask.js +3 -7
  52. package/dist/src/Number.d.ts +49 -13
  53. package/dist/src/Number.d.ts.map +1 -1
  54. package/dist/src/Number.js +34 -5
  55. package/dist/src/Object.d.ts +160 -40
  56. package/dist/src/Object.d.ts.map +1 -1
  57. package/dist/src/Object.js +92 -46
  58. package/dist/src/Option.d.ts +10 -7
  59. package/dist/src/Option.d.ts.map +1 -1
  60. package/dist/src/Option.js +9 -6
  61. package/dist/src/Order.d.ts +21 -21
  62. package/dist/src/Order.d.ts.map +1 -1
  63. package/dist/src/Order.js +18 -21
  64. package/dist/src/Platform.d.ts +31 -0
  65. package/dist/src/Platform.d.ts.map +1 -1
  66. package/dist/src/Platform.js +98 -0
  67. package/dist/src/Random.d.ts +32 -17
  68. package/dist/src/Random.d.ts.map +1 -1
  69. package/dist/src/Random.js +12 -8
  70. package/dist/src/Redacted.d.ts +43 -29
  71. package/dist/src/Redacted.d.ts.map +1 -1
  72. package/dist/src/Redacted.js +14 -3
  73. package/dist/src/Ref.d.ts +11 -3
  74. package/dist/src/Ref.d.ts.map +1 -1
  75. package/dist/src/Ref.js +2 -2
  76. package/dist/src/RefCount.d.ts +2 -6
  77. package/dist/src/RefCount.d.ts.map +1 -1
  78. package/dist/src/RefCount.js +33 -90
  79. package/dist/src/Relation.d.ts +70 -5
  80. package/dist/src/Relation.d.ts.map +1 -1
  81. package/dist/src/Relation.js +77 -2
  82. package/dist/src/Resource.d.ts +590 -155
  83. package/dist/src/Resource.d.ts.map +1 -1
  84. package/dist/src/Resource.js +592 -343
  85. package/dist/src/Result.d.ts +838 -191
  86. package/dist/src/Result.d.ts.map +1 -1
  87. package/dist/src/Result.js +163 -102
  88. package/dist/src/Schedule.d.ts +684 -231
  89. package/dist/src/Schedule.d.ts.map +1 -1
  90. package/dist/src/Schedule.js +766 -295
  91. package/dist/src/Set.d.ts +89 -40
  92. package/dist/src/Set.d.ts.map +1 -1
  93. package/dist/src/Set.js +50 -29
  94. package/dist/src/Sqlite.d.ts +29 -72
  95. package/dist/src/Sqlite.d.ts.map +1 -1
  96. package/dist/src/Sqlite.js +41 -46
  97. package/dist/src/StackTrace.d.ts +40 -0
  98. package/dist/src/StackTrace.d.ts.map +1 -0
  99. package/dist/src/StackTrace.js +140 -0
  100. package/dist/src/Store.d.ts +5 -4
  101. package/dist/src/Store.d.ts.map +1 -1
  102. package/dist/src/Store.js +5 -4
  103. package/dist/src/String.d.ts +7 -1
  104. package/dist/src/String.d.ts.map +1 -1
  105. package/dist/src/String.js +20 -7
  106. package/dist/src/Task.d.ts +3572 -1770
  107. package/dist/src/Task.d.ts.map +1 -1
  108. package/dist/src/Task.js +1879 -1274
  109. package/dist/src/Test.d.ts +17 -125
  110. package/dist/src/Test.d.ts.map +1 -1
  111. package/dist/src/Test.js +17 -68
  112. package/dist/src/Time.d.ts +108 -49
  113. package/dist/src/Time.d.ts.map +1 -1
  114. package/dist/src/Time.js +172 -73
  115. package/dist/src/Type.d.ts +3542 -1926
  116. package/dist/src/Type.d.ts.map +1 -1
  117. package/dist/src/Type.js +3070 -1784
  118. package/dist/src/Types.d.ts +200 -108
  119. package/dist/src/Types.d.ts.map +1 -1
  120. package/dist/src/Types.js +39 -8
  121. package/dist/src/WebSocket.d.ts +48 -23
  122. package/dist/src/WebSocket.d.ts.map +1 -1
  123. package/dist/src/WebSocket.js +15 -6
  124. package/dist/src/Worker.d.ts +94 -36
  125. package/dist/src/Worker.d.ts.map +1 -1
  126. package/dist/src/Worker.js +58 -24
  127. package/dist/src/index.d.ts +55 -52
  128. package/dist/src/index.d.ts.map +1 -1
  129. package/dist/src/index.js +3 -1
  130. package/dist/src/intl/cs.d.ts +94 -0
  131. package/dist/src/intl/cs.d.ts.map +1 -0
  132. package/dist/src/intl/cs.js +220 -0
  133. package/dist/src/intl/index.d.ts +7 -0
  134. package/dist/src/intl/index.d.ts.map +1 -0
  135. package/dist/src/intl/index.js +6 -0
  136. package/dist/src/local-first/Db.d.ts +12 -8
  137. package/dist/src/local-first/Db.d.ts.map +1 -1
  138. package/dist/src/local-first/Db.js +109 -132
  139. package/dist/src/local-first/Error.d.ts +4 -4
  140. package/dist/src/local-first/Evolu.d.ts +338 -92
  141. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  142. package/dist/src/local-first/Evolu.js +47 -55
  143. package/dist/src/local-first/LocalAuth.d.ts +4 -4
  144. package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
  145. package/dist/src/local-first/Owner.d.ts +61 -24
  146. package/dist/src/local-first/Owner.d.ts.map +1 -1
  147. package/dist/src/local-first/Owner.js +45 -8
  148. package/dist/src/local-first/Protocol.d.ts +44 -31
  149. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  150. package/dist/src/local-first/Protocol.js +36 -13
  151. package/dist/src/local-first/Query.d.ts +147 -62
  152. package/dist/src/local-first/Query.d.ts.map +1 -1
  153. package/dist/src/local-first/Query.js +112 -58
  154. package/dist/src/local-first/Relay.d.ts +44 -14
  155. package/dist/src/local-first/Relay.d.ts.map +1 -1
  156. package/dist/src/local-first/Schema.d.ts +92 -41
  157. package/dist/src/local-first/Schema.d.ts.map +1 -1
  158. package/dist/src/local-first/Schema.js +25 -8
  159. package/dist/src/local-first/Shared.d.ts +23 -21
  160. package/dist/src/local-first/Shared.d.ts.map +1 -1
  161. package/dist/src/local-first/Shared.js +100 -57
  162. package/dist/src/local-first/Storage.d.ts +53 -32
  163. package/dist/src/local-first/Storage.d.ts.map +1 -1
  164. package/dist/src/local-first/Storage.js +194 -234
  165. package/dist/src/local-first/Timestamp.d.ts +21 -21
  166. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  167. package/dist/src/local-first/Timestamp.js +2 -2
  168. package/dist/src/local-first/index.d.ts +11 -11
  169. package/package.json +14 -13
  170. package/src/Array.ts +306 -205
  171. package/src/Assert.ts +54 -69
  172. package/src/BigInt.ts +6 -3
  173. package/src/Brand.ts +27 -40
  174. package/src/Buffer.ts +28 -12
  175. package/src/Cache.ts +9 -4
  176. package/src/Callbacks.ts +30 -19
  177. package/src/Console.ts +156 -84
  178. package/src/Crypto.ts +83 -41
  179. package/src/Eq.ts +95 -22
  180. package/src/Error.ts +8 -4
  181. package/src/Function.ts +167 -59
  182. package/src/Http.ts +549 -0
  183. package/src/Identicon.ts +16 -7
  184. package/src/LeakDetector.ts +182 -0
  185. package/src/LockManager.ts +43 -39
  186. package/src/Lookup.ts +62 -28
  187. package/src/Microtask.ts +19 -23
  188. package/src/Number.ts +64 -12
  189. package/src/Object.ts +173 -49
  190. package/src/Option.ts +10 -7
  191. package/src/Order.ts +23 -21
  192. package/src/Platform.ts +136 -0
  193. package/src/Polyfills.ts +6 -12
  194. package/src/Random.ts +32 -19
  195. package/src/Redacted.ts +44 -30
  196. package/src/Ref.ts +14 -6
  197. package/src/RefCount.ts +38 -80
  198. package/src/Relation.ts +202 -10
  199. package/src/Resource.ts +1199 -591
  200. package/src/Result.ts +930 -271
  201. package/src/Schedule.ts +859 -343
  202. package/src/Set.ts +89 -40
  203. package/src/Sqlite.ts +144 -138
  204. package/src/StackTrace.ts +230 -0
  205. package/src/Store.ts +8 -7
  206. package/src/String.ts +22 -5
  207. package/src/Task.ts +5101 -2832
  208. package/src/Test.ts +20 -168
  209. package/src/Time.ts +293 -90
  210. package/src/Type.ts +10034 -4117
  211. package/src/Types.ts +227 -110
  212. package/src/WebSocket.ts +64 -36
  213. package/src/Worker.ts +180 -72
  214. package/src/index.ts +55 -52
  215. package/src/intl/cs.ts +388 -0
  216. package/src/intl/index.ts +7 -0
  217. package/src/local-first/Db.ts +152 -179
  218. package/src/local-first/Error.ts +4 -4
  219. package/src/local-first/Evolu.ts +495 -250
  220. package/src/local-first/LocalAuth.ts +6 -12
  221. package/src/local-first/Owner.ts +58 -21
  222. package/src/local-first/Protocol.ts +49 -31
  223. package/src/local-first/Query.ts +146 -61
  224. package/src/local-first/Relay.ts +51 -21
  225. package/src/local-first/Schema.ts +109 -51
  226. package/src/local-first/Shared.ts +266 -226
  227. package/src/local-first/Storage.ts +266 -264
  228. package/src/local-first/Timestamp.ts +25 -18
  229. package/src/local-first/index.ts +11 -11
  230. package/dist/src/Skiplist.d.ts +0 -28
  231. package/dist/src/Skiplist.d.ts.map +0 -1
  232. package/dist/src/Skiplist.js +0 -64
  233. package/dist/src/Tracer.d.ts +0 -48
  234. package/dist/src/Tracer.d.ts.map +0 -1
  235. package/dist/src/Tracer.js +0 -6
  236. package/src/Skiplist.ts +0 -108
  237. package/src/Tracer.ts +0 -54
@@ -10,32 +10,36 @@
10
10
  * ### Example
11
11
  *
12
12
  * ```ts
13
+ * import { exhaustiveCheck } from "@evolu/common";
14
+ *
13
15
  * type Color = "red" | "green" | "blue";
16
+ * const handled: Array<string> = [];
14
17
  *
15
18
  * const handleColor = (color: Color): void => {
16
19
  * switch (color) {
17
20
  * case "red":
18
- * console.log("Handling red");
21
+ * handled.push("Handling red");
19
22
  * break;
20
23
  * case "green":
21
- * console.log("Handling green");
24
+ * handled.push("Handling green");
22
25
  * break;
23
26
  * case "blue":
24
- * console.log("Handling blue");
27
+ * handled.push("Handling blue");
25
28
  * break;
26
29
  * default:
27
- * exhaustiveCheck(color); // Ensures all cases are handled
30
+ * exhaustiveCheck(color);
28
31
  * }
29
32
  * };
33
+ *
34
+ * handleColor("blue");
35
+ * expect(handled).toEqual(["Handling blue"]);
30
36
  * ```
31
37
  *
32
38
  * Use this primarily in side-effect switches (`void` branches). For
33
39
  * value-producing switches, TypeScript can enforce exhaustiveness without a
34
- * `default` branch.
35
- *
36
- * ### Example
40
+ * `default` branch in either of the following styles.
37
41
  *
38
- * Return from each case for value-producing switches.
42
+ * ### Return from every case
39
43
  *
40
44
  * ```ts
41
45
  * type Color = "red" | "green" | "blue";
@@ -50,11 +54,11 @@
50
54
  * return "#0000ff";
51
55
  * }
52
56
  * };
53
- * ```
54
57
  *
55
- * ### Example
58
+ * expect(colorToHex("green")).toBe("#00ff00");
59
+ * ```
56
60
  *
57
- * Use assignment + no `default` to get exhaustiveness by definite assignment.
61
+ * ### Assign in every case
58
62
  *
59
63
  * ```ts
60
64
  * type Input =
@@ -62,7 +66,7 @@
62
66
  * | { readonly type: "Query" }
63
67
  * | { readonly type: "Export" };
64
68
  *
65
- * const onInput = (input: Input): void => {
69
+ * const inputToKind = (input: Input): "A" | "B" | "C" => {
66
70
  * let result: "A" | "B" | "C";
67
71
  *
68
72
  * switch (input.type) {
@@ -77,12 +81,10 @@
77
81
  * break;
78
82
  * }
79
83
  *
80
- * handleKind(result);
84
+ * return result;
81
85
  * };
82
86
  *
83
- * const handleKind = (kind: "A" | "B" | "C"): void => {
84
- * console.log(kind);
85
- * };
87
+ * expect(inputToKind({ type: "Query" })).toBe("B");
86
88
  * ```
87
89
  */
88
90
  export declare const exhaustiveCheck: (value: never) => never;
@@ -95,71 +97,128 @@ export declare const exhaustiveCheck: (value: never) => never;
95
97
  * ### Example
96
98
  *
97
99
  * ```ts
98
- * const values = [1, 2, 3];
99
- * const same = values.map(identity); // [1, 2, 3]
100
+ * import { identity } from "@evolu/common";
100
101
  *
102
+ * const values = [1, 2, 3];
103
+ * const object = { value: 1 };
101
104
  * const getTransform = (shouldDouble: boolean) =>
102
- * shouldDouble ? (x: number) => x * 2 : identity;
105
+ * shouldDouble ? (value: number) => value * 2 : identity;
106
+ *
107
+ * expect(values.map(identity)).toEqual([1, 2, 3]);
108
+ * expect(identity(object)).toBe(object);
109
+ * expect(getTransform(false)(2)).toBe(2);
103
110
  * ```
104
111
  */
105
112
  export declare const identity: <A>(a: A) => A;
106
113
  /**
107
- * A function that takes no arguments and returns a value of type T. Also known
108
- * as a thunk.
114
+ * Creates an object that follows JavaScript disposal semantics.
115
+ *
116
+ * The first argument is the object to make disposable. The returned object gets
117
+ * a disposal method and its functions are wrapped with a disposal guard. This
118
+ * is the JavaScript equivalent of .NET `ObjectDisposedException`: once an
119
+ * object has been disposed, calling its methods is a programmer error and
120
+ * should throw immediately instead of continuing with invalid state. Evolu
121
+ * asserts this invariant with the "Cannot use a disposed object." message.
122
+ *
123
+ * The second argument is an optional disposer. When provided, it is
124
+ * [moved](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DisposableStack/move)
125
+ * into the returned object, and the returned object's disposal method disposes
126
+ * it. Omit it when the object has no cleanup resources but still must become
127
+ * unusable after disposal, such as with reference count helpers where disposal
128
+ * enforces correct ownership tracking.
129
+ *
130
+ * ### Example
131
+ *
132
+ * ```ts
133
+ * import { disposable } from "@evolu/common";
134
+ *
135
+ * let cleaned = false;
136
+ * const createResource = () => {
137
+ * using disposer = new DisposableStack();
138
+ * disposer.defer(() => {
139
+ * cleaned = true;
140
+ * });
141
+ * return disposable({ read: () => "ready" }, disposer);
142
+ * };
143
+ *
144
+ * const resource = createResource();
145
+ * expect(resource.read()).toBe("ready");
146
+ * resource[Symbol.dispose]();
147
+ *
148
+ * expect(cleaned).toBe(true);
149
+ * expect(() => resource.read()).toThrow("Cannot use a disposed object.");
150
+ * ```
151
+ */
152
+ export declare function disposable<T extends object>(value: T extends Disposable ? Omit<T, typeof Symbol.dispose> : T, disposer?: DisposableStack): T extends Disposable ? T : T & Disposable;
153
+ export declare function disposable<T extends object>(value: T extends AsyncDisposable ? Omit<T, typeof Symbol.asyncDispose> : T, disposer: AsyncDisposableStack): T extends AsyncDisposable ? T : T & AsyncDisposable;
154
+ export declare const isDisposable: (value: unknown) => value is Disposable | AsyncDisposable;
155
+ /**
156
+ * A function that takes no arguments and returns a value.
109
157
  *
110
158
  * Useful for:
111
159
  *
112
- * - Providing default callbacks (see {@link lazyVoid}, {@link lazyTrue}, etc.)
160
+ * - Providing default callbacks (see {@link constVoid}, {@link constTrue}, etc.)
113
161
  * - Delaying expensive operations until actually needed
114
162
  * - Deferring side effects so the callee controls when they run
115
163
  *
116
164
  * ### Example
117
165
  *
118
166
  * ```ts
119
- * // Default callback
120
- * const notify = (onDone: Lazy<void> = lazyVoid) => {
121
- * onDone();
122
- * };
167
+ * import { constVoid, type Thunk } from "@evolu/common";
123
168
  *
124
- * // Delay computation
125
- * const getData: Lazy<Data> = () => compute();
126
- * const data = getData();
169
+ * const notify = (onDone: Thunk<void> = constVoid) => onDone();
170
+ * notify();
127
171
  *
128
- * // Defer side effects
129
- * const schedule = (job: Lazy<void>) => {
130
- * queueMicrotask(job);
172
+ * let value = 0;
173
+ * const compute: Thunk<number> = () => ++value;
174
+ * const jobs: Array<Thunk<void>> = [];
175
+ * const schedule = (job: Thunk<void>): void => {
176
+ * jobs.push(job);
131
177
  * };
132
- * schedule(() => logMetric("loaded"));
178
+ * schedule(() => {
179
+ * value += 10;
180
+ * });
181
+ *
182
+ * const computed = compute();
183
+ * jobs.shift()?.();
184
+ * expect(computed).toBe(1);
185
+ * expect(value).toBe(11);
133
186
  * ```
134
187
  */
135
- export type Lazy<T> = () => T;
188
+ export type Thunk<T> = () => T;
136
189
  /**
137
- * Creates a {@link Lazy} from a precomputed value.
190
+ * Creates a {@link Thunk} that always returns a precomputed value.
138
191
  *
139
- * Use when the value is expensive to compute and want to compute it once at
192
+ * Use when the value is expensive to compute and you want to compute it once at
140
193
  * definition time rather than on every call.
141
194
  *
142
195
  * ### Example
143
196
  *
144
197
  * ```ts
145
- * // Computed once at definition, returned on every call
146
- * const getConfig = lazy(parseConfig(rawConfig));
198
+ * import { constant } from "@evolu/common";
199
+ *
200
+ * let version = 0;
201
+ * const readConfig = () => ({ version: ++version });
202
+ * const getConstantConfig = constant(readConfig());
203
+ * const getFreshConfig = () => readConfig();
147
204
  *
148
- * // vs. computed on every call
149
- * const getConfig = () => parseConfig(rawConfig);
205
+ * expect(getConstantConfig()).toBe(getConstantConfig());
206
+ * expect(getConstantConfig().version).toBe(1);
207
+ * expect(getFreshConfig().version).toBe(2);
208
+ * expect(getFreshConfig().version).toBe(3);
150
209
  * ```
151
210
  */
152
- export declare const lazy: <T>(value: T) => Lazy<T>;
153
- /** A {@link Lazy} that returns `true`. */
154
- export declare const lazyTrue: Lazy<true>;
155
- /** A {@link Lazy} that returns `false`. */
156
- export declare const lazyFalse: Lazy<false>;
157
- /** A {@link Lazy} that returns `null`. */
158
- export declare const lazyNull: Lazy<null>;
159
- /** A {@link Lazy} that returns `undefined`. */
160
- export declare const lazyUndefined: Lazy<undefined>;
161
- /** A {@link Lazy} that returns `undefined` for void callbacks. */
162
- export declare const lazyVoid: Lazy<void>;
211
+ export declare const constant: <T>(value: T) => Thunk<T>;
212
+ /** A {@link Thunk} that returns `true`. */
213
+ export declare const constTrue: Thunk<true>;
214
+ /** A {@link Thunk} that returns `false`. */
215
+ export declare const constFalse: Thunk<false>;
216
+ /** A {@link Thunk} that returns `null`. */
217
+ export declare const constNull: Thunk<null>;
218
+ /** A {@link Thunk} that returns `undefined`. */
219
+ export declare const constUndefined: Thunk<undefined>;
220
+ /** A {@link Thunk} that returns `undefined` for void callbacks. */
221
+ export declare const constVoid: Thunk<void>;
163
222
  /**
164
223
  * Development placeholder that always throws.
165
224
  *
@@ -170,17 +229,19 @@ export declare const lazyVoid: Lazy<void>;
170
229
  * ### Example
171
230
  *
172
231
  * ```ts
173
- * // Type inferred from return type annotation
174
- * const fetchUser = (id: UserId): Result<User, FetchError> => todo();
232
+ * import { todo } from "@evolu/common";
175
233
  *
176
- * expectTypeOf(fetchUser).returns.toEqualTypeOf<
177
- * Result<User, FetchError>
178
- * >();
234
+ * interface Config {
235
+ * readonly theme: string;
236
+ * }
179
237
  *
180
- * // Explicit generic when no return type
238
+ * const getCount = (): number => todo();
181
239
  * const getConfig = () => todo<Config>();
182
240
  *
183
- * expectTypeOf(getConfig).returns.toEqualTypeOf<Config>();
241
+ * expectTypeOf<
242
+ * [ReturnType<typeof getCount>, ReturnType<typeof getConfig>]
243
+ * >().toEqualTypeOf<[number, Config]>();
244
+ * expect(getCount).toThrow("not yet implemented");
184
245
  * ```
185
246
  */
186
247
  export declare const todo: <T>() => T;
@@ -1 +1 @@
1
- {"version":3,"file":"Function.d.ts","sourceRoot":"","sources":["../../src/Function.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiFG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,KAAK,KAAG,KAE9C,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EAAE,GAAG,CAAC,KAAG,CAAM,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,IAAI,GACd,CAAC,EAAE,OAAO,CAAC,KAAG,IAAI,CAAC,CAAC,CAEd,CAAC;AAEV,0CAA0C;AAC1C,eAAO,MAAM,QAAQ,EAAE,IAAI,CAAC,IAAI,CAA4B,CAAC;AAE7D,2CAA2C;AAC3C,eAAO,MAAM,SAAS,EAAE,IAAI,CAAC,KAAK,CAA6B,CAAC;AAEhE,0CAA0C;AAC1C,eAAO,MAAM,QAAQ,EAAE,IAAI,CAAC,IAAI,CAA4B,CAAC;AAE7D,+CAA+C;AAC/C,eAAO,MAAM,aAAa,EAAE,IAAI,CAAC,SAAS,CAAiC,CAAC;AAE5E,kEAAkE;AAClE,eAAO,MAAM,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAiB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,eAAO,MAAM,IAAI,GAAI,CAAC,OAAK,CAE1B,CAAC"}
1
+ {"version":3,"file":"Function.d.ts","sourceRoot":"","sources":["../../src/Function.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmFG;AACH,eAAO,MAAM,eAAe,UAAW,KAAK,KAAG,KAE9C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,KAAK,CAAC,KAAG,CAAM,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACzC,KAAK,EAAE,CAAC,SAAS,UAAU,GAAG,IAAI,CAAC,CAAC,EAAE,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAChE,QAAQ,CAAC,EAAE,eAAe,GACzB,CAAC,SAAS,UAAU,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;AAC7C,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACzC,KAAK,EAAE,CAAC,SAAS,eAAe,GAAG,IAAI,CAAC,CAAC,EAAE,OAAO,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,EAC1E,QAAQ,EAAE,oBAAoB,GAC7B,CAAC,SAAS,eAAe,GAAG,CAAC,GAAG,CAAC,GAAG,eAAe,CAAC;AA2BvD,eAAO,MAAM,YAAY,UAChB,OAAO,KACb,KAAK,IAAI,UAAU,GAAG,eAOxB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,QAAQ,GAClB,CAAC,SAAS,CAAC,KAAG,KAAK,CAAC,CAAC,CAEf,CAAC;AAEV,2CAA2C;AAC3C,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,IAAI,CAAgC,CAAC;AAEnE,4CAA4C;AAC5C,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,KAAK,CAAiC,CAAC;AAEtE,2CAA2C;AAC3C,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,IAAI,CAAgC,CAAC;AAEnE,gDAAgD;AAChD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,SAAS,CACT,CAAC;AAEpC,mEAAmE;AACnE,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,IAAI,CAAkB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,eAAO,MAAM,IAAI,GAAI,CAAC,OAAK,CAE1B,CAAC"}
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * @module
5
5
  */
6
+ import { assertNotDisposed } from "./Assert.js";
7
+ import { isFunction } from "./Object.js";
6
8
  /**
7
9
  * Helper function to ensure exhaustive matching in a switch statement. Throws
8
10
  * an error if an unhandled case is encountered.
@@ -10,32 +12,36 @@
10
12
  * ### Example
11
13
  *
12
14
  * ```ts
15
+ * import { exhaustiveCheck } from "@evolu/common";
16
+ *
13
17
  * type Color = "red" | "green" | "blue";
18
+ * const handled: Array<string> = [];
14
19
  *
15
20
  * const handleColor = (color: Color): void => {
16
21
  * switch (color) {
17
22
  * case "red":
18
- * console.log("Handling red");
23
+ * handled.push("Handling red");
19
24
  * break;
20
25
  * case "green":
21
- * console.log("Handling green");
26
+ * handled.push("Handling green");
22
27
  * break;
23
28
  * case "blue":
24
- * console.log("Handling blue");
29
+ * handled.push("Handling blue");
25
30
  * break;
26
31
  * default:
27
- * exhaustiveCheck(color); // Ensures all cases are handled
32
+ * exhaustiveCheck(color);
28
33
  * }
29
34
  * };
35
+ *
36
+ * handleColor("blue");
37
+ * expect(handled).toEqual(["Handling blue"]);
30
38
  * ```
31
39
  *
32
40
  * Use this primarily in side-effect switches (`void` branches). For
33
41
  * value-producing switches, TypeScript can enforce exhaustiveness without a
34
- * `default` branch.
35
- *
36
- * ### Example
42
+ * `default` branch in either of the following styles.
37
43
  *
38
- * Return from each case for value-producing switches.
44
+ * ### Return from every case
39
45
  *
40
46
  * ```ts
41
47
  * type Color = "red" | "green" | "blue";
@@ -50,11 +56,11 @@
50
56
  * return "#0000ff";
51
57
  * }
52
58
  * };
53
- * ```
54
59
  *
55
- * ### Example
60
+ * expect(colorToHex("green")).toBe("#00ff00");
61
+ * ```
56
62
  *
57
- * Use assignment + no `default` to get exhaustiveness by definite assignment.
63
+ * ### Assign in every case
58
64
  *
59
65
  * ```ts
60
66
  * type Input =
@@ -62,7 +68,7 @@
62
68
  * | { readonly type: "Query" }
63
69
  * | { readonly type: "Export" };
64
70
  *
65
- * const onInput = (input: Input): void => {
71
+ * const inputToKind = (input: Input): "A" | "B" | "C" => {
66
72
  * let result: "A" | "B" | "C";
67
73
  *
68
74
  * switch (input.type) {
@@ -77,12 +83,10 @@
77
83
  * break;
78
84
  * }
79
85
  *
80
- * handleKind(result);
86
+ * return result;
81
87
  * };
82
88
  *
83
- * const handleKind = (kind: "A" | "B" | "C"): void => {
84
- * console.log(kind);
85
- * };
89
+ * expect(inputToKind({ type: "Query" })).toBe("B");
86
90
  * ```
87
91
  */
88
92
  export const exhaustiveCheck = (value) => {
@@ -97,41 +101,78 @@ export const exhaustiveCheck = (value) => {
97
101
  * ### Example
98
102
  *
99
103
  * ```ts
100
- * const values = [1, 2, 3];
101
- * const same = values.map(identity); // [1, 2, 3]
104
+ * import { identity } from "@evolu/common";
102
105
  *
106
+ * const values = [1, 2, 3];
107
+ * const object = { value: 1 };
103
108
  * const getTransform = (shouldDouble: boolean) =>
104
- * shouldDouble ? (x: number) => x * 2 : identity;
109
+ * shouldDouble ? (value: number) => value * 2 : identity;
110
+ *
111
+ * expect(values.map(identity)).toEqual([1, 2, 3]);
112
+ * expect(identity(object)).toBe(object);
113
+ * expect(getTransform(false)(2)).toBe(2);
105
114
  * ```
106
115
  */
107
116
  export const identity = (a) => a;
117
+ export function disposable(value, disposer = null) {
118
+ const mutableValue = value;
119
+ const ownedDisposer = disposer?.move() ?? new DisposableStack();
120
+ for (const [key, property] of Object.entries(value)) {
121
+ if (!isFunction(property))
122
+ continue;
123
+ mutableValue[key] = (...args) => {
124
+ assertNotDisposed(ownedDisposer);
125
+ return property(...args);
126
+ };
127
+ }
128
+ if (ownedDisposer instanceof AsyncDisposableStack) {
129
+ value[Symbol.asyncDispose] = () => ownedDisposer.disposeAsync();
130
+ }
131
+ else {
132
+ value[Symbol.dispose] = () => ownedDisposer.dispose();
133
+ }
134
+ return value;
135
+ }
136
+ export const isDisposable = (value) => {
137
+ if (typeof value !== "object" || value === null)
138
+ return false;
139
+ return (isFunction(value[Symbol.dispose]) ||
140
+ isFunction(value[Symbol.asyncDispose]));
141
+ };
108
142
  /**
109
- * Creates a {@link Lazy} from a precomputed value.
143
+ * Creates a {@link Thunk} that always returns a precomputed value.
110
144
  *
111
- * Use when the value is expensive to compute and want to compute it once at
145
+ * Use when the value is expensive to compute and you want to compute it once at
112
146
  * definition time rather than on every call.
113
147
  *
114
148
  * ### Example
115
149
  *
116
150
  * ```ts
117
- * // Computed once at definition, returned on every call
118
- * const getConfig = lazy(parseConfig(rawConfig));
151
+ * import { constant } from "@evolu/common";
152
+ *
153
+ * let version = 0;
154
+ * const readConfig = () => ({ version: ++version });
155
+ * const getConstantConfig = constant(readConfig());
156
+ * const getFreshConfig = () => readConfig();
119
157
  *
120
- * // vs. computed on every call
121
- * const getConfig = () => parseConfig(rawConfig);
158
+ * expect(getConstantConfig()).toBe(getConstantConfig());
159
+ * expect(getConstantConfig().version).toBe(1);
160
+ * expect(getFreshConfig().version).toBe(2);
161
+ * expect(getFreshConfig().version).toBe(3);
122
162
  * ```
123
163
  */
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;
164
+ export const constant = (value) => () => value;
165
+ /** A {@link Thunk} that returns `true`. */
166
+ export const constTrue = /*#__PURE__*/ constant(true);
167
+ /** A {@link Thunk} that returns `false`. */
168
+ export const constFalse = /*#__PURE__*/ constant(false);
169
+ /** A {@link Thunk} that returns `null`. */
170
+ export const constNull = /*#__PURE__*/ constant(null);
171
+ /** A {@link Thunk} that returns `undefined`. */
172
+ export const constUndefined =
173
+ /*#__PURE__*/ constant(undefined);
174
+ /** A {@link Thunk} that returns `undefined` for void callbacks. */
175
+ export const constVoid = constUndefined;
135
176
  /**
136
177
  * Development placeholder that always throws.
137
178
  *
@@ -142,17 +183,19 @@ export const lazyVoid = lazyUndefined;
142
183
  * ### Example
143
184
  *
144
185
  * ```ts
145
- * // Type inferred from return type annotation
146
- * const fetchUser = (id: UserId): Result<User, FetchError> => todo();
186
+ * import { todo } from "@evolu/common";
147
187
  *
148
- * expectTypeOf(fetchUser).returns.toEqualTypeOf<
149
- * Result<User, FetchError>
150
- * >();
188
+ * interface Config {
189
+ * readonly theme: string;
190
+ * }
151
191
  *
152
- * // Explicit generic when no return type
192
+ * const getCount = (): number => todo();
153
193
  * const getConfig = () => todo<Config>();
154
194
  *
155
- * expectTypeOf(getConfig).returns.toEqualTypeOf<Config>();
195
+ * expectTypeOf<
196
+ * [ReturnType<typeof getCount>, ReturnType<typeof getConfig>]
197
+ * >().toEqualTypeOf<[number, Config]>();
198
+ * expect(getCount).toThrow("not yet implemented");
156
199
  * ```
157
200
  */
158
201
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters