@confect/core 5.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/dist/FunctionProvenance.d.ts +12 -3
- package/dist/FunctionProvenance.d.ts.map +1 -1
- package/dist/FunctionProvenance.js +3 -2
- package/dist/FunctionProvenance.js.map +1 -1
- package/dist/FunctionSpec.d.ts +48 -26
- package/dist/FunctionSpec.d.ts.map +1 -1
- package/dist/FunctionSpec.js +2 -2
- package/dist/FunctionSpec.js.map +1 -1
- package/dist/Ref.d.ts +60 -25
- package/dist/Ref.d.ts.map +1 -1
- package/dist/Ref.js +70 -15
- package/dist/Ref.js.map +1 -1
- package/dist/Spec.d.ts +4 -4
- package/dist/Types.d.ts +3 -2
- package/dist/Types.d.ts.map +1 -1
- package/dist/Types.js.map +1 -1
- package/package.json +1 -1
- package/src/FunctionProvenance.ts +7 -0
- package/src/FunctionSpec.ts +26 -2
- package/src/Ref.ts +197 -45
- package/src/Types.ts +19 -15
package/src/Ref.ts
CHANGED
|
@@ -3,8 +3,10 @@ import type {
|
|
|
3
3
|
FunctionVisibility,
|
|
4
4
|
} from "convex/server";
|
|
5
5
|
import { makeFunctionReference } from "convex/server";
|
|
6
|
+
import type { Value } from "convex/values";
|
|
7
|
+
import { ConvexError } from "convex/values";
|
|
6
8
|
import type { ParseResult } from "effect";
|
|
7
|
-
import { Effect, Match, Schema } from "effect";
|
|
9
|
+
import { Effect, Match, Option, Schema } from "effect";
|
|
8
10
|
import type * as FunctionSpec from "./FunctionSpec";
|
|
9
11
|
import type * as RuntimeAndFunctionType from "./RuntimeAndFunctionType";
|
|
10
12
|
|
|
@@ -13,27 +15,30 @@ export interface Ref<
|
|
|
13
15
|
_FunctionVisibility extends FunctionVisibility,
|
|
14
16
|
_Args,
|
|
15
17
|
_Returns,
|
|
18
|
+
_Error = never,
|
|
16
19
|
> {
|
|
17
20
|
readonly _RuntimeAndFunctionType?: _RuntimeAndFunctionType;
|
|
18
21
|
readonly _FunctionVisibility?: _FunctionVisibility;
|
|
19
22
|
readonly _Args?: _Args;
|
|
20
23
|
readonly _Returns?: _Returns;
|
|
24
|
+
readonly _Error?: _Error;
|
|
21
25
|
/** @internal */
|
|
22
26
|
readonly functionSpec: FunctionSpec.AnyWithProps;
|
|
23
27
|
/** @internal */
|
|
24
28
|
readonly functionNamespace: string;
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
export interface Any extends Ref<any, any, any, any> {}
|
|
31
|
+
export interface Any extends Ref<any, any, any, any, any> {}
|
|
28
32
|
|
|
29
|
-
export interface AnyInternal extends Ref<any, "internal", any, any> {}
|
|
33
|
+
export interface AnyInternal extends Ref<any, "internal", any, any, any> {}
|
|
30
34
|
|
|
31
|
-
export interface AnyPublic extends Ref<any, "public", any, any> {}
|
|
35
|
+
export interface AnyPublic extends Ref<any, "public", any, any, any> {}
|
|
32
36
|
|
|
33
37
|
export interface AnyQuery extends Ref<
|
|
34
38
|
RuntimeAndFunctionType.AnyQuery,
|
|
35
39
|
FunctionVisibility,
|
|
36
40
|
any,
|
|
41
|
+
any,
|
|
37
42
|
any
|
|
38
43
|
> {}
|
|
39
44
|
|
|
@@ -41,6 +46,7 @@ export interface AnyMutation extends Ref<
|
|
|
41
46
|
RuntimeAndFunctionType.AnyMutation,
|
|
42
47
|
FunctionVisibility,
|
|
43
48
|
any,
|
|
49
|
+
any,
|
|
44
50
|
any
|
|
45
51
|
> {}
|
|
46
52
|
|
|
@@ -48,6 +54,7 @@ export interface AnyAction extends Ref<
|
|
|
48
54
|
RuntimeAndFunctionType.AnyAction,
|
|
49
55
|
FunctionVisibility,
|
|
50
56
|
any,
|
|
57
|
+
any,
|
|
51
58
|
any
|
|
52
59
|
> {}
|
|
53
60
|
|
|
@@ -55,6 +62,7 @@ export interface AnyPublicQuery extends Ref<
|
|
|
55
62
|
RuntimeAndFunctionType.AnyQuery,
|
|
56
63
|
"public",
|
|
57
64
|
any,
|
|
65
|
+
any,
|
|
58
66
|
any
|
|
59
67
|
> {}
|
|
60
68
|
|
|
@@ -62,6 +70,7 @@ export interface AnyPublicMutation extends Ref<
|
|
|
62
70
|
RuntimeAndFunctionType.AnyMutation,
|
|
63
71
|
"public",
|
|
64
72
|
any,
|
|
73
|
+
any,
|
|
65
74
|
any
|
|
66
75
|
> {}
|
|
67
76
|
|
|
@@ -69,6 +78,7 @@ export interface AnyPublicAction extends Ref<
|
|
|
69
78
|
RuntimeAndFunctionType.AnyAction,
|
|
70
79
|
"public",
|
|
71
80
|
any,
|
|
81
|
+
any,
|
|
72
82
|
any
|
|
73
83
|
> {}
|
|
74
84
|
|
|
@@ -77,7 +87,8 @@ export type GetRuntimeAndFunctionType<Ref_> =
|
|
|
77
87
|
infer RuntimeAndFunctionType_,
|
|
78
88
|
infer _FunctionVisibility,
|
|
79
89
|
infer _Args,
|
|
80
|
-
infer _Returns
|
|
90
|
+
infer _Returns,
|
|
91
|
+
infer _Error
|
|
81
92
|
>
|
|
82
93
|
? RuntimeAndFunctionType_
|
|
83
94
|
: never;
|
|
@@ -87,7 +98,8 @@ export type GetRuntime<Ref_> =
|
|
|
87
98
|
infer RuntimeAndFunctionType_,
|
|
88
99
|
infer _FunctionVisibility,
|
|
89
100
|
infer _Args,
|
|
90
|
-
infer _Returns
|
|
101
|
+
infer _Returns,
|
|
102
|
+
infer _Error
|
|
91
103
|
>
|
|
92
104
|
? RuntimeAndFunctionType.GetRuntime<RuntimeAndFunctionType_>
|
|
93
105
|
: never;
|
|
@@ -97,7 +109,8 @@ export type GetFunctionType<Ref_> =
|
|
|
97
109
|
infer RuntimeAndFunctionType_,
|
|
98
110
|
infer _FunctionVisibility,
|
|
99
111
|
infer _Args,
|
|
100
|
-
infer _Returns
|
|
112
|
+
infer _Returns,
|
|
113
|
+
infer _Error
|
|
101
114
|
>
|
|
102
115
|
? RuntimeAndFunctionType.GetFunctionType<RuntimeAndFunctionType_>
|
|
103
116
|
: never;
|
|
@@ -107,7 +120,8 @@ export type GetFunctionVisibility<Ref_> =
|
|
|
107
120
|
infer _RuntimeAndFunctionType,
|
|
108
121
|
infer FunctionVisibility_,
|
|
109
122
|
infer _Args,
|
|
110
|
-
infer _Returns
|
|
123
|
+
infer _Returns,
|
|
124
|
+
infer _Error
|
|
111
125
|
>
|
|
112
126
|
? FunctionVisibility_
|
|
113
127
|
: never;
|
|
@@ -117,21 +131,38 @@ export type Args<Ref_> =
|
|
|
117
131
|
infer _RuntimeAndFunctionType,
|
|
118
132
|
infer _FunctionVisibility,
|
|
119
133
|
infer Args_,
|
|
120
|
-
infer _Returns
|
|
134
|
+
infer _Returns,
|
|
135
|
+
infer _Error
|
|
121
136
|
>
|
|
122
137
|
? Args_
|
|
123
138
|
: never;
|
|
124
139
|
|
|
140
|
+
export type OptionalArgs<Ref_ extends Any> = keyof Args<Ref_> extends never
|
|
141
|
+
? [args?: Args<Ref_>]
|
|
142
|
+
: [args: Args<Ref_>];
|
|
143
|
+
|
|
125
144
|
export type Returns<Ref_> =
|
|
126
145
|
Ref_ extends Ref<
|
|
127
146
|
infer _RuntimeAndFunctionType,
|
|
128
147
|
infer _FunctionVisibility,
|
|
129
148
|
infer _Args,
|
|
130
|
-
infer Returns_
|
|
149
|
+
infer Returns_,
|
|
150
|
+
infer _Error
|
|
131
151
|
>
|
|
132
152
|
? Returns_
|
|
133
153
|
: never;
|
|
134
154
|
|
|
155
|
+
export type Error<Ref_> =
|
|
156
|
+
Ref_ extends Ref<
|
|
157
|
+
infer _RuntimeAndFunctionType,
|
|
158
|
+
infer _FunctionVisibility,
|
|
159
|
+
infer _Args,
|
|
160
|
+
infer _Returns,
|
|
161
|
+
infer Error_
|
|
162
|
+
>
|
|
163
|
+
? Error_
|
|
164
|
+
: never;
|
|
165
|
+
|
|
135
166
|
export type FunctionReference<Ref_ extends Any> = ConvexFunctionReference<
|
|
136
167
|
GetFunctionType<Ref_>,
|
|
137
168
|
GetFunctionVisibility<Ref_>
|
|
@@ -142,7 +173,8 @@ export type FromFunctionSpec<FunctionSpec_ extends FunctionSpec.AnyWithProps> =
|
|
|
142
173
|
FunctionSpec.GetRuntimeAndFunctionType<FunctionSpec_>,
|
|
143
174
|
FunctionSpec.GetFunctionVisibility<FunctionSpec_>,
|
|
144
175
|
FunctionSpec.Args<FunctionSpec_>,
|
|
145
|
-
FunctionSpec.Returns<FunctionSpec_
|
|
176
|
+
FunctionSpec.Returns<FunctionSpec_>,
|
|
177
|
+
FunctionSpec.Error<FunctionSpec_>
|
|
146
178
|
>;
|
|
147
179
|
|
|
148
180
|
export const make = <FunctionSpec_ extends FunctionSpec.AnyWithProps>(
|
|
@@ -163,12 +195,25 @@ export const getFunctionReference = <Ref_ extends Any>(
|
|
|
163
195
|
): FunctionReference<Ref_> =>
|
|
164
196
|
makeFunctionReference(getConvexFunctionName(ref)) as FunctionReference<Ref_>;
|
|
165
197
|
|
|
198
|
+
export const hasErrorSchema = (ref: Any): boolean =>
|
|
199
|
+
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
200
|
+
Match.tag(
|
|
201
|
+
"Confect",
|
|
202
|
+
(confectFunctionProvenance) =>
|
|
203
|
+
confectFunctionProvenance.error !== undefined,
|
|
204
|
+
),
|
|
205
|
+
Match.tag("Convex", () => false),
|
|
206
|
+
Match.exhaustive,
|
|
207
|
+
);
|
|
208
|
+
|
|
166
209
|
export const encodeArgs = <Ref_ extends Any>(
|
|
167
210
|
ref: Ref_,
|
|
168
211
|
args: Args<Ref_>,
|
|
169
212
|
): Effect.Effect<unknown, ParseResult.ParseError> =>
|
|
170
213
|
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
171
|
-
Match.tag("Confect", (
|
|
214
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
215
|
+
Schema.encode(confectFunctionProvenance.args)(args),
|
|
216
|
+
),
|
|
172
217
|
Match.tag("Convex", () => Effect.succeed(args)),
|
|
173
218
|
Match.exhaustive,
|
|
174
219
|
);
|
|
@@ -178,7 +223,9 @@ export const decodeReturns = <Ref_ extends Any>(
|
|
|
178
223
|
returns: unknown,
|
|
179
224
|
): Effect.Effect<Returns<Ref_>, ParseResult.ParseError> =>
|
|
180
225
|
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
181
|
-
Match.tag("Confect", (
|
|
226
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
227
|
+
Schema.decode(confectFunctionProvenance.returns)(returns),
|
|
228
|
+
),
|
|
182
229
|
Match.tag("Convex", () => Effect.succeed(returns)),
|
|
183
230
|
Match.exhaustive,
|
|
184
231
|
);
|
|
@@ -188,7 +235,9 @@ export const encodeArgsSync = <Ref_ extends Any>(
|
|
|
188
235
|
args: Args<Ref_>,
|
|
189
236
|
): unknown =>
|
|
190
237
|
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
191
|
-
Match.tag("Confect", (
|
|
238
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
239
|
+
Schema.encodeSync(confectFunctionProvenance.args)(args),
|
|
240
|
+
),
|
|
192
241
|
Match.tag("Convex", () => args),
|
|
193
242
|
Match.exhaustive,
|
|
194
243
|
);
|
|
@@ -198,52 +247,155 @@ export const decodeReturnsSync = <Ref_ extends Any>(
|
|
|
198
247
|
encodedReturns: unknown,
|
|
199
248
|
): Returns<Ref_> =>
|
|
200
249
|
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
201
|
-
Match.tag("Confect", (
|
|
250
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
251
|
+
Schema.decodeSync(confectFunctionProvenance.returns)(encodedReturns),
|
|
252
|
+
),
|
|
202
253
|
Match.tag("Convex", () => encodedReturns),
|
|
203
254
|
Match.exhaustive,
|
|
204
255
|
) as Returns<Ref_>;
|
|
205
256
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
257
|
+
const ConvexErrorIdentifier = Symbol.for("ConvexError");
|
|
258
|
+
|
|
259
|
+
export const isConvexError = (error: unknown): error is ConvexError<Value> =>
|
|
260
|
+
error instanceof ConvexError ||
|
|
261
|
+
(typeof error === "object" &&
|
|
262
|
+
error !== null &&
|
|
263
|
+
ConvexErrorIdentifier in error);
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Build a callback-style handler that decodes the ref's typed error from a
|
|
267
|
+
* caught `ConvexError`, or else forwards the value to `mapUnknownError`. The
|
|
268
|
+
* fallback is also invoked when the input *is* a `ConvexError` but the ref
|
|
269
|
+
* doesn't declare a typed-error schema—by definition such a value falls
|
|
270
|
+
* outside the ref's error contract. Useful when adapting non-Effect APIs (e.g.
|
|
271
|
+
* emitter callbacks for streamed subscriptions) to the same error semantics
|
|
272
|
+
* that `runWithCodec` provides.
|
|
273
|
+
*/
|
|
274
|
+
export const decodeErrorOrElse =
|
|
275
|
+
<Ref_ extends Any, E>(ref: Ref_, mapUnknownError: (error: unknown) => E) =>
|
|
276
|
+
(error: unknown): Error<Ref_> | E => {
|
|
277
|
+
if (isConvexError(error)) {
|
|
278
|
+
const decoded = decodeErrorSync(ref, error.data);
|
|
279
|
+
if (Option.isSome(decoded)) {
|
|
280
|
+
return decoded.value;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return mapUnknownError(error);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Decode `encodedError` against the ref's error schema. Returns `None` if the
|
|
288
|
+
* ref doesn't declare a typed error (Confect ref without an `error` schema, or
|
|
289
|
+
* a Convex-provenance ref)—by definition there's nothing to decode the value
|
|
290
|
+
* into, and the caller is responsible for deciding what to do (typically:
|
|
291
|
+
* surface the original value as a defect).
|
|
292
|
+
*/
|
|
293
|
+
export const decodeError = <Ref_ extends Any>(
|
|
294
|
+
ref: Ref_,
|
|
295
|
+
encodedError: unknown,
|
|
296
|
+
): Effect.Effect<Option.Option<Error<Ref_>>, ParseResult.ParseError> =>
|
|
297
|
+
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
298
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
299
|
+
confectFunctionProvenance.error !== undefined
|
|
300
|
+
? Effect.map(
|
|
301
|
+
Schema.decode(confectFunctionProvenance.error)(encodedError),
|
|
302
|
+
Option.some,
|
|
303
|
+
)
|
|
304
|
+
: Effect.succeed(Option.none<Error<Ref_>>()),
|
|
305
|
+
),
|
|
306
|
+
Match.tag("Convex", () => Effect.succeed(Option.none<Error<Ref_>>())),
|
|
307
|
+
Match.exhaustive,
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Synchronous counterpart to `decodeError`. Throws on schema decode failure;
|
|
312
|
+
* returns `None` when the ref doesn't declare a typed error.
|
|
313
|
+
*/
|
|
314
|
+
export const decodeErrorSync = <Ref_ extends Any>(
|
|
315
|
+
ref: Ref_,
|
|
316
|
+
encodedError: unknown,
|
|
317
|
+
): Option.Option<Error<Ref_>> =>
|
|
318
|
+
Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
319
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
320
|
+
confectFunctionProvenance.error !== undefined
|
|
321
|
+
? Option.some(
|
|
322
|
+
Schema.decodeSync(confectFunctionProvenance.error)(
|
|
323
|
+
encodedError,
|
|
324
|
+
) as Error<Ref_>,
|
|
325
|
+
)
|
|
326
|
+
: Option.none<Error<Ref_>>(),
|
|
327
|
+
),
|
|
328
|
+
Match.tag("Convex", () => Option.none<Error<Ref_>>()),
|
|
329
|
+
Match.exhaustive,
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
export const maybeDecodeErrorSync = <Ref_ extends Any>(
|
|
333
|
+
ref: Ref_,
|
|
334
|
+
error: unknown,
|
|
335
|
+
): unknown =>
|
|
336
|
+
isConvexError(error)
|
|
337
|
+
? Match.value(ref.functionSpec.functionProvenance).pipe(
|
|
338
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
339
|
+
confectFunctionProvenance.error !== undefined
|
|
340
|
+
? Schema.decodeSync(confectFunctionProvenance.error)(error.data)
|
|
341
|
+
: error,
|
|
342
|
+
),
|
|
343
|
+
Match.tag("Convex", () => error),
|
|
344
|
+
Match.exhaustive,
|
|
345
|
+
)
|
|
346
|
+
: error;
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Encode args via the ref's args schema, invoke `call`, decode returns via the
|
|
350
|
+
* ref's returns schema, and translate any thrown `ConvexError` into the ref's
|
|
351
|
+
* typed error. Anything else the Promise rejects with—network failures,
|
|
352
|
+
* server-side runtime errors, validation failures, etc.—is passed to
|
|
353
|
+
* `mapUnknownError` to be turned into a typed `E`, or surfaced as a defect when
|
|
354
|
+
* no handler is provided.
|
|
355
|
+
*/
|
|
356
|
+
export const runWithCodec = <Ref_ extends Any, E = never>(
|
|
224
357
|
ref: Ref_,
|
|
225
358
|
args: Args<Ref_>,
|
|
226
|
-
|
|
359
|
+
call: (
|
|
227
360
|
functionReference: FunctionReference<Ref_>,
|
|
228
361
|
encodedArgs: unknown,
|
|
229
|
-
) =>
|
|
230
|
-
|
|
362
|
+
) => PromiseLike<unknown>,
|
|
363
|
+
mapUnknownError?: (error: unknown) => E,
|
|
364
|
+
): Effect.Effect<Returns<Ref_>, E | Error<Ref_> | ParseResult.ParseError> =>
|
|
231
365
|
Effect.gen(function* () {
|
|
232
366
|
const functionReference = getFunctionReference(ref);
|
|
233
367
|
const functionProvenance = ref.functionSpec.functionProvenance;
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
368
|
+
const invoke = (
|
|
369
|
+
encodedArgs: unknown,
|
|
370
|
+
): Effect.Effect<unknown, Error<Ref_> | E> =>
|
|
371
|
+
Effect.tryPromise({
|
|
372
|
+
try: () => Promise.resolve(call(functionReference, encodedArgs)),
|
|
373
|
+
catch: (error): Error<Ref_> | E => {
|
|
374
|
+
if (isConvexError(error)) {
|
|
375
|
+
const decoded = decodeErrorSync(ref, error.data);
|
|
376
|
+
if (Option.isSome(decoded)) {
|
|
377
|
+
return decoded.value;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
if (mapUnknownError !== undefined) {
|
|
381
|
+
return mapUnknownError(error);
|
|
382
|
+
}
|
|
383
|
+
throw error;
|
|
384
|
+
},
|
|
385
|
+
});
|
|
238
386
|
return yield* Match.value(functionProvenance).pipe(
|
|
239
|
-
Match.tag("Confect", (
|
|
387
|
+
Match.tag("Confect", (confectFunctionProvenance) =>
|
|
240
388
|
Effect.gen(function* () {
|
|
241
|
-
const encodedArgs = yield* Schema.encode(
|
|
242
|
-
|
|
243
|
-
|
|
389
|
+
const encodedArgs = yield* Schema.encode(
|
|
390
|
+
confectFunctionProvenance.args,
|
|
391
|
+
)(args);
|
|
392
|
+
const encodedReturns = yield* invoke(encodedArgs);
|
|
393
|
+
return yield* Schema.decode(confectFunctionProvenance.returns)(
|
|
394
|
+
encodedReturns,
|
|
395
|
+
);
|
|
244
396
|
}),
|
|
245
397
|
),
|
|
246
|
-
Match.tag("Convex", () =>
|
|
398
|
+
Match.tag("Convex", () => invoke(args)),
|
|
247
399
|
Match.exhaustive,
|
|
248
400
|
);
|
|
249
401
|
});
|
package/src/Types.ts
CHANGED
|
@@ -58,7 +58,7 @@ export type IsRecord<T> = [T] extends [never]
|
|
|
58
58
|
export type DeepMutable<T> =
|
|
59
59
|
IsAny<T> extends true
|
|
60
60
|
? any
|
|
61
|
-
: T extends
|
|
61
|
+
: T extends NonRecursiveLeaf
|
|
62
62
|
? T
|
|
63
63
|
: T extends ReadonlyMap<infer K, infer V>
|
|
64
64
|
? Map<DeepMutable<K>, DeepMutable<V>>
|
|
@@ -74,25 +74,29 @@ export type TypeDefect<Message extends string, T = never> = [Message, T];
|
|
|
74
74
|
|
|
75
75
|
export type IsRecursive<T> = true extends DetectCycle<T> ? true : false;
|
|
76
76
|
|
|
77
|
+
type NonRecursiveLeaf = Brand.Brand<any> | GenericId<any> | ArrayBuffer;
|
|
78
|
+
|
|
77
79
|
type DetectCycle<T, Cache extends any[] = []> =
|
|
78
80
|
IsAny<T> extends true
|
|
79
81
|
? false
|
|
80
82
|
: [T] extends [any]
|
|
81
|
-
? T extends
|
|
82
|
-
?
|
|
83
|
-
: T extends
|
|
84
|
-
?
|
|
85
|
-
: T extends
|
|
86
|
-
? DetectCycle<
|
|
87
|
-
: T extends
|
|
88
|
-
? DetectCycle<
|
|
89
|
-
: T extends
|
|
90
|
-
?
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
83
|
+
? T extends NonRecursiveLeaf
|
|
84
|
+
? false
|
|
85
|
+
: T extends Cache[number]
|
|
86
|
+
? true
|
|
87
|
+
: T extends Array<infer U>
|
|
88
|
+
? DetectCycle<U, [...Cache, T]>
|
|
89
|
+
: T extends Map<infer _U, infer V>
|
|
90
|
+
? DetectCycle<V, [...Cache, T]>
|
|
91
|
+
: T extends Set<infer U>
|
|
92
|
+
? DetectCycle<U, [...Cache, T]>
|
|
93
|
+
: T extends object
|
|
94
|
+
? true extends {
|
|
95
|
+
[K in keyof T]: DetectCycle<T[K], [...Cache, T]>;
|
|
96
|
+
}[keyof T]
|
|
97
|
+
? true
|
|
98
|
+
: false
|
|
94
99
|
: false
|
|
95
|
-
: false
|
|
96
100
|
: never;
|
|
97
101
|
|
|
98
102
|
//////////////////////////////////
|