@atproto/lex-schema 0.0.11 → 0.0.13
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 +54 -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 +232 -5
- 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 +60 -0
- 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 +54 -1
- package/dist/core/validation-issue.js.map +1 -1
- package/dist/core/validator.d.ts +356 -11
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +203 -4
- package/dist/core/validator.js.map +1 -1
- package/dist/helpers.d.ts +12 -28
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js.map +1 -1
- package/dist/schema/array.d.ts +46 -0
- package/dist/schema/array.d.ts.map +1 -1
- package/dist/schema/array.js +16 -1
- package/dist/schema/array.js.map +1 -1
- package/dist/schema/blob.d.ts +50 -2
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +44 -2
- package/dist/schema/blob.js.map +1 -1
- package/dist/schema/boolean.d.ts +29 -0
- package/dist/schema/boolean.d.ts.map +1 -1
- package/dist/schema/boolean.js +30 -1
- package/dist/schema/boolean.js.map +1 -1
- package/dist/schema/bytes.d.ts +39 -0
- package/dist/schema/bytes.d.ts.map +1 -1
- package/dist/schema/bytes.js +34 -1
- package/dist/schema/bytes.js.map +1 -1
- package/dist/schema/cid.d.ts +39 -0
- package/dist/schema/cid.d.ts.map +1 -1
- package/dist/schema/cid.js +35 -1
- package/dist/schema/cid.js.map +1 -1
- package/dist/schema/custom.d.ts +67 -1
- package/dist/schema/custom.d.ts.map +1 -1
- package/dist/schema/custom.js +55 -0
- package/dist/schema/custom.js.map +1 -1
- package/dist/schema/dict.d.ts +45 -0
- package/dist/schema/dict.d.ts.map +1 -1
- package/dist/schema/dict.js +46 -1
- package/dist/schema/dict.js.map +1 -1
- package/dist/schema/discriminated-union.d.ts +59 -0
- package/dist/schema/discriminated-union.d.ts.map +1 -1
- package/dist/schema/discriminated-union.js +47 -1
- package/dist/schema/discriminated-union.js.map +1 -1
- package/dist/schema/enum.d.ts +49 -0
- package/dist/schema/enum.d.ts.map +1 -1
- package/dist/schema/enum.js +49 -0
- package/dist/schema/enum.js.map +1 -1
- package/dist/schema/integer.d.ts +43 -0
- package/dist/schema/integer.d.ts.map +1 -1
- package/dist/schema/integer.js +38 -1
- package/dist/schema/integer.js.map +1 -1
- package/dist/schema/intersection.d.ts +55 -0
- package/dist/schema/intersection.d.ts.map +1 -1
- package/dist/schema/intersection.js +50 -0
- package/dist/schema/intersection.js.map +1 -1
- package/dist/schema/lex-map.d.ts +37 -0
- package/dist/schema/lex-map.d.ts.map +1 -0
- package/dist/schema/lex-map.js +60 -0
- package/dist/schema/lex-map.js.map +1 -0
- package/dist/schema/lex-value.d.ts +35 -0
- package/dist/schema/lex-value.d.ts.map +1 -0
- package/dist/schema/lex-value.js +87 -0
- package/dist/schema/lex-value.js.map +1 -0
- package/dist/schema/literal.d.ts +45 -0
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +45 -0
- package/dist/schema/literal.js.map +1 -1
- package/dist/schema/never.d.ts +43 -0
- package/dist/schema/never.d.ts.map +1 -1
- package/dist/schema/never.js +44 -1
- package/dist/schema/never.js.map +1 -1
- package/dist/schema/null.d.ts +30 -0
- package/dist/schema/null.d.ts.map +1 -1
- package/dist/schema/null.js +31 -1
- package/dist/schema/null.js.map +1 -1
- package/dist/schema/nullable.d.ts +42 -0
- package/dist/schema/nullable.d.ts.map +1 -1
- package/dist/schema/nullable.js +42 -0
- package/dist/schema/nullable.js.map +1 -1
- package/dist/schema/object.d.ts +57 -0
- package/dist/schema/object.d.ts.map +1 -1
- package/dist/schema/object.js +53 -1
- package/dist/schema/object.js.map +1 -1
- package/dist/schema/optional.d.ts +43 -0
- package/dist/schema/optional.d.ts.map +1 -1
- package/dist/schema/optional.js +43 -0
- package/dist/schema/optional.js.map +1 -1
- package/dist/schema/params.d.ts +96 -12
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +155 -21
- 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 +73 -3
- 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 +76 -25
- package/dist/schema/record.d.ts.map +1 -1
- package/dist/schema/record.js +21 -0
- package/dist/schema/record.js.map +1 -1
- package/dist/schema/ref.d.ts +51 -0
- package/dist/schema/ref.d.ts.map +1 -1
- package/dist/schema/ref.js +18 -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 +45 -0
- package/dist/schema/regexp.d.ts.map +1 -1
- package/dist/schema/regexp.js +46 -1
- package/dist/schema/regexp.js.map +1 -1
- package/dist/schema/string.d.ts +72 -6
- package/dist/schema/string.d.ts.map +1 -1
- package/dist/schema/string.js +56 -8
- 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 +48 -0
- package/dist/schema/token.d.ts.map +1 -1
- package/dist/schema/token.js +49 -1
- package/dist/schema/token.js.map +1 -1
- package/dist/schema/typed-object.d.ts +73 -23
- package/dist/schema/typed-object.d.ts.map +1 -1
- package/dist/schema/typed-object.js +20 -1
- package/dist/schema/typed-object.js.map +1 -1
- package/dist/schema/typed-ref.d.ts +54 -0
- package/dist/schema/typed-ref.d.ts.map +1 -1
- package/dist/schema/typed-ref.js +16 -0
- package/dist/schema/typed-ref.js.map +1 -1
- package/dist/schema/typed-union.d.ts +51 -1
- package/dist/schema/typed-union.d.ts.map +1 -1
- package/dist/schema/typed-union.js +52 -2
- package/dist/schema/typed-union.js.map +1 -1
- package/dist/schema/union.d.ts +46 -0
- package/dist/schema/union.d.ts.map +1 -1
- package/dist/schema/union.js +41 -0
- package/dist/schema/union.js.map +1 -1
- package/dist/schema/unknown.d.ts +34 -0
- package/dist/schema/unknown.d.ts.map +1 -1
- package/dist/schema/unknown.js +34 -0
- package/dist/schema/unknown.js.map +1 -1
- package/dist/schema/with-default.d.ts +45 -0
- package/dist/schema/with-default.d.ts.map +1 -1
- package/dist/schema/with-default.js +45 -0
- package/dist/schema/with-default.js.map +1 -1
- package/dist/schema.d.ts +2 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -1
- package/dist/schema.js.map +1 -1
- package/dist/util/if-any.d.ts +2 -0
- package/dist/util/if-any.d.ts.map +1 -0
- package/dist/util/if-any.js +3 -0
- package/dist/util/if-any.js.map +1 -0
- package/package.json +3 -3
- 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 +244 -9
- 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 +68 -2
- package/src/core/validator.ts +373 -12
- package/src/helpers.test.ts +110 -29
- package/src/helpers.ts +54 -25
- package/src/schema/array.test.ts +94 -79
- package/src/schema/array.ts +48 -1
- package/src/schema/blob.ts +50 -1
- package/src/schema/boolean.ts +31 -1
- package/src/schema/bytes.ts +41 -1
- package/src/schema/cid.ts +41 -1
- package/src/schema/custom.ts +68 -1
- package/src/schema/dict.ts +47 -1
- package/src/schema/discriminated-union.ts +61 -1
- package/src/schema/enum.ts +50 -0
- package/src/schema/integer.ts +45 -1
- package/src/schema/intersection.ts +56 -0
- package/src/schema/{unknown-object.test.ts → lex-map.test.ts} +9 -9
- package/src/schema/lex-map.ts +63 -0
- package/src/schema/lex-value.test.ts +81 -0
- package/src/schema/lex-value.ts +86 -0
- package/src/schema/literal.ts +46 -0
- package/src/schema/never.ts +45 -1
- package/src/schema/null.ts +32 -1
- package/src/schema/nullable.ts +43 -0
- package/src/schema/object.ts +59 -1
- package/src/schema/optional.ts +44 -0
- package/src/schema/params.test.ts +133 -38
- package/src/schema/params.ts +237 -37
- package/src/schema/payload.test.ts +3 -3
- package/src/schema/payload.ts +145 -42
- 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 +82 -16
- package/src/schema/ref.ts +52 -0
- package/src/schema/refine.ts +58 -9
- package/src/schema/regexp.ts +47 -1
- package/src/schema/string.test.ts +99 -2
- package/src/schema/string.ts +108 -15
- package/src/schema/subscription.ts +72 -2
- package/src/schema/token.ts +50 -1
- package/src/schema/typed-object.ts +81 -16
- package/src/schema/typed-ref.ts +55 -0
- package/src/schema/typed-union.ts +58 -3
- package/src/schema/union.ts +47 -0
- package/src/schema/unknown.ts +35 -0
- package/src/schema/with-default.ts +46 -0
- package/src/schema.ts +2 -1
- package/src/util/if-any.ts +3 -0
- package/dist/schema/unknown-object.d.ts +0 -8
- package/dist/schema/unknown-object.d.ts.map +0 -1
- package/dist/schema/unknown-object.js +0 -19
- package/dist/schema/unknown-object.js.map +0 -1
- package/src/schema/unknown-object.ts +0 -19
package/src/core/validator.ts
CHANGED
|
@@ -12,15 +12,79 @@ import {
|
|
|
12
12
|
MeasurableType,
|
|
13
13
|
} from './validation-issue.js'
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Represents a successful validation result.
|
|
17
|
+
*
|
|
18
|
+
* @typeParam Value - The type of the validated value
|
|
19
|
+
*/
|
|
15
20
|
export type ValidationSuccess<Value = unknown> = ResultSuccess<Value>
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Represents a failed validation result containing a {@link ValidationError}.
|
|
24
|
+
*/
|
|
16
25
|
export type ValidationFailure = ResultFailure<ValidationError>
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Discriminated union representing the outcome of a validation operation.
|
|
29
|
+
*
|
|
30
|
+
* Check the `success` property to determine if validation passed or failed:
|
|
31
|
+
* - If `success` is `true`, the `value` property contains the validated data
|
|
32
|
+
* - If `success` is `false`, the `reason` property contains the {@link ValidationError}
|
|
33
|
+
*
|
|
34
|
+
* @typeParam Value - The type of the validated value on success
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* const result: ValidationResult<string> = schema.safeParse(data)
|
|
39
|
+
* if (result.success) {
|
|
40
|
+
* // result.value is string
|
|
41
|
+
* } else {
|
|
42
|
+
* // result.reason is ValidationError
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
17
46
|
export type ValidationResult<Value = unknown> =
|
|
18
47
|
| ValidationSuccess<Value>
|
|
19
48
|
| ValidationFailure
|
|
20
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Extracts the input type that a validator accepts.
|
|
52
|
+
*
|
|
53
|
+
* Use this utility type to infer what type a schema will accept during validation.
|
|
54
|
+
*
|
|
55
|
+
* @typeParam V - A validator type
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* const userSchema = new ObjectSchema({ name: stringSchema, age: numberSchema })
|
|
60
|
+
* type UserInput = InferInput<typeof userSchema>
|
|
61
|
+
* // { name: string; age: number }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
21
64
|
export type InferInput<V extends Validator> = V['__lex']['input']
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Extracts the output type that a validator produces after parsing.
|
|
68
|
+
*
|
|
69
|
+
* The output type may differ from the input type when the schema applies
|
|
70
|
+
* transformations such as default values or type coercion during parsing.
|
|
71
|
+
*
|
|
72
|
+
* @typeParam V - A validator type
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const schema = new StringSchema().default('hello')
|
|
77
|
+
* type Input = InferInput<typeof schema> // string | undefined
|
|
78
|
+
* type Output = InferOutput<typeof schema> // string
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
22
81
|
export type InferOutput<V extends Validator> = V['__lex']['output']
|
|
23
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Alias for {@link InferInput} for convenient type inference.
|
|
85
|
+
*
|
|
86
|
+
* @typeParam V - A validator type
|
|
87
|
+
*/
|
|
24
88
|
export type { InferInput as Infer }
|
|
25
89
|
|
|
26
90
|
export interface Validator<TInput = unknown, TOutput = TInput> {
|
|
@@ -28,12 +92,11 @@ export interface Validator<TInput = unknown, TOutput = TInput> {
|
|
|
28
92
|
* This property is used for type inference purposes and does not actually
|
|
29
93
|
* exist at runtime.
|
|
30
94
|
*
|
|
95
|
+
* @internal
|
|
31
96
|
* @deprecated **INTERNAL API, DO NOT USE**.
|
|
32
97
|
*/
|
|
33
98
|
readonly ['__lex']: {
|
|
34
|
-
/** @internal The inferred validation type */
|
|
35
99
|
input: TInput
|
|
36
|
-
/** @internal The inferred parse type */
|
|
37
100
|
output: TOutput
|
|
38
101
|
}
|
|
39
102
|
|
|
@@ -66,22 +129,87 @@ export interface Validator<TInput = unknown, TOutput = TInput> {
|
|
|
66
129
|
validateInContext(input: unknown, ctx: ValidationContext): ValidationResult
|
|
67
130
|
}
|
|
68
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Configuration options for validation and parsing operations.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* // Validate mode (strict, no transformations)
|
|
138
|
+
* ValidationContext.validate(data, schema, { mode: 'validate' })
|
|
139
|
+
*
|
|
140
|
+
* // Parse mode (allows transformations like defaults)
|
|
141
|
+
* ValidationContext.validate(data, schema, { mode: 'parse' })
|
|
142
|
+
*
|
|
143
|
+
* // With initial path for nested validation
|
|
144
|
+
* ValidationContext.validate(data, schema, { path: ['user', 'profile'] })
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
69
147
|
export type ValidationOptions = {
|
|
70
148
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
* default
|
|
149
|
+
* The validation mode determining how transformations are handled.
|
|
150
|
+
*
|
|
151
|
+
* - `"validate"` (default): Strict validation where the result must be
|
|
152
|
+
* strictly equal to the input value. No transformations such as applying
|
|
153
|
+
* default values are allowed.
|
|
154
|
+
* - `"parse"`: Allows the schema to transform the input value, such as
|
|
155
|
+
* applying default values or performing type coercion.
|
|
74
156
|
*/
|
|
75
157
|
mode?: 'validate' | 'parse'
|
|
76
158
|
|
|
77
159
|
/**
|
|
78
|
-
* The path to the value being validated.
|
|
79
|
-
*
|
|
160
|
+
* The initial path to the value being validated.
|
|
161
|
+
*
|
|
162
|
+
* This is used to provide context in validation issues when validating
|
|
163
|
+
* nested structures. The path is prepended to all issue paths.
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* // Issues will be reported at paths like "user.name" instead of just "name"
|
|
168
|
+
* ValidationContext.validate(data, schema, { path: ['user'] })
|
|
169
|
+
* ```
|
|
80
170
|
*/
|
|
81
171
|
path?: readonly PropertyKey[]
|
|
82
172
|
}
|
|
83
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Manages the state and context for validation operations.
|
|
176
|
+
*
|
|
177
|
+
* The `ValidationContext` class is responsible for:
|
|
178
|
+
* - Tracking the current path in nested structures for error reporting
|
|
179
|
+
* - Collecting validation issues during traversal
|
|
180
|
+
* - Enforcing validation mode (validate vs parse)
|
|
181
|
+
* - Providing factory methods for creating validation results
|
|
182
|
+
*
|
|
183
|
+
* Use the static {@link ValidationContext.validate} method as the primary entry point
|
|
184
|
+
* for validation. This ensures proper mode enforcement and issue aggregation.
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* // Primary usage via static method
|
|
189
|
+
* const result = ValidationContext.validate(data, schema, { mode: 'parse' })
|
|
190
|
+
*
|
|
191
|
+
* // Within a custom validator implementation
|
|
192
|
+
* class MyValidator implements Validator {
|
|
193
|
+
* validateInContext(input: unknown, ctx: ValidationContext): ValidationResult {
|
|
194
|
+
* if (typeof input !== 'string') {
|
|
195
|
+
* return ctx.issueUnexpectedType(input, 'string')
|
|
196
|
+
* }
|
|
197
|
+
* return ctx.success(input)
|
|
198
|
+
* }
|
|
199
|
+
* }
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
84
202
|
export class ValidationContext {
|
|
203
|
+
/**
|
|
204
|
+
* Validates input against a validator in parse mode.
|
|
205
|
+
*
|
|
206
|
+
* In parse mode, the schema may transform the input (e.g., apply defaults).
|
|
207
|
+
*
|
|
208
|
+
* @param input - The value to validate
|
|
209
|
+
* @param validator - The validator to use
|
|
210
|
+
* @param options - Validation options with mode set to 'parse'
|
|
211
|
+
* @returns A validation result with the parsed output type
|
|
212
|
+
*/
|
|
85
213
|
static validate<V extends Validator>(
|
|
86
214
|
input: unknown,
|
|
87
215
|
validator: V,
|
|
@@ -89,6 +217,19 @@ export class ValidationContext {
|
|
|
89
217
|
mode: 'parse'
|
|
90
218
|
},
|
|
91
219
|
): ValidationResult<InferOutput<V>>
|
|
220
|
+
/**
|
|
221
|
+
* Validates input against a validator in validate mode (default).
|
|
222
|
+
*
|
|
223
|
+
* In validate mode, the result must be strictly equal to the input.
|
|
224
|
+
* No transformations are allowed.
|
|
225
|
+
*
|
|
226
|
+
* @typeParam V - The validator type
|
|
227
|
+
* @typeParam I - The input type
|
|
228
|
+
* @param input - The value to validate
|
|
229
|
+
* @param validator - The validator to use
|
|
230
|
+
* @param options - Optional validation options (defaults to validate mode)
|
|
231
|
+
* @returns A validation result preserving the input type intersected with the schema type
|
|
232
|
+
*/
|
|
92
233
|
static validate<V extends Validator, I = unknown>(
|
|
93
234
|
input: I,
|
|
94
235
|
validator: V,
|
|
@@ -96,6 +237,14 @@ export class ValidationContext {
|
|
|
96
237
|
mode?: 'validate'
|
|
97
238
|
},
|
|
98
239
|
): ValidationResult<I & InferInput<V>>
|
|
240
|
+
/**
|
|
241
|
+
* Validates input against a validator with configurable options.
|
|
242
|
+
*
|
|
243
|
+
* @param input - The value to validate
|
|
244
|
+
* @param validator - The validator to use
|
|
245
|
+
* @param options - Optional validation options
|
|
246
|
+
* @returns A validation result with either the input or output type
|
|
247
|
+
*/
|
|
99
248
|
static validate<V extends Validator>(
|
|
100
249
|
input: unknown,
|
|
101
250
|
validator: V,
|
|
@@ -113,27 +262,58 @@ export class ValidationContext {
|
|
|
113
262
|
return context.validate(input, validator)
|
|
114
263
|
}
|
|
115
264
|
|
|
265
|
+
/**
|
|
266
|
+
* The current path being validated, used for error reporting.
|
|
267
|
+
*/
|
|
116
268
|
protected readonly currentPath: PropertyKey[]
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Accumulated validation issues collected during traversal.
|
|
272
|
+
*/
|
|
117
273
|
protected readonly issues: Issue[] = []
|
|
118
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Creates a new validation context with the specified options.
|
|
277
|
+
*
|
|
278
|
+
* @param options - The validation options (path and mode are required)
|
|
279
|
+
*/
|
|
119
280
|
constructor(readonly options: Required<ValidationOptions>) {
|
|
120
281
|
// Create a copy because we will be mutating the array during validation.
|
|
121
282
|
this.currentPath = Array.from(options.path)
|
|
122
283
|
}
|
|
123
284
|
|
|
285
|
+
/**
|
|
286
|
+
* Returns a copy of the current validation path.
|
|
287
|
+
*
|
|
288
|
+
* The path represents the location in the data structure being validated,
|
|
289
|
+
* used for constructing meaningful error messages.
|
|
290
|
+
*/
|
|
124
291
|
get path() {
|
|
125
292
|
return Array.from(this.currentPath)
|
|
126
293
|
}
|
|
127
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Creates a new path by appending segments to the current path.
|
|
297
|
+
*
|
|
298
|
+
* @param path - Optional path segment(s) to append
|
|
299
|
+
* @returns A new path array with the segment(s) appended
|
|
300
|
+
*/
|
|
128
301
|
concatPath(path?: PropertyKey | readonly PropertyKey[]) {
|
|
129
302
|
if (path == null) return this.path
|
|
130
303
|
return this.currentPath.concat(path)
|
|
131
304
|
}
|
|
132
305
|
|
|
133
306
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
307
|
+
* Validates input against a validator within this context.
|
|
308
|
+
*
|
|
309
|
+
* This is the primary entry point for validation within a context. Always use
|
|
310
|
+
* this method instead of calling {@link Validator.validateInContext} directly,
|
|
311
|
+
* as this method enforces validation mode rules and handles transformation detection.
|
|
312
|
+
*
|
|
313
|
+
* @typeParam V - The validator type
|
|
314
|
+
* @param input - The value to validate
|
|
315
|
+
* @param validator - The validator to use
|
|
316
|
+
* @returns A validation result with the validated value or error
|
|
137
317
|
*/
|
|
138
318
|
validate<V extends Validator>(
|
|
139
319
|
input: unknown,
|
|
@@ -170,11 +350,42 @@ export class ValidationContext {
|
|
|
170
350
|
return result as ValidationResult<InferInput<V>>
|
|
171
351
|
}
|
|
172
352
|
|
|
353
|
+
/**
|
|
354
|
+
* Validates a child property of an object within this context.
|
|
355
|
+
*
|
|
356
|
+
* This method automatically manages the path stack, pushing the property key
|
|
357
|
+
* before validation and popping it afterward. Use this for validating object
|
|
358
|
+
* properties to ensure proper path tracking in error messages.
|
|
359
|
+
*
|
|
360
|
+
* @typeParam I - The input object type
|
|
361
|
+
* @typeParam K - The property key type
|
|
362
|
+
* @typeParam V - The validator type
|
|
363
|
+
* @param input - The parent object containing the property
|
|
364
|
+
* @param key - The property key to validate
|
|
365
|
+
* @param validator - The validator to use for the property value
|
|
366
|
+
* @returns A validation result for the property value
|
|
367
|
+
*
|
|
368
|
+
* @example
|
|
369
|
+
* ```typescript
|
|
370
|
+
* // In a custom object validator
|
|
371
|
+
* const result = ctx.validateChild(input, 'name', stringSchema)
|
|
372
|
+
* // If validation fails, error path will include 'name'
|
|
373
|
+
* ```
|
|
374
|
+
*/
|
|
173
375
|
validateChild<
|
|
174
376
|
I extends object,
|
|
175
377
|
K extends PropertyKey & keyof I,
|
|
176
378
|
V extends Validator,
|
|
177
379
|
>(input: I, key: K, validator: V): ValidationResult<InferInput<V>> {
|
|
380
|
+
// @NOTE we could add support for recursive schemas by keeping track of
|
|
381
|
+
// "parent" objects in the context and checking for circular references
|
|
382
|
+
// here. This would allow us to validate recursive structures without
|
|
383
|
+
// hitting maximum call stack errors, and would also allow us to provide
|
|
384
|
+
// better error messages for circular reference issues. However, this is not
|
|
385
|
+
// a priority at the moment as recursive structures are not supported in
|
|
386
|
+
// the context of AT Protocol lexicons, and we can always add this in the
|
|
387
|
+
// future if needed.
|
|
388
|
+
|
|
178
389
|
// Instead of creating a new context, we just push/pop the path segment.
|
|
179
390
|
this.currentPath.push(key)
|
|
180
391
|
try {
|
|
@@ -184,38 +395,117 @@ export class ValidationContext {
|
|
|
184
395
|
}
|
|
185
396
|
}
|
|
186
397
|
|
|
398
|
+
/**
|
|
399
|
+
* Adds a validation issue to the context without immediately failing.
|
|
400
|
+
*
|
|
401
|
+
* Use this method to collect multiple issues during validation before
|
|
402
|
+
* determining the final result. Issues added this way will be included
|
|
403
|
+
* in the final error if validation fails.
|
|
404
|
+
*
|
|
405
|
+
* @param issue - The validation issue to add
|
|
406
|
+
*/
|
|
187
407
|
addIssue(issue: Issue): void {
|
|
188
408
|
this.issues.push(issue)
|
|
189
409
|
}
|
|
190
410
|
|
|
411
|
+
/**
|
|
412
|
+
* Creates a successful validation result with the given value.
|
|
413
|
+
*
|
|
414
|
+
* @typeParam V - The value type
|
|
415
|
+
* @param value - The validated value
|
|
416
|
+
* @returns A successful validation result
|
|
417
|
+
*/
|
|
191
418
|
success<V>(value: V): ValidationResult<V> {
|
|
192
419
|
return success(value)
|
|
193
420
|
}
|
|
194
421
|
|
|
422
|
+
/**
|
|
423
|
+
* Creates a failed validation result with the given error.
|
|
424
|
+
*
|
|
425
|
+
* @param reason - The validation error
|
|
426
|
+
* @returns A failed validation result
|
|
427
|
+
*/
|
|
195
428
|
failure(reason: ValidationError): ValidationFailure {
|
|
196
429
|
return failure(reason)
|
|
197
430
|
}
|
|
198
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Creates a failed validation result from a single issue.
|
|
434
|
+
*
|
|
435
|
+
* Any previously accumulated issues in the context are included in the error.
|
|
436
|
+
*
|
|
437
|
+
* @param issue - The validation issue that caused the failure
|
|
438
|
+
* @returns A failed validation result
|
|
439
|
+
*/
|
|
199
440
|
issue(issue: Issue) {
|
|
200
441
|
return this.failure(new ValidationError([...this.issues, issue]))
|
|
201
442
|
}
|
|
202
443
|
|
|
444
|
+
/**
|
|
445
|
+
* Creates a failure for an invalid value that doesn't match expected values.
|
|
446
|
+
*
|
|
447
|
+
* @param input - The actual value that was received
|
|
448
|
+
* @param values - The expected valid values
|
|
449
|
+
* @returns A failed validation result with an invalid value issue
|
|
450
|
+
*/
|
|
203
451
|
issueInvalidValue(input: unknown, values: readonly unknown[]) {
|
|
204
452
|
return this.issue(new IssueInvalidValue(this.path, input, values))
|
|
205
453
|
}
|
|
206
454
|
|
|
207
|
-
|
|
208
|
-
|
|
455
|
+
/**
|
|
456
|
+
* Creates a failure for an invalid type.
|
|
457
|
+
*
|
|
458
|
+
* @param input - The actual value that was received
|
|
459
|
+
* @param expected - An array of expected type names
|
|
460
|
+
* @returns A failed validation result with an invalid type issue
|
|
461
|
+
*/
|
|
462
|
+
issueInvalidType(input: unknown, expected: readonly string[]) {
|
|
463
|
+
return this.issue(new IssueInvalidType(this.path, input, expected))
|
|
209
464
|
}
|
|
210
465
|
|
|
466
|
+
/**
|
|
467
|
+
* Creates a failure for an invalid type.
|
|
468
|
+
*
|
|
469
|
+
* @param input - The actual value that was received
|
|
470
|
+
* @param expected - The expected type name
|
|
471
|
+
* @returns A failed validation result with an invalid type issue
|
|
472
|
+
*/
|
|
473
|
+
issueUnexpectedType(input: unknown, expected: string) {
|
|
474
|
+
return this.issueInvalidType(input, [expected])
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Creates a failure for a missing required key in an object.
|
|
479
|
+
*
|
|
480
|
+
* @param input - The object missing the required key
|
|
481
|
+
* @param key - The name of the required key
|
|
482
|
+
* @returns A failed validation result with a required key issue
|
|
483
|
+
*/
|
|
211
484
|
issueRequiredKey(input: object, key: PropertyKey) {
|
|
212
485
|
return this.issue(new IssueRequiredKey(this.path, input, key))
|
|
213
486
|
}
|
|
214
487
|
|
|
488
|
+
/**
|
|
489
|
+
* Creates a failure for an invalid string format.
|
|
490
|
+
*
|
|
491
|
+
* @param input - The actual value that was received
|
|
492
|
+
* @param format - The expected format name (e.g., 'did', 'handle', 'uri')
|
|
493
|
+
* @param msg - Optional additional message describing the format error
|
|
494
|
+
* @returns A failed validation result with an invalid format issue
|
|
495
|
+
*/
|
|
215
496
|
issueInvalidFormat(input: unknown, format: string, msg?: string) {
|
|
216
497
|
return this.issue(new IssueInvalidFormat(this.path, input, format, msg))
|
|
217
498
|
}
|
|
218
499
|
|
|
500
|
+
/**
|
|
501
|
+
* Creates a failure for a value that exceeds a maximum constraint.
|
|
502
|
+
*
|
|
503
|
+
* @param input - The actual value that was received
|
|
504
|
+
* @param type - The type of measurement (e.g., 'string', 'array', 'bytes')
|
|
505
|
+
* @param max - The maximum allowed value
|
|
506
|
+
* @param actual - The actual measured value
|
|
507
|
+
* @returns A failed validation result with a too big issue
|
|
508
|
+
*/
|
|
219
509
|
issueTooBig(
|
|
220
510
|
input: unknown,
|
|
221
511
|
type: MeasurableType,
|
|
@@ -225,6 +515,15 @@ export class ValidationContext {
|
|
|
225
515
|
return this.issue(new IssueTooBig(this.path, input, max, type, actual))
|
|
226
516
|
}
|
|
227
517
|
|
|
518
|
+
/**
|
|
519
|
+
* Creates a failure for a value that is below a minimum constraint.
|
|
520
|
+
*
|
|
521
|
+
* @param input - The actual value that was received
|
|
522
|
+
* @param type - The type of measurement (e.g., 'string', 'array', 'bytes')
|
|
523
|
+
* @param min - The minimum required value
|
|
524
|
+
* @param actual - The actual measured value
|
|
525
|
+
* @returns A failed validation result with a too small issue
|
|
526
|
+
*/
|
|
228
527
|
issueTooSmall(
|
|
229
528
|
input: unknown,
|
|
230
529
|
type: MeasurableType,
|
|
@@ -234,6 +533,18 @@ export class ValidationContext {
|
|
|
234
533
|
return this.issue(new IssueTooSmall(this.path, input, min, type, actual))
|
|
235
534
|
}
|
|
236
535
|
|
|
536
|
+
/**
|
|
537
|
+
* Creates a failure for an invalid property value within an object.
|
|
538
|
+
*
|
|
539
|
+
* This is a convenience method that automatically extracts the property value
|
|
540
|
+
* and constructs the appropriate path.
|
|
541
|
+
*
|
|
542
|
+
* @typeParam I - The input object type
|
|
543
|
+
* @param input - The object containing the invalid property
|
|
544
|
+
* @param property - The property key with the invalid value
|
|
545
|
+
* @param values - The expected valid values
|
|
546
|
+
* @returns A failed validation result with an invalid value issue at the property path
|
|
547
|
+
*/
|
|
237
548
|
issueInvalidPropertyValue<I>(
|
|
238
549
|
input: I,
|
|
239
550
|
property: keyof I & PropertyKey,
|
|
@@ -244,6 +555,18 @@ export class ValidationContext {
|
|
|
244
555
|
return this.issue(new IssueInvalidValue(path, value, values))
|
|
245
556
|
}
|
|
246
557
|
|
|
558
|
+
/**
|
|
559
|
+
* Creates a failure for an invalid property type within an object.
|
|
560
|
+
*
|
|
561
|
+
* This is a convenience method that automatically extracts the property value
|
|
562
|
+
* and constructs the appropriate path.
|
|
563
|
+
*
|
|
564
|
+
* @typeParam I - The input object type
|
|
565
|
+
* @param input - The object containing the invalid property
|
|
566
|
+
* @param property - The property key with the invalid type
|
|
567
|
+
* @param expected - The expected type name
|
|
568
|
+
* @returns A failed validation result with an invalid type issue at the property path
|
|
569
|
+
*/
|
|
247
570
|
issueInvalidPropertyType<I>(
|
|
248
571
|
input: I,
|
|
249
572
|
property: keyof I & PropertyKey,
|
|
@@ -255,12 +578,50 @@ export class ValidationContext {
|
|
|
255
578
|
}
|
|
256
579
|
}
|
|
257
580
|
|
|
581
|
+
/**
|
|
582
|
+
* Recursively unwraps a wrapped validator to its innermost validator type.
|
|
583
|
+
*
|
|
584
|
+
* Some validators wrap other validators (e.g., optional, nullable). This type
|
|
585
|
+
* utility recursively unwraps such wrappers to reveal the core validator.
|
|
586
|
+
*
|
|
587
|
+
* @typeParam T - A validator type, possibly wrapped
|
|
588
|
+
*
|
|
589
|
+
* @example
|
|
590
|
+
* ```typescript
|
|
591
|
+
* type Inner = UnwrapValidator<OptionalValidator<NullableValidator<StringSchema>>>
|
|
592
|
+
* // Result: StringSchema
|
|
593
|
+
* ```
|
|
594
|
+
*/
|
|
258
595
|
export type UnwrapValidator<T extends Validator> = T extends {
|
|
259
596
|
unwrap(): infer U extends Validator
|
|
260
597
|
}
|
|
261
598
|
? UnwrapValidator<U>
|
|
262
599
|
: T
|
|
263
600
|
|
|
601
|
+
/**
|
|
602
|
+
* Interface for validators that wrap another validator.
|
|
603
|
+
*
|
|
604
|
+
* Implement this interface when creating validators that wrap or modify
|
|
605
|
+
* the behavior of another validator (e.g., optional, nullable, transform).
|
|
606
|
+
*
|
|
607
|
+
* @typeParam Validator - The type of the wrapped validator
|
|
608
|
+
*
|
|
609
|
+
* @example
|
|
610
|
+
* ```typescript
|
|
611
|
+
* class OptionalSchema<V extends Validator> implements WrappedValidator<V> {
|
|
612
|
+
* constructor(private inner: V) {}
|
|
613
|
+
*
|
|
614
|
+
* unwrap(): V {
|
|
615
|
+
* return this.inner
|
|
616
|
+
* }
|
|
617
|
+
* }
|
|
618
|
+
* ```
|
|
619
|
+
*/
|
|
264
620
|
export interface WrappedValidator<out Validator> {
|
|
621
|
+
/**
|
|
622
|
+
* Returns the inner wrapped validator.
|
|
623
|
+
*
|
|
624
|
+
* @returns The wrapped validator
|
|
625
|
+
*/
|
|
265
626
|
unwrap(): Validator
|
|
266
627
|
}
|