@atproto/lex-schema 0.0.10 → 0.0.12
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 +26 -0
- package/dist/core/$type.d.ts +149 -0
- package/dist/core/$type.d.ts.map +1 -1
- package/dist/core/$type.js +44 -0
- package/dist/core/$type.js.map +1 -1
- package/dist/core/record-key.d.ts +44 -0
- package/dist/core/record-key.d.ts.map +1 -1
- package/dist/core/record-key.js +30 -0
- package/dist/core/record-key.js.map +1 -1
- package/dist/core/result.d.ts +85 -4
- package/dist/core/result.d.ts.map +1 -1
- package/dist/core/result.js +60 -4
- package/dist/core/result.js.map +1 -1
- package/dist/core/schema.d.ts +229 -2
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +197 -4
- package/dist/core/schema.js.map +1 -1
- package/dist/core/string-format.d.ts +244 -11
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js +150 -0
- package/dist/core/string-format.js.map +1 -1
- package/dist/core/types.d.ts +90 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/validation-error.d.ts +61 -1
- package/dist/core/validation-error.d.ts.map +1 -1
- package/dist/core/validation-error.js +60 -0
- package/dist/core/validation-error.js.map +1 -1
- package/dist/core/validation-issue.d.ts +61 -0
- package/dist/core/validation-issue.d.ts.map +1 -1
- package/dist/core/validation-issue.js +51 -0
- package/dist/core/validation-issue.js.map +1 -1
- package/dist/core/validator.d.ts +347 -10
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +184 -3
- package/dist/core/validator.js.map +1 -1
- package/dist/helpers.d.ts +13 -25
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +2 -2
- package/dist/helpers.js.map +1 -1
- package/dist/schema/array.d.ts +45 -0
- package/dist/schema/array.d.ts.map +1 -1
- package/dist/schema/array.js +14 -0
- package/dist/schema/array.js.map +1 -1
- package/dist/schema/blob.d.ts +46 -0
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +39 -0
- package/dist/schema/blob.js.map +1 -1
- package/dist/schema/boolean.d.ts +28 -0
- package/dist/schema/boolean.d.ts.map +1 -1
- package/dist/schema/boolean.js +28 -0
- package/dist/schema/boolean.js.map +1 -1
- package/dist/schema/bytes.d.ts +38 -0
- package/dist/schema/bytes.d.ts.map +1 -1
- package/dist/schema/bytes.js +32 -0
- package/dist/schema/bytes.js.map +1 -1
- package/dist/schema/cid.d.ts +38 -0
- package/dist/schema/cid.d.ts.map +1 -1
- package/dist/schema/cid.js +33 -0
- package/dist/schema/cid.js.map +1 -1
- package/dist/schema/custom.d.ts +66 -1
- package/dist/schema/custom.d.ts.map +1 -1
- package/dist/schema/custom.js +54 -0
- package/dist/schema/custom.js.map +1 -1
- package/dist/schema/dict.d.ts +44 -0
- package/dist/schema/dict.d.ts.map +1 -1
- package/dist/schema/dict.js +44 -0
- package/dist/schema/dict.js.map +1 -1
- package/dist/schema/discriminated-union.d.ts +58 -0
- package/dist/schema/discriminated-union.d.ts.map +1 -1
- package/dist/schema/discriminated-union.js +45 -0
- package/dist/schema/discriminated-union.js.map +1 -1
- package/dist/schema/enum.d.ts +48 -0
- package/dist/schema/enum.d.ts.map +1 -1
- package/dist/schema/enum.js +48 -0
- package/dist/schema/enum.js.map +1 -1
- package/dist/schema/integer.d.ts +42 -0
- package/dist/schema/integer.d.ts.map +1 -1
- package/dist/schema/integer.js +36 -0
- package/dist/schema/integer.js.map +1 -1
- package/dist/schema/intersection.d.ts +54 -0
- package/dist/schema/intersection.d.ts.map +1 -1
- package/dist/schema/intersection.js +49 -0
- package/dist/schema/intersection.js.map +1 -1
- package/dist/schema/literal.d.ts +44 -0
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +44 -0
- package/dist/schema/literal.js.map +1 -1
- package/dist/schema/never.d.ts +42 -0
- package/dist/schema/never.d.ts.map +1 -1
- package/dist/schema/never.js +42 -0
- package/dist/schema/never.js.map +1 -1
- package/dist/schema/null.d.ts +29 -0
- package/dist/schema/null.d.ts.map +1 -1
- package/dist/schema/null.js +29 -0
- package/dist/schema/null.js.map +1 -1
- package/dist/schema/nullable.d.ts +41 -0
- package/dist/schema/nullable.d.ts.map +1 -1
- package/dist/schema/nullable.js +41 -0
- package/dist/schema/nullable.js.map +1 -1
- package/dist/schema/object.d.ts +56 -0
- package/dist/schema/object.d.ts.map +1 -1
- package/dist/schema/object.js +51 -0
- package/dist/schema/object.js.map +1 -1
- package/dist/schema/optional.d.ts +42 -0
- package/dist/schema/optional.d.ts.map +1 -1
- package/dist/schema/optional.js +42 -0
- package/dist/schema/optional.js.map +1 -1
- package/dist/schema/params.d.ts +89 -7
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +84 -10
- package/dist/schema/params.js.map +1 -1
- package/dist/schema/payload.d.ts +111 -15
- package/dist/schema/payload.d.ts.map +1 -1
- package/dist/schema/payload.js +70 -0
- package/dist/schema/payload.js.map +1 -1
- package/dist/schema/permission-set.d.ts +58 -0
- package/dist/schema/permission-set.d.ts.map +1 -1
- package/dist/schema/permission-set.js +50 -0
- package/dist/schema/permission-set.js.map +1 -1
- package/dist/schema/permission.d.ts +42 -0
- package/dist/schema/permission.d.ts.map +1 -1
- package/dist/schema/permission.js +39 -0
- package/dist/schema/permission.js.map +1 -1
- package/dist/schema/procedure.d.ts +64 -0
- package/dist/schema/procedure.d.ts.map +1 -1
- package/dist/schema/procedure.js +64 -0
- package/dist/schema/procedure.js.map +1 -1
- package/dist/schema/query.d.ts +55 -0
- package/dist/schema/query.d.ts.map +1 -1
- package/dist/schema/query.js +55 -0
- package/dist/schema/query.js.map +1 -1
- package/dist/schema/record.d.ts +63 -8
- package/dist/schema/record.d.ts.map +1 -1
- package/dist/schema/record.js +20 -0
- package/dist/schema/record.js.map +1 -1
- package/dist/schema/ref.d.ts +50 -0
- package/dist/schema/ref.d.ts.map +1 -1
- package/dist/schema/ref.js +17 -0
- package/dist/schema/ref.js.map +1 -1
- package/dist/schema/refine.d.ts +58 -9
- package/dist/schema/refine.d.ts.map +1 -1
- package/dist/schema/refine.js.map +1 -1
- package/dist/schema/regexp.d.ts +44 -0
- package/dist/schema/regexp.d.ts.map +1 -1
- package/dist/schema/regexp.js +44 -0
- package/dist/schema/regexp.js.map +1 -1
- package/dist/schema/string.d.ts +50 -0
- package/dist/schema/string.d.ts.map +1 -1
- package/dist/schema/string.js +41 -0
- package/dist/schema/string.js.map +1 -1
- package/dist/schema/subscription.d.ts +72 -2
- package/dist/schema/subscription.d.ts.map +1 -1
- package/dist/schema/subscription.js +59 -0
- package/dist/schema/subscription.js.map +1 -1
- package/dist/schema/token.d.ts +47 -0
- package/dist/schema/token.d.ts.map +1 -1
- package/dist/schema/token.js +47 -0
- package/dist/schema/token.js.map +1 -1
- package/dist/schema/typed-object.d.ts +62 -8
- package/dist/schema/typed-object.d.ts.map +1 -1
- package/dist/schema/typed-object.js +18 -0
- package/dist/schema/typed-object.js.map +1 -1
- package/dist/schema/typed-ref.d.ts +53 -0
- package/dist/schema/typed-ref.d.ts.map +1 -1
- package/dist/schema/typed-ref.js +15 -0
- package/dist/schema/typed-ref.js.map +1 -1
- package/dist/schema/typed-union.d.ts +50 -1
- package/dist/schema/typed-union.d.ts.map +1 -1
- package/dist/schema/typed-union.js +50 -1
- package/dist/schema/typed-union.js.map +1 -1
- package/dist/schema/union.d.ts +45 -0
- package/dist/schema/union.d.ts.map +1 -1
- package/dist/schema/union.js +40 -0
- package/dist/schema/union.js.map +1 -1
- package/dist/schema/unknown-object.d.ts +34 -0
- package/dist/schema/unknown-object.d.ts.map +1 -1
- package/dist/schema/unknown-object.js +31 -0
- package/dist/schema/unknown-object.js.map +1 -1
- package/dist/schema/unknown.d.ts +33 -0
- package/dist/schema/unknown.d.ts.map +1 -1
- package/dist/schema/unknown.js +33 -0
- package/dist/schema/unknown.js.map +1 -1
- package/dist/schema/with-default.d.ts +44 -0
- package/dist/schema/with-default.d.ts.map +1 -1
- package/dist/schema/with-default.js +44 -0
- package/dist/schema/with-default.js.map +1 -1
- package/package.json +4 -4
- package/src/core/$type.ts +150 -18
- package/src/core/record-key.ts +44 -0
- package/src/core/result.ts +86 -4
- package/src/core/schema.ts +236 -7
- package/src/core/string-format.ts +259 -13
- package/src/core/types.ts +91 -3
- package/src/core/validation-error.ts +60 -0
- package/src/core/validation-issue.ts +65 -0
- package/src/core/validator.ts +351 -10
- package/src/helpers.test.ts +110 -29
- package/src/helpers.ts +14 -14
- package/src/schema/array.test.ts +94 -79
- package/src/schema/array.ts +45 -0
- package/src/schema/blob.ts +46 -0
- package/src/schema/boolean.ts +28 -0
- package/src/schema/bytes.ts +38 -0
- package/src/schema/cid.ts +38 -0
- package/src/schema/custom.ts +66 -1
- package/src/schema/dict.ts +44 -0
- package/src/schema/discriminated-union.ts +58 -0
- package/src/schema/enum.ts +48 -0
- package/src/schema/integer.ts +42 -0
- package/src/schema/intersection.ts +54 -0
- package/src/schema/literal.ts +44 -0
- package/src/schema/never.ts +42 -0
- package/src/schema/null.ts +29 -0
- package/src/schema/nullable.ts +41 -0
- package/src/schema/object.ts +56 -0
- package/src/schema/optional.ts +42 -0
- package/src/schema/params.test.ts +58 -2
- package/src/schema/params.ts +124 -16
- package/src/schema/payload.test.ts +3 -3
- package/src/schema/payload.ts +142 -38
- package/src/schema/permission-set.ts +58 -0
- package/src/schema/permission.ts +42 -0
- package/src/schema/procedure.ts +64 -0
- package/src/schema/query.ts +55 -0
- package/src/schema/record.ts +63 -8
- package/src/schema/ref.ts +50 -0
- package/src/schema/refine.ts +58 -9
- package/src/schema/regexp.ts +44 -0
- package/src/schema/string.ts +50 -0
- package/src/schema/subscription.ts +72 -2
- package/src/schema/token.ts +47 -0
- package/src/schema/typed-object.ts +62 -8
- package/src/schema/typed-ref.ts +53 -0
- package/src/schema/typed-union.ts +55 -2
- package/src/schema/union.ts +45 -0
- package/src/schema/unknown-object.ts +34 -0
- package/src/schema/unknown.ts +33 -0
- package/src/schema/with-default.ts +44 -0
|
@@ -9,10 +9,15 @@ import { DictSchema } from './dict.js'
|
|
|
9
9
|
import { ObjectSchema } from './object.js'
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
+
* Type utility for computing the intersection of two object types.
|
|
13
|
+
*
|
|
12
14
|
* Allows to more accurately represent the intersection of two object types
|
|
13
15
|
* where both types may share some keys, and one of them uses an index
|
|
14
16
|
* signature.
|
|
15
17
|
*
|
|
18
|
+
* @template A - First object type (typically from ObjectSchema)
|
|
19
|
+
* @template B - Second object type (typically from DictSchema)
|
|
20
|
+
*
|
|
16
21
|
* @see {@link https://www.typescriptlang.org/play/?#code/C4TwDgpgBAglC8UDeUBmB7dAuKByARgIYBOuUAvlAGTJQDaA+lAJYB2UAzsMWwOYC6OVgFcAtvgjEKAKGkATCAGMANiWiL0rLlEI4YsjVuBQA1hBA4uPVrwRQARBnT2Dm7QDdCy4dESE6ZiD8UAD0IVAi4pJQABQcABbowspyUBIORMT2AJSyEAAeYOjExqCQUACSrMCSHErAzJoAPNJQsFAFNaxyHFAASkrFck1WfAA0UMKsJqzoAO6sAHxjrVAAQh35XT39g8TDozYTUzPzSyuLdqtwVKttMYHoqO00j88bnRDdvawQ7pJ3NpQAD860BbRwSHBQLadAA0ix2G91oJ1vDggAfWABcxPF5QOH8aFtci5aRlaAwVDMfIQVKIKo1Yh1RQNZq0Jw4AgkMjkCYoRiIzjcPioyISKTkRayBQqNRQQzaQgAMRpdL01NpclcRignm8EFVWrsKrVchxQVC4XF0SxmSAA Playground link}
|
|
17
22
|
*/
|
|
18
23
|
export type Intersect<A, B> = B[keyof B] extends never
|
|
@@ -24,6 +29,26 @@ export type Intersect<A, B> = B[keyof B] extends never
|
|
|
24
29
|
// index signature could return a value from either A or B
|
|
25
30
|
A & { [K in keyof B]: B[K] | A[keyof A & K] }
|
|
26
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Schema for combining an object schema with a dictionary schema.
|
|
34
|
+
*
|
|
35
|
+
* Validates that the input matches both the fixed object shape and allows
|
|
36
|
+
* additional properties that match the dictionary schema. Properties defined
|
|
37
|
+
* in the object schema are validated by the object, and remaining properties
|
|
38
|
+
* are validated by the dictionary.
|
|
39
|
+
*
|
|
40
|
+
* @template Left - The ObjectSchema type for fixed properties
|
|
41
|
+
* @template Right - The DictSchema type for additional properties
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const schema = new IntersectionSchema(
|
|
46
|
+
* l.object({ name: l.string() }),
|
|
47
|
+
* l.dict(l.string(), l.integer())
|
|
48
|
+
* )
|
|
49
|
+
* // Validates: { name: 'test', score: 100, count: 5 }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
27
52
|
export class IntersectionSchema<
|
|
28
53
|
const Left extends ObjectSchema = any,
|
|
29
54
|
const Right extends DictSchema = any,
|
|
@@ -48,6 +73,35 @@ export class IntersectionSchema<
|
|
|
48
73
|
}
|
|
49
74
|
}
|
|
50
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Creates an intersection schema combining fixed object properties with dynamic dictionary properties.
|
|
78
|
+
*
|
|
79
|
+
* Useful for objects that have a known set of properties plus additional
|
|
80
|
+
* arbitrary properties that follow a pattern.
|
|
81
|
+
*
|
|
82
|
+
* @param left - Object schema defining the fixed, known properties
|
|
83
|
+
* @param right - Dictionary schema for validating additional properties
|
|
84
|
+
* @returns A new {@link IntersectionSchema} instance
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* // Object with fixed and dynamic properties
|
|
89
|
+
* const configSchema = l.intersection(
|
|
90
|
+
* l.object({
|
|
91
|
+
* version: l.integer(),
|
|
92
|
+
* name: l.string(),
|
|
93
|
+
* }),
|
|
94
|
+
* l.dict(l.string(), l.string()) // Additional string properties
|
|
95
|
+
* )
|
|
96
|
+
*
|
|
97
|
+
* configSchema.parse({
|
|
98
|
+
* version: 1,
|
|
99
|
+
* name: 'my-config',
|
|
100
|
+
* customField: 'value',
|
|
101
|
+
* anotherField: 'another',
|
|
102
|
+
* })
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
51
105
|
/*@__NO_SIDE_EFFECTS__*/
|
|
52
106
|
export function intersection<
|
|
53
107
|
const Left extends ObjectSchema,
|
package/src/schema/literal.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { Schema, ValidationContext } from '../core.js'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* Schema that only accepts a specific literal value.
|
|
5
|
+
*
|
|
6
|
+
* Validates that the input is exactly equal to the specified value using
|
|
7
|
+
* strict equality (===).
|
|
8
|
+
*
|
|
9
|
+
* @template TValue - The literal type (null, string, number, or boolean)
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const schema = new LiteralSchema('admin')
|
|
14
|
+
* schema.validate('admin') // success
|
|
15
|
+
* schema.validate('user') // fails
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
3
18
|
export class LiteralSchema<
|
|
4
19
|
const TValue extends null | string | number | boolean,
|
|
5
20
|
> extends Schema<TValue> {
|
|
@@ -16,6 +31,35 @@ export class LiteralSchema<
|
|
|
16
31
|
}
|
|
17
32
|
}
|
|
18
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Creates a literal schema that only accepts the exact specified value.
|
|
36
|
+
*
|
|
37
|
+
* Useful for discriminator fields in unions, constant values, or type narrowing.
|
|
38
|
+
*
|
|
39
|
+
* @param value - The exact value that must be matched
|
|
40
|
+
* @returns A new {@link LiteralSchema} instance
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* // String literal
|
|
45
|
+
* const roleSchema = l.literal('admin')
|
|
46
|
+
*
|
|
47
|
+
* // Number literal
|
|
48
|
+
* const versionSchema = l.literal(1)
|
|
49
|
+
*
|
|
50
|
+
* // Boolean literal
|
|
51
|
+
* const enabledSchema = l.literal(true)
|
|
52
|
+
*
|
|
53
|
+
* // Null literal
|
|
54
|
+
* const nullSchema = l.literal(null)
|
|
55
|
+
*
|
|
56
|
+
* // In discriminated unions
|
|
57
|
+
* const actionSchema = l.discriminatedUnion('type', [
|
|
58
|
+
* l.object({ type: l.literal('create'), data: l.unknown() }),
|
|
59
|
+
* l.object({ type: l.literal('delete'), id: l.string() }),
|
|
60
|
+
* ])
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
19
63
|
/*@__NO_SIDE_EFFECTS__*/
|
|
20
64
|
export function literal<const V extends null | string | number | boolean>(
|
|
21
65
|
value: V,
|
package/src/schema/never.ts
CHANGED
|
@@ -1,12 +1,54 @@
|
|
|
1
1
|
import { Schema, ValidationContext } from '../core.js'
|
|
2
2
|
import { memoizedOptions } from '../util/memoize.js'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Schema that always fails validation.
|
|
6
|
+
*
|
|
7
|
+
* Represents an impossible type - no value can satisfy this schema.
|
|
8
|
+
* Useful for exhaustiveness checking or marking impossible branches.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const schema = new NeverSchema()
|
|
13
|
+
* schema.validate(anything) // always fails
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
4
16
|
export class NeverSchema extends Schema<never> {
|
|
5
17
|
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
6
18
|
return ctx.issueInvalidType(input, 'never')
|
|
7
19
|
}
|
|
8
20
|
}
|
|
9
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Creates a never schema that always fails validation.
|
|
24
|
+
*
|
|
25
|
+
* Useful for exhaustiveness checking in TypeScript or marking impossible
|
|
26
|
+
* code paths.
|
|
27
|
+
*
|
|
28
|
+
* @returns A new {@link NeverSchema} instance
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* // Exhaustiveness checking
|
|
33
|
+
* type Status = 'active' | 'inactive'
|
|
34
|
+
*
|
|
35
|
+
* function handleStatus(status: Status) {
|
|
36
|
+
* switch (status) {
|
|
37
|
+
* case 'active': return 'Active'
|
|
38
|
+
* case 'inactive': return 'Inactive'
|
|
39
|
+
* default:
|
|
40
|
+
* // TypeScript will error if we miss a case
|
|
41
|
+
* l.never().parse(status)
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* // In impossible union branches
|
|
46
|
+
* const schema = l.object({
|
|
47
|
+
* type: l.literal('fixed'),
|
|
48
|
+
* dynamic: l.never(), // This property can never exist
|
|
49
|
+
* })
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
10
52
|
export const never = /*#__PURE__*/ memoizedOptions(function () {
|
|
11
53
|
return new NeverSchema()
|
|
12
54
|
})
|
package/src/schema/null.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import { Schema, ValidationContext } from '../core.js'
|
|
2
2
|
import { memoizedOptions } from '../util/memoize.js'
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Schema for validating null values.
|
|
6
|
+
*
|
|
7
|
+
* Only accepts the JavaScript `null` value. Rejects `undefined` and all
|
|
8
|
+
* other values.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const schema = new NullSchema()
|
|
13
|
+
* schema.validate(null) // success
|
|
14
|
+
* schema.validate(undefined) // fails
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
4
17
|
export class NullSchema extends Schema<null> {
|
|
5
18
|
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
6
19
|
if (input !== null) {
|
|
@@ -11,6 +24,22 @@ export class NullSchema extends Schema<null> {
|
|
|
11
24
|
}
|
|
12
25
|
}
|
|
13
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Creates a null schema that only accepts the null value.
|
|
29
|
+
*
|
|
30
|
+
* Useful for explicitly representing null in union types or optional fields.
|
|
31
|
+
*
|
|
32
|
+
* @returns A new {@link NullSchema} instance
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* // Explicit null
|
|
37
|
+
* const nullOnlySchema = l.null()
|
|
38
|
+
*
|
|
39
|
+
* // Nullable string (string or null)
|
|
40
|
+
* const nullableStringSchema = l.union([l.string(), l.null()])
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
14
43
|
export const nullSchema = /*#__PURE__*/ memoizedOptions(function () {
|
|
15
44
|
return new NullSchema()
|
|
16
45
|
})
|
package/src/schema/nullable.ts
CHANGED
|
@@ -7,6 +7,21 @@ import {
|
|
|
7
7
|
} from '../core.js'
|
|
8
8
|
import { memoizedTransformer } from '../util/memoize.js'
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Schema wrapper that allows null values in addition to the wrapped schema.
|
|
12
|
+
*
|
|
13
|
+
* When the input is `null`, validation succeeds immediately. Otherwise,
|
|
14
|
+
* the input is validated against the wrapped schema.
|
|
15
|
+
*
|
|
16
|
+
* @template TValidator - The wrapped validator type
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const schema = new NullableSchema(l.string())
|
|
21
|
+
* schema.validate(null) // success
|
|
22
|
+
* schema.validate('hello') // success
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
10
25
|
export class NullableSchema<const TValidator extends Validator> extends Schema<
|
|
11
26
|
InferInput<TValidator> | null,
|
|
12
27
|
InferOutput<TValidator> | null
|
|
@@ -24,6 +39,32 @@ export class NullableSchema<const TValidator extends Validator> extends Schema<
|
|
|
24
39
|
}
|
|
25
40
|
}
|
|
26
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Creates a nullable schema that accepts null in addition to the wrapped type.
|
|
44
|
+
*
|
|
45
|
+
* Wraps another schema to allow null values. Different from `optional()` which
|
|
46
|
+
* allows undefined.
|
|
47
|
+
*
|
|
48
|
+
* @param validator - The validator to make nullable
|
|
49
|
+
* @returns A new {@link NullableSchema} instance
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* // Nullable string
|
|
54
|
+
* const nullableString = l.nullable(l.string())
|
|
55
|
+
* nullableString.parse(null) // null
|
|
56
|
+
* nullableString.parse('hello') // 'hello'
|
|
57
|
+
*
|
|
58
|
+
* // In an object
|
|
59
|
+
* const userSchema = l.object({
|
|
60
|
+
* name: l.string(),
|
|
61
|
+
* deletedAt: l.nullable(l.string({ format: 'datetime' })),
|
|
62
|
+
* })
|
|
63
|
+
*
|
|
64
|
+
* // Combine with optional for null or undefined
|
|
65
|
+
* const maybeString = l.optional(l.nullable(l.string()))
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
27
68
|
export const nullable = /*#__PURE__*/ memoizedTransformer(function <
|
|
28
69
|
const TValidator extends Validator,
|
|
29
70
|
>(validator: TValidator) {
|
package/src/schema/object.ts
CHANGED
|
@@ -9,8 +9,30 @@ import {
|
|
|
9
9
|
} from '../core.js'
|
|
10
10
|
import { lazyProperty } from '../util/lazy-property.js'
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Type representing the shape of an object schema.
|
|
14
|
+
*
|
|
15
|
+
* Maps property names to their corresponding validators.
|
|
16
|
+
*/
|
|
12
17
|
export type ObjectSchemaShape = Record<string, Validator>
|
|
13
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Schema for validating objects with a defined shape.
|
|
21
|
+
*
|
|
22
|
+
* Each property in the shape is validated against its corresponding schema.
|
|
23
|
+
* Properties wrapped in `optional()` are not required.
|
|
24
|
+
*
|
|
25
|
+
* @template TShape - The object shape type mapping property names to validators
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* const schema = new ObjectSchema({
|
|
30
|
+
* name: l.string(),
|
|
31
|
+
* age: l.optional(l.integer()),
|
|
32
|
+
* })
|
|
33
|
+
* const result = schema.validate({ name: 'Alice' })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
14
36
|
export class ObjectSchema<
|
|
15
37
|
const TShape extends ObjectSchemaShape = any,
|
|
16
38
|
> extends Schema<
|
|
@@ -70,6 +92,40 @@ export class ObjectSchema<
|
|
|
70
92
|
}
|
|
71
93
|
}
|
|
72
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Creates an object schema with the specified property validators.
|
|
97
|
+
*
|
|
98
|
+
* Validates that the input is a plain object and each property matches
|
|
99
|
+
* its corresponding schema. Properties wrapped in `optional()` are not required.
|
|
100
|
+
*
|
|
101
|
+
* @param properties - Object mapping property names to their validators
|
|
102
|
+
* @returns A new {@link ObjectSchema} instance
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```ts
|
|
106
|
+
* // Basic object
|
|
107
|
+
* const userSchema = l.object({
|
|
108
|
+
* name: l.string(),
|
|
109
|
+
* email: l.string({ format: 'uri' }),
|
|
110
|
+
* })
|
|
111
|
+
*
|
|
112
|
+
* // With optional properties
|
|
113
|
+
* const profileSchema = l.object({
|
|
114
|
+
* displayName: l.string(),
|
|
115
|
+
* bio: l.optional(l.string({ maxLength: 256 })),
|
|
116
|
+
* avatar: l.optional(l.blob({ accept: ['image/*'] })),
|
|
117
|
+
* })
|
|
118
|
+
*
|
|
119
|
+
* // Nested objects
|
|
120
|
+
* const postSchema = l.object({
|
|
121
|
+
* text: l.string(),
|
|
122
|
+
* author: l.object({
|
|
123
|
+
* did: l.string({ format: 'did' }),
|
|
124
|
+
* handle: l.string({ format: 'handle' }),
|
|
125
|
+
* }),
|
|
126
|
+
* })
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
73
129
|
/*@__NO_SIDE_EFFECTS__*/
|
|
74
130
|
export function object<const TShape extends ObjectSchemaShape>(
|
|
75
131
|
properties: TShape,
|
package/src/schema/optional.ts
CHANGED
|
@@ -9,6 +9,22 @@ import {
|
|
|
9
9
|
import { memoizedTransformer } from '../util/memoize.js'
|
|
10
10
|
import { WithDefaultSchema } from './with-default.js'
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Schema wrapper that makes a value optional (allows undefined).
|
|
14
|
+
*
|
|
15
|
+
* When the input is `undefined`, validation succeeds without running the
|
|
16
|
+
* inner validator. If the inner validator has a default value (via `withDefault`),
|
|
17
|
+
* that default will be applied in parse mode.
|
|
18
|
+
*
|
|
19
|
+
* @template TValidator - The wrapped validator type
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const schema = new OptionalSchema(l.string())
|
|
24
|
+
* schema.validate(undefined) // success
|
|
25
|
+
* schema.validate('hello') // success
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
12
28
|
export class OptionalSchema<TValidator extends Validator> extends Schema<
|
|
13
29
|
InferInput<TValidator> | undefined,
|
|
14
30
|
UnwrapValidator<TValidator> extends WithDefaultSchema<infer TValidator>
|
|
@@ -41,6 +57,32 @@ export class OptionalSchema<TValidator extends Validator> extends Schema<
|
|
|
41
57
|
}
|
|
42
58
|
}
|
|
43
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Creates an optional schema that allows undefined values.
|
|
62
|
+
*
|
|
63
|
+
* Wraps another schema to make it optional. When used in an object schema,
|
|
64
|
+
* properties with optional schemas are not required.
|
|
65
|
+
*
|
|
66
|
+
* @param validator - The validator to make optional
|
|
67
|
+
* @returns A new {@link OptionalSchema} instance
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* // Optional string
|
|
72
|
+
* const optionalBio = l.optional(l.string())
|
|
73
|
+
*
|
|
74
|
+
* // In an object - property is not required
|
|
75
|
+
* const userSchema = l.object({
|
|
76
|
+
* name: l.string(),
|
|
77
|
+
* bio: l.optional(l.string()),
|
|
78
|
+
* })
|
|
79
|
+
* userSchema.parse({ name: 'Alice' }) // Valid, bio is undefined
|
|
80
|
+
*
|
|
81
|
+
* // With default value
|
|
82
|
+
* const countSchema = l.optional(l.withDefault(l.integer(), 0))
|
|
83
|
+
* countSchema.parse(undefined) // Returns 0
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
44
86
|
export const optional = /*#__PURE__*/ memoizedTransformer(function <
|
|
45
87
|
const TValidator extends Validator,
|
|
46
88
|
>(validator: TValidator) {
|
|
@@ -265,6 +265,9 @@ describe('ParamsSchema', () => {
|
|
|
265
265
|
name: string(),
|
|
266
266
|
age: optional(integer()),
|
|
267
267
|
active: optional(boolean()),
|
|
268
|
+
tags: optional(array(string())),
|
|
269
|
+
ids: optional(array(integer())),
|
|
270
|
+
bools: optional(array(boolean())),
|
|
268
271
|
})
|
|
269
272
|
|
|
270
273
|
it('parses string parameters', () => {
|
|
@@ -310,9 +313,9 @@ describe('ParamsSchema', () => {
|
|
|
310
313
|
})
|
|
311
314
|
|
|
312
315
|
it('parses multiple values as array', () => {
|
|
313
|
-
const urlParams = new URLSearchParams('name=Alice&
|
|
316
|
+
const urlParams = new URLSearchParams('name=Alice&tags=one&tags=two')
|
|
314
317
|
const result = schema.fromURLSearchParams(urlParams)
|
|
315
|
-
expect(result).toEqual({ name: 'Alice',
|
|
318
|
+
expect(result).toEqual({ name: 'Alice', tags: ['one', 'two'] })
|
|
316
319
|
})
|
|
317
320
|
|
|
318
321
|
it('coerces array values correctly', () => {
|
|
@@ -346,6 +349,59 @@ describe('ParamsSchema', () => {
|
|
|
346
349
|
extra: 'value',
|
|
347
350
|
})
|
|
348
351
|
})
|
|
352
|
+
|
|
353
|
+
it('coerces single values into arrays in parse mode', () => {
|
|
354
|
+
expect(
|
|
355
|
+
schema.fromURLSearchParams([
|
|
356
|
+
['name', 'Alice'],
|
|
357
|
+
['tags', 'tag1'],
|
|
358
|
+
]),
|
|
359
|
+
).toEqual({ name: 'Alice', tags: ['tag1'] })
|
|
360
|
+
|
|
361
|
+
expect(
|
|
362
|
+
schema.fromURLSearchParams([
|
|
363
|
+
['name', 'Alice'],
|
|
364
|
+
['tags', 'true'],
|
|
365
|
+
]),
|
|
366
|
+
).toEqual({ name: 'Alice', tags: ['true'] })
|
|
367
|
+
|
|
368
|
+
expect(
|
|
369
|
+
schema.fromURLSearchParams([
|
|
370
|
+
['name', 'Alice'],
|
|
371
|
+
['tags', '1'],
|
|
372
|
+
]),
|
|
373
|
+
).toEqual({ name: 'Alice', tags: ['1'] })
|
|
374
|
+
})
|
|
375
|
+
|
|
376
|
+
it('coerces single boolean values into arrays in parse mode', () => {
|
|
377
|
+
expect(
|
|
378
|
+
schema.fromURLSearchParams([
|
|
379
|
+
['name', 'Alice'],
|
|
380
|
+
['bools', 'true'],
|
|
381
|
+
]),
|
|
382
|
+
).toEqual({ name: 'Alice', bools: [true] })
|
|
383
|
+
|
|
384
|
+
expect(
|
|
385
|
+
schema.fromURLSearchParams([
|
|
386
|
+
['name', 'Alice'],
|
|
387
|
+
['bools', 'false'],
|
|
388
|
+
]),
|
|
389
|
+
).toEqual({ name: 'Alice', bools: [false] })
|
|
390
|
+
|
|
391
|
+
expect(() =>
|
|
392
|
+
schema.fromURLSearchParams([
|
|
393
|
+
['name', 'Alice'],
|
|
394
|
+
['bools', 'notabool'],
|
|
395
|
+
]),
|
|
396
|
+
).toThrow('Expected boolean value type at $.bools[0] (got string)')
|
|
397
|
+
|
|
398
|
+
expect(() =>
|
|
399
|
+
schema.fromURLSearchParams([
|
|
400
|
+
['name', 'Alice'],
|
|
401
|
+
['bools', '2'],
|
|
402
|
+
]),
|
|
403
|
+
).toThrow('Expected boolean value type at $.bools[0] (got integer)')
|
|
404
|
+
})
|
|
349
405
|
})
|
|
350
406
|
|
|
351
407
|
describe('toURLSearchParams', () => {
|
package/src/schema/params.ts
CHANGED
|
@@ -10,27 +10,82 @@ import {
|
|
|
10
10
|
} from '../core.js'
|
|
11
11
|
import { lazyProperty } from '../util/lazy-property.js'
|
|
12
12
|
import { memoizedOptions } from '../util/memoize.js'
|
|
13
|
-
import { array } from './array.js'
|
|
14
|
-
import { boolean } from './boolean.js'
|
|
13
|
+
import { ArraySchema, array } from './array.js'
|
|
14
|
+
import { BooleanSchema, boolean } from './boolean.js'
|
|
15
15
|
import { dict } from './dict.js'
|
|
16
|
-
import { integer } from './integer.js'
|
|
17
|
-
import { optional } from './optional.js'
|
|
16
|
+
import { IntegerSchema, integer } from './integer.js'
|
|
17
|
+
import { OptionalSchema, optional } from './optional.js'
|
|
18
18
|
import { StringSchema, string } from './string.js'
|
|
19
19
|
import { union } from './union.js'
|
|
20
|
+
import { WithDefaultSchema } from './with-default.js'
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Scalar types allowed in URL parameters: boolean, integer, or string.
|
|
24
|
+
*/
|
|
21
25
|
export type ParamScalar = Infer<typeof paramScalarSchema>
|
|
22
26
|
const paramScalarSchema = union([boolean(), integer(), string()])
|
|
23
27
|
|
|
28
|
+
/**
|
|
29
|
+
* A single parameter value: scalar or array of scalars.
|
|
30
|
+
*/
|
|
24
31
|
export type Param = Infer<typeof paramSchema>
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Schema for validating individual parameter values.
|
|
35
|
+
*/
|
|
25
36
|
export const paramSchema = union([paramScalarSchema, array(paramScalarSchema)])
|
|
26
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Type for a params object with string keys and optional param values.
|
|
40
|
+
*/
|
|
27
41
|
export type Params = Infer<typeof paramsSchema>
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Schema for validating arbitrary params objects.
|
|
45
|
+
*/
|
|
28
46
|
export const paramsSchema = dict(string(), optional(paramSchema))
|
|
29
47
|
|
|
48
|
+
// @NOTE In order to properly coerce URLSearchParams, we need to distinguish
|
|
49
|
+
// between scalar and array validators, requiring to be able to detect which
|
|
50
|
+
// schema types are being used, restricting the allowed param validators here.
|
|
51
|
+
type ParamScalarValidator = StringSchema | BooleanSchema | IntegerSchema
|
|
52
|
+
type ParamValueValidator =
|
|
53
|
+
| ParamScalarValidator
|
|
54
|
+
| ArraySchema<ParamScalarValidator>
|
|
55
|
+
type ParamValidator =
|
|
56
|
+
| ParamValueValidator
|
|
57
|
+
| OptionalSchema<ParamValueValidator>
|
|
58
|
+
| OptionalSchema<WithDefaultSchema<ParamValueValidator>>
|
|
59
|
+
| WithDefaultSchema<ParamValueValidator>
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Type representing the shape of a params schema definition.
|
|
63
|
+
*
|
|
64
|
+
* Maps parameter names to their validators (must be Param or undefined).
|
|
65
|
+
*/
|
|
30
66
|
export type ParamsSchemaShape = {
|
|
31
|
-
[x: string]:
|
|
67
|
+
[x: string]: ParamValidator
|
|
32
68
|
}
|
|
33
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Schema for validating URL query parameters in Lexicon endpoints.
|
|
72
|
+
*
|
|
73
|
+
* Params are the query string parameters passed to queries, procedures,
|
|
74
|
+
* and subscriptions. Values must be scalars (boolean, integer, string)
|
|
75
|
+
* or arrays of scalars, as they need to be serializable to URL format.
|
|
76
|
+
*
|
|
77
|
+
* Provides methods for converting to/from URLSearchParams.
|
|
78
|
+
*
|
|
79
|
+
* @template TShape - The params shape type mapping names to validators
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const schema = new ParamsSchema({
|
|
84
|
+
* limit: l.optional(l.integer({ minimum: 1, maximum: 100 })),
|
|
85
|
+
* cursor: l.optional(l.string()),
|
|
86
|
+
* })
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
34
89
|
export class ParamsSchema<
|
|
35
90
|
const TShape extends ParamsSchemaShape = ParamsSchemaShape,
|
|
36
91
|
> extends Schema<
|
|
@@ -45,14 +100,13 @@ export class ParamsSchema<
|
|
|
45
100
|
super()
|
|
46
101
|
}
|
|
47
102
|
|
|
48
|
-
get shapeValidators(): Map<string,
|
|
103
|
+
get shapeValidators(): Map<string, ParamValidator> {
|
|
49
104
|
const map = new Map(Object.entries(this.shape))
|
|
50
105
|
|
|
51
106
|
return lazyProperty(this, 'shapeValidators', map)
|
|
52
107
|
}
|
|
53
108
|
|
|
54
109
|
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
55
|
-
// @TODO BETTER SUPPORT Input/Output
|
|
56
110
|
if (!isPlainObject(input)) {
|
|
57
111
|
return ctx.issueInvalidType(input, 'object')
|
|
58
112
|
}
|
|
@@ -109,14 +163,22 @@ export class ParamsSchema<
|
|
|
109
163
|
return ctx.success(copy ?? input)
|
|
110
164
|
}
|
|
111
165
|
|
|
112
|
-
fromURLSearchParams(
|
|
166
|
+
fromURLSearchParams(iterable: Iterable<[string, string]>): InferOutput<this> {
|
|
113
167
|
const params: Record<string, Param> = {}
|
|
114
168
|
|
|
115
|
-
|
|
116
|
-
|
|
169
|
+
// Compatibility with URLSearchParams not being iterable in some environments
|
|
170
|
+
const entries =
|
|
171
|
+
iterable instanceof URLSearchParams ? iterable.entries() : iterable
|
|
172
|
+
|
|
173
|
+
for (const [key, value] of entries) {
|
|
174
|
+
const validator = unwrapValidator(this.shapeValidators.get(key))
|
|
175
|
+
const expectsArray = validator instanceof ArraySchema
|
|
176
|
+
const scalarValidator = expectsArray
|
|
177
|
+
? unwrapValidator(validator.validator)
|
|
178
|
+
: validator
|
|
117
179
|
|
|
118
180
|
const coerced: ParamScalar =
|
|
119
|
-
|
|
181
|
+
scalarValidator instanceof StringSchema
|
|
120
182
|
? value
|
|
121
183
|
: value === 'true'
|
|
122
184
|
? true
|
|
@@ -126,12 +188,13 @@ export class ParamsSchema<
|
|
|
126
188
|
? Number(value)
|
|
127
189
|
: value
|
|
128
190
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
191
|
+
const currentParam = params[key]
|
|
192
|
+
if (currentParam === undefined) {
|
|
193
|
+
params[key] = expectsArray ? [coerced] : coerced
|
|
194
|
+
} else if (Array.isArray(currentParam)) {
|
|
195
|
+
currentParam.push(coerced)
|
|
133
196
|
} else {
|
|
134
|
-
params[key] = [
|
|
197
|
+
params[key] = [currentParam, coerced]
|
|
135
198
|
}
|
|
136
199
|
}
|
|
137
200
|
|
|
@@ -159,8 +222,53 @@ export class ParamsSchema<
|
|
|
159
222
|
}
|
|
160
223
|
}
|
|
161
224
|
|
|
225
|
+
/**
|
|
226
|
+
* Creates a params schema for URL query parameters.
|
|
227
|
+
*
|
|
228
|
+
* Params schemas validate query string parameters for Lexicon endpoints.
|
|
229
|
+
* Values must be boolean, integer, string, or arrays of those types.
|
|
230
|
+
*
|
|
231
|
+
* @param properties - Object mapping parameter names to their validators
|
|
232
|
+
* @returns A new {@link ParamsSchema} instance
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* // Simple pagination params
|
|
237
|
+
* const paginationParams = l.params({
|
|
238
|
+
* limit: l.optional(l.withDefault(l.integer({ minimum: 1, maximum: 100 }), 50)),
|
|
239
|
+
* cursor: l.optional(l.string()),
|
|
240
|
+
* })
|
|
241
|
+
*
|
|
242
|
+
* // Required parameter
|
|
243
|
+
* const actorParams = l.params({
|
|
244
|
+
* actor: l.string({ format: 'at-identifier' }),
|
|
245
|
+
* })
|
|
246
|
+
*
|
|
247
|
+
* // Array parameter (multiple values)
|
|
248
|
+
* const filterParams = l.params({
|
|
249
|
+
* tags: l.optional(l.array(l.string())),
|
|
250
|
+
* })
|
|
251
|
+
*
|
|
252
|
+
* // Convert from URL
|
|
253
|
+
* const urlParams = new URLSearchParams('limit=25&cursor=abc')
|
|
254
|
+
* const validated = paginationParams.fromURLSearchParams(urlParams)
|
|
255
|
+
*
|
|
256
|
+
* // Convert to URL
|
|
257
|
+
* const searchParams = paginationParams.toURLSearchParams({ limit: 25 })
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
162
260
|
export const params = /*#__PURE__*/ memoizedOptions(function params<
|
|
163
261
|
const TShape extends ParamsSchemaShape = NonNullable<unknown>,
|
|
164
262
|
>(properties: TShape = {} as TShape) {
|
|
165
263
|
return new ParamsSchema<TShape>(properties)
|
|
166
264
|
})
|
|
265
|
+
|
|
266
|
+
function unwrapValidator(schema?: Validator): Validator | undefined {
|
|
267
|
+
while (
|
|
268
|
+
schema instanceof OptionalSchema ||
|
|
269
|
+
schema instanceof WithDefaultSchema
|
|
270
|
+
) {
|
|
271
|
+
schema = schema.validator
|
|
272
|
+
}
|
|
273
|
+
return schema
|
|
274
|
+
}
|