@atproto/lex-schema 0.0.9 → 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 +34 -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 +7 -7
- 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 +13 -12
- 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/ref.test.ts
CHANGED
|
@@ -1,39 +1,44 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import { Schema } from '../core.js'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
2
|
+
import { Schema, Validator } from '../core.js'
|
|
3
|
+
import { integer } from './integer.js'
|
|
4
|
+
import { object } from './object.js'
|
|
5
|
+
import { optional } from './optional.js'
|
|
6
|
+
import { ref } from './ref.js'
|
|
7
|
+
import { string } from './string.js'
|
|
8
8
|
|
|
9
9
|
describe('RefSchema', () => {
|
|
10
10
|
describe('basic validation', () => {
|
|
11
11
|
it('validates through a simple string reference', () => {
|
|
12
|
-
const schema =
|
|
12
|
+
const schema = ref(() => innerSchema)
|
|
13
|
+
const innerSchema = string()
|
|
13
14
|
const result = schema.safeParse('hello')
|
|
14
15
|
expect(result.success).toBe(true)
|
|
15
16
|
})
|
|
16
17
|
|
|
17
18
|
it('validates through an integer reference', () => {
|
|
18
|
-
const schema =
|
|
19
|
+
const schema = ref(() => innerSchema)
|
|
20
|
+
const innerSchema = integer()
|
|
19
21
|
const result = schema.safeParse(42)
|
|
20
22
|
expect(result.success).toBe(true)
|
|
21
23
|
})
|
|
22
24
|
|
|
23
25
|
it('rejects invalid input through reference', () => {
|
|
24
|
-
const schema =
|
|
26
|
+
const schema = ref(() => innerSchema)
|
|
27
|
+
const innerSchema = string()
|
|
25
28
|
const result = schema.safeParse(123)
|
|
26
29
|
expect(result.success).toBe(false)
|
|
27
30
|
})
|
|
28
31
|
|
|
29
32
|
it('validates null rejection through reference', () => {
|
|
30
|
-
const schema =
|
|
33
|
+
const schema = ref(() => innerSchema)
|
|
34
|
+
const innerSchema = string()
|
|
31
35
|
const result = schema.safeParse(null)
|
|
32
36
|
expect(result.success).toBe(false)
|
|
33
37
|
})
|
|
34
38
|
|
|
35
39
|
it('validates undefined rejection through reference', () => {
|
|
36
|
-
const schema =
|
|
40
|
+
const schema = ref(() => innerSchema)
|
|
41
|
+
const innerSchema = integer()
|
|
37
42
|
const result = schema.safeParse(undefined)
|
|
38
43
|
expect(result.success).toBe(false)
|
|
39
44
|
})
|
|
@@ -42,9 +47,9 @@ describe('RefSchema', () => {
|
|
|
42
47
|
describe('lazy schema resolution', () => {
|
|
43
48
|
it('does not call getter until first validation', () => {
|
|
44
49
|
let getterCalled = false
|
|
45
|
-
const schema =
|
|
50
|
+
const schema = ref(() => {
|
|
46
51
|
getterCalled = true
|
|
47
|
-
return
|
|
52
|
+
return string()
|
|
48
53
|
})
|
|
49
54
|
expect(getterCalled).toBe(false)
|
|
50
55
|
|
|
@@ -52,31 +57,18 @@ describe('RefSchema', () => {
|
|
|
52
57
|
expect(getterCalled).toBe(true)
|
|
53
58
|
})
|
|
54
59
|
|
|
55
|
-
it('caches the resolved schema', () => {
|
|
56
|
-
let callCount = 0
|
|
57
|
-
const schema = new RefSchema(() => {
|
|
58
|
-
callCount++
|
|
59
|
-
return new StringSchema({})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
schema.safeParse('first')
|
|
63
|
-
schema.safeParse('second')
|
|
64
|
-
schema.safeParse('third')
|
|
65
|
-
|
|
66
|
-
expect(callCount).toBe(1)
|
|
67
|
-
})
|
|
68
|
-
|
|
69
60
|
it('throws error if getter is called multiple times', () => {
|
|
70
|
-
const schema =
|
|
61
|
+
const schema = ref(() => innerSchema)
|
|
62
|
+
const innerSchema = string()
|
|
71
63
|
|
|
72
64
|
// Access schema property to resolve it
|
|
73
|
-
schema.
|
|
65
|
+
schema.validator
|
|
74
66
|
|
|
75
67
|
// Try to access the original getter again (which should throw)
|
|
76
68
|
// This is internal behavior, but we're testing the protection mechanism
|
|
77
69
|
expect(() => {
|
|
78
70
|
// Force access to the cached schema property
|
|
79
|
-
const schemaValue = schema.
|
|
71
|
+
const schemaValue = schema.validator
|
|
80
72
|
// This should work fine as it's now cached
|
|
81
73
|
expect(schemaValue).toBeDefined()
|
|
82
74
|
}).not.toThrow()
|
|
@@ -85,28 +77,28 @@ describe('RefSchema', () => {
|
|
|
85
77
|
|
|
86
78
|
describe('with object schemas', () => {
|
|
87
79
|
it('validates objects through reference', () => {
|
|
88
|
-
const schema =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
80
|
+
const schema = ref(() => innerSchema)
|
|
81
|
+
const innerSchema = object({
|
|
82
|
+
name: string(),
|
|
83
|
+
age: integer(),
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
expect(
|
|
87
|
+
schema.safeValidate({
|
|
88
|
+
name: 'Alice',
|
|
89
|
+
age: 30,
|
|
90
|
+
}),
|
|
91
|
+
).toMatchObject({
|
|
92
|
+
success: true,
|
|
98
93
|
})
|
|
99
|
-
expect(result.success).toBe(true)
|
|
100
94
|
})
|
|
101
95
|
|
|
102
96
|
it('rejects invalid objects through reference', () => {
|
|
103
|
-
const schema =
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}),
|
|
109
|
-
)
|
|
97
|
+
const schema = ref(() => innerSchema)
|
|
98
|
+
const innerSchema = object({
|
|
99
|
+
name: string(),
|
|
100
|
+
age: integer(),
|
|
101
|
+
})
|
|
110
102
|
const result = schema.safeParse({
|
|
111
103
|
name: 'Alice',
|
|
112
104
|
age: 'thirty',
|
|
@@ -115,13 +107,11 @@ describe('RefSchema', () => {
|
|
|
115
107
|
})
|
|
116
108
|
|
|
117
109
|
it('rejects objects with missing properties through reference', () => {
|
|
118
|
-
const schema =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}),
|
|
124
|
-
)
|
|
110
|
+
const schema = ref(() => innerSchema)
|
|
111
|
+
const innerSchema = object({
|
|
112
|
+
name: string(),
|
|
113
|
+
age: integer(),
|
|
114
|
+
})
|
|
125
115
|
const result = schema.safeParse({
|
|
126
116
|
name: 'Alice',
|
|
127
117
|
})
|
|
@@ -131,52 +121,35 @@ describe('RefSchema', () => {
|
|
|
131
121
|
|
|
132
122
|
describe('with constrained schemas', () => {
|
|
133
123
|
it('validates string with minLength constraint through reference', () => {
|
|
134
|
-
const schema =
|
|
124
|
+
const schema = ref(() => innerSchema)
|
|
125
|
+
const innerSchema = string({ minLength: 5 })
|
|
135
126
|
const result = schema.safeParse('hello')
|
|
136
127
|
expect(result.success).toBe(true)
|
|
137
128
|
})
|
|
138
129
|
|
|
139
130
|
it('rejects string violating minLength through reference', () => {
|
|
140
|
-
const schema =
|
|
131
|
+
const schema = ref(() => innerSchema)
|
|
132
|
+
const innerSchema = string({ minLength: 5 })
|
|
141
133
|
const result = schema.safeParse('hi')
|
|
142
134
|
expect(result.success).toBe(false)
|
|
143
135
|
})
|
|
144
136
|
|
|
145
137
|
it('validates integer with range constraints through reference', () => {
|
|
146
|
-
const schema =
|
|
147
|
-
|
|
148
|
-
)
|
|
138
|
+
const schema = ref(() => innerSchema)
|
|
139
|
+
const innerSchema = integer({ minimum: 0, maximum: 100 })
|
|
149
140
|
const result = schema.safeParse(50)
|
|
150
141
|
expect(result.success).toBe(true)
|
|
151
142
|
})
|
|
152
143
|
|
|
153
144
|
it('rejects integer violating constraints through reference', () => {
|
|
154
|
-
const schema =
|
|
155
|
-
|
|
156
|
-
)
|
|
145
|
+
const schema = ref(() => innerSchema)
|
|
146
|
+
const innerSchema = integer({ minimum: 0, maximum: 100 })
|
|
157
147
|
const result = schema.safeParse(150)
|
|
158
148
|
expect(result.success).toBe(false)
|
|
159
149
|
})
|
|
160
150
|
})
|
|
161
151
|
|
|
162
152
|
describe('circular references', () => {
|
|
163
|
-
it('prevents recursive getter calls', () => {
|
|
164
|
-
// Create a schema that would cause infinite recursion if not protected
|
|
165
|
-
let schema: RefSchema<any>
|
|
166
|
-
|
|
167
|
-
// eslint-disable-next-line prefer-const
|
|
168
|
-
schema = new RefSchema(() => {
|
|
169
|
-
// This would normally cause infinite recursion
|
|
170
|
-
// but the getter protection should prevent it
|
|
171
|
-
return schema.schema
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
// The first access causes stack overflow before the protection can kick in
|
|
175
|
-
expect(() => {
|
|
176
|
-
schema.safeParse('test')
|
|
177
|
-
}).toThrow()
|
|
178
|
-
})
|
|
179
|
-
|
|
180
153
|
it('supports indirect circular references', () => {
|
|
181
154
|
// Create two schemas that reference each other
|
|
182
155
|
// This demonstrates forward references are possible
|
|
@@ -184,14 +157,14 @@ describe('RefSchema', () => {
|
|
|
184
157
|
type A = { value: string; ref?: B }
|
|
185
158
|
type B = { value: number; ref?: A }
|
|
186
159
|
|
|
187
|
-
const schemaA: Schema<A> =
|
|
188
|
-
value:
|
|
189
|
-
ref:
|
|
160
|
+
const schemaA: Schema<A> = object({
|
|
161
|
+
value: string(),
|
|
162
|
+
ref: optional(ref<Validator<B>>((() => schemaB) as any)),
|
|
190
163
|
})
|
|
191
164
|
|
|
192
|
-
const schemaB: Schema<B> =
|
|
193
|
-
value:
|
|
194
|
-
ref:
|
|
165
|
+
const schemaB: Schema<B> = object({
|
|
166
|
+
value: integer(),
|
|
167
|
+
ref: optional(ref<Validator<A>>((() => schemaA) as any)),
|
|
195
168
|
})
|
|
196
169
|
|
|
197
170
|
expect(
|
|
@@ -222,7 +195,8 @@ describe('RefSchema', () => {
|
|
|
222
195
|
|
|
223
196
|
describe('multiple validations', () => {
|
|
224
197
|
it('validates multiple inputs correctly', () => {
|
|
225
|
-
const schema =
|
|
198
|
+
const schema = ref(() => innerSchema)
|
|
199
|
+
const innerSchema = string({ minLength: 3 })
|
|
226
200
|
|
|
227
201
|
const result1 = schema.safeParse('hello')
|
|
228
202
|
expect(result1.success).toBe(true)
|
|
@@ -238,12 +212,11 @@ describe('RefSchema', () => {
|
|
|
238
212
|
})
|
|
239
213
|
|
|
240
214
|
it('handles different types of validation failures', () => {
|
|
241
|
-
const schema =
|
|
242
|
-
(
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}),
|
|
215
|
+
const schema = ref(() =>
|
|
216
|
+
object({
|
|
217
|
+
name: string({ minLength: 2 }),
|
|
218
|
+
age: integer({ minimum: 0 }),
|
|
219
|
+
}),
|
|
247
220
|
)
|
|
248
221
|
|
|
249
222
|
const result1 = schema.safeParse({ name: 'A', age: 25 })
|
|
@@ -259,43 +232,50 @@ describe('RefSchema', () => {
|
|
|
259
232
|
|
|
260
233
|
describe('edge cases', () => {
|
|
261
234
|
it('handles empty string validation', () => {
|
|
262
|
-
const schema =
|
|
235
|
+
const schema = ref(() => innerSchema)
|
|
236
|
+
const innerSchema = string()
|
|
263
237
|
const result = schema.safeParse('')
|
|
264
238
|
expect(result.success).toBe(true)
|
|
265
239
|
})
|
|
266
240
|
|
|
267
241
|
it('handles zero validation', () => {
|
|
268
|
-
const schema =
|
|
242
|
+
const schema = ref(() => innerSchema)
|
|
243
|
+
const innerSchema = integer()
|
|
269
244
|
const result = schema.safeParse(0)
|
|
270
245
|
expect(result.success).toBe(true)
|
|
271
246
|
})
|
|
272
247
|
|
|
273
248
|
it('rejects NaN through integer reference', () => {
|
|
274
|
-
const schema =
|
|
249
|
+
const schema = ref(() => innerSchema)
|
|
250
|
+
const innerSchema = integer()
|
|
275
251
|
const result = schema.safeParse(NaN)
|
|
276
252
|
expect(result.success).toBe(false)
|
|
277
253
|
})
|
|
278
254
|
|
|
279
255
|
it('rejects Infinity through integer reference', () => {
|
|
280
|
-
const schema =
|
|
256
|
+
const schema = ref(() => innerSchema)
|
|
257
|
+
const innerSchema = integer()
|
|
281
258
|
const result = schema.safeParse(Infinity)
|
|
282
259
|
expect(result.success).toBe(false)
|
|
283
260
|
})
|
|
284
261
|
|
|
285
262
|
it('rejects arrays when expecting string', () => {
|
|
286
|
-
const schema =
|
|
263
|
+
const schema = ref(() => innerSchema)
|
|
264
|
+
const innerSchema = string()
|
|
287
265
|
const result = schema.safeParse(['array'])
|
|
288
266
|
expect(result.success).toBe(false)
|
|
289
267
|
})
|
|
290
268
|
|
|
291
269
|
it('rejects objects when expecting string', () => {
|
|
292
|
-
const schema =
|
|
270
|
+
const schema = ref(() => innerSchema)
|
|
271
|
+
const innerSchema = string()
|
|
293
272
|
const result = schema.safeParse({ key: 'value' })
|
|
294
273
|
expect(result.success).toBe(false)
|
|
295
274
|
})
|
|
296
275
|
|
|
297
276
|
it('rejects booleans when expecting string', () => {
|
|
298
|
-
const schema =
|
|
277
|
+
const schema = ref(() => innerSchema)
|
|
278
|
+
const innerSchema = string()
|
|
299
279
|
const result = schema.safeParse(true)
|
|
300
280
|
expect(result.success).toBe(false)
|
|
301
281
|
})
|
|
@@ -303,25 +283,28 @@ describe('RefSchema', () => {
|
|
|
303
283
|
|
|
304
284
|
describe('nested references', () => {
|
|
305
285
|
it('validates through nested RefSchema', () => {
|
|
306
|
-
const innerRef =
|
|
307
|
-
const
|
|
286
|
+
const innerRef = ref(() => innerSchema)
|
|
287
|
+
const innerSchema = string({ minLength: 3 })
|
|
288
|
+
const outerRef = ref(() => innerRef)
|
|
308
289
|
|
|
309
290
|
const result = outerRef.safeParse('hello')
|
|
310
291
|
expect(result.success).toBe(true)
|
|
311
292
|
})
|
|
312
293
|
|
|
313
294
|
it('rejects invalid input through nested RefSchema', () => {
|
|
314
|
-
const innerRef =
|
|
315
|
-
const
|
|
295
|
+
const innerRef = ref(() => innerSchema)
|
|
296
|
+
const innerSchema = string({ minLength: 3 })
|
|
297
|
+
const outerRef = ref(() => innerRef)
|
|
316
298
|
|
|
317
299
|
const result = outerRef.safeParse('hi')
|
|
318
300
|
expect(result.success).toBe(false)
|
|
319
301
|
})
|
|
320
302
|
|
|
321
303
|
it('validates with deeply nested references', () => {
|
|
322
|
-
const level3 =
|
|
323
|
-
const
|
|
324
|
-
const
|
|
304
|
+
const level3 = ref(() => innerSchema)
|
|
305
|
+
const innerSchema = integer({ minimum: 0 })
|
|
306
|
+
const level2 = ref(() => level3)
|
|
307
|
+
const level1 = ref(() => level2)
|
|
325
308
|
|
|
326
309
|
const result = level1.safeParse(42)
|
|
327
310
|
expect(result.success).toBe(true)
|
|
@@ -330,20 +313,20 @@ describe('RefSchema', () => {
|
|
|
330
313
|
|
|
331
314
|
describe('schema property access', () => {
|
|
332
315
|
it('allows direct access to resolved schema', () => {
|
|
333
|
-
const innerSchema =
|
|
334
|
-
const refSchema =
|
|
316
|
+
const innerSchema = string({ minLength: 5 })
|
|
317
|
+
const refSchema = ref(() => innerSchema)
|
|
335
318
|
|
|
336
|
-
const resolved = refSchema.
|
|
319
|
+
const resolved = refSchema.validator
|
|
337
320
|
expect(resolved).toBe(innerSchema)
|
|
338
321
|
})
|
|
339
322
|
|
|
340
323
|
it('returns same instance on multiple schema property accesses', () => {
|
|
341
|
-
const innerSchema =
|
|
342
|
-
const refSchema =
|
|
324
|
+
const innerSchema = string()
|
|
325
|
+
const refSchema = ref(() => innerSchema)
|
|
343
326
|
|
|
344
|
-
const first = refSchema.
|
|
345
|
-
const second = refSchema.
|
|
346
|
-
const third = refSchema.
|
|
327
|
+
const first = refSchema.validator
|
|
328
|
+
const second = refSchema.validator
|
|
329
|
+
const third = refSchema.validator
|
|
347
330
|
|
|
348
331
|
expect(first).toBe(second)
|
|
349
332
|
expect(second).toBe(third)
|
|
@@ -351,14 +334,14 @@ describe('RefSchema', () => {
|
|
|
351
334
|
|
|
352
335
|
it('resolves schema before validation', () => {
|
|
353
336
|
let resolved = false
|
|
354
|
-
const refSchema =
|
|
337
|
+
const refSchema = ref(() => {
|
|
355
338
|
resolved = true
|
|
356
|
-
return
|
|
339
|
+
return string()
|
|
357
340
|
})
|
|
358
341
|
|
|
359
342
|
expect(resolved).toBe(false)
|
|
360
343
|
|
|
361
|
-
const schemaValue = refSchema.
|
|
344
|
+
const schemaValue = refSchema.validator
|
|
362
345
|
expect(resolved).toBe(true)
|
|
363
346
|
expect(schemaValue).toBeDefined()
|
|
364
347
|
})
|
package/src/schema/ref.ts
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
+
InferInput,
|
|
3
|
+
InferOutput,
|
|
2
4
|
Schema,
|
|
3
|
-
|
|
5
|
+
ValidationContext,
|
|
4
6
|
Validator,
|
|
5
|
-
|
|
7
|
+
WrappedValidator,
|
|
6
8
|
} from '../core.js'
|
|
7
9
|
|
|
8
|
-
export type RefSchemaGetter<
|
|
10
|
+
export type RefSchemaGetter<out TValidator extends Validator> = () => TValidator
|
|
9
11
|
|
|
10
|
-
export class RefSchema<
|
|
11
|
-
|
|
12
|
+
export class RefSchema<const TValidator extends Validator>
|
|
13
|
+
extends Schema<
|
|
14
|
+
InferInput<TValidator>,
|
|
15
|
+
InferOutput<TValidator>,
|
|
16
|
+
TValidator['__lex']
|
|
17
|
+
>
|
|
18
|
+
implements WrappedValidator<TValidator>
|
|
19
|
+
{
|
|
20
|
+
#getter: RefSchemaGetter<TValidator>
|
|
12
21
|
|
|
13
|
-
constructor(getter: RefSchemaGetter<
|
|
22
|
+
constructor(getter: RefSchemaGetter<TValidator>) {
|
|
14
23
|
// @NOTE In order to avoid circular dependency issues, we don't resolve
|
|
15
24
|
// the schema here. Instead, we resolve it lazily when first accessed.
|
|
16
25
|
|
|
@@ -19,32 +28,28 @@ export class RefSchema<V = any> extends Schema<V> {
|
|
|
19
28
|
this.#getter = getter
|
|
20
29
|
}
|
|
21
30
|
|
|
22
|
-
get
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// Prevents a getter from depending on itself recursively, also allows GC to
|
|
26
|
-
// clean up the getter function.
|
|
27
|
-
this.#getter = throwAlreadyCalled
|
|
28
|
-
|
|
29
|
-
// Disable the getter and cache the resolved schema on the instance
|
|
30
|
-
Object.defineProperty(this, 'schema', {
|
|
31
|
-
value,
|
|
32
|
-
writable: false,
|
|
33
|
-
enumerable: false,
|
|
34
|
-
configurable: true,
|
|
35
|
-
})
|
|
31
|
+
get validator(): TValidator {
|
|
32
|
+
return this.#getter.call(null)
|
|
33
|
+
}
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
unwrap(): TValidator {
|
|
36
|
+
return this.validator
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
validateInContext(
|
|
41
|
-
input
|
|
42
|
-
ctx: ValidatorContext,
|
|
43
|
-
): ValidationResult<V> {
|
|
44
|
-
return ctx.validate(input, this.schema)
|
|
39
|
+
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
40
|
+
return ctx.validate(input, this.validator)
|
|
45
41
|
}
|
|
46
42
|
}
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
45
|
+
export function ref<const TValidator extends Validator>(
|
|
46
|
+
get: RefSchemaGetter<TValidator>,
|
|
47
|
+
): RefSchema<TValidator>
|
|
48
|
+
export function ref<TInput, TOutput extends TInput = TInput>(
|
|
49
|
+
get: RefSchemaGetter<Validator<TInput, TOutput>>,
|
|
50
|
+
): RefSchema<Validator<TInput, TOutput>>
|
|
51
|
+
export function ref<const TValidator extends Validator>(
|
|
52
|
+
get: RefSchemaGetter<TValidator>,
|
|
53
|
+
) {
|
|
54
|
+
return new RefSchema<TValidator>(get)
|
|
50
55
|
}
|