@naturalcycles/nodejs-lib 15.57.0 → 15.58.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.
@@ -374,6 +374,27 @@ export function createAjv(opt) {
374
374
  return true;
375
375
  },
376
376
  });
377
+ ajv.addKeyword({
378
+ keyword: 'keySchema',
379
+ type: 'object',
380
+ modifying: true,
381
+ errors: false,
382
+ schemaType: 'object',
383
+ compile(innerSchema, _parentSchema, _it) {
384
+ const isValidKeyFn = ajv.compile(innerSchema);
385
+ function validate(data, _ctx) {
386
+ if (typeof data !== 'object' || data === null)
387
+ return true;
388
+ for (const key of Object.keys(data)) {
389
+ if (!isValidKeyFn(key)) {
390
+ delete data[key];
391
+ }
392
+ }
393
+ return true;
394
+ }
395
+ return validate;
396
+ },
397
+ });
377
398
  return ajv;
378
399
  }
379
400
  const monthLengths = [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
@@ -9,7 +9,40 @@ export declare const j: {
9
9
  infer: typeof objectInfer;
10
10
  any(): JsonSchemaObjectBuilder<AnyObject, AnyObject, false>;
11
11
  stringMap<S extends JsonSchemaTerminal<any, any, any>>(schema: S): JsonSchemaObjectBuilder<StringMap<SchemaIn<S>>, StringMap<SchemaOut<S>>>;
12
+ /**
13
+ * @experimental Look around, maybe you find a rule that is better for your use-case.
14
+ *
15
+ * For Record<K, V> type of validations.
16
+ * ```ts
17
+ * const schema = j.object
18
+ * .record(
19
+ * j
20
+ * .string()
21
+ * .regex(/^\d{3,4}$/)
22
+ * .branded<B>(),
23
+ * j.number().nullable(),
24
+ * )
25
+ * .isOfType<Record<B, number | null>>()
26
+ * ```
27
+ *
28
+ * When the keys of the Record are values from an Enum, prefer `j.object.withEnumKeys`!
29
+ *
30
+ * Non-matching keys will be stripped from the object, i.e. they will not cause an error.
31
+ *
32
+ * Caveat: This rule first validates values of every properties of the object, and only then validates the keys.
33
+ * A consequence of that is that the validation will throw when there is an unexpected property with a value not matching the value schema.
34
+ */
35
+ record: typeof record;
36
+ /**
37
+ * For Record<ENUM, V> type of validations.
38
+ *
39
+ * When the keys of the Record are values from an Enum,
40
+ * this helper is more performant and behaves in a more conventional manner than `j.object.record` would.
41
+ *
42
+ *
43
+ */
12
44
  withEnumKeys: typeof withEnumKeys;
45
+ withRegexKeys: typeof withRegexKeys;
13
46
  };
14
47
  array<IN, OUT, Opt>(itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>): JsonSchemaArrayBuilder<IN, OUT, Opt>;
15
48
  set<IN, OUT, Opt>(itemSchema: JsonSchemaAnyBuilder<IN, OUT, Opt>): JsonSchemaSet2Builder<IN, OUT, Opt>;
@@ -49,6 +82,8 @@ export declare class JsonSchemaAnyBuilder<IN, OUT, Opt> extends JsonSchemaTermin
49
82
  *
50
83
  * const schemaBad = j.string().isOfType<number>() // ❌
51
84
  * schemaBad.build() // TypeError: property "build" does not exist on type "never"
85
+ *
86
+ * const result = ajvValidateRequest.body(req, schemaBad) // result will have `unknown` type
52
87
  * ```
53
88
  */
54
89
  isOfType<ExpectedType>(): ExactMatch<ExpectedType, OUT> extends true ? this : never;
@@ -203,6 +238,7 @@ export declare class JsonSchemaObjectBuilder<IN extends AnyObject, OUT extends A
203
238
  interface JsonSchemaObjectBuilderOpts {
204
239
  hasIsOfTypeCheck?: false;
205
240
  patternProperties?: StringMap<JsonSchema<any, any>>;
241
+ keySchema?: JsonSchema;
206
242
  }
207
243
  export declare class JsonSchemaObjectInferringBuilder<PROPS extends Record<string, JsonSchemaAnyBuilder<any, any, any>>, Opt extends boolean = false> extends JsonSchemaAnyBuilder<Expand<{
208
244
  [K in keyof PROPS as PROPS[K] extends JsonSchemaAnyBuilder<any, any, infer IsOpt> ? IsOpt extends true ? never : K : never]: PROPS[K] extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never;
@@ -314,6 +350,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
314
350
  };
315
351
  errorMessages?: StringMap<string>;
316
352
  optionalValues?: (string | number | boolean)[];
353
+ keySchema?: JsonSchema;
317
354
  }
318
355
  declare function object(props: AnyObject): never;
319
356
  declare function object<IN extends AnyObject>(props: {
@@ -336,6 +373,8 @@ declare function objectDbEntity<IN extends BaseDBEntity & AnyObject, EXTRA_KEYS
336
373
  } : {
337
374
  updated: BuilderFor<IN['updated']>;
338
375
  })): JsonSchemaObjectBuilder<IN, IN, false>;
376
+ declare function record<KS extends JsonSchemaAnyBuilder<any, any, any>, VS extends JsonSchemaAnyBuilder<any, any, any>, Opt extends boolean = SchemaOpt<VS>>(keySchema: KS, valueSchema: VS): JsonSchemaObjectBuilder<Opt extends true ? Partial<Record<SchemaIn<KS>, SchemaIn<VS>>> : Record<SchemaIn<KS>, SchemaIn<VS>>, Opt extends true ? Partial<Record<SchemaOut<KS>, SchemaOut<VS>>> : Record<SchemaOut<KS>, SchemaOut<VS>>, false>;
377
+ declare function withRegexKeys<S extends JsonSchemaAnyBuilder<any, any, any>, Opt extends boolean = SchemaOpt<S>>(keyRegex: RegExp | string, schema: S): JsonSchemaObjectBuilder<Opt extends true ? StringMap<SchemaIn<S>> : StringMap<SchemaIn<S>>, Opt extends true ? StringMap<SchemaOut<S>> : StringMap<SchemaOut<S>>, false>;
339
378
  /**
340
379
  * Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
341
380
  */
@@ -376,5 +415,5 @@ interface JsonBuilderRuleOpt {
376
415
  type EnumKeyUnion<T> = T extends readonly (infer U)[] ? U : T extends StringEnum | NumberEnum ? T[keyof T] : never;
377
416
  type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never;
378
417
  type SchemaOut<S> = S extends JsonSchemaAnyBuilder<any, infer OUT, any> ? OUT : never;
379
- type SchemaOpt<S> = S extends JsonSchemaAnyBuilder<any, any, infer Opt> ? Opt : false;
418
+ type SchemaOpt<S> = S extends JsonSchemaAnyBuilder<any, any, infer Opt> ? (Opt extends true ? true : false) : false;
380
419
  export {};
@@ -26,8 +26,6 @@ export const j = {
26
26
  },
27
27
  stringMap(schema) {
28
28
  const builtSchema = schema.build();
29
- _assert(!builtSchema?.optionalField, 'In a StringMap schema the value cannot be `undefined`, because `undefined` is not a valid JSON Schema value.');
30
- builtSchema.optionalField = undefined;
31
29
  return new JsonSchemaObjectBuilder({}, {
32
30
  hasIsOfTypeCheck: false,
33
31
  patternProperties: {
@@ -35,7 +33,40 @@ export const j = {
35
33
  },
36
34
  });
37
35
  },
36
+ /**
37
+ * @experimental Look around, maybe you find a rule that is better for your use-case.
38
+ *
39
+ * For Record<K, V> type of validations.
40
+ * ```ts
41
+ * const schema = j.object
42
+ * .record(
43
+ * j
44
+ * .string()
45
+ * .regex(/^\d{3,4}$/)
46
+ * .branded<B>(),
47
+ * j.number().nullable(),
48
+ * )
49
+ * .isOfType<Record<B, number | null>>()
50
+ * ```
51
+ *
52
+ * When the keys of the Record are values from an Enum, prefer `j.object.withEnumKeys`!
53
+ *
54
+ * Non-matching keys will be stripped from the object, i.e. they will not cause an error.
55
+ *
56
+ * Caveat: This rule first validates values of every properties of the object, and only then validates the keys.
57
+ * A consequence of that is that the validation will throw when there is an unexpected property with a value not matching the value schema.
58
+ */
59
+ record,
60
+ /**
61
+ * For Record<ENUM, V> type of validations.
62
+ *
63
+ * When the keys of the Record are values from an Enum,
64
+ * this helper is more performant and behaves in a more conventional manner than `j.object.record` would.
65
+ *
66
+ *
67
+ */
38
68
  withEnumKeys,
69
+ withRegexKeys,
39
70
  }),
40
71
  array(itemSchema) {
41
72
  return new JsonSchemaArrayBuilder(itemSchema);
@@ -111,7 +142,9 @@ export class JsonSchemaTerminal {
111
142
  * Same as if it would be JSON.stringified.
112
143
  */
113
144
  build() {
114
- return _sortObject(JSON.parse(JSON.stringify(this.schema)), JSON_SCHEMA_ORDER);
145
+ const jsonSchema = _sortObject(JSON.parse(JSON.stringify(this.schema)), JSON_SCHEMA_ORDER);
146
+ delete jsonSchema.optionalField;
147
+ return jsonSchema;
115
148
  }
116
149
  clone() {
117
150
  return new JsonSchemaAnyBuilder(_deepCopy(this.schema));
@@ -140,6 +173,8 @@ export class JsonSchemaAnyBuilder extends JsonSchemaTerminal {
140
173
  *
141
174
  * const schemaBad = j.string().isOfType<number>() // ❌
142
175
  * schemaBad.build() // TypeError: property "build" does not exist on type "never"
176
+ *
177
+ * const result = ajvValidateRequest.body(req, schemaBad) // result will have `unknown` type
143
178
  * ```
144
179
  */
145
180
  isOfType() {
@@ -525,6 +560,7 @@ export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
525
560
  additionalProperties: false,
526
561
  hasIsOfTypeCheck: opt?.hasIsOfTypeCheck ?? true,
527
562
  patternProperties: opt?.patternProperties ?? undefined,
563
+ keySchema: opt?.keySchema ?? undefined,
528
564
  });
529
565
  if (props)
530
566
  this.addProperties(props);
@@ -533,13 +569,11 @@ export class JsonSchemaObjectBuilder extends JsonSchemaAnyBuilder {
533
569
  const properties = {};
534
570
  const required = [];
535
571
  for (const [key, builder] of Object.entries(props)) {
536
- const schema = builder.build();
537
- if (!schema.optionalField) {
572
+ const isOptional = builder.getSchema().optionalField;
573
+ if (!isOptional) {
538
574
  required.push(key);
539
575
  }
540
- else {
541
- schema.optionalField = undefined;
542
- }
576
+ const schema = builder.build();
543
577
  properties[key] = schema;
544
578
  }
545
579
  this.schema.properties = properties;
@@ -595,13 +629,11 @@ export class JsonSchemaObjectInferringBuilder extends JsonSchemaAnyBuilder {
595
629
  const properties = {};
596
630
  const required = [];
597
631
  for (const [key, builder] of Object.entries(props)) {
598
- const schema = builder.build();
599
- if (!schema.optionalField) {
632
+ const isOptional = builder.getSchema().optionalField;
633
+ if (!isOptional) {
600
634
  required.push(key);
601
635
  }
602
- else {
603
- schema.optionalField = undefined;
604
- }
636
+ const schema = builder.build();
605
637
  properties[key] = schema;
606
638
  }
607
639
  this.schema.properties = properties;
@@ -717,6 +749,27 @@ function objectDbEntity(props) {
717
749
  ...props,
718
750
  });
719
751
  }
752
+ function record(keySchema, valueSchema) {
753
+ const keyJsonSchema = keySchema.build();
754
+ const valueJsonSchema = valueSchema.build();
755
+ return new JsonSchemaObjectBuilder([], {
756
+ hasIsOfTypeCheck: false,
757
+ keySchema: keyJsonSchema,
758
+ patternProperties: {
759
+ ['^.*$']: valueJsonSchema,
760
+ },
761
+ });
762
+ }
763
+ function withRegexKeys(keyRegex, schema) {
764
+ const pattern = keyRegex instanceof RegExp ? keyRegex.source : keyRegex;
765
+ const jsonSchema = schema.build();
766
+ return new JsonSchemaObjectBuilder([], {
767
+ hasIsOfTypeCheck: false,
768
+ patternProperties: {
769
+ [pattern]: jsonSchema,
770
+ },
771
+ });
772
+ }
720
773
  /**
721
774
  * Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
722
775
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/nodejs-lib",
3
3
  "type": "module",
4
- "version": "15.57.0",
4
+ "version": "15.58.0",
5
5
  "dependencies": {
6
6
  "@naturalcycles/js-lib": "^15",
7
7
  "@types/js-yaml": "^4",
@@ -1,6 +1,7 @@
1
1
  import { _lazyValue } from '@naturalcycles/js-lib'
2
2
  import { Set2 } from '@naturalcycles/js-lib/object'
3
3
  import { _substringAfterLast } from '@naturalcycles/js-lib/string'
4
+ import type { AnyObject } from '@naturalcycles/js-lib/types'
4
5
  import { Ajv, type Options, type ValidateFunction } from 'ajv'
5
6
  import { validTLDs } from '../tlds.js'
6
7
  import type { JsonSchemaIsoDateOptions, JsonSchemaStringEmailOptions } from './jsonSchemaBuilder.js'
@@ -429,6 +430,31 @@ export function createAjv(opt?: Options): Ajv {
429
430
  },
430
431
  })
431
432
 
433
+ ajv.addKeyword({
434
+ keyword: 'keySchema',
435
+ type: 'object',
436
+ modifying: true,
437
+ errors: false,
438
+ schemaType: 'object',
439
+ compile(innerSchema, _parentSchema, _it) {
440
+ const isValidKeyFn: ValidateFunction = ajv.compile(innerSchema)
441
+
442
+ function validate(data: AnyObject, _ctx: any): boolean {
443
+ if (typeof data !== 'object' || data === null) return true
444
+
445
+ for (const key of Object.keys(data)) {
446
+ if (!isValidKeyFn(key)) {
447
+ delete data[key]
448
+ }
449
+ }
450
+
451
+ return true
452
+ }
453
+
454
+ return validate
455
+ },
456
+ })
457
+
432
458
  return ajv
433
459
  }
434
460
 
@@ -70,11 +70,6 @@ export const j = {
70
70
  schema: S,
71
71
  ): JsonSchemaObjectBuilder<StringMap<SchemaIn<S>>, StringMap<SchemaOut<S>>> {
72
72
  const builtSchema = schema.build()
73
- _assert(
74
- !builtSchema?.optionalField,
75
- 'In a StringMap schema the value cannot be `undefined`, because `undefined` is not a valid JSON Schema value.',
76
- )
77
- builtSchema.optionalField = undefined
78
73
 
79
74
  return new JsonSchemaObjectBuilder<StringMap<SchemaIn<S>>, StringMap<SchemaOut<S>>>(
80
75
  {},
@@ -87,7 +82,41 @@ export const j = {
87
82
  )
88
83
  },
89
84
 
85
+ /**
86
+ * @experimental Look around, maybe you find a rule that is better for your use-case.
87
+ *
88
+ * For Record<K, V> type of validations.
89
+ * ```ts
90
+ * const schema = j.object
91
+ * .record(
92
+ * j
93
+ * .string()
94
+ * .regex(/^\d{3,4}$/)
95
+ * .branded<B>(),
96
+ * j.number().nullable(),
97
+ * )
98
+ * .isOfType<Record<B, number | null>>()
99
+ * ```
100
+ *
101
+ * When the keys of the Record are values from an Enum, prefer `j.object.withEnumKeys`!
102
+ *
103
+ * Non-matching keys will be stripped from the object, i.e. they will not cause an error.
104
+ *
105
+ * Caveat: This rule first validates values of every properties of the object, and only then validates the keys.
106
+ * A consequence of that is that the validation will throw when there is an unexpected property with a value not matching the value schema.
107
+ */
108
+ record,
109
+
110
+ /**
111
+ * For Record<ENUM, V> type of validations.
112
+ *
113
+ * When the keys of the Record are values from an Enum,
114
+ * this helper is more performant and behaves in a more conventional manner than `j.object.record` would.
115
+ *
116
+ *
117
+ */
90
118
  withEnumKeys,
119
+ withRegexKeys,
91
120
  }),
92
121
 
93
122
  array<IN, OUT, Opt>(
@@ -193,7 +222,14 @@ export class JsonSchemaTerminal<IN, OUT, Opt> {
193
222
  * Same as if it would be JSON.stringified.
194
223
  */
195
224
  build(): JsonSchema<IN, OUT> {
196
- return _sortObject(JSON.parse(JSON.stringify(this.schema)), JSON_SCHEMA_ORDER)
225
+ const jsonSchema = _sortObject(
226
+ JSON.parse(JSON.stringify(this.schema)),
227
+ JSON_SCHEMA_ORDER,
228
+ ) as JsonSchema<IN, OUT>
229
+
230
+ delete jsonSchema.optionalField
231
+
232
+ return jsonSchema
197
233
  }
198
234
 
199
235
  clone(): JsonSchemaAnyBuilder<IN, OUT, Opt> {
@@ -226,6 +262,8 @@ export class JsonSchemaAnyBuilder<IN, OUT, Opt> extends JsonSchemaTerminal<IN, O
226
262
  *
227
263
  * const schemaBad = j.string().isOfType<number>() // ❌
228
264
  * schemaBad.build() // TypeError: property "build" does not exist on type "never"
265
+ *
266
+ * const result = ajvValidateRequest.body(req, schemaBad) // result will have `unknown` type
229
267
  * ```
230
268
  */
231
269
  isOfType<ExpectedType>(): ExactMatch<ExpectedType, OUT> extends true ? this : never {
@@ -745,6 +783,7 @@ export class JsonSchemaObjectBuilder<
745
783
  additionalProperties: false,
746
784
  hasIsOfTypeCheck: opt?.hasIsOfTypeCheck ?? true,
747
785
  patternProperties: opt?.patternProperties ?? undefined,
786
+ keySchema: opt?.keySchema ?? undefined,
748
787
  })
749
788
 
750
789
  if (props) this.addProperties(props)
@@ -755,12 +794,12 @@ export class JsonSchemaObjectBuilder<
755
794
  const required: string[] = []
756
795
 
757
796
  for (const [key, builder] of Object.entries(props)) {
758
- const schema = builder.build()
759
- if (!schema.optionalField) {
797
+ const isOptional = (builder as JsonSchemaTerminal<any, any, any>).getSchema().optionalField
798
+ if (!isOptional) {
760
799
  required.push(key)
761
- } else {
762
- schema.optionalField = undefined
763
800
  }
801
+
802
+ const schema = builder.build()
764
803
  properties[key] = schema
765
804
  }
766
805
 
@@ -816,6 +855,7 @@ export class JsonSchemaObjectBuilder<
816
855
  interface JsonSchemaObjectBuilderOpts {
817
856
  hasIsOfTypeCheck?: false
818
857
  patternProperties?: StringMap<JsonSchema<any, any>>
858
+ keySchema?: JsonSchema
819
859
  }
820
860
 
821
861
  export class JsonSchemaObjectInferringBuilder<
@@ -870,12 +910,12 @@ export class JsonSchemaObjectInferringBuilder<
870
910
  const required: string[] = []
871
911
 
872
912
  for (const [key, builder] of Object.entries(props)) {
873
- const schema = builder.build()
874
- if (!schema.optionalField) {
913
+ const isOptional = (builder as JsonSchemaTerminal<any, any, any>).getSchema().optionalField
914
+ if (!isOptional) {
875
915
  required.push(key)
876
- } else {
877
- schema.optionalField = undefined
878
916
  }
917
+
918
+ const schema = builder.build()
879
919
  properties[key] = schema
880
920
  }
881
921
 
@@ -1103,6 +1143,7 @@ export interface JsonSchema<IN = unknown, OUT = IN> {
1103
1143
  transform?: { trim?: true; toLowerCase?: true; toUpperCase?: true; truncate?: number }
1104
1144
  errorMessages?: StringMap<string>
1105
1145
  optionalValues?: (string | number | boolean)[]
1146
+ keySchema?: JsonSchema
1106
1147
  }
1107
1148
 
1108
1149
  function object(props: AnyObject): never
@@ -1152,6 +1193,68 @@ function objectDbEntity(props: AnyObject): any {
1152
1193
  })
1153
1194
  }
1154
1195
 
1196
+ function record<
1197
+ KS extends JsonSchemaAnyBuilder<any, any, any>,
1198
+ VS extends JsonSchemaAnyBuilder<any, any, any>,
1199
+ Opt extends boolean = SchemaOpt<VS>,
1200
+ >(
1201
+ keySchema: KS,
1202
+ valueSchema: VS,
1203
+ ): JsonSchemaObjectBuilder<
1204
+ Opt extends true
1205
+ ? Partial<Record<SchemaIn<KS>, SchemaIn<VS>>>
1206
+ : Record<SchemaIn<KS>, SchemaIn<VS>>,
1207
+ Opt extends true
1208
+ ? Partial<Record<SchemaOut<KS>, SchemaOut<VS>>>
1209
+ : Record<SchemaOut<KS>, SchemaOut<VS>>,
1210
+ false
1211
+ > {
1212
+ const keyJsonSchema = keySchema.build()
1213
+ const valueJsonSchema = valueSchema.build()
1214
+
1215
+ return new JsonSchemaObjectBuilder<
1216
+ Opt extends true
1217
+ ? Partial<Record<SchemaIn<KS>, SchemaIn<VS>>>
1218
+ : Record<SchemaIn<KS>, SchemaIn<VS>>,
1219
+ Opt extends true
1220
+ ? Partial<Record<SchemaOut<KS>, SchemaOut<VS>>>
1221
+ : Record<SchemaOut<KS>, SchemaOut<VS>>,
1222
+ false
1223
+ >([], {
1224
+ hasIsOfTypeCheck: false,
1225
+ keySchema: keyJsonSchema,
1226
+ patternProperties: {
1227
+ ['^.*$']: valueJsonSchema,
1228
+ },
1229
+ })
1230
+ }
1231
+
1232
+ function withRegexKeys<
1233
+ S extends JsonSchemaAnyBuilder<any, any, any>,
1234
+ Opt extends boolean = SchemaOpt<S>,
1235
+ >(
1236
+ keyRegex: RegExp | string,
1237
+ schema: S,
1238
+ ): JsonSchemaObjectBuilder<
1239
+ Opt extends true ? StringMap<SchemaIn<S>> : StringMap<SchemaIn<S>>,
1240
+ Opt extends true ? StringMap<SchemaOut<S>> : StringMap<SchemaOut<S>>,
1241
+ false
1242
+ > {
1243
+ const pattern = keyRegex instanceof RegExp ? keyRegex.source : keyRegex
1244
+ const jsonSchema = schema.build()
1245
+
1246
+ return new JsonSchemaObjectBuilder<
1247
+ Opt extends true ? StringMap<SchemaIn<S>> : StringMap<SchemaIn<S>>,
1248
+ Opt extends true ? StringMap<SchemaOut<S>> : StringMap<SchemaOut<S>>,
1249
+ false
1250
+ >([], {
1251
+ hasIsOfTypeCheck: false,
1252
+ patternProperties: {
1253
+ [pattern]: jsonSchema,
1254
+ },
1255
+ })
1256
+ }
1257
+
1155
1258
  /**
1156
1259
  * Builds the object schema with the indicated `keys` and uses the `schema` for their validation.
1157
1260
  */
@@ -1241,4 +1344,5 @@ type EnumKeyUnion<T> =
1241
1344
 
1242
1345
  type SchemaIn<S> = S extends JsonSchemaAnyBuilder<infer IN, any, any> ? IN : never
1243
1346
  type SchemaOut<S> = S extends JsonSchemaAnyBuilder<any, infer OUT, any> ? OUT : never
1244
- type SchemaOpt<S> = S extends JsonSchemaAnyBuilder<any, any, infer Opt> ? Opt : false
1347
+ type SchemaOpt<S> =
1348
+ S extends JsonSchemaAnyBuilder<any, any, infer Opt> ? (Opt extends true ? true : false) : false