@atproto/lex-schema 0.0.8 → 0.0.10
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 +41 -0
- package/LICENSE.txt +1 -1
- package/dist/core/$type.d.ts +11 -0
- package/dist/core/$type.d.ts.map +1 -1
- package/dist/core/$type.js +4 -0
- package/dist/core/$type.js.map +1 -1
- package/dist/core/schema.d.ts +31 -24
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +38 -8
- package/dist/core/schema.js.map +1 -1
- package/dist/core/string-format.d.ts +35 -35
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js +49 -91
- package/dist/core/string-format.js.map +1 -1
- package/dist/core/validation-issue.js +1 -1
- package/dist/core/validation-issue.js.map +1 -1
- package/dist/core/validator.d.ts +53 -32
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +18 -22
- package/dist/core/validator.js.map +1 -1
- package/dist/external.d.ts +0 -85
- package/dist/external.d.ts.map +1 -1
- package/dist/external.js +0 -164
- package/dist/external.js.map +1 -1
- package/dist/helpers.d.ts +10 -5
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +3 -3
- package/dist/helpers.js.map +1 -1
- package/dist/schema/array.d.ts +9 -5
- package/dist/schema/array.d.ts.map +1 -1
- package/dist/schema/array.js +14 -5
- package/dist/schema/array.js.map +1 -1
- package/dist/schema/blob.d.ts +9 -7
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +9 -5
- package/dist/schema/blob.js.map +1 -1
- package/dist/schema/boolean.d.ts +3 -7
- package/dist/schema/boolean.d.ts.map +1 -1
- package/dist/schema/boolean.js +6 -7
- package/dist/schema/boolean.js.map +1 -1
- package/dist/schema/bytes.d.ts +3 -2
- package/dist/schema/bytes.d.ts.map +1 -1
- package/dist/schema/bytes.js +7 -3
- package/dist/schema/bytes.js.map +1 -1
- package/dist/schema/cid.d.ts +10 -8
- package/dist/schema/cid.d.ts.map +1 -1
- package/dist/schema/cid.js +5 -1
- package/dist/schema/cid.js.map +1 -1
- package/dist/schema/custom.d.ts +6 -5
- package/dist/schema/custom.d.ts.map +1 -1
- package/dist/schema/custom.js +10 -4
- package/dist/schema/custom.js.map +1 -1
- package/dist/schema/dict.d.ts +8 -8
- package/dist/schema/dict.d.ts.map +1 -1
- package/dist/schema/dict.js +11 -2
- package/dist/schema/dict.js.map +1 -1
- package/dist/schema/discriminated-union.d.ts +21 -14
- package/dist/schema/discriminated-union.d.ts.map +1 -1
- package/dist/schema/discriminated-union.js +7 -0
- package/dist/schema/discriminated-union.js.map +1 -1
- package/dist/schema/enum.d.ts +7 -9
- package/dist/schema/enum.d.ts.map +1 -1
- package/dist/schema/enum.js +8 -4
- package/dist/schema/enum.js.map +1 -1
- package/dist/schema/integer.d.ts +5 -5
- package/dist/schema/integer.d.ts.map +1 -1
- package/dist/schema/integer.js +9 -5
- package/dist/schema/integer.js.map +1 -1
- package/dist/schema/intersection.d.ts +4 -4
- package/dist/schema/intersection.d.ts.map +1 -1
- package/dist/schema/intersection.js +5 -0
- package/dist/schema/intersection.js.map +1 -1
- package/dist/schema/literal.d.ts +6 -9
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +7 -4
- package/dist/schema/literal.js.map +1 -1
- package/dist/schema/never.d.ts +3 -2
- package/dist/schema/never.d.ts.map +1 -1
- package/dist/schema/never.js +5 -1
- package/dist/schema/never.js.map +1 -1
- package/dist/schema/null.d.ts +4 -3
- package/dist/schema/null.d.ts.map +1 -1
- package/dist/schema/null.js +6 -4
- package/dist/schema/null.js.map +1 -1
- package/dist/schema/nullable.d.ts +6 -5
- package/dist/schema/nullable.d.ts.map +1 -1
- package/dist/schema/nullable.js +9 -5
- package/dist/schema/nullable.js.map +1 -1
- package/dist/schema/object.d.ts +10 -8
- package/dist/schema/object.d.ts.map +1 -1
- package/dist/schema/object.js +11 -3
- package/dist/schema/object.js.map +1 -1
- package/dist/schema/optional.d.ts +7 -5
- package/dist/schema/optional.d.ts.map +1 -1
- package/dist/schema/optional.js +14 -6
- package/dist/schema/optional.js.map +1 -1
- package/dist/schema/params.d.ts +24 -13
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +47 -25
- package/dist/schema/params.js.map +1 -1
- package/dist/schema/payload.d.ts +12 -9
- package/dist/schema/payload.d.ts.map +1 -1
- package/dist/schema/payload.js +11 -0
- package/dist/schema/payload.js.map +1 -1
- package/dist/schema/permission-set.d.ts +1 -0
- package/dist/schema/permission-set.d.ts.map +1 -1
- package/dist/schema/permission-set.js +5 -0
- package/dist/schema/permission-set.js.map +1 -1
- package/dist/schema/permission.d.ts +6 -5
- package/dist/schema/permission.d.ts.map +1 -1
- package/dist/schema/permission.js +5 -0
- package/dist/schema/permission.js.map +1 -1
- package/dist/schema/procedure.d.ts +2 -1
- package/dist/schema/procedure.d.ts.map +1 -1
- package/dist/schema/procedure.js +5 -0
- package/dist/schema/procedure.js.map +1 -1
- package/dist/schema/query.d.ts +2 -1
- package/dist/schema/query.d.ts.map +1 -1
- package/dist/schema/query.js +5 -0
- package/dist/schema/query.js.map +1 -1
- package/dist/schema/record.d.ts +48 -30
- package/dist/schema/record.d.ts.map +1 -1
- package/dist/schema/record.js +12 -9
- package/dist/schema/record.js.map +1 -1
- package/dist/schema/ref.d.ts +9 -6
- package/dist/schema/ref.d.ts.map +1 -1
- package/dist/schema/ref.js +9 -16
- package/dist/schema/ref.js.map +1 -1
- package/dist/schema/refine.d.ts +4 -4
- package/dist/schema/refine.d.ts.map +1 -1
- package/dist/schema/refine.js.map +1 -1
- package/dist/schema/regexp.d.ts +4 -3
- package/dist/schema/regexp.d.ts.map +1 -1
- package/dist/schema/regexp.js +5 -0
- package/dist/schema/regexp.js.map +1 -1
- package/dist/schema/string.d.ts +7 -8
- package/dist/schema/string.d.ts.map +1 -1
- package/dist/schema/string.js +13 -19
- package/dist/schema/string.js.map +1 -1
- package/dist/schema/subscription.d.ts +2 -1
- package/dist/schema/subscription.d.ts.map +1 -1
- package/dist/schema/subscription.js +5 -0
- package/dist/schema/subscription.js.map +1 -1
- package/dist/schema/token.d.ts +6 -5
- package/dist/schema/token.d.ts.map +1 -1
- package/dist/schema/token.js +5 -0
- package/dist/schema/token.js.map +1 -1
- package/dist/schema/typed-object.d.ts +43 -26
- package/dist/schema/typed-object.d.ts.map +1 -1
- package/dist/schema/typed-object.js +6 -3
- package/dist/schema/typed-object.js.map +1 -1
- package/dist/schema/typed-ref.d.ts +16 -25
- package/dist/schema/typed-ref.d.ts.map +1 -1
- package/dist/schema/typed-ref.js +7 -17
- package/dist/schema/typed-ref.js.map +1 -1
- package/dist/schema/typed-union.d.ts +9 -21
- package/dist/schema/typed-union.d.ts.map +1 -1
- package/dist/schema/typed-union.js +15 -11
- package/dist/schema/typed-union.js.map +1 -1
- package/dist/schema/union.d.ts +6 -6
- package/dist/schema/union.d.ts.map +1 -1
- package/dist/schema/union.js +7 -5
- package/dist/schema/union.js.map +1 -1
- package/dist/schema/unknown-object.d.ts +5 -4
- package/dist/schema/unknown-object.d.ts.map +1 -1
- package/dist/schema/unknown-object.js +5 -1
- package/dist/schema/unknown-object.js.map +1 -1
- package/dist/schema/unknown.d.ts +3 -2
- package/dist/schema/unknown.d.ts.map +1 -1
- package/dist/schema/unknown.js +5 -1
- package/dist/schema/unknown.js.map +1 -1
- package/dist/schema/with-default.d.ts +9 -0
- package/dist/schema/with-default.d.ts.map +1 -0
- package/dist/schema/with-default.js +27 -0
- package/dist/schema/with-default.js.map +1 -0
- package/dist/schema.d.ts +2 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -4
- package/dist/schema.js.map +1 -1
- package/dist/util/assertion-util.d.ts +0 -6
- package/dist/util/assertion-util.d.ts.map +1 -1
- package/dist/util/assertion-util.js +0 -28
- package/dist/util/assertion-util.js.map +1 -1
- package/dist/util/memoize.d.ts +2 -2
- package/dist/util/memoize.d.ts.map +1 -1
- package/dist/util/memoize.js +23 -39
- package/dist/util/memoize.js.map +1 -1
- package/package.json +3 -3
- package/src/core/$type.test.ts +20 -0
- package/src/core/$type.ts +30 -0
- package/src/core/schema.ts +86 -38
- package/src/core/string-format.ts +119 -158
- package/src/core/validation-issue.ts +1 -1
- package/src/core/validator.ts +93 -53
- package/src/external.ts +0 -404
- package/src/helpers.test.ts +22 -21
- package/src/helpers.ts +14 -14
- package/src/schema/array.test.ts +38 -40
- package/src/schema/array.ts +35 -13
- package/src/schema/blob.test.ts +21 -21
- package/src/schema/blob.ts +19 -17
- package/src/schema/boolean.test.ts +9 -8
- package/src/schema/boolean.ts +7 -13
- package/src/schema/bytes.test.ts +13 -13
- package/src/schema/bytes.ts +13 -8
- package/src/schema/cid.test.ts +3 -3
- package/src/schema/cid.ts +15 -13
- package/src/schema/custom.test.ts +26 -26
- package/src/schema/custom.ts +20 -13
- package/src/schema/dict.test.ts +21 -39
- package/src/schema/dict.ts +28 -19
- package/src/schema/discriminated-union.test.ts +128 -128
- package/src/schema/discriminated-union.ts +45 -26
- package/src/schema/enum.test.ts +17 -16
- package/src/schema/enum.ts +16 -16
- package/src/schema/integer.test.ts +22 -21
- package/src/schema/integer.ts +12 -9
- package/src/schema/intersection.test.ts +10 -10
- package/src/schema/intersection.ts +17 -14
- package/src/schema/literal.test.ts +35 -34
- package/src/schema/literal.ts +12 -15
- package/src/schema/never.test.ts +5 -5
- package/src/schema/never.ts +7 -2
- package/src/schema/null.test.ts +3 -3
- package/src/schema/null.ts +9 -9
- package/src/schema/nullable.test.ts +31 -42
- package/src/schema/nullable.ts +17 -9
- package/src/schema/object.test.ts +10 -12
- package/src/schema/object.ts +27 -18
- package/src/schema/optional.test.ts +21 -28
- package/src/schema/optional.ts +27 -10
- package/src/schema/params.test.ts +471 -47
- package/src/schema/params.ts +72 -38
- package/src/schema/payload.test.ts +150 -156
- package/src/schema/payload.ts +35 -19
- package/src/schema/permission-set.test.ts +206 -273
- package/src/schema/permission-set.ts +8 -0
- package/src/schema/permission.test.ts +177 -177
- package/src/schema/permission.ts +13 -5
- package/src/schema/procedure.test.ts +183 -242
- package/src/schema/procedure.ts +18 -5
- package/src/schema/query.test.ts +186 -200
- package/src/schema/query.ts +16 -4
- package/src/schema/record.test.ts +121 -101
- package/src/schema/record.ts +74 -40
- package/src/schema/ref.test.ts +101 -118
- package/src/schema/ref.ts +33 -28
- package/src/schema/refine.test.ts +28 -28
- package/src/schema/refine.ts +23 -20
- package/src/schema/regexp.test.ts +29 -33
- package/src/schema/regexp.ts +11 -7
- package/src/schema/string.test.ts +35 -35
- package/src/schema/string.ts +24 -33
- package/src/schema/subscription.test.ts +259 -387
- package/src/schema/subscription.ts +16 -4
- package/src/schema/token.test.ts +47 -324
- package/src/schema/token.ts +14 -7
- package/src/schema/typed-object.test.ts +98 -81
- package/src/schema/typed-object.ts +68 -33
- package/src/schema/typed-ref.test.ts +206 -234
- package/src/schema/typed-ref.ts +40 -42
- package/src/schema/typed-union.test.ts +40 -64
- package/src/schema/typed-union.ts +36 -58
- package/src/schema/union.test.ts +17 -27
- package/src/schema/union.ts +20 -16
- package/src/schema/unknown-object.test.ts +8 -8
- package/src/schema/unknown-object.ts +9 -7
- package/src/schema/unknown.test.ts +4 -4
- package/src/schema/unknown.ts +7 -5
- package/src/schema/with-default.ts +35 -0
- package/src/schema.ts +2 -6
- package/src/util/assertion-util.ts +0 -39
- package/src/util/memoize.ts +26 -46
- package/dist/schema/_parameters.d.ts +0 -17
- package/dist/schema/_parameters.d.ts.map +0 -1
- package/dist/schema/_parameters.js +0 -20
- package/dist/schema/_parameters.js.map +0 -1
- package/src/schema/_parameters.test.ts +0 -417
- package/src/schema/_parameters.ts +0 -26
package/src/schema/null.test.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
2
|
+
import { nullSchema } from './null.js'
|
|
3
3
|
|
|
4
4
|
describe('NullSchema', () => {
|
|
5
5
|
describe('basic validation', () => {
|
|
6
|
-
const schema =
|
|
6
|
+
const schema = nullSchema()
|
|
7
7
|
|
|
8
8
|
it('validates null', () => {
|
|
9
9
|
const result = schema.safeParse(null)
|
|
@@ -50,7 +50,7 @@ describe('NullSchema', () => {
|
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
describe('edge cases', () => {
|
|
53
|
-
const schema =
|
|
53
|
+
const schema = nullSchema()
|
|
54
54
|
|
|
55
55
|
it('rejects falsy values', () => {
|
|
56
56
|
const result = schema.safeParse(0)
|
package/src/schema/null.ts
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
import { Schema,
|
|
1
|
+
import { Schema, ValidationContext } from '../core.js'
|
|
2
|
+
import { memoizedOptions } from '../util/memoize.js'
|
|
2
3
|
|
|
3
4
|
export class NullSchema extends Schema<null> {
|
|
4
|
-
|
|
5
|
-
super()
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
validateInContext(
|
|
9
|
-
input: unknown,
|
|
10
|
-
ctx: ValidatorContext,
|
|
11
|
-
): ValidationResult<null> {
|
|
5
|
+
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
12
6
|
if (input !== null) {
|
|
13
7
|
return ctx.issueInvalidType(input, 'null')
|
|
14
8
|
}
|
|
@@ -16,3 +10,9 @@ export class NullSchema extends Schema<null> {
|
|
|
16
10
|
return ctx.success(null)
|
|
17
11
|
}
|
|
18
12
|
}
|
|
13
|
+
|
|
14
|
+
export const nullSchema = /*#__PURE__*/ memoizedOptions(function () {
|
|
15
|
+
return new NullSchema()
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
export { nullSchema as null }
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { enumSchema } from './enum.js'
|
|
3
|
+
import { integer } from './integer.js'
|
|
4
|
+
import { nullable } from './nullable.js'
|
|
5
|
+
import { object } from './object.js'
|
|
6
|
+
import { string } from './string.js'
|
|
7
|
+
import { withDefault } from './with-default.js'
|
|
7
8
|
|
|
8
9
|
describe('NullableSchema', () => {
|
|
9
10
|
describe('with StringSchema', () => {
|
|
10
|
-
const schema =
|
|
11
|
+
const schema = nullable(string())
|
|
11
12
|
|
|
12
13
|
it('validates null', () => {
|
|
13
14
|
const result = schema.safeParse(null)
|
|
@@ -57,7 +58,7 @@ describe('NullableSchema', () => {
|
|
|
57
58
|
})
|
|
58
59
|
|
|
59
60
|
describe('with IntegerSchema', () => {
|
|
60
|
-
const schema =
|
|
61
|
+
const schema = nullable(integer())
|
|
61
62
|
|
|
62
63
|
it('validates null', () => {
|
|
63
64
|
const result = schema.safeParse(null)
|
|
@@ -102,7 +103,7 @@ describe('NullableSchema', () => {
|
|
|
102
103
|
})
|
|
103
104
|
|
|
104
105
|
describe('with EnumSchema', () => {
|
|
105
|
-
const schema =
|
|
106
|
+
const schema = nullable(enumSchema(['red', 'green', 'blue']))
|
|
106
107
|
|
|
107
108
|
it('validates null', () => {
|
|
108
109
|
const result = schema.safeParse(null)
|
|
@@ -135,9 +136,7 @@ describe('NullableSchema', () => {
|
|
|
135
136
|
})
|
|
136
137
|
|
|
137
138
|
describe('with constrained StringSchema', () => {
|
|
138
|
-
const schema =
|
|
139
|
-
new StringSchema({ minLength: 3, maxLength: 10 }),
|
|
140
|
-
)
|
|
139
|
+
const schema = nullable(string({ minLength: 3, maxLength: 10 }))
|
|
141
140
|
|
|
142
141
|
it('validates null', () => {
|
|
143
142
|
const result = schema.safeParse(null)
|
|
@@ -171,9 +170,7 @@ describe('NullableSchema', () => {
|
|
|
171
170
|
})
|
|
172
171
|
|
|
173
172
|
describe('with constrained IntegerSchema', () => {
|
|
174
|
-
const schema =
|
|
175
|
-
new IntegerSchema({ minimum: 0, maximum: 100 }),
|
|
176
|
-
)
|
|
173
|
+
const schema = nullable(integer({ minimum: 0, maximum: 100 }))
|
|
177
174
|
|
|
178
175
|
it('validates null', () => {
|
|
179
176
|
const result = schema.safeParse(null)
|
|
@@ -207,7 +204,7 @@ describe('NullableSchema', () => {
|
|
|
207
204
|
})
|
|
208
205
|
|
|
209
206
|
describe('with StringSchema having default value', () => {
|
|
210
|
-
const schema =
|
|
207
|
+
const schema = nullable(withDefault(string(), 'default'))
|
|
211
208
|
|
|
212
209
|
it('validates null explicitly', () => {
|
|
213
210
|
const result = schema.safeParse(null)
|
|
@@ -235,10 +232,10 @@ describe('NullableSchema', () => {
|
|
|
235
232
|
})
|
|
236
233
|
|
|
237
234
|
describe('with ObjectSchema', () => {
|
|
238
|
-
const schema =
|
|
239
|
-
|
|
240
|
-
name:
|
|
241
|
-
age:
|
|
235
|
+
const schema = nullable(
|
|
236
|
+
object({
|
|
237
|
+
name: string(),
|
|
238
|
+
age: integer(),
|
|
242
239
|
}),
|
|
243
240
|
)
|
|
244
241
|
|
|
@@ -277,7 +274,7 @@ describe('NullableSchema', () => {
|
|
|
277
274
|
})
|
|
278
275
|
|
|
279
276
|
describe('nested nullable schemas', () => {
|
|
280
|
-
const schema =
|
|
277
|
+
const schema = nullable(nullable(string()))
|
|
281
278
|
|
|
282
279
|
it('validates null at outer level', () => {
|
|
283
280
|
const result = schema.safeParse(null)
|
|
@@ -307,7 +304,7 @@ describe('NullableSchema', () => {
|
|
|
307
304
|
})
|
|
308
305
|
|
|
309
306
|
describe('with StringSchema format constraints', () => {
|
|
310
|
-
const schema =
|
|
307
|
+
const schema = nullable(string({ format: 'uri' }))
|
|
311
308
|
|
|
312
309
|
it('validates null', () => {
|
|
313
310
|
const result = schema.safeParse(null)
|
|
@@ -331,7 +328,7 @@ describe('NullableSchema', () => {
|
|
|
331
328
|
})
|
|
332
329
|
|
|
333
330
|
describe('edge cases', () => {
|
|
334
|
-
const stringSchema =
|
|
331
|
+
const stringSchema = nullable(string())
|
|
335
332
|
|
|
336
333
|
it('handles null correctly without coercion', () => {
|
|
337
334
|
const result = stringSchema.safeParse(null)
|
|
@@ -366,7 +363,7 @@ describe('NullableSchema', () => {
|
|
|
366
363
|
|
|
367
364
|
describe('type preservation', () => {
|
|
368
365
|
it('preserves string type for valid strings', () => {
|
|
369
|
-
const schema =
|
|
366
|
+
const schema = nullable(string())
|
|
370
367
|
const result = schema.safeParse('test')
|
|
371
368
|
expect(result.success).toBe(true)
|
|
372
369
|
if (result.success) {
|
|
@@ -376,7 +373,7 @@ describe('NullableSchema', () => {
|
|
|
376
373
|
})
|
|
377
374
|
|
|
378
375
|
it('preserves number type for valid integers', () => {
|
|
379
|
-
const schema =
|
|
376
|
+
const schema = nullable(integer())
|
|
380
377
|
const result = schema.safeParse(42)
|
|
381
378
|
expect(result.success).toBe(true)
|
|
382
379
|
if (result.success) {
|
|
@@ -386,9 +383,7 @@ describe('NullableSchema', () => {
|
|
|
386
383
|
})
|
|
387
384
|
|
|
388
385
|
it('preserves object type for valid objects', () => {
|
|
389
|
-
const schema =
|
|
390
|
-
new ObjectSchema({ key: new StringSchema({}) }),
|
|
391
|
-
)
|
|
386
|
+
const schema = nullable(object({ key: string() }))
|
|
392
387
|
const input = { key: 'value' }
|
|
393
388
|
const result = schema.safeParse(input)
|
|
394
389
|
expect(result.success).toBe(true)
|
|
@@ -399,7 +394,7 @@ describe('NullableSchema', () => {
|
|
|
399
394
|
})
|
|
400
395
|
|
|
401
396
|
it('preserves null type exactly', () => {
|
|
402
|
-
const schema =
|
|
397
|
+
const schema = nullable(string())
|
|
403
398
|
const result = schema.safeParse(null)
|
|
404
399
|
expect(result.success).toBe(true)
|
|
405
400
|
if (result.success) {
|
|
@@ -412,8 +407,8 @@ describe('NullableSchema', () => {
|
|
|
412
407
|
|
|
413
408
|
describe('with complex wrapped schemas', () => {
|
|
414
409
|
it('validates nullable enum with default', () => {
|
|
415
|
-
const schema =
|
|
416
|
-
|
|
410
|
+
const schema = nullable(
|
|
411
|
+
withDefault(enumSchema(['option1', 'option2']), 'option1'),
|
|
417
412
|
)
|
|
418
413
|
|
|
419
414
|
expect(schema.safeParse(null).success).toBe(true)
|
|
@@ -424,9 +419,7 @@ describe('NullableSchema', () => {
|
|
|
424
419
|
})
|
|
425
420
|
|
|
426
421
|
it('handles nullable schema with grapheme constraints', () => {
|
|
427
|
-
const schema =
|
|
428
|
-
new StringSchema({ minGraphemes: 2, maxGraphemes: 5 }),
|
|
429
|
-
)
|
|
422
|
+
const schema = nullable(string({ minGraphemes: 2, maxGraphemes: 5 }))
|
|
430
423
|
|
|
431
424
|
expect(schema.safeParse(null).success).toBe(true)
|
|
432
425
|
expect(schema.safeParse('ab').success).toBe(true)
|
|
@@ -436,9 +429,7 @@ describe('NullableSchema', () => {
|
|
|
436
429
|
})
|
|
437
430
|
|
|
438
431
|
it('handles nullable integer with negative range', () => {
|
|
439
|
-
const schema =
|
|
440
|
-
new IntegerSchema({ minimum: -100, maximum: -10 }),
|
|
441
|
-
)
|
|
432
|
+
const schema = nullable(integer({ minimum: -100, maximum: -10 }))
|
|
442
433
|
|
|
443
434
|
expect(schema.safeParse(null).success).toBe(true)
|
|
444
435
|
expect(schema.safeParse(-50).success).toBe(true)
|
|
@@ -452,27 +443,25 @@ describe('NullableSchema', () => {
|
|
|
452
443
|
|
|
453
444
|
describe('validation error behavior', () => {
|
|
454
445
|
it('returns failure for wrapped schema validation errors', () => {
|
|
455
|
-
const schema =
|
|
446
|
+
const schema = nullable(integer({ minimum: 10 }))
|
|
456
447
|
const result = schema.safeParse(5)
|
|
457
448
|
expect(result.success).toBe(false)
|
|
458
449
|
})
|
|
459
450
|
|
|
460
451
|
it('returns failure for type mismatches', () => {
|
|
461
|
-
const schema =
|
|
452
|
+
const schema = nullable(string())
|
|
462
453
|
const result = schema.safeParse(123)
|
|
463
454
|
expect(result.success).toBe(false)
|
|
464
455
|
})
|
|
465
456
|
|
|
466
457
|
it('returns success for null regardless of wrapped constraints', () => {
|
|
467
|
-
const schema =
|
|
468
|
-
new StringSchema({ minLength: 100, format: 'uri' }),
|
|
469
|
-
)
|
|
458
|
+
const schema = nullable(string({ minLength: 100, format: 'uri' }))
|
|
470
459
|
const result = schema.safeParse(null)
|
|
471
460
|
expect(result.success).toBe(true)
|
|
472
461
|
})
|
|
473
462
|
|
|
474
463
|
it('wrapped schema validation applies when value is not null', () => {
|
|
475
|
-
const schema =
|
|
464
|
+
const schema = nullable(string({ minLength: 5 }))
|
|
476
465
|
expect(schema.safeParse(null).success).toBe(true)
|
|
477
466
|
expect(schema.safeParse('hello').success).toBe(true)
|
|
478
467
|
expect(schema.safeParse('hi').success).toBe(false)
|
package/src/schema/nullable.ts
CHANGED
|
@@ -1,23 +1,31 @@
|
|
|
1
1
|
import {
|
|
2
|
+
InferInput,
|
|
3
|
+
InferOutput,
|
|
2
4
|
Schema,
|
|
3
|
-
|
|
5
|
+
ValidationContext,
|
|
4
6
|
Validator,
|
|
5
|
-
ValidatorContext,
|
|
6
7
|
} from '../core.js'
|
|
8
|
+
import { memoizedTransformer } from '../util/memoize.js'
|
|
7
9
|
|
|
8
|
-
export class NullableSchema<
|
|
9
|
-
|
|
10
|
+
export class NullableSchema<const TValidator extends Validator> extends Schema<
|
|
11
|
+
InferInput<TValidator> | null,
|
|
12
|
+
InferOutput<TValidator> | null
|
|
13
|
+
> {
|
|
14
|
+
constructor(readonly validator: TValidator) {
|
|
10
15
|
super()
|
|
11
16
|
}
|
|
12
17
|
|
|
13
|
-
validateInContext(
|
|
14
|
-
input: unknown,
|
|
15
|
-
ctx: ValidatorContext,
|
|
16
|
-
): ValidationResult<V | null> {
|
|
18
|
+
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
17
19
|
if (input === null) {
|
|
18
20
|
return ctx.success(null)
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
return ctx.validate(input, this.
|
|
23
|
+
return ctx.validate(input, this.validator)
|
|
22
24
|
}
|
|
23
25
|
}
|
|
26
|
+
|
|
27
|
+
export const nullable = /*#__PURE__*/ memoizedTransformer(function <
|
|
28
|
+
const TValidator extends Validator,
|
|
29
|
+
>(validator: TValidator) {
|
|
30
|
+
return new NullableSchema<TValidator>(validator)
|
|
31
|
+
})
|
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { enumSchema } from './enum.js'
|
|
3
|
+
import { integer } from './integer.js'
|
|
4
|
+
import { nullable } from './nullable.js'
|
|
5
|
+
import { object } from './object.js'
|
|
6
|
+
import { optional } from './optional.js'
|
|
7
|
+
import { string } from './string.js'
|
|
8
8
|
|
|
9
9
|
describe('ObjectSchema', () => {
|
|
10
|
-
const schema =
|
|
11
|
-
name:
|
|
12
|
-
age:
|
|
13
|
-
gender:
|
|
14
|
-
new NullableSchema(new EnumSchema(['male', 'female'])),
|
|
15
|
-
),
|
|
10
|
+
const schema = object({
|
|
11
|
+
name: string(),
|
|
12
|
+
age: optional(integer()),
|
|
13
|
+
gender: optional(nullable(enumSchema(['male', 'female']))),
|
|
16
14
|
})
|
|
17
15
|
|
|
18
16
|
it('validates plain objects', () => {
|
package/src/schema/object.ts
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
import { isPlainObject } from '@atproto/lex-data'
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
InferInput,
|
|
4
|
+
InferOutput,
|
|
4
5
|
Schema,
|
|
5
|
-
|
|
6
|
+
ValidationContext,
|
|
6
7
|
Validator,
|
|
7
|
-
ValidatorContext,
|
|
8
8
|
WithOptionalProperties,
|
|
9
9
|
} from '../core.js'
|
|
10
10
|
import { lazyProperty } from '../util/lazy-property.js'
|
|
11
11
|
|
|
12
12
|
export type ObjectSchemaShape = Record<string, Validator>
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export class ObjectSchema<
|
|
15
|
+
const TShape extends ObjectSchemaShape = any,
|
|
16
|
+
> extends Schema<
|
|
17
|
+
WithOptionalProperties<{
|
|
18
|
+
[K in keyof TShape]: InferInput<TShape[K]>
|
|
19
|
+
}>,
|
|
15
20
|
WithOptionalProperties<{
|
|
16
|
-
[K in keyof
|
|
21
|
+
[K in keyof TShape]: InferOutput<TShape[K]>
|
|
17
22
|
}>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const Shape extends ObjectSchemaShape = any,
|
|
21
|
-
> extends Schema<ObjectSchemaOutput<Shape>> {
|
|
22
|
-
constructor(readonly shape: Shape) {
|
|
23
|
+
> {
|
|
24
|
+
constructor(readonly shape: TShape) {
|
|
23
25
|
super()
|
|
24
26
|
}
|
|
25
27
|
|
|
@@ -29,10 +31,7 @@ export class ObjectSchema<
|
|
|
29
31
|
return lazyProperty(this, 'validatorsMap', map)
|
|
30
32
|
}
|
|
31
33
|
|
|
32
|
-
validateInContext(
|
|
33
|
-
input: unknown,
|
|
34
|
-
ctx: ValidatorContext,
|
|
35
|
-
): ValidationResult<ObjectSchemaOutput<Shape>> {
|
|
34
|
+
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
36
35
|
if (!isPlainObject(input)) {
|
|
37
36
|
return ctx.issueInvalidType(input, 'object')
|
|
38
37
|
}
|
|
@@ -56,14 +55,24 @@ export class ObjectSchema<
|
|
|
56
55
|
continue
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
if (result.value
|
|
58
|
+
if (!Object.is(result.value, input[key])) {
|
|
59
|
+
if (ctx.options.mode === 'validate') {
|
|
60
|
+
// In "validate" mode, we can't modify the input, so we issue an error
|
|
61
|
+
return ctx.issueInvalidPropertyValue(input, key, [result.value])
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
copy ??= { ...input }
|
|
61
65
|
copy[key] = result.value
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return ctx.success(output)
|
|
69
|
+
return ctx.success(copy ?? input)
|
|
68
70
|
}
|
|
69
71
|
}
|
|
72
|
+
|
|
73
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
74
|
+
export function object<const TShape extends ObjectSchemaShape>(
|
|
75
|
+
properties: TShape,
|
|
76
|
+
) {
|
|
77
|
+
return new ObjectSchema<TShape>(properties)
|
|
78
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { boolean } from './boolean.js'
|
|
3
|
+
import { integer } from './integer.js'
|
|
4
|
+
import { optional } from './optional.js'
|
|
5
|
+
import { string } from './string.js'
|
|
6
|
+
import { withDefault } from './with-default.js'
|
|
6
7
|
|
|
7
8
|
describe('OptionalSchema', () => {
|
|
8
9
|
describe('basic validation with string schema', () => {
|
|
9
|
-
const schema =
|
|
10
|
+
const schema = optional(string())
|
|
10
11
|
|
|
11
12
|
it('validates defined string values', () => {
|
|
12
13
|
const result = schema.safeParse('hello')
|
|
@@ -59,7 +60,7 @@ describe('OptionalSchema', () => {
|
|
|
59
60
|
})
|
|
60
61
|
|
|
61
62
|
describe('basic validation with integer schema', () => {
|
|
62
|
-
const schema =
|
|
63
|
+
const schema = optional(integer())
|
|
63
64
|
|
|
64
65
|
it('validates defined integer values', () => {
|
|
65
66
|
const result = schema.safeParse(42)
|
|
@@ -110,7 +111,7 @@ describe('OptionalSchema', () => {
|
|
|
110
111
|
})
|
|
111
112
|
|
|
112
113
|
describe('basic validation with boolean schema', () => {
|
|
113
|
-
const schema =
|
|
114
|
+
const schema = optional(boolean())
|
|
114
115
|
|
|
115
116
|
it('validates true', () => {
|
|
116
117
|
const result = schema.safeParse(true)
|
|
@@ -153,9 +154,7 @@ describe('OptionalSchema', () => {
|
|
|
153
154
|
})
|
|
154
155
|
|
|
155
156
|
describe('inner schema with constraints', () => {
|
|
156
|
-
const schema =
|
|
157
|
-
new StringSchema({ minLength: 5, maxLength: 10 }),
|
|
158
|
-
)
|
|
157
|
+
const schema = optional(string({ minLength: 5, maxLength: 10 }))
|
|
159
158
|
|
|
160
159
|
it('validates values meeting inner schema constraints', () => {
|
|
161
160
|
const result = schema.safeParse('hello')
|
|
@@ -194,7 +193,7 @@ describe('OptionalSchema', () => {
|
|
|
194
193
|
})
|
|
195
194
|
|
|
196
195
|
describe('inner schema with default value', () => {
|
|
197
|
-
const schema =
|
|
196
|
+
const schema = optional(withDefault(string(), 'default'))
|
|
198
197
|
|
|
199
198
|
it('applies default value when undefined is provided', () => {
|
|
200
199
|
const result = schema.safeParse(undefined)
|
|
@@ -222,9 +221,7 @@ describe('OptionalSchema', () => {
|
|
|
222
221
|
})
|
|
223
222
|
|
|
224
223
|
describe('inner schema with default value and constraints', () => {
|
|
225
|
-
const schema =
|
|
226
|
-
new StringSchema({ default: 'default', minLength: 5 }),
|
|
227
|
-
)
|
|
224
|
+
const schema = optional(withDefault(string({ minLength: 5 }), 'default'))
|
|
228
225
|
|
|
229
226
|
it('applies default value when undefined is provided', () => {
|
|
230
227
|
const result = schema.safeParse(undefined)
|
|
@@ -246,9 +243,7 @@ describe('OptionalSchema', () => {
|
|
|
246
243
|
})
|
|
247
244
|
|
|
248
245
|
describe('inner schema with invalid default value', () => {
|
|
249
|
-
const schema =
|
|
250
|
-
new StringSchema({ default: 'bad', minLength: 5 }),
|
|
251
|
-
)
|
|
246
|
+
const schema = optional(string({ default: 'bad', minLength: 5 }))
|
|
252
247
|
|
|
253
248
|
it('returns undefined when default value violates constraints', () => {
|
|
254
249
|
const result = schema.safeParse(undefined)
|
|
@@ -265,7 +260,7 @@ describe('OptionalSchema', () => {
|
|
|
265
260
|
})
|
|
266
261
|
|
|
267
262
|
describe('inner schema with integer default', () => {
|
|
268
|
-
const schema =
|
|
263
|
+
const schema = optional(withDefault(integer(), 42))
|
|
269
264
|
|
|
270
265
|
it('applies default value when undefined is provided', () => {
|
|
271
266
|
const result = schema.safeParse(undefined)
|
|
@@ -293,7 +288,7 @@ describe('OptionalSchema', () => {
|
|
|
293
288
|
})
|
|
294
289
|
|
|
295
290
|
describe('inner schema with boolean default', () => {
|
|
296
|
-
const schema =
|
|
291
|
+
const schema = optional(withDefault(boolean(), true))
|
|
297
292
|
|
|
298
293
|
it('applies default value when undefined is provided', () => {
|
|
299
294
|
const result = schema.safeParse(undefined)
|
|
@@ -321,7 +316,7 @@ describe('OptionalSchema', () => {
|
|
|
321
316
|
})
|
|
322
317
|
|
|
323
318
|
describe('edge cases', () => {
|
|
324
|
-
const schema =
|
|
319
|
+
const schema = optional(string())
|
|
325
320
|
|
|
326
321
|
it('handles very long strings', () => {
|
|
327
322
|
const longString = 'a'.repeat(10000)
|
|
@@ -356,7 +351,7 @@ describe('OptionalSchema', () => {
|
|
|
356
351
|
|
|
357
352
|
describe('type distinctions', () => {
|
|
358
353
|
it('distinguishes between zero and undefined for integers', () => {
|
|
359
|
-
const schema =
|
|
354
|
+
const schema = optional(integer())
|
|
360
355
|
|
|
361
356
|
const zeroResult = schema.safeParse(0)
|
|
362
357
|
expect(zeroResult.success).toBe(true)
|
|
@@ -372,7 +367,7 @@ describe('OptionalSchema', () => {
|
|
|
372
367
|
})
|
|
373
368
|
|
|
374
369
|
it('distinguishes between false and undefined for booleans', () => {
|
|
375
|
-
const schema =
|
|
370
|
+
const schema = optional(boolean())
|
|
376
371
|
|
|
377
372
|
const falseResult = schema.safeParse(false)
|
|
378
373
|
expect(falseResult.success).toBe(true)
|
|
@@ -388,7 +383,7 @@ describe('OptionalSchema', () => {
|
|
|
388
383
|
})
|
|
389
384
|
|
|
390
385
|
it('distinguishes between empty string and undefined for strings', () => {
|
|
391
|
-
const schema =
|
|
386
|
+
const schema = optional(string())
|
|
392
387
|
|
|
393
388
|
const emptyResult = schema.safeParse('')
|
|
394
389
|
expect(emptyResult.success).toBe(true)
|
|
@@ -405,7 +400,7 @@ describe('OptionalSchema', () => {
|
|
|
405
400
|
})
|
|
406
401
|
|
|
407
402
|
describe('nested optional schemas', () => {
|
|
408
|
-
const schema =
|
|
403
|
+
const schema = optional(optional(string()))
|
|
409
404
|
|
|
410
405
|
it('validates defined values through nested optionals', () => {
|
|
411
406
|
const result = schema.safeParse('hello')
|
|
@@ -430,7 +425,7 @@ describe('OptionalSchema', () => {
|
|
|
430
425
|
})
|
|
431
426
|
|
|
432
427
|
describe('inner schema format constraints', () => {
|
|
433
|
-
const schema =
|
|
428
|
+
const schema = optional(string({ format: 'uri' }))
|
|
434
429
|
|
|
435
430
|
it('validates values meeting format constraint', () => {
|
|
436
431
|
const result = schema.safeParse('https://example.com')
|
|
@@ -449,9 +444,7 @@ describe('OptionalSchema', () => {
|
|
|
449
444
|
})
|
|
450
445
|
|
|
451
446
|
describe('integer constraint validation', () => {
|
|
452
|
-
const schema =
|
|
453
|
-
new IntegerSchema({ minimum: 0, maximum: 100 }),
|
|
454
|
-
)
|
|
447
|
+
const schema = optional(integer({ minimum: 0, maximum: 100 }))
|
|
455
448
|
|
|
456
449
|
it('validates values within range', () => {
|
|
457
450
|
const result = schema.safeParse(50)
|
package/src/schema/optional.ts
CHANGED
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
import {
|
|
2
|
+
InferInput,
|
|
3
|
+
InferOutput,
|
|
2
4
|
Schema,
|
|
3
|
-
|
|
5
|
+
UnwrapValidator,
|
|
6
|
+
ValidationContext,
|
|
4
7
|
Validator,
|
|
5
|
-
ValidatorContext,
|
|
6
8
|
} from '../core.js'
|
|
9
|
+
import { memoizedTransformer } from '../util/memoize.js'
|
|
10
|
+
import { WithDefaultSchema } from './with-default.js'
|
|
7
11
|
|
|
8
|
-
export class OptionalSchema<
|
|
9
|
-
|
|
12
|
+
export class OptionalSchema<TValidator extends Validator> extends Schema<
|
|
13
|
+
InferInput<TValidator> | undefined,
|
|
14
|
+
UnwrapValidator<TValidator> extends WithDefaultSchema<infer TValidator>
|
|
15
|
+
? InferOutput<TValidator>
|
|
16
|
+
: InferOutput<TValidator> | undefined
|
|
17
|
+
> {
|
|
18
|
+
constructor(readonly validator: TValidator) {
|
|
10
19
|
super()
|
|
11
20
|
}
|
|
12
21
|
|
|
13
|
-
validateInContext(
|
|
14
|
-
|
|
15
|
-
ctx
|
|
16
|
-
|
|
22
|
+
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
23
|
+
// Optimization: No need to apply child schema defaults in validation mode
|
|
24
|
+
if (input === undefined && ctx.options.mode === 'validate') {
|
|
25
|
+
return ctx.success(input)
|
|
26
|
+
}
|
|
27
|
+
|
|
17
28
|
// @NOTE The inner schema might apply a default value so we need to run it
|
|
18
|
-
//
|
|
19
|
-
const result = ctx.validate(input, this.
|
|
29
|
+
// even if input is undefined.
|
|
30
|
+
const result = ctx.validate(input, this.validator)
|
|
20
31
|
|
|
21
32
|
if (result.success) {
|
|
22
33
|
return result
|
|
@@ -29,3 +40,9 @@ export class OptionalSchema<V> extends Schema<V | undefined> {
|
|
|
29
40
|
return result
|
|
30
41
|
}
|
|
31
42
|
}
|
|
43
|
+
|
|
44
|
+
export const optional = /*#__PURE__*/ memoizedTransformer(function <
|
|
45
|
+
const TValidator extends Validator,
|
|
46
|
+
>(validator: TValidator) {
|
|
47
|
+
return new OptionalSchema<TValidator>(validator)
|
|
48
|
+
})
|