@atproto/lex-schema 0.1.4 → 0.1.6
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 +24 -0
- package/dist/core/$type.d.ts +2 -2
- package/dist/core/$type.d.ts.map +1 -1
- package/dist/core/$type.js.map +1 -1
- package/dist/core/record-key.d.ts +1 -1
- package/dist/core/record-key.d.ts.map +1 -1
- package/dist/core/record-key.js.map +1 -1
- package/dist/core/schema.d.ts +3 -2
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +1 -1
- package/dist/core/schema.js.map +1 -1
- package/dist/core/standard-schema.d.ts +2 -2
- package/dist/core/standard-schema.d.ts.map +1 -1
- package/dist/core/standard-schema.js.map +1 -1
- package/dist/core/string-format.d.ts +2 -2
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js.map +1 -1
- package/dist/core/validation-error.d.ts +1 -1
- package/dist/core/validation-error.d.ts.map +1 -1
- package/dist/core/validation-error.js +1 -1
- package/dist/core/validation-error.js.map +1 -1
- package/dist/core/validator.d.ts +1 -1
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +1 -1
- package/dist/core/validator.js.map +1 -1
- package/dist/helpers.d.ts +2 -2
- 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 +1 -1
- package/dist/schema/array.d.ts.map +1 -1
- package/dist/schema/array.js +1 -1
- package/dist/schema/array.js.map +1 -1
- package/dist/schema/blob.d.ts +1 -1
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +2 -2
- package/dist/schema/blob.js.map +1 -1
- package/dist/schema/boolean.js +1 -1
- package/dist/schema/boolean.js.map +1 -1
- package/dist/schema/bytes.js +1 -1
- package/dist/schema/bytes.js.map +1 -1
- package/dist/schema/cid.d.ts +1 -1
- package/dist/schema/cid.d.ts.map +1 -1
- package/dist/schema/cid.js +3 -3
- package/dist/schema/cid.js.map +1 -1
- package/dist/schema/custom.js +1 -1
- package/dist/schema/custom.js.map +1 -1
- package/dist/schema/dict.d.ts +1 -1
- package/dist/schema/dict.d.ts.map +1 -1
- package/dist/schema/dict.js +1 -1
- package/dist/schema/dict.js.map +1 -1
- package/dist/schema/discriminated-union.d.ts +1 -1
- package/dist/schema/discriminated-union.d.ts.map +1 -1
- package/dist/schema/discriminated-union.js +2 -1
- package/dist/schema/discriminated-union.js.map +1 -1
- package/dist/schema/enum.js +1 -1
- package/dist/schema/enum.js.map +1 -1
- package/dist/schema/integer.js +1 -1
- package/dist/schema/integer.js.map +1 -1
- package/dist/schema/intersection.d.ts +1 -1
- package/dist/schema/intersection.d.ts.map +1 -1
- package/dist/schema/intersection.js +3 -1
- package/dist/schema/intersection.js.map +1 -1
- package/dist/schema/lex-map.d.ts +1 -1
- package/dist/schema/lex-map.d.ts.map +1 -1
- package/dist/schema/lex-map.js +1 -1
- package/dist/schema/lex-map.js.map +1 -1
- package/dist/schema/lex-value.d.ts +1 -1
- package/dist/schema/lex-value.d.ts.map +1 -1
- package/dist/schema/lex-value.js +1 -1
- package/dist/schema/lex-value.js.map +1 -1
- package/dist/schema/literal.js +1 -1
- package/dist/schema/literal.js.map +1 -1
- package/dist/schema/never.js +1 -1
- package/dist/schema/never.js.map +1 -1
- package/dist/schema/null.js +1 -1
- package/dist/schema/null.js.map +1 -1
- package/dist/schema/nullable.d.ts +1 -1
- package/dist/schema/nullable.d.ts.map +1 -1
- package/dist/schema/nullable.js +1 -1
- package/dist/schema/nullable.js.map +1 -1
- package/dist/schema/object.d.ts +2 -1
- package/dist/schema/object.d.ts.map +1 -1
- package/dist/schema/object.js +1 -1
- package/dist/schema/object.js.map +1 -1
- package/dist/schema/optional.d.ts +2 -1
- package/dist/schema/optional.d.ts.map +1 -1
- package/dist/schema/optional.js +2 -1
- package/dist/schema/optional.js.map +1 -1
- package/dist/schema/params.d.ts +1 -1
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +1 -1
- package/dist/schema/params.js.map +1 -1
- package/dist/schema/payload.d.ts +3 -2
- package/dist/schema/payload.d.ts.map +1 -1
- package/dist/schema/payload.js +2 -1
- package/dist/schema/payload.js.map +1 -1
- package/dist/schema/permission-set.d.ts +1 -1
- package/dist/schema/permission-set.d.ts.map +1 -1
- package/dist/schema/permission-set.js +1 -0
- package/dist/schema/permission-set.js.map +1 -1
- package/dist/schema/permission.d.ts +1 -1
- package/dist/schema/permission.d.ts.map +1 -1
- package/dist/schema/permission.js.map +1 -1
- package/dist/schema/procedure.d.ts +1 -1
- package/dist/schema/procedure.d.ts.map +1 -1
- package/dist/schema/procedure.js +2 -0
- package/dist/schema/procedure.js.map +1 -1
- package/dist/schema/query.d.ts +1 -1
- package/dist/schema/query.d.ts.map +1 -1
- package/dist/schema/query.js +2 -0
- package/dist/schema/query.js.map +1 -1
- package/dist/schema/record.d.ts +2 -2
- package/dist/schema/record.d.ts.map +1 -1
- package/dist/schema/record.js +1 -1
- package/dist/schema/record.js.map +1 -1
- package/dist/schema/ref.d.ts +1 -1
- package/dist/schema/ref.d.ts.map +1 -1
- package/dist/schema/ref.js +1 -1
- package/dist/schema/ref.js.map +1 -1
- package/dist/schema/refine.d.ts +2 -2
- package/dist/schema/refine.d.ts.map +1 -1
- package/dist/schema/refine.js +1 -1
- package/dist/schema/refine.js.map +1 -1
- package/dist/schema/regexp.js +1 -1
- package/dist/schema/regexp.js.map +1 -1
- package/dist/schema/string.d.ts +2 -2
- package/dist/schema/string.d.ts.map +1 -1
- package/dist/schema/string.js +1 -1
- package/dist/schema/string.js.map +1 -1
- package/dist/schema/subscription.d.ts +3 -2
- package/dist/schema/subscription.d.ts.map +1 -1
- package/dist/schema/subscription.js +2 -0
- package/dist/schema/subscription.js.map +1 -1
- package/dist/schema/token.d.ts +1 -1
- package/dist/schema/token.d.ts.map +1 -1
- package/dist/schema/token.js +1 -1
- package/dist/schema/token.js.map +1 -1
- package/dist/schema/typed-object.d.ts +2 -2
- package/dist/schema/typed-object.d.ts.map +1 -1
- package/dist/schema/typed-object.js +1 -1
- package/dist/schema/typed-object.js.map +1 -1
- package/dist/schema/typed-ref.d.ts +1 -1
- package/dist/schema/typed-ref.d.ts.map +1 -1
- package/dist/schema/typed-ref.js +1 -1
- package/dist/schema/typed-ref.js.map +1 -1
- package/dist/schema/typed-union.d.ts +1 -1
- package/dist/schema/typed-union.d.ts.map +1 -1
- package/dist/schema/typed-union.js +3 -1
- package/dist/schema/typed-union.js.map +1 -1
- package/dist/schema/union.d.ts +1 -1
- package/dist/schema/union.d.ts.map +1 -1
- package/dist/schema/union.js +1 -1
- package/dist/schema/union.js.map +1 -1
- package/dist/schema/unknown.js +1 -1
- package/dist/schema/unknown.js.map +1 -1
- package/dist/schema/with-default.d.ts +1 -1
- package/dist/schema/with-default.d.ts.map +1 -1
- package/dist/schema/with-default.js +1 -1
- package/dist/schema/with-default.js.map +1 -1
- package/package.json +6 -10
- package/src/core/$type.test.ts +0 -24
- package/src/core/$type.ts +0 -199
- package/src/core/record-key.ts +0 -85
- package/src/core/result.ts +0 -15
- package/src/core/schema.ts +0 -412
- package/src/core/standard-schema.test.ts +0 -124
- package/src/core/standard-schema.ts +0 -31
- package/src/core/string-format.ts +0 -411
- package/src/core/types.ts +0 -120
- package/src/core/validation-error.ts +0 -134
- package/src/core/validation-issue.ts +0 -340
- package/src/core/validator.ts +0 -636
- package/src/core.ts +0 -9
- package/src/external.ts +0 -3
- package/src/helpers.test.ts +0 -694
- package/src/helpers.ts +0 -222
- package/src/index.ts +0 -3
- package/src/schema/array.test.ts +0 -251
- package/src/schema/array.ts +0 -126
- package/src/schema/blob.test.ts +0 -733
- package/src/schema/blob.ts +0 -150
- package/src/schema/boolean.test.ts +0 -118
- package/src/schema/boolean.ts +0 -46
- package/src/schema/bytes.test.ts +0 -227
- package/src/schema/bytes.ts +0 -81
- package/src/schema/cid.test.ts +0 -125
- package/src/schema/cid.ts +0 -69
- package/src/schema/custom.test.ts +0 -414
- package/src/schema/custom.ts +0 -106
- package/src/schema/dict.test.ts +0 -181
- package/src/schema/dict.ts +0 -122
- package/src/schema/discriminated-union.test.ts +0 -676
- package/src/schema/discriminated-union.ts +0 -196
- package/src/schema/enum.test.ts +0 -398
- package/src/schema/enum.ts +0 -77
- package/src/schema/integer.test.ts +0 -314
- package/src/schema/integer.ts +0 -86
- package/src/schema/intersection.test.ts +0 -33
- package/src/schema/intersection.ts +0 -113
- package/src/schema/lex-map.test.ts +0 -593
- package/src/schema/lex-map.ts +0 -63
- package/src/schema/lex-value.test.ts +0 -81
- package/src/schema/lex-value.ts +0 -86
- package/src/schema/literal.test.ts +0 -533
- package/src/schema/literal.ts +0 -70
- package/src/schema/never.test.ts +0 -175
- package/src/schema/never.ts +0 -56
- package/src/schema/null.test.ts +0 -80
- package/src/schema/null.ts +0 -49
- package/src/schema/nullable.test.ts +0 -470
- package/src/schema/nullable.ts +0 -74
- package/src/schema/object.test.ts +0 -69
- package/src/schema/object.ts +0 -136
- package/src/schema/optional.test.ts +0 -479
- package/src/schema/optional.ts +0 -92
- package/src/schema/params.test.ts +0 -1118
- package/src/schema/params.ts +0 -371
- package/src/schema/payload.test.ts +0 -340
- package/src/schema/payload.ts +0 -204
- package/src/schema/permission-set.test.ts +0 -613
- package/src/schema/permission-set.ts +0 -86
- package/src/schema/permission.test.ts +0 -537
- package/src/schema/permission.ts +0 -63
- package/src/schema/procedure.test.ts +0 -324
- package/src/schema/procedure.ts +0 -98
- package/src/schema/query.test.ts +0 -348
- package/src/schema/query.ts +0 -86
- package/src/schema/record.test.ts +0 -812
- package/src/schema/record.ts +0 -217
- package/src/schema/ref.test.ts +0 -349
- package/src/schema/ref.ts +0 -103
- package/src/schema/refine.test.ts +0 -579
- package/src/schema/refine.ts +0 -153
- package/src/schema/regexp.test.ts +0 -577
- package/src/schema/regexp.ts +0 -82
- package/src/schema/string.test.ts +0 -773
- package/src/schema/string.ts +0 -229
- package/src/schema/subscription.test.ts +0 -499
- package/src/schema/subscription.ts +0 -108
- package/src/schema/token.test.ts +0 -152
- package/src/schema/token.ts +0 -103
- package/src/schema/typed-object.test.ts +0 -745
- package/src/schema/typed-object.ts +0 -181
- package/src/schema/typed-ref.test.ts +0 -796
- package/src/schema/typed-ref.ts +0 -126
- package/src/schema/typed-union.test.ts +0 -355
- package/src/schema/typed-union.ts +0 -130
- package/src/schema/union.test.ts +0 -191
- package/src/schema/union.ts +0 -89
- package/src/schema/unknown.test.ts +0 -313
- package/src/schema/unknown.ts +0 -47
- package/src/schema/with-default.ts +0 -81
- package/src/schema.ts +0 -43
- package/src/util/array-agg.test.ts +0 -42
- package/src/util/array-agg.ts +0 -44
- package/src/util/assertion-util.ts +0 -1
- package/src/util/if-any.ts +0 -3
- package/src/util/lazy-property.ts +0 -14
- package/src/util/memoize.ts +0 -37
- package/tsconfig.build.json +0 -12
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -8
package/src/core/schema.ts
DELETED
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
import { StandardSchemaV1 } from '@standard-schema/spec'
|
|
2
|
-
import { lazyProperty } from '../util/lazy-property.js'
|
|
3
|
-
import { StandardSchemaAdapter } from './standard-schema.js'
|
|
4
|
-
import {
|
|
5
|
-
InferInput,
|
|
6
|
-
InferOutput,
|
|
7
|
-
ValidationContext,
|
|
8
|
-
ValidationOptions,
|
|
9
|
-
ValidationResult,
|
|
10
|
-
Validator,
|
|
11
|
-
} from './validator.js'
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Options for parsing operations.
|
|
15
|
-
* Excludes the `mode` option as it is implicitly set to `"parse"`.
|
|
16
|
-
*/
|
|
17
|
-
export type ParseOptions = Omit<ValidationOptions, 'mode'>
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Options for validation operations.
|
|
21
|
-
* Excludes the `mode` option as it is implicitly set to `"validate"`.
|
|
22
|
-
*/
|
|
23
|
-
export type ValidateOptions = Omit<ValidationOptions, 'mode'>
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Internal type structure for schema type inference.
|
|
27
|
-
*
|
|
28
|
-
* This interface defines the phantom types used for compile-time type inference
|
|
29
|
-
* without affecting runtime behavior. The `input` and `output` properties
|
|
30
|
-
* represent the expected input type during validation and the resulting output
|
|
31
|
-
* type after parsing, respectively.
|
|
32
|
-
*
|
|
33
|
-
* @typeParam TInput - The type accepted as input during validation
|
|
34
|
-
* @typeParam TOutput - The type returned after parsing (may differ from input due to coercion)
|
|
35
|
-
*/
|
|
36
|
-
export interface SchemaInternals<out TInput = unknown, out TOutput = TInput> {
|
|
37
|
-
input: TInput
|
|
38
|
-
output: TOutput
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Abstract base class for all schema validators in the lexicon system.
|
|
43
|
-
*
|
|
44
|
-
* This class provides the standard validation interface that all schema types
|
|
45
|
-
* implement. It offers multiple methods for validating and parsing data:
|
|
46
|
-
*
|
|
47
|
-
* - **Assertion methods**: `assert()`, `check()` - throw on invalid input
|
|
48
|
-
* - **Type guard methods**: `matches()`, `ifMatches()` - return boolean or optional value
|
|
49
|
-
* - **Parse methods**: `parse()`, `safeParse()` - allow value transformation/coercion
|
|
50
|
-
* - **Validate methods**: `validate()`, `safeValidate()` - validation without coercion
|
|
51
|
-
*
|
|
52
|
-
* All methods are also available with a `$` prefix (e.g., `$parse()`, `$validate()`)
|
|
53
|
-
* for consistent access in generated lexicon namespaces.
|
|
54
|
-
*
|
|
55
|
-
* @typeParam TInput - The type accepted as valid input during validation
|
|
56
|
-
* @typeParam TOutput - The type returned after parsing (may include transformations)
|
|
57
|
-
*
|
|
58
|
-
* @example
|
|
59
|
-
* ```typescript
|
|
60
|
-
* class MySchema extends Schema<string> {
|
|
61
|
-
* validateInContext(input: unknown, ctx: ValidationContext): ValidationResult {
|
|
62
|
-
* if (typeof input !== 'string') {
|
|
63
|
-
* return ctx.issueUnexpectedType(input, 'string')
|
|
64
|
-
* }
|
|
65
|
-
* return ctx.success(input)
|
|
66
|
-
* }
|
|
67
|
-
* }
|
|
68
|
-
*
|
|
69
|
-
* const schema = new MySchema()
|
|
70
|
-
* schema.assert('hello') // OK
|
|
71
|
-
* schema.assert(123) // Throws LexValidationError
|
|
72
|
-
* schema.matches('hello') // true
|
|
73
|
-
* schema.matches(123) // false
|
|
74
|
-
* ```
|
|
75
|
-
*/
|
|
76
|
-
export abstract class Schema<out TInput = unknown, out TOutput = TInput>
|
|
77
|
-
implements Validator<TInput, TOutput>, StandardSchemaV1<TInput, TOutput>
|
|
78
|
-
{
|
|
79
|
-
/**
|
|
80
|
-
* Internal phantom property for type inference.
|
|
81
|
-
* This property does not exist at runtime.
|
|
82
|
-
*
|
|
83
|
-
* @internal
|
|
84
|
-
*/
|
|
85
|
-
declare readonly ['__lex']: SchemaInternals<TInput, TOutput>
|
|
86
|
-
|
|
87
|
-
get '~standard'(): StandardSchemaV1.Props<TInput, TOutput> {
|
|
88
|
-
// Lazily create, and cache, the Standard Schema adapter for this schema
|
|
89
|
-
// instance.
|
|
90
|
-
return lazyProperty(this, '~standard', new StandardSchemaAdapter(this))
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Needed to discriminate multiple schema types when used in unions. Without
|
|
94
|
-
// this, Typescript could allow an EnumSchema<"foo" | "bar"> to be used where
|
|
95
|
-
// a StringSchema is expected, since they would both be structurally
|
|
96
|
-
// compatible.
|
|
97
|
-
abstract readonly type: string
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Performs validation of the input value within a validation context.
|
|
101
|
-
*
|
|
102
|
-
* This method must be implemented by subclasses to define the actual
|
|
103
|
-
* validation logic. It should not be called directly; use
|
|
104
|
-
* {@link ValidationContext.validate} instead to ensure proper mode enforcement.
|
|
105
|
-
*
|
|
106
|
-
* @param input - The value to validate
|
|
107
|
-
* @param ctx - The validation context providing path tracking and issue reporting
|
|
108
|
-
* @returns A validation result indicating success with the validated value or failure with issues
|
|
109
|
-
*
|
|
110
|
-
* @internal
|
|
111
|
-
*/
|
|
112
|
-
abstract validateInContext(
|
|
113
|
-
input: unknown,
|
|
114
|
-
ctx: ValidationContext,
|
|
115
|
-
): ValidationResult
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* @note use {@link check}() instead of {@link assert}() if you encounter a
|
|
119
|
-
* `ts(2775)` error and you are not able to fully type the validator. This
|
|
120
|
-
* will typically arise in generic contexts, where the narrowed type is not
|
|
121
|
-
* needed.
|
|
122
|
-
*/
|
|
123
|
-
assert(
|
|
124
|
-
input: unknown,
|
|
125
|
-
options?: ValidateOptions,
|
|
126
|
-
): asserts input is InferInput<this> {
|
|
127
|
-
const result = this.safeValidate(input, options)
|
|
128
|
-
if (!result.success) throw result.reason
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Alias for {@link assert}(). Most useful in generic contexts where the
|
|
133
|
-
* validator is not exactly typed, allowing to avoid "_Assertions require
|
|
134
|
-
* every name in the call target to be declared with an explicit type
|
|
135
|
-
* annotation. ts(2775)_" errors.
|
|
136
|
-
*/
|
|
137
|
-
check(input: unknown, options?: ValidateOptions): void {
|
|
138
|
-
this.assert(input, options)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Casts the input (by validating it) to the output type if it matches the
|
|
143
|
-
* schema, otherwise throws. This is the same as calling {@link parse}() with
|
|
144
|
-
* `mode: "validate"`.
|
|
145
|
-
*/
|
|
146
|
-
cast<I>(input: I, options?: ValidateOptions): I & InferInput<this> {
|
|
147
|
-
const result = this.safeValidate(input, options)
|
|
148
|
-
if (result.success) return result.value
|
|
149
|
-
throw result.reason
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Type guard that checks if the input matches this schema.
|
|
154
|
-
*
|
|
155
|
-
* @example
|
|
156
|
-
* ```typescript
|
|
157
|
-
* if (schema.matches(data)) {
|
|
158
|
-
* // data is narrowed to the schema's input type
|
|
159
|
-
* console.log(data)
|
|
160
|
-
* }
|
|
161
|
-
* ```
|
|
162
|
-
*/
|
|
163
|
-
matches<I>(
|
|
164
|
-
input: I,
|
|
165
|
-
options?: ValidateOptions,
|
|
166
|
-
): input is I & InferInput<this> {
|
|
167
|
-
const result = this.safeValidate(input, options)
|
|
168
|
-
return result.success
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Returns the input if it matches this schema, otherwise returns `undefined`.
|
|
173
|
-
*
|
|
174
|
-
* This is useful for optional filtering operations where you want to
|
|
175
|
-
* conditionally extract values that match a schema.
|
|
176
|
-
*
|
|
177
|
-
* @example
|
|
178
|
-
* ```typescript
|
|
179
|
-
* const validData = schema.ifMatches(data)
|
|
180
|
-
* if (validData !== undefined) {
|
|
181
|
-
* // validData is the schema's input type
|
|
182
|
-
* console.log(validData)
|
|
183
|
-
* }
|
|
184
|
-
* ```
|
|
185
|
-
*/
|
|
186
|
-
ifMatches<I>(
|
|
187
|
-
input: I,
|
|
188
|
-
options?: ValidateOptions,
|
|
189
|
-
): (I & InferInput<this>) | undefined {
|
|
190
|
-
return this.matches(input, options) ? input : undefined
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Parses the input, allowing value transformations and coercion.
|
|
195
|
-
*
|
|
196
|
-
* Unlike {@link validate}, this method allows the schema to transform
|
|
197
|
-
* the input value (e.g., applying default values, type coercion).
|
|
198
|
-
* Throws a {@link LexValidationError} if the input is invalid.
|
|
199
|
-
*
|
|
200
|
-
* @param input - The value to parse
|
|
201
|
-
* @param options - Optional parsing configuration
|
|
202
|
-
* @returns The parsed and potentially transformed value
|
|
203
|
-
* @throws {LexValidationError} If the input fails validation
|
|
204
|
-
*
|
|
205
|
-
* @example
|
|
206
|
-
* ```typescript
|
|
207
|
-
* const result = schema.parse(rawData)
|
|
208
|
-
* // result has defaults applied and is fully typed
|
|
209
|
-
* ```
|
|
210
|
-
*/
|
|
211
|
-
parse(input: unknown, options?: ParseOptions): InferOutput<this> {
|
|
212
|
-
const result = this.safeParse(input, options)
|
|
213
|
-
if (result.success) return result.value
|
|
214
|
-
throw result.reason
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Safely parses the input without throwing, returning a result object.
|
|
219
|
-
*
|
|
220
|
-
* This method allows value transformations like {@link parse}, but
|
|
221
|
-
* returns a discriminated union result instead of throwing on error.
|
|
222
|
-
*
|
|
223
|
-
* @param input - The value to parse
|
|
224
|
-
* @param options - Optional parsing configuration
|
|
225
|
-
* @returns A {@link ValidationResult} with either the parsed value or validation errors
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* ```typescript
|
|
229
|
-
* const result = schema.safeParse(data)
|
|
230
|
-
* if (result.success) {
|
|
231
|
-
* console.log(result.value)
|
|
232
|
-
* } else {
|
|
233
|
-
* console.error(result.reason.issues)
|
|
234
|
-
* }
|
|
235
|
-
* ```
|
|
236
|
-
*/
|
|
237
|
-
safeParse(
|
|
238
|
-
input: unknown,
|
|
239
|
-
options?: ParseOptions,
|
|
240
|
-
): ValidationResult<InferOutput<this>> {
|
|
241
|
-
return ValidationContext.validate(input, this, {
|
|
242
|
-
...options,
|
|
243
|
-
mode: 'parse',
|
|
244
|
-
})
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Validates the input strictly without allowing transformations.
|
|
249
|
-
*
|
|
250
|
-
* Unlike {@link parse}, this method requires the input to exactly match
|
|
251
|
-
* the schema without any transformations (no defaults applied, no coercion).
|
|
252
|
-
* Throws a {@link LexValidationError} if the input is invalid or would require transformation.
|
|
253
|
-
*
|
|
254
|
-
* @typeParam I - The input type (preserved in the return type)
|
|
255
|
-
* @param input - The value to validate
|
|
256
|
-
* @param options - Optional validation configuration
|
|
257
|
-
* @returns The validated input with narrowed type
|
|
258
|
-
* @throws {LexValidationError} If the input fails validation or requires transformation
|
|
259
|
-
*
|
|
260
|
-
* @example
|
|
261
|
-
* ```typescript
|
|
262
|
-
* const validated = schema.validate(data)
|
|
263
|
-
* // validated is typed as the intersection of input type and schema type
|
|
264
|
-
* ```
|
|
265
|
-
*/
|
|
266
|
-
validate<I>(input: I, options?: ValidateOptions): I & InferInput<this> {
|
|
267
|
-
const result = this.safeValidate(input, options)
|
|
268
|
-
if (result.success) return result.value
|
|
269
|
-
throw result.reason
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Safely validates the input without throwing, returning a result object.
|
|
274
|
-
*
|
|
275
|
-
* This method performs strict validation like {@link validate}, but
|
|
276
|
-
* returns a discriminated union result instead of throwing on error.
|
|
277
|
-
*
|
|
278
|
-
* @typeParam I - The input type (preserved in the result value type)
|
|
279
|
-
* @param input - The value to validate
|
|
280
|
-
* @param options - Optional validation configuration
|
|
281
|
-
* @returns A {@link ValidationResult} with either the validated value or validation errors
|
|
282
|
-
*
|
|
283
|
-
* @example
|
|
284
|
-
* ```typescript
|
|
285
|
-
* const result = schema.safeValidate(data)
|
|
286
|
-
* if (result.success) {
|
|
287
|
-
* console.log(result.value)
|
|
288
|
-
* } else {
|
|
289
|
-
* console.error(result.reason.issues)
|
|
290
|
-
* }
|
|
291
|
-
* ```
|
|
292
|
-
*/
|
|
293
|
-
safeValidate<I>(
|
|
294
|
-
input: I,
|
|
295
|
-
options?: ValidateOptions,
|
|
296
|
-
): ValidationResult<I & InferInput<this>> {
|
|
297
|
-
return ValidationContext.validate(input, this, {
|
|
298
|
-
...options,
|
|
299
|
-
mode: 'validate',
|
|
300
|
-
})
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// @NOTE Dollar-prefixed aliases
|
|
304
|
-
//
|
|
305
|
-
// The `lex-builder` lib generates namespaced utility functions that allow
|
|
306
|
-
// accessing the schema's methods without the need to specify the ".main."
|
|
307
|
-
// part of the namespace. This allows utilities for a particular record type
|
|
308
|
-
// to be called like "app.bsky.feed.post.<utility>()" instead of
|
|
309
|
-
// "app.bsky.feed.post.main.<utility>()".
|
|
310
|
-
//
|
|
311
|
-
// Because those utilities could conflict with other schemas (e.g. if there is
|
|
312
|
-
// a lexicon definition with the same name as the "<utility>"), those exported
|
|
313
|
-
// utilities will be prefixed with "$".
|
|
314
|
-
//
|
|
315
|
-
// Similarly, since those utilities are defined as simple "const", they are
|
|
316
|
-
// also bound (using JS's .bind) to the schema instance, so that they can be
|
|
317
|
-
// used without worrying about the context (e.g. "app.bsky.feed.post.$parse()"
|
|
318
|
-
// will work regardless of how it is imported or called).
|
|
319
|
-
//
|
|
320
|
-
// In order to provide the same functionalities for non-main definitions, we
|
|
321
|
-
// also define those aliases directly on the schema instance, so that they can
|
|
322
|
-
// be used in the same way as the utilities generated by "lex-builder". For
|
|
323
|
-
// example, if there is a non-main definition "app.bsky.feed.defs.postView",
|
|
324
|
-
// it will also be possible to call "app.bsky.feed.defs.postView.$parse()".
|
|
325
|
-
//
|
|
326
|
-
// These methods are also "bound" to the instance so that they can be used
|
|
327
|
-
// exactly like the utilities generated by "lex-builder", without worrying
|
|
328
|
-
// about the context.
|
|
329
|
-
//
|
|
330
|
-
// There are two ways we could "bind" those methods to the instance:
|
|
331
|
-
// 1. Define them as getters that return the bound method (e.g. get $parse() {
|
|
332
|
-
// return this.parse.bind(this) })
|
|
333
|
-
// 2. Define them as properties that are initialized in the constructor (e.g.
|
|
334
|
-
// this.$parse = this.parse.bind(this))
|
|
335
|
-
//
|
|
336
|
-
// Since a **lot** of those methods would end-up being created in systems that
|
|
337
|
-
// contains many schemas (e.g. the appview), we choose the first approach
|
|
338
|
-
// (getters) in order to avoid the overhead of creating all those bound
|
|
339
|
-
// functions upfront when instantiating the schemas.
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Bound alias for {@link assert} for compatibility with generated utilities.
|
|
343
|
-
* @see {@link assert}
|
|
344
|
-
*/
|
|
345
|
-
get $assert(): typeof this.assert {
|
|
346
|
-
return lazyProperty(this, '$assert', this.assert.bind(this))
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Bound alias for {@link check} for compatibility with generated utilities.
|
|
351
|
-
* @see {@link check}
|
|
352
|
-
*/
|
|
353
|
-
get $check(): typeof this.check {
|
|
354
|
-
return lazyProperty(this, '$check', this.check.bind(this))
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Bound alias for {@link cast} for compatibility with generated utilities.
|
|
359
|
-
* @see {@link cast}
|
|
360
|
-
*/
|
|
361
|
-
get $cast(): typeof this.cast {
|
|
362
|
-
return lazyProperty(this, '$cast', this.cast.bind(this))
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* Bound alias for {@link matches} for compatibility with generated utilities.
|
|
367
|
-
* @see {@link matches}
|
|
368
|
-
*/
|
|
369
|
-
get $matches(): typeof this.matches {
|
|
370
|
-
return lazyProperty(this, '$matches', this.matches.bind(this))
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/**
|
|
374
|
-
* Bound alias for {@link ifMatches} for compatibility with generated utilities.
|
|
375
|
-
* @see {@link ifMatches}
|
|
376
|
-
*/
|
|
377
|
-
get $ifMatches(): typeof this.ifMatches {
|
|
378
|
-
return lazyProperty(this, '$ifMatches', this.ifMatches.bind(this))
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
/**
|
|
382
|
-
* Bound alias for {@link parse} for compatibility with generated utilities.
|
|
383
|
-
* @see {@link parse}
|
|
384
|
-
*/
|
|
385
|
-
get $parse(): typeof this.parse {
|
|
386
|
-
return lazyProperty(this, '$parse', this.parse.bind(this))
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Bound alias for {@link safeParse} for compatibility with generated utilities.
|
|
391
|
-
* @see {@link safeParse}
|
|
392
|
-
*/
|
|
393
|
-
get $safeParse(): typeof this.safeParse {
|
|
394
|
-
return lazyProperty(this, '$safeParse', this.safeParse.bind(this))
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Bound alias for {@link validate} for compatibility with generated utilities.
|
|
399
|
-
* @see {@link validate}
|
|
400
|
-
*/
|
|
401
|
-
get $validate(): typeof this.validate {
|
|
402
|
-
return lazyProperty(this, '$validate', this.validate.bind(this))
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
/**
|
|
406
|
-
* Bound alias for {@link safeValidate} for compatibility with generated utilities.
|
|
407
|
-
* @see {@link safeValidate}
|
|
408
|
-
*/
|
|
409
|
-
get $safeValidate(): typeof this.safeValidate {
|
|
410
|
-
return lazyProperty(this, '$safeValidate', this.safeValidate.bind(this))
|
|
411
|
-
}
|
|
412
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { assert, describe, expect, it } from 'vitest'
|
|
2
|
-
import { array } from '../schema/array.js'
|
|
3
|
-
import { integer } from '../schema/integer.js'
|
|
4
|
-
import { object } from '../schema/object.js'
|
|
5
|
-
import { optional } from '../schema/optional.js'
|
|
6
|
-
import { string } from '../schema/string.js'
|
|
7
|
-
import { withDefault } from '../schema/with-default.js'
|
|
8
|
-
import { LexValidationError } from './validation-error.js'
|
|
9
|
-
|
|
10
|
-
describe('StandardSchemaAdapter', () => {
|
|
11
|
-
describe('metadata', () => {
|
|
12
|
-
const schema = integer()
|
|
13
|
-
|
|
14
|
-
it('has version 1', () => {
|
|
15
|
-
expect(schema['~standard'].version).toBe(1)
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
it('has vendor @atproto/lex-schema', () => {
|
|
19
|
-
expect(schema['~standard'].vendor).toBe('@atproto/lex-schema')
|
|
20
|
-
})
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
describe('lazy caching', () => {
|
|
24
|
-
it('returns the same adapter instance on repeated accesses', () => {
|
|
25
|
-
const schema = integer()
|
|
26
|
-
const first = schema['~standard']
|
|
27
|
-
const second = schema['~standard']
|
|
28
|
-
expect(first).toBe(second)
|
|
29
|
-
})
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
describe('validate() result shape on success', () => {
|
|
33
|
-
it('returns a value property for a valid integer', () => {
|
|
34
|
-
const result = integer()['~standard'].validate(42)
|
|
35
|
-
expect(result).toMatchObject({ value: 42 })
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
it('returns a value property for a valid string', () => {
|
|
39
|
-
const result = string()['~standard'].validate('hello')
|
|
40
|
-
expect(result).toMatchObject({ value: 'hello' })
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('does not include an issues property on success', () => {
|
|
44
|
-
const result = integer()['~standard'].validate(1)
|
|
45
|
-
expect(result).not.toHaveProperty('issues')
|
|
46
|
-
})
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
describe('validate() result shape on failure', () => {
|
|
50
|
-
it('returns a LexValidationError with issues for an invalid value', () => {
|
|
51
|
-
const result = integer()['~standard'].validate('not-a-number')
|
|
52
|
-
assert(result instanceof LexValidationError)
|
|
53
|
-
expect(Array.isArray(result.issues)).toBe(true)
|
|
54
|
-
expect(result.issues.length).toBeGreaterThan(0)
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
it('does not include a value property on failure', () => {
|
|
58
|
-
const result = integer()['~standard'].validate('not-a-number')
|
|
59
|
-
expect(result).not.toHaveProperty('value')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
describe('issues[].message', () => {
|
|
63
|
-
it('is a non-empty string', () => {
|
|
64
|
-
const result = integer()['~standard'].validate('not-a-number')
|
|
65
|
-
assert(result instanceof LexValidationError)
|
|
66
|
-
for (const issue of result.issues) {
|
|
67
|
-
expect(typeof issue.message).toBe('string')
|
|
68
|
-
expect(issue.message.length).toBeGreaterThan(0)
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('describes the type mismatch', () => {
|
|
73
|
-
const result = integer()['~standard'].validate('not-a-number')
|
|
74
|
-
assert(result instanceof LexValidationError)
|
|
75
|
-
expect(result.issues[0].message).toContain('integer')
|
|
76
|
-
})
|
|
77
|
-
})
|
|
78
|
-
|
|
79
|
-
describe('issues[].path', () => {
|
|
80
|
-
it('is an empty array for a root-level failure', () => {
|
|
81
|
-
const result = integer()['~standard'].validate('not-a-number')
|
|
82
|
-
assert(result instanceof LexValidationError)
|
|
83
|
-
expect(result.issues[0].path).toEqual([])
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
it('reflects the property key for a nested object failure', () => {
|
|
87
|
-
const schema = object({ age: integer() })
|
|
88
|
-
const result = schema['~standard'].validate({ age: 'not-a-number' })
|
|
89
|
-
assert(result instanceof LexValidationError)
|
|
90
|
-
expect(result.issues[0].path).toContain('age')
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('reflects the index for an array element failure', () => {
|
|
94
|
-
const schema = array(integer())
|
|
95
|
-
const result = schema['~standard'].validate([1, 'bad', 3])
|
|
96
|
-
assert(result instanceof LexValidationError)
|
|
97
|
-
expect(result.issues[0].path).toContain(1)
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
describe('parse mode (default value application)', () => {
|
|
103
|
-
it('applies default values when input is undefined', () => {
|
|
104
|
-
const schema = withDefault(integer(), 10)
|
|
105
|
-
const result = schema['~standard'].validate(undefined)
|
|
106
|
-
expect(result).toMatchObject({ value: 10 })
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
it('uses the provided value instead of default when input is present', () => {
|
|
110
|
-
const schema = withDefault(integer(), 10)
|
|
111
|
-
const result = schema['~standard'].validate(42)
|
|
112
|
-
expect(result).toMatchObject({ value: 42 })
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('applies defaults for optional object properties in parse mode', () => {
|
|
116
|
-
const schema = object({
|
|
117
|
-
name: string(),
|
|
118
|
-
count: optional(withDefault(integer(), 0)),
|
|
119
|
-
})
|
|
120
|
-
const result = schema['~standard'].validate({ name: 'Alice' })
|
|
121
|
-
expect(result).toMatchObject({ value: { name: 'Alice', count: 0 } })
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
})
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { StandardSchemaV1 } from '@standard-schema/spec'
|
|
2
|
-
import { ValidationContext, Validator } from './validator.js'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The Standard Schema adapter for {@link Validator} instances.
|
|
6
|
-
*/
|
|
7
|
-
export class StandardSchemaAdapter<TInput, TOutput>
|
|
8
|
-
implements StandardSchemaV1.Props<TInput, TOutput>
|
|
9
|
-
{
|
|
10
|
-
readonly version = 1
|
|
11
|
-
|
|
12
|
-
readonly vendor = '@atproto/lex-schema'
|
|
13
|
-
|
|
14
|
-
declare readonly types: StandardSchemaV1.Types<TInput, TOutput>
|
|
15
|
-
|
|
16
|
-
constructor(private readonly validator: Validator<TInput, TOutput>) {}
|
|
17
|
-
|
|
18
|
-
validate(
|
|
19
|
-
value: unknown,
|
|
20
|
-
options?: StandardSchemaV1.Options,
|
|
21
|
-
): StandardSchemaV1.Result<TOutput> {
|
|
22
|
-
// Perform validation in "parse" mode to ensure transformations (defaults,
|
|
23
|
-
// coercions, etc.) are applied. Also ensures that the output type is
|
|
24
|
-
// returned. Note that ValidationResult is compatible with
|
|
25
|
-
// StandardSchemaV1.Result :-)
|
|
26
|
-
return ValidationContext.validate(value, this.validator, {
|
|
27
|
-
...options?.libraryOptions,
|
|
28
|
-
mode: 'parse',
|
|
29
|
-
})
|
|
30
|
-
}
|
|
31
|
-
}
|