@confect/core 10.0.0-next.9 → 10.1.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 (103) hide show
  1. package/CHANGELOG.md +964 -47
  2. package/README.md +3 -1
  3. package/dist/FunctionProvenance.d.ts +166 -68
  4. package/dist/FunctionProvenance.d.ts.map +1 -1
  5. package/dist/FunctionProvenance.js +55 -13
  6. package/dist/FunctionProvenance.js.map +1 -1
  7. package/dist/FunctionSpec.d.ts +320 -138
  8. package/dist/FunctionSpec.d.ts.map +1 -1
  9. package/dist/FunctionSpec.js +56 -13
  10. package/dist/FunctionSpec.js.map +1 -1
  11. package/dist/GenericId.d.ts.map +1 -1
  12. package/dist/GenericId.js +1 -1
  13. package/dist/GroupPath.d.ts +6 -10
  14. package/dist/GroupPath.d.ts.map +1 -1
  15. package/dist/GroupPath.js.map +1 -1
  16. package/dist/GroupSpec.d.ts +25 -12
  17. package/dist/GroupSpec.d.ts.map +1 -1
  18. package/dist/GroupSpec.js +51 -14
  19. package/dist/GroupSpec.js.map +1 -1
  20. package/dist/Identifier.d.ts +6 -5
  21. package/dist/Identifier.d.ts.map +1 -1
  22. package/dist/Identifier.js +6 -5
  23. package/dist/Identifier.js.map +1 -1
  24. package/dist/Lazy.d.ts +11 -14
  25. package/dist/Lazy.d.ts.map +1 -1
  26. package/dist/Lazy.js +11 -14
  27. package/dist/Lazy.js.map +1 -1
  28. package/dist/MiddlewareAttachment.d.ts +171 -0
  29. package/dist/MiddlewareAttachment.d.ts.map +1 -0
  30. package/dist/MiddlewareAttachment.js +48 -0
  31. package/dist/MiddlewareAttachment.js.map +1 -0
  32. package/dist/MiddlewareSpec.d.ts +198 -0
  33. package/dist/MiddlewareSpec.d.ts.map +1 -0
  34. package/dist/MiddlewareSpec.js +60 -0
  35. package/dist/MiddlewareSpec.js.map +1 -0
  36. package/dist/PaginationError.d.ts +20 -0
  37. package/dist/PaginationError.d.ts.map +1 -0
  38. package/dist/PaginationError.js +31 -0
  39. package/dist/PaginationError.js.map +1 -0
  40. package/dist/PaginationOptions.d.ts +23 -0
  41. package/dist/PaginationOptions.d.ts.map +1 -0
  42. package/dist/PaginationOptions.js +29 -0
  43. package/dist/PaginationOptions.js.map +1 -0
  44. package/dist/PaginationResult.d.ts +1 -0
  45. package/dist/PaginationResult.d.ts.map +1 -1
  46. package/dist/PaginationResult.js.map +1 -1
  47. package/dist/Ref.d.ts +135 -47
  48. package/dist/Ref.d.ts.map +1 -1
  49. package/dist/Ref.js +104 -46
  50. package/dist/Ref.js.map +1 -1
  51. package/dist/Refs.d.ts +10 -5
  52. package/dist/Refs.d.ts.map +1 -1
  53. package/dist/Refs.js +5 -4
  54. package/dist/Refs.js.map +1 -1
  55. package/dist/SchemaToValidator.d.ts +99 -0
  56. package/dist/SchemaToValidator.d.ts.map +1 -0
  57. package/dist/SchemaToValidator.js +158 -0
  58. package/dist/SchemaToValidator.js.map +1 -0
  59. package/dist/Spec.d.ts +16 -12
  60. package/dist/Spec.d.ts.map +1 -1
  61. package/dist/Spec.js +14 -9
  62. package/dist/Spec.js.map +1 -1
  63. package/dist/SystemFields.d.ts +20 -19
  64. package/dist/SystemFields.d.ts.map +1 -1
  65. package/dist/SystemFields.js +22 -21
  66. package/dist/SystemFields.js.map +1 -1
  67. package/dist/Table.d.ts +75 -0
  68. package/dist/Table.d.ts.map +1 -0
  69. package/dist/Table.js +77 -0
  70. package/dist/Table.js.map +1 -0
  71. package/dist/Types.d.ts +8 -2
  72. package/dist/Types.d.ts.map +1 -1
  73. package/dist/Types.js.map +1 -1
  74. package/dist/UserIdentity.d.ts.map +1 -1
  75. package/dist/index.d.ts +6 -1
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +9 -4
  78. package/package.json +17 -15
  79. package/src/FunctionProvenance.ts +197 -34
  80. package/src/FunctionSpec.ts +332 -86
  81. package/src/GroupPath.ts +6 -12
  82. package/src/GroupSpec.ts +184 -25
  83. package/src/Identifier.ts +6 -5
  84. package/src/Lazy.ts +11 -14
  85. package/src/MiddlewareAttachment.ts +106 -0
  86. package/src/MiddlewareSpec.ts +392 -0
  87. package/src/PaginationError.ts +78 -0
  88. package/src/PaginationOptions.ts +23 -0
  89. package/src/PaginationResult.ts +4 -0
  90. package/src/Ref.ts +468 -236
  91. package/src/Refs.ts +43 -18
  92. package/src/SchemaToValidator.ts +612 -0
  93. package/src/Spec.ts +50 -39
  94. package/src/SystemFields.ts +40 -42
  95. package/src/Table.ts +427 -0
  96. package/src/Types.ts +9 -3
  97. package/src/index.ts +6 -1
  98. package/dist/Registry.d.ts +0 -24
  99. package/dist/Registry.d.ts.map +0 -1
  100. package/dist/Registry.js +0 -19
  101. package/dist/Registry.js.map +0 -1
  102. package/dist/tsconfig.src.tsbuildinfo +0 -1
  103. package/src/Registry.ts +0 -30
@@ -0,0 +1,612 @@
1
+ import type {
2
+ PropertyValidators,
3
+ Validator,
4
+ VAny,
5
+ VArray,
6
+ VBoolean,
7
+ VBytes,
8
+ VFloat64,
9
+ VId,
10
+ VInt64,
11
+ VLiteral,
12
+ VNull,
13
+ VObject,
14
+ VOptional,
15
+ VRecord,
16
+ VString,
17
+ VUnion,
18
+ } from "convex/values";
19
+ import { v } from "convex/values";
20
+ import { pipe } from "effect/Function";
21
+ import * as Array from "effect/Array";
22
+ import * as Data from "effect/Data";
23
+ import * as Effect from "effect/Effect";
24
+ import * as Match from "effect/Match";
25
+ import * as Number from "effect/Number";
26
+ import * as Option from "effect/Option";
27
+ import * as Predicate from "effect/Predicate";
28
+ import * as Schema from "effect/Schema";
29
+ import * as SchemaAST from "effect/SchemaAST";
30
+ import * as String from "effect/String";
31
+
32
+ import * as GenericId from "./GenericId";
33
+ import type {
34
+ IsAny,
35
+ IsOptional,
36
+ IsRecord,
37
+ IsRecursive,
38
+ IsUnion,
39
+ TypeError,
40
+ UnionToTuple,
41
+ } from "./Types";
42
+
43
+ // Args
44
+
45
+ export const compileArgsSchema = <ConfectValue, ConvexValue>(
46
+ argsSchema: Schema.Codec<ConfectValue, ConvexValue>,
47
+ ): PropertyValidators => {
48
+ const ast = Schema.toEncoded(argsSchema).ast;
49
+
50
+ return pipe(
51
+ ast,
52
+ Match.value,
53
+ Match.tag("Objects", (objectsAst) =>
54
+ Array.isReadonlyArrayEmpty(objectsAst.indexSignatures)
55
+ ? handlePropertySignatures(objectsAst)
56
+ : Effect.fail(new IndexSignaturesAreNotSupportedError()),
57
+ ),
58
+ Match.orElse(() => Effect.fail(new TopLevelMustBeObjectError())),
59
+ Effect.runSync,
60
+ );
61
+ };
62
+
63
+ // Returns
64
+
65
+ export const compileReturnsSchema = <ConfectValue, ConvexValue>(
66
+ schema: Schema.Codec<ConfectValue, ConvexValue>,
67
+ ): Validator<any, any, any> =>
68
+ Effect.runSync(compileAst(Schema.toEncoded(schema).ast));
69
+
70
+ // Table
71
+
72
+ /**
73
+ * Convert a table `Schema` to a table `Validator`.
74
+ */
75
+ export type TableSchemaToTableValidator<
76
+ TableSchema extends Schema.Codec<any, any>,
77
+ > =
78
+ ValueToValidator<TableSchema["Encoded"]> extends infer Vd extends
79
+ | VObject<any, any, any, any>
80
+ | VUnion<any, any, any, any>
81
+ ? Vd
82
+ : never;
83
+
84
+ export const compileTableSchema = <TableSchema extends Schema.Codec<any, any>>(
85
+ schema: TableSchema,
86
+ ): TableSchemaToTableValidator<TableSchema> => {
87
+ const ast = Schema.toEncoded(schema).ast;
88
+
89
+ return pipe(
90
+ ast,
91
+ Match.value,
92
+ Match.tag("Objects", ({ indexSignatures }) =>
93
+ Array.isReadonlyArrayEmpty(indexSignatures)
94
+ ? // oxlint-disable-next-line effecttsgo/unsafe-effect-type-assertion -- The return type is derived from the input schema and cannot be recovered from the runtime AST.
95
+ (compileAst(ast) as Effect.Effect<any>)
96
+ : Effect.fail(new IndexSignaturesAreNotSupportedError()),
97
+ ),
98
+ Match.tag("Union", (unionAst) => compileAst(unionAst)),
99
+ Match.orElse(() => Effect.fail(new TopLevelMustBeObjectOrUnionError())),
100
+ Effect.runSync,
101
+ );
102
+ };
103
+
104
+ // Compiler
105
+
106
+ export type ReadonlyValue =
107
+ | string
108
+ | number
109
+ | bigint
110
+ | boolean
111
+ | ArrayBuffer
112
+ | ReadonlyArrayValue
113
+ | ReadonlyRecordValue
114
+ | null;
115
+
116
+ type ReadonlyArrayValue = readonly ReadonlyValue[];
117
+
118
+ export type ReadonlyRecordValue = {
119
+ readonly [key: string]: ReadonlyValue | undefined;
120
+ };
121
+
122
+ type MutableValue<T> =
123
+ T extends ReadonlyArray<infer El>
124
+ ? MutableValue<El>[]
125
+ : T extends ReadonlyRecordValue
126
+ ? { -readonly [K in keyof T]: MutableValue<Exclude<T[K], undefined>> }
127
+ : T;
128
+
129
+ export type ValueToValidator<Vl> = [Vl] extends [never]
130
+ ? never
131
+ : IsAny<Vl> extends true
132
+ ? VAny
133
+ : [Vl] extends [null]
134
+ ? VNull
135
+ : [Vl] extends [boolean]
136
+ ? [boolean] extends [Vl]
137
+ ? VBoolean
138
+ : VLiteral<Vl>
139
+ : IsUnion<Vl> extends true
140
+ ? IsRecursive<Vl> extends true
141
+ ? VAny
142
+ : [Vl] extends [ReadonlyValue]
143
+ ? UnionValueToValidator<Vl>
144
+ : TypeError<"Provided value is not a valid Convex value", Vl>
145
+ : [Vl] extends [number]
146
+ ? [number] extends [Vl]
147
+ ? VFloat64
148
+ : VLiteral<Vl>
149
+ : [Vl] extends [bigint]
150
+ ? [bigint] extends [Vl]
151
+ ? VInt64
152
+ : VLiteral<Vl>
153
+ : [Vl] extends [string]
154
+ ? Vl extends {
155
+ __tableName: infer TableName extends string;
156
+ }
157
+ ? VId<GenericId.GenericId<TableName>>
158
+ : [string] extends [Vl]
159
+ ? VString
160
+ : VLiteral<Vl>
161
+ : [Vl] extends [ArrayBuffer]
162
+ ? VBytes
163
+ : IsRecursive<Vl> extends true
164
+ ? VAny
165
+ : [Vl] extends [ReadonlyValue]
166
+ ? Vl extends ReadonlyArray<ReadonlyValue>
167
+ ? ArrayValueToValidator<Vl>
168
+ : Vl extends ReadonlyRecordValue
169
+ ? RecordValueToValidator<Vl>
170
+ : TypeError<"Unexpected value", Vl>
171
+ : TypeError<
172
+ "Provided value is not a valid Convex value",
173
+ Vl
174
+ >;
175
+
176
+ type ArrayValueToValidator<Vl extends ReadonlyArray<ReadonlyValue>> =
177
+ Vl extends ReadonlyArray<infer El extends ReadonlyValue>
178
+ ? ValueToValidator<El> extends infer Vd extends Validator<any, any, any>
179
+ ? VArray<MutableValue<El[]>, Vd>
180
+ : never
181
+ : never;
182
+
183
+ type RecordValueToValidator<Vl> = Vl extends ReadonlyRecordValue
184
+ ? {
185
+ -readonly [K in keyof Vl]-?: IsAny<Vl[K]> extends true
186
+ ? IsOptional<Vl, K> extends true
187
+ ? VOptional<VAny>
188
+ : VAny
189
+ : UndefinedOrValueToValidator<Vl[K]>;
190
+ } extends infer VdRecord extends Record<string, any>
191
+ ? MutableValue<Vl> extends infer VlRecord extends Record<string, any>
192
+ ? IsRecord<VlRecord> extends true
193
+ ? VRecord<VlRecord, VString, VdRecord[keyof VdRecord]>
194
+ : VObject<VlRecord, VdRecord>
195
+ : never
196
+ : never
197
+ : never;
198
+
199
+ export type UndefinedOrValueToValidator<Vl extends ReadonlyValue | undefined> =
200
+ undefined extends Vl
201
+ ? [Vl] extends [(infer Val extends ReadonlyValue) | undefined]
202
+ ? ValueToValidator<Val> extends infer Vd extends Validator<
203
+ any,
204
+ "required",
205
+ any
206
+ >
207
+ ? VOptional<Vd>
208
+ : never
209
+ : never
210
+ : [Vl] extends [ReadonlyValue]
211
+ ? ValueToValidator<Vl>
212
+ : never;
213
+
214
+ type UnionValueToValidator<Vl extends ReadonlyValue> = [Vl] extends [
215
+ ReadonlyValue,
216
+ ]
217
+ ? IsUnion<Vl> extends true
218
+ ? UnionToTuple<Vl> extends infer VlTuple extends
219
+ ReadonlyArray<ReadonlyValue>
220
+ ? ValueTupleToValidatorTuple<VlTuple> extends infer VdTuple extends
221
+ Validator<any, "required", any>[]
222
+ ? VUnion<MutableValue<Vl>, VdTuple>
223
+ : TypeError<"Failed to convert value tuple to validator tuple">
224
+ : TypeError<"Failed to convert union to tuple">
225
+ : TypeError<"Expected a union of values, but got a single value instead">
226
+ : TypeError<"Provided value is not a valid Convex value">;
227
+
228
+ type ValueTupleToValidatorTuple<VlTuple extends ReadonlyArray<ReadonlyValue>> =
229
+ VlTuple extends
230
+ | [true, false, ...infer VlRest extends ReadonlyArray<ReadonlyValue>]
231
+ | [false, true, ...infer VlRest extends ReadonlyArray<ReadonlyValue>]
232
+ ? ValueTupleToValidatorTuple<VlRest> extends infer VdRest extends Validator<
233
+ any,
234
+ any,
235
+ any
236
+ >[]
237
+ ? [VBoolean<boolean>, ...VdRest]
238
+ : never
239
+ : VlTuple extends [
240
+ infer Vl extends ReadonlyValue,
241
+ ...infer VlRest extends ReadonlyArray<ReadonlyValue>,
242
+ ]
243
+ ? ValueToValidator<Vl> extends infer Vd extends Validator<any, any, any>
244
+ ? ValueTupleToValidatorTuple<VlRest> extends infer VdRest extends
245
+ Validator<any, "required", any>[]
246
+ ? [Vd, ...VdRest]
247
+ : never
248
+ : never
249
+ : [];
250
+
251
+ export const compileSchema = <T, E>(
252
+ schema: Schema.Codec<T, E>,
253
+ ): ValueToValidator<(typeof schema)["Encoded"]> =>
254
+ Effect.runSync(compileAst(schema.ast)) as any;
255
+
256
+ export const isRecursive = (ast: SchemaAST.AST): boolean =>
257
+ pipe(
258
+ ast,
259
+ Match.value,
260
+ Match.tag(
261
+ "Literal",
262
+ "Null",
263
+ "Boolean",
264
+ "String",
265
+ "Number",
266
+ "BigInt",
267
+ "Unknown",
268
+ "Any",
269
+ "Declaration",
270
+ "UniqueSymbol",
271
+ "Symbol",
272
+ "Undefined",
273
+ "Void",
274
+ "Never",
275
+ "Enum",
276
+ "TemplateLiteral",
277
+ "ObjectKeyword",
278
+ () => false,
279
+ ),
280
+ Match.tag("Union", ({ types }) =>
281
+ Array.some(types, (type) => isRecursive(type)),
282
+ ),
283
+ Match.tag("Objects", ({ propertySignatures }) =>
284
+ Array.some(propertySignatures, ({ type }) => isRecursive(type)),
285
+ ),
286
+ Match.tag(
287
+ "Arrays",
288
+ ({ elements, rest }) =>
289
+ Array.some(elements, (element) => isRecursive(element)) ||
290
+ Array.some(rest, (element) => isRecursive(element)),
291
+ ),
292
+ Match.tag("Suspend", () => true),
293
+ Match.exhaustive,
294
+ );
295
+
296
+ export const compileAst = (
297
+ ast: SchemaAST.AST,
298
+ isOptionalPropertyOfTypeLiteral = false,
299
+ ): Effect.Effect<
300
+ Validator<any, any, any>,
301
+ | UnsupportedSchemaTypeError
302
+ | UnsupportedPropertySignatureKeyTypeError
303
+ | IndexSignaturesAreNotSupportedError
304
+ | MixedIndexAndPropertySignaturesAreNotSupportedError
305
+ | OptionalTupleElementsAreNotSupportedError
306
+ | EmptyTupleIsNotSupportedError
307
+ | EmptyUnionIsNotSupportedError
308
+ > =>
309
+ isRecursive(ast)
310
+ ? Effect.succeed(v.any())
311
+ : pipe(
312
+ ast,
313
+ Match.value,
314
+ Match.tag("Literal", ({ literal }) =>
315
+ pipe(
316
+ literal,
317
+ Match.value,
318
+ Match.whenOr(
319
+ Match.string,
320
+ Match.number,
321
+ Match.bigint,
322
+ Match.boolean,
323
+ (l) => v.literal(l),
324
+ ),
325
+ Match.exhaustive,
326
+ Effect.succeed,
327
+ ),
328
+ ),
329
+ Match.tag("Null", () => Effect.succeed(v.null())),
330
+ Match.tag("Boolean", () => Effect.succeed(v.boolean())),
331
+ Match.tag("String", (stringAst) =>
332
+ GenericId.tableName(stringAst).pipe(
333
+ Option.match({
334
+ onNone: () => Effect.succeed(v.string()),
335
+ onSome: (tableName) => Effect.succeed(v.id(tableName)),
336
+ }),
337
+ ),
338
+ ),
339
+ Match.tag("Number", () => Effect.succeed(v.float64())),
340
+ Match.tag("BigInt", () => Effect.succeed(v.int64())),
341
+ Match.tag("Union", (unionAst) =>
342
+ handleUnion(unionAst, isOptionalPropertyOfTypeLiteral),
343
+ ),
344
+ Match.tag("Objects", (objectsAst) => handleObjects(objectsAst)),
345
+ Match.tag("Arrays", (arraysAst) => handleArrays(arraysAst)),
346
+ Match.tag("Unknown", "Any", () => Effect.succeed(v.any())),
347
+ Match.tag("Declaration", (declaration) =>
348
+ Effect.mapBoth(
349
+ // oxlint-disable-next-line effecttsgo/any-unknown-in-error-context -- Codec inputs are context-free, but Effect's SchemaAST.DeclarationRun erases their requirements to `any`.
350
+ declaration.run(declaration.typeParameters)(
351
+ new ArrayBuffer(0),
352
+ declaration,
353
+ {},
354
+ ) as Effect.Effect<ArrayBuffer, unknown, never>,
355
+ {
356
+ onSuccess: () => v.bytes(),
357
+ onFailure: () =>
358
+ new UnsupportedSchemaTypeError({
359
+ schemaType: declaration._tag,
360
+ }),
361
+ },
362
+ ),
363
+ ),
364
+ Match.tag("Suspend", () => Effect.succeed(v.any())),
365
+ Match.tag(
366
+ "UniqueSymbol",
367
+ "Symbol",
368
+ "Undefined",
369
+ "Void",
370
+ "Never",
371
+ "Enum",
372
+ "TemplateLiteral",
373
+ "ObjectKeyword",
374
+ () =>
375
+ Effect.fail(
376
+ new UnsupportedSchemaTypeError({
377
+ schemaType: ast._tag,
378
+ }),
379
+ ),
380
+ ),
381
+ Match.exhaustive,
382
+ );
383
+
384
+ const handleUnion = (
385
+ { types }: SchemaAST.Union,
386
+ isOptionalPropertyOfTypeLiteral: boolean,
387
+ ) => handleUnionTypes(types, isOptionalPropertyOfTypeLiteral);
388
+
389
+ const handleUnionTypes = Effect.fnUntraced(function* (
390
+ types: SchemaAST.Union["types"],
391
+ isOptionalPropertyOfTypeLiteral: boolean,
392
+ ) {
393
+ const members = isOptionalPropertyOfTypeLiteral
394
+ ? Array.filter(types, Predicate.not(SchemaAST.isUndefined))
395
+ : types;
396
+
397
+ const [firstValidator, secondValidator, ...restValidators] =
398
+ yield* Effect.all(Array.map(members, (type) => compileAst(type)));
399
+
400
+ if (firstValidator === undefined) {
401
+ return yield* new EmptyUnionIsNotSupportedError();
402
+ } else if (secondValidator === undefined) {
403
+ return firstValidator;
404
+ } else {
405
+ return v.union(firstValidator, secondValidator, ...restValidators);
406
+ }
407
+ });
408
+
409
+ const handleObjects = (objectsAst: SchemaAST.Objects) =>
410
+ pipe(
411
+ objectsAst.indexSignatures,
412
+ Array.head,
413
+ Option.match({
414
+ onNone: () => Effect.map(handlePropertySignatures(objectsAst), v.object),
415
+ onSome: ({ parameter, type }) =>
416
+ pipe(
417
+ objectsAst.propertySignatures,
418
+ Array.head,
419
+ Option.match({
420
+ onNone: () =>
421
+ Effect.map(
422
+ Effect.all({
423
+ parameter_: compileAst(parameter),
424
+ type_: compileAst(type),
425
+ }),
426
+ ({ parameter_, type_ }) => v.record(parameter_, type_),
427
+ ),
428
+ onSome: () =>
429
+ Effect.fail(
430
+ new MixedIndexAndPropertySignaturesAreNotSupportedError(),
431
+ ),
432
+ }),
433
+ ),
434
+ }),
435
+ );
436
+
437
+ const handleArrays = ({ elements, rest }: SchemaAST.Arrays) =>
438
+ handleArrayElements(elements, rest);
439
+
440
+ const handleArrayElements = Effect.fnUntraced(function* (
441
+ elements: SchemaAST.Arrays["elements"],
442
+ rest: SchemaAST.Arrays["rest"],
443
+ ) {
444
+ const [f, s, ...r] = elements;
445
+
446
+ const elementToValidator = (element: SchemaAST.AST) =>
447
+ SchemaAST.isOptional(element)
448
+ ? Effect.fail(new OptionalTupleElementsAreNotSupportedError())
449
+ : compileAst(element);
450
+
451
+ const arrayItemsValidator = yield* f === undefined
452
+ ? pipe(
453
+ rest,
454
+ Array.head,
455
+ Option.match({
456
+ onNone: () => Effect.fail(new EmptyTupleIsNotSupportedError()),
457
+ onSome: (type) => compileAst(type),
458
+ }),
459
+ )
460
+ : s === undefined
461
+ ? elementToValidator(f)
462
+ : Effect.gen(function* () {
463
+ const firstValidator = yield* elementToValidator(f);
464
+ const secondValidator = yield* elementToValidator(s);
465
+ const restValidators = yield* Effect.forEach(r, elementToValidator);
466
+
467
+ return v.union(firstValidator, secondValidator, ...restValidators);
468
+ });
469
+
470
+ return v.array(arrayItemsValidator);
471
+ });
472
+
473
+ const handlePropertySignatures = (objectsAst: SchemaAST.Objects) =>
474
+ pipe(
475
+ objectsAst.propertySignatures,
476
+ Effect.forEach(({ type, name }) => {
477
+ const isOptional = SchemaAST.isOptional(type);
478
+ if (String.isString(name)) {
479
+ // Somehow, somewhere, keys of type number are being coerced to strings…
480
+ return Option.match(Number.parse(name), {
481
+ onNone: () =>
482
+ Effect.gen(function* () {
483
+ const validator = yield* compileAst(type, isOptional);
484
+
485
+ return {
486
+ propertyName: name,
487
+ validator: isOptional ? v.optional(validator) : validator,
488
+ };
489
+ }),
490
+ onSome: (number) =>
491
+ Effect.fail(
492
+ new UnsupportedPropertySignatureKeyTypeError({
493
+ propertyKey: number,
494
+ }),
495
+ ),
496
+ });
497
+ } else {
498
+ return Effect.fail(
499
+ new UnsupportedPropertySignatureKeyTypeError({ propertyKey: name }),
500
+ );
501
+ }
502
+ }),
503
+ Effect.andThen((propertyNamesWithValidators) =>
504
+ pipe(
505
+ propertyNamesWithValidators,
506
+ Array.reduce(
507
+ {} as Record<string, Validator<any, any, any>>,
508
+ (acc, { propertyName, validator }) => ({
509
+ [propertyName]: validator,
510
+ ...acc,
511
+ }),
512
+ ),
513
+ Effect.succeed,
514
+ ),
515
+ ),
516
+ );
517
+
518
+ // Errors
519
+
520
+ export class TopLevelMustBeObjectError extends Data.TaggedError(
521
+ "TopLevelMustBeObjectError",
522
+ ) {
523
+ /* v8 ignore start */
524
+ override get message() {
525
+ return "Top level schema must be an object";
526
+ }
527
+ /* v8 ignore stop */
528
+ }
529
+
530
+ export class TopLevelMustBeObjectOrUnionError extends Data.TaggedError(
531
+ "TopLevelMustBeObjectOrUnionError",
532
+ ) {
533
+ /* v8 ignore start */
534
+ override get message() {
535
+ return "Top level schema must be an object or a union";
536
+ }
537
+ /* v8 ignore stop */
538
+ }
539
+
540
+ export class UnsupportedPropertySignatureKeyTypeError extends Data.TaggedError(
541
+ "UnsupportedPropertySignatureKeyTypeError",
542
+ )<{
543
+ readonly propertyKey: number | symbol;
544
+ }> {
545
+ /* v8 ignore start */
546
+ override get message() {
547
+ return `Unsupported property signature '${this.propertyKey.toString()}'. Property is of type '${typeof this.propertyKey}' but only 'string' properties are supported.`;
548
+ }
549
+ /* v8 ignore stop */
550
+ }
551
+
552
+ export class EmptyTupleIsNotSupportedError extends Data.TaggedError(
553
+ "EmptyTupleIsNotSupportedError",
554
+ ) {
555
+ /* v8 ignore start */
556
+ override get message() {
557
+ return "Tuple must have at least one element";
558
+ }
559
+ /* v8 ignore stop */
560
+ }
561
+
562
+ export class EmptyUnionIsNotSupportedError extends Data.TaggedError(
563
+ "EmptyUnionIsNotSupportedError",
564
+ ) {
565
+ /* v8 ignore start */
566
+ override get message() {
567
+ return "Union must have at least one member that compiles to a validator";
568
+ }
569
+ /* v8 ignore stop */
570
+ }
571
+
572
+ export class UnsupportedSchemaTypeError extends Data.TaggedError(
573
+ "UnsupportedSchemaTypeError",
574
+ )<{
575
+ readonly schemaType: SchemaAST.AST["_tag"];
576
+ }> {
577
+ /* v8 ignore start */
578
+ override get message() {
579
+ return `Unsupported schema type '${this.schemaType}'`;
580
+ }
581
+ /* v8 ignore stop */
582
+ }
583
+
584
+ export class IndexSignaturesAreNotSupportedError extends Data.TaggedError(
585
+ "IndexSignaturesAreNotSupportedError",
586
+ ) {
587
+ /* v8 ignore start */
588
+ override get message() {
589
+ return "Index signatures are not supported";
590
+ }
591
+ /* v8 ignore stop */
592
+ }
593
+
594
+ export class MixedIndexAndPropertySignaturesAreNotSupportedError extends Data.TaggedError(
595
+ "MixedIndexAndPropertySignaturesAreNotSupportedError",
596
+ ) {
597
+ /* v8 ignore start */
598
+ override get message() {
599
+ return "Mixed index and property signatures are not supported";
600
+ }
601
+ /* v8 ignore stop */
602
+ }
603
+
604
+ export class OptionalTupleElementsAreNotSupportedError extends Data.TaggedError(
605
+ "OptionalTupleElementsAreNotSupportedError",
606
+ ) {
607
+ /* v8 ignore start */
608
+ override get message() {
609
+ return "Optional tuple elements are not supported";
610
+ }
611
+ /* v8 ignore stop */
612
+ }