@atproto/lex-schema 0.0.1 → 0.0.3
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 +68 -0
- package/dist/core/$type.d.ts +6 -3
- package/dist/core/$type.d.ts.map +1 -1
- package/dist/core/$type.js +1 -0
- package/dist/core/$type.js.map +1 -1
- package/dist/core/record-key.d.ts +3 -3
- package/dist/core/record-key.d.ts.map +1 -1
- package/dist/core/record-key.js +12 -6
- package/dist/core/record-key.js.map +1 -1
- package/dist/core/result.d.ts.map +1 -1
- package/dist/core/result.js +6 -0
- package/dist/core/result.js.map +1 -1
- package/dist/core/string-format.d.ts +30 -27
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js +56 -42
- package/dist/core/string-format.js.map +1 -1
- package/dist/core/types.d.ts +9 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/external.d.ts +31 -28
- package/dist/external.d.ts.map +1 -1
- package/dist/external.js +33 -17
- package/dist/external.js.map +1 -1
- package/dist/schema/_parameters.d.ts +2 -2
- package/dist/schema/_parameters.d.ts.map +1 -1
- package/dist/schema/array.d.ts +5 -6
- package/dist/schema/array.d.ts.map +1 -1
- package/dist/schema/array.js +5 -6
- package/dist/schema/array.js.map +1 -1
- package/dist/schema/blob.d.ts +2 -3
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +1 -2
- package/dist/schema/blob.js.map +1 -1
- package/dist/schema/boolean.d.ts +4 -5
- package/dist/schema/boolean.d.ts.map +1 -1
- package/dist/schema/boolean.js +2 -3
- package/dist/schema/boolean.js.map +1 -1
- package/dist/schema/bytes.d.ts +3 -4
- package/dist/schema/bytes.d.ts.map +1 -1
- package/dist/schema/bytes.js +2 -3
- package/dist/schema/bytes.js.map +1 -1
- package/dist/schema/cid.d.ts +13 -6
- package/dist/schema/cid.d.ts.map +1 -1
- package/dist/schema/cid.js +2 -4
- package/dist/schema/cid.js.map +1 -1
- package/dist/schema/custom.d.ts +3 -4
- package/dist/schema/custom.d.ts.map +1 -1
- package/dist/schema/custom.js +4 -3
- package/dist/schema/custom.js.map +1 -1
- package/dist/schema/dict.d.ts +3 -3
- 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 +15 -24
- package/dist/schema/discriminated-union.d.ts.map +1 -1
- package/dist/schema/discriminated-union.js +40 -64
- package/dist/schema/discriminated-union.js.map +1 -1
- package/dist/schema/enum.d.ts +8 -4
- package/dist/schema/enum.d.ts.map +1 -1
- package/dist/schema/enum.js +5 -3
- package/dist/schema/enum.js.map +1 -1
- package/dist/schema/integer.d.ts +3 -4
- package/dist/schema/integer.d.ts.map +1 -1
- package/dist/schema/integer.js +3 -4
- package/dist/schema/integer.js.map +1 -1
- package/dist/schema/intersection.d.ts +22 -14
- package/dist/schema/intersection.d.ts.map +1 -1
- package/dist/schema/intersection.js +12 -22
- package/dist/schema/intersection.js.map +1 -1
- package/dist/schema/literal.d.ts +8 -4
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +5 -3
- package/dist/schema/literal.js.map +1 -1
- package/dist/schema/never.d.ts +2 -2
- package/dist/schema/never.d.ts.map +1 -1
- package/dist/schema/never.js +1 -1
- package/dist/schema/never.js.map +1 -1
- package/dist/schema/null.d.ts +2 -3
- package/dist/schema/null.d.ts.map +1 -1
- package/dist/schema/null.js +1 -2
- package/dist/schema/null.js.map +1 -1
- package/dist/schema/nullable.d.ts +7 -0
- package/dist/schema/nullable.d.ts.map +1 -0
- package/dist/schema/nullable.js +19 -0
- package/dist/schema/nullable.js.map +1 -0
- package/dist/schema/object.d.ts +10 -44
- package/dist/schema/object.d.ts.map +1 -1
- package/dist/schema/object.js +13 -56
- package/dist/schema/object.js.map +1 -1
- package/dist/schema/optional.d.ts +7 -0
- package/dist/schema/optional.d.ts.map +1 -0
- package/dist/schema/optional.js +25 -0
- package/dist/schema/optional.js.map +1 -0
- package/dist/schema/params.d.ts +14 -19
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +10 -24
- package/dist/schema/params.js.map +1 -1
- package/dist/schema/payload.d.ts +4 -4
- package/dist/schema/payload.d.ts.map +1 -1
- package/dist/schema/payload.js.map +1 -1
- package/dist/schema/permission-set.d.ts +6 -6
- package/dist/schema/permission-set.d.ts.map +1 -1
- package/dist/schema/permission-set.js +1 -2
- package/dist/schema/permission-set.js.map +1 -1
- package/dist/schema/permission.d.ts +0 -1
- package/dist/schema/permission.d.ts.map +1 -1
- package/dist/schema/permission.js +0 -1
- package/dist/schema/permission.js.map +1 -1
- package/dist/schema/procedure.d.ts +8 -9
- package/dist/schema/procedure.d.ts.map +1 -1
- package/dist/schema/procedure.js +0 -1
- package/dist/schema/procedure.js.map +1 -1
- package/dist/schema/query.d.ts +7 -8
- package/dist/schema/query.d.ts.map +1 -1
- package/dist/schema/query.js +0 -1
- package/dist/schema/query.js.map +1 -1
- package/dist/schema/record.d.ts +34 -28
- package/dist/schema/record.d.ts.map +1 -1
- package/dist/schema/record.js +1 -2
- package/dist/schema/record.js.map +1 -1
- package/dist/schema/ref.d.ts +2 -3
- package/dist/schema/ref.d.ts.map +1 -1
- package/dist/schema/ref.js +1 -2
- package/dist/schema/ref.js.map +1 -1
- package/dist/schema/refine.d.ts +18 -0
- package/dist/schema/refine.d.ts.map +1 -0
- package/dist/schema/refine.js +33 -0
- package/dist/schema/refine.js.map +1 -0
- package/dist/schema/regexp.d.ts +7 -0
- package/dist/schema/regexp.d.ts.map +1 -0
- package/dist/schema/regexp.js +22 -0
- package/dist/schema/regexp.js.map +1 -0
- package/dist/schema/string.d.ts +4 -8
- package/dist/schema/string.d.ts.map +1 -1
- package/dist/schema/string.js +6 -3
- package/dist/schema/string.js.map +1 -1
- package/dist/schema/subscription.d.ts +7 -6
- package/dist/schema/subscription.d.ts.map +1 -1
- package/dist/schema/subscription.js.map +1 -1
- package/dist/schema/token.d.ts +2 -3
- package/dist/schema/token.d.ts.map +1 -1
- package/dist/schema/token.js +1 -2
- package/dist/schema/token.js.map +1 -1
- package/dist/schema/typed-object.d.ts +29 -27
- package/dist/schema/typed-object.d.ts.map +1 -1
- package/dist/schema/typed-object.js +1 -2
- package/dist/schema/typed-object.js.map +1 -1
- package/dist/schema/typed-ref.d.ts +2 -2
- 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 +3 -4
- package/dist/schema/typed-union.d.ts.map +1 -1
- package/dist/schema/typed-union.js +3 -10
- package/dist/schema/typed-union.js.map +1 -1
- package/dist/schema/union.d.ts +2 -2
- 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-object.d.ts +2 -3
- package/dist/schema/unknown-object.d.ts.map +1 -1
- package/dist/schema/unknown-object.js +1 -2
- package/dist/schema/unknown-object.js.map +1 -1
- package/dist/schema/unknown.d.ts +2 -2
- package/dist/schema/unknown.d.ts.map +1 -1
- package/dist/schema/unknown.js +1 -1
- package/dist/schema/unknown.js.map +1 -1
- package/dist/schema.d.ts +4 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +6 -1
- package/dist/schema.js.map +1 -1
- package/dist/util/array-agg.d.ts.map +1 -1
- package/dist/util/array-agg.js +1 -0
- package/dist/util/array-agg.js.map +1 -1
- package/dist/util/lazy-property.d.ts +2 -0
- package/dist/util/lazy-property.d.ts.map +1 -0
- package/dist/util/lazy-property.js +14 -0
- package/dist/util/lazy-property.js.map +1 -0
- package/dist/validation/schema.d.ts +24 -0
- package/dist/validation/schema.d.ts.map +1 -0
- package/dist/validation/schema.js +57 -0
- package/dist/validation/schema.js.map +1 -0
- package/dist/validation/validation-error.d.ts +3 -3
- package/dist/validation/validation-error.d.ts.map +1 -1
- package/dist/validation/validation-error.js +32 -4
- package/dist/validation/validation-error.js.map +1 -1
- package/dist/validation/validation-issue.d.ts +32 -24
- package/dist/validation/validation-issue.d.ts.map +1 -1
- package/dist/validation/validation-issue.js +136 -92
- package/dist/validation/validation-issue.js.map +1 -1
- package/dist/validation/validator.d.ts +20 -50
- package/dist/validation/validator.d.ts.map +1 -1
- package/dist/validation/validator.js +40 -134
- package/dist/validation/validator.js.map +1 -1
- package/dist/validation.d.ts +1 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1 -0
- package/dist/validation.js.map +1 -1
- package/package.json +8 -4
- package/src/core/$type.ts +7 -4
- package/src/core/record-key.ts +12 -5
- package/src/core/result.ts +6 -0
- package/src/core/string-format.ts +97 -61
- package/src/core/types.ts +12 -6
- package/src/external.ts +92 -70
- package/src/schema/_parameters.test.ts +416 -0
- package/src/schema/array.test.ts +237 -0
- package/src/schema/array.ts +17 -11
- package/src/schema/blob.test.ts +506 -0
- package/src/schema/blob.ts +3 -5
- package/src/schema/boolean.test.ts +116 -0
- package/src/schema/boolean.ts +5 -7
- package/src/schema/bytes.test.ts +226 -0
- package/src/schema/bytes.ts +4 -6
- package/src/schema/cid.test.ts +155 -0
- package/src/schema/cid.ts +14 -8
- package/src/schema/custom.test.ts +413 -0
- package/src/schema/custom.ts +10 -8
- package/src/schema/dict.test.ts +198 -0
- package/src/schema/dict.ts +6 -8
- package/src/schema/discriminated-union.test.ts +675 -0
- package/src/schema/discriminated-union.ts +68 -95
- package/src/schema/enum.test.ts +396 -0
- package/src/schema/enum.ts +12 -5
- package/src/schema/integer.test.ts +312 -0
- package/src/schema/integer.ts +5 -7
- package/src/schema/intersection.test.ts +32 -0
- package/src/schema/intersection.ts +37 -40
- package/src/schema/literal.test.ts +531 -0
- package/src/schema/literal.ts +12 -5
- package/src/schema/never.test.ts +174 -0
- package/src/schema/never.ts +3 -10
- package/src/schema/null.test.ts +79 -0
- package/src/schema/null.ts +3 -5
- package/src/schema/nullable.test.ts +480 -0
- package/src/schema/nullable.ts +23 -0
- package/src/schema/object.test.ts +47 -115
- package/src/schema/object.ts +23 -134
- package/src/schema/optional.test.ts +485 -0
- package/src/schema/optional.ts +31 -0
- package/src/schema/params.test.ts +582 -0
- package/src/schema/params.ts +37 -55
- package/src/schema/payload.test.ts +345 -0
- package/src/schema/payload.ts +5 -5
- package/src/schema/permission-set.test.ts +679 -0
- package/src/schema/permission-set.ts +6 -8
- package/src/schema/permission.test.ts +536 -0
- package/src/schema/permission.ts +0 -2
- package/src/schema/procedure.test.ts +443 -0
- package/src/schema/procedure.ts +11 -13
- package/src/schema/query.test.ts +408 -0
- package/src/schema/query.ts +9 -11
- package/src/schema/record.test.ts +694 -0
- package/src/schema/record.ts +38 -36
- package/src/schema/ref.test.ts +365 -0
- package/src/schema/ref.ts +8 -5
- package/src/schema/refine.test.ts +578 -0
- package/src/schema/refine.ts +85 -0
- package/src/schema/regexp.test.ts +580 -0
- package/src/schema/regexp.ts +22 -0
- package/src/schema/string.test.ts +612 -0
- package/src/schema/string.ts +11 -17
- package/src/schema/subscription.test.ts +689 -0
- package/src/schema/subscription.ts +13 -8
- package/src/schema/token.test.ts +428 -0
- package/src/schema/token.ts +3 -5
- package/src/schema/typed-object.test.ts +612 -0
- package/src/schema/typed-object.ts +23 -20
- package/src/schema/typed-ref.test.ts +823 -0
- package/src/schema/typed-ref.ts +10 -5
- package/src/schema/typed-union.test.ts +378 -0
- package/src/schema/typed-union.ts +6 -15
- package/src/schema/union.test.ts +200 -0
- package/src/schema/union.ts +5 -4
- package/src/schema/unknown-object.test.ts +592 -0
- package/src/schema/unknown-object.ts +3 -5
- package/src/schema/unknown.test.ts +312 -0
- package/src/schema/unknown.ts +3 -3
- package/src/schema.ts +7 -1
- package/src/util/array-agg.ts +1 -0
- package/src/util/lazy-property.ts +14 -0
- package/src/validation/schema.ts +92 -0
- package/src/validation/validation-error.ts +60 -9
- package/src/validation/validation-issue.ts +141 -144
- package/src/validation/validator.ts +67 -206
- package/src/validation.ts +1 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +7 -0
- package/tsconfig.tests.json +9 -0
|
@@ -0,0 +1,823 @@
|
|
|
1
|
+
import { IntegerSchema } from './integer.js'
|
|
2
|
+
import { ObjectSchema } from './object.js'
|
|
3
|
+
import { StringSchema } from './string.js'
|
|
4
|
+
import { TypedObjectSchema } from './typed-object.js'
|
|
5
|
+
import { TypedRefSchema } from './typed-ref.js'
|
|
6
|
+
|
|
7
|
+
describe('TypedRefSchema', () => {
|
|
8
|
+
describe('basic validation', () => {
|
|
9
|
+
it('validates through a typed object reference with explicit $type', () => {
|
|
10
|
+
const typedObject = new TypedObjectSchema(
|
|
11
|
+
'com.example.user',
|
|
12
|
+
new ObjectSchema({
|
|
13
|
+
name: new StringSchema({}),
|
|
14
|
+
age: new IntegerSchema({}),
|
|
15
|
+
}),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
19
|
+
|
|
20
|
+
const result = schema.safeParse({
|
|
21
|
+
$type: 'com.example.user',
|
|
22
|
+
name: 'Alice',
|
|
23
|
+
age: 30,
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
expect(result.success).toBe(true)
|
|
27
|
+
if (result.success) {
|
|
28
|
+
expect(result.value.$type).toBe('com.example.user')
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('validates through a typed object with explicit $type', () => {
|
|
33
|
+
const typedObject = new TypedObjectSchema(
|
|
34
|
+
'com.example.user',
|
|
35
|
+
new ObjectSchema({
|
|
36
|
+
name: new StringSchema({}),
|
|
37
|
+
age: new IntegerSchema({}),
|
|
38
|
+
}),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
42
|
+
|
|
43
|
+
const result = schema.safeParse({
|
|
44
|
+
$type: 'com.example.user',
|
|
45
|
+
name: 'Alice',
|
|
46
|
+
age: 30,
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
expect(result.success).toBe(true)
|
|
50
|
+
if (result.success) {
|
|
51
|
+
expect(result.value.$type).toBe('com.example.user')
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('rejects input with wrong $type', () => {
|
|
56
|
+
const typedObject = new TypedObjectSchema(
|
|
57
|
+
'com.example.user',
|
|
58
|
+
new ObjectSchema({
|
|
59
|
+
name: new StringSchema({}),
|
|
60
|
+
}),
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
64
|
+
|
|
65
|
+
const result = schema.safeParse({
|
|
66
|
+
$type: 'com.example.wrong',
|
|
67
|
+
name: 'Alice',
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
expect(result.success).toBe(false)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('rejects invalid input through reference', () => {
|
|
74
|
+
const typedObject = new TypedObjectSchema(
|
|
75
|
+
'com.example.user',
|
|
76
|
+
new ObjectSchema({
|
|
77
|
+
name: new StringSchema({}),
|
|
78
|
+
age: new IntegerSchema({}),
|
|
79
|
+
}),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
83
|
+
|
|
84
|
+
const result = schema.safeParse({
|
|
85
|
+
$type: 'com.example.user',
|
|
86
|
+
name: 'Alice',
|
|
87
|
+
age: 'thirty',
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
expect(result.success).toBe(false)
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
it('rejects non-objects through reference', () => {
|
|
94
|
+
const typedObject = new TypedObjectSchema(
|
|
95
|
+
'com.example.value',
|
|
96
|
+
new ObjectSchema({
|
|
97
|
+
value: new StringSchema({}),
|
|
98
|
+
}),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
102
|
+
|
|
103
|
+
const result = schema.safeParse('not an object')
|
|
104
|
+
expect(result.success).toBe(false)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('rejects null through reference', () => {
|
|
108
|
+
const typedObject = new TypedObjectSchema(
|
|
109
|
+
'com.example.user',
|
|
110
|
+
new ObjectSchema({
|
|
111
|
+
name: new StringSchema({}),
|
|
112
|
+
}),
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
116
|
+
|
|
117
|
+
const result = schema.safeParse(null)
|
|
118
|
+
expect(result.success).toBe(false)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('rejects undefined through reference', () => {
|
|
122
|
+
const typedObject = new TypedObjectSchema(
|
|
123
|
+
'com.example.user',
|
|
124
|
+
new ObjectSchema({
|
|
125
|
+
name: new StringSchema({}),
|
|
126
|
+
}),
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
130
|
+
|
|
131
|
+
const result = schema.safeParse(undefined)
|
|
132
|
+
expect(result.success).toBe(false)
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
describe('$type property', () => {
|
|
137
|
+
it('exposes the $type from the referenced schema', () => {
|
|
138
|
+
const typedObject = new TypedObjectSchema(
|
|
139
|
+
'com.example.post',
|
|
140
|
+
new ObjectSchema({
|
|
141
|
+
text: new StringSchema({}),
|
|
142
|
+
}),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
146
|
+
|
|
147
|
+
expect(schema.$type).toBe('com.example.post')
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('validates that output has correct $type', () => {
|
|
151
|
+
const typedObject = new TypedObjectSchema(
|
|
152
|
+
'com.example.like',
|
|
153
|
+
new ObjectSchema({
|
|
154
|
+
subject: new StringSchema({}),
|
|
155
|
+
}),
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
159
|
+
|
|
160
|
+
const result = schema.safeParse({
|
|
161
|
+
$type: 'com.example.like',
|
|
162
|
+
subject: 'at://did:plc:abc/app.bsky.feed.post/123',
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
expect(result.success).toBe(true)
|
|
166
|
+
if (result.success) {
|
|
167
|
+
expect(result.value.$type).toBe('com.example.like')
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('ensures $type matches expected value', () => {
|
|
172
|
+
const typedObject = new TypedObjectSchema(
|
|
173
|
+
'com.example.follow',
|
|
174
|
+
new ObjectSchema({
|
|
175
|
+
subject: new StringSchema({}),
|
|
176
|
+
}),
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
180
|
+
|
|
181
|
+
// Try to pass wrong $type
|
|
182
|
+
const result = schema.safeParse({
|
|
183
|
+
$type: 'com.example.block',
|
|
184
|
+
subject: 'did:plc:abc',
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
expect(result.success).toBe(false)
|
|
188
|
+
})
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
describe('lazy schema resolution', () => {
|
|
192
|
+
it('does not call getter until first validation', () => {
|
|
193
|
+
let getterCalled = false
|
|
194
|
+
|
|
195
|
+
const schema = new TypedRefSchema(() => {
|
|
196
|
+
getterCalled = true
|
|
197
|
+
return new TypedObjectSchema(
|
|
198
|
+
'com.example.test',
|
|
199
|
+
new ObjectSchema({
|
|
200
|
+
value: new StringSchema({}),
|
|
201
|
+
}),
|
|
202
|
+
)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
expect(getterCalled).toBe(false)
|
|
206
|
+
|
|
207
|
+
schema.safeParse({ value: 'test' })
|
|
208
|
+
expect(getterCalled).toBe(true)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('does not call getter until $type is accessed', () => {
|
|
212
|
+
let getterCalled = false
|
|
213
|
+
|
|
214
|
+
const schema = new TypedRefSchema(() => {
|
|
215
|
+
getterCalled = true
|
|
216
|
+
return new TypedObjectSchema(
|
|
217
|
+
'com.example.test',
|
|
218
|
+
new ObjectSchema({
|
|
219
|
+
value: new StringSchema({}),
|
|
220
|
+
}),
|
|
221
|
+
)
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
expect(getterCalled).toBe(false)
|
|
225
|
+
|
|
226
|
+
// Access $type should trigger getter
|
|
227
|
+
const type = schema.$type
|
|
228
|
+
expect(getterCalled).toBe(true)
|
|
229
|
+
expect(type).toBe('com.example.test')
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('caches the resolved schema', () => {
|
|
233
|
+
let callCount = 0
|
|
234
|
+
|
|
235
|
+
const schema = new TypedRefSchema(() => {
|
|
236
|
+
callCount++
|
|
237
|
+
return new TypedObjectSchema(
|
|
238
|
+
'com.example.test',
|
|
239
|
+
new ObjectSchema({
|
|
240
|
+
value: new StringSchema({}),
|
|
241
|
+
}),
|
|
242
|
+
)
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
schema.safeParse({ value: 'first' })
|
|
246
|
+
schema.safeParse({ value: 'second' })
|
|
247
|
+
schema.safeParse({ value: 'third' })
|
|
248
|
+
|
|
249
|
+
expect(callCount).toBe(1)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('caches schema after $type access', () => {
|
|
253
|
+
let callCount = 0
|
|
254
|
+
|
|
255
|
+
const schema = new TypedRefSchema(() => {
|
|
256
|
+
callCount++
|
|
257
|
+
return new TypedObjectSchema(
|
|
258
|
+
'com.example.test',
|
|
259
|
+
new ObjectSchema({
|
|
260
|
+
value: new StringSchema({}),
|
|
261
|
+
}),
|
|
262
|
+
)
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
// Access $type first
|
|
266
|
+
schema.$type
|
|
267
|
+
expect(callCount).toBe(1)
|
|
268
|
+
|
|
269
|
+
// Then validate multiple times
|
|
270
|
+
schema.safeParse({ value: 'test1' })
|
|
271
|
+
schema.safeParse({ value: 'test2' })
|
|
272
|
+
|
|
273
|
+
expect(callCount).toBe(1)
|
|
274
|
+
})
|
|
275
|
+
|
|
276
|
+
it('throws error if getter is called recursively', () => {
|
|
277
|
+
// @ts-expect-error
|
|
278
|
+
const schema = new TypedRefSchema(() => {
|
|
279
|
+
// This would cause infinite recursion if not protected
|
|
280
|
+
return schema.schema
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
expect(() => {
|
|
284
|
+
schema.safeParse({ value: 'test' })
|
|
285
|
+
}).toThrow()
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
describe('with constrained schemas', () => {
|
|
290
|
+
it('validates typed object with string constraints', () => {
|
|
291
|
+
const typedObject = new TypedObjectSchema(
|
|
292
|
+
'com.example.post',
|
|
293
|
+
new ObjectSchema({
|
|
294
|
+
text: new StringSchema({ minLength: 1, maxLength: 300 }),
|
|
295
|
+
}),
|
|
296
|
+
)
|
|
297
|
+
|
|
298
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
299
|
+
|
|
300
|
+
const result = schema.safeParse({
|
|
301
|
+
$type: 'com.example.post',
|
|
302
|
+
text: 'This is a valid post',
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
expect(result.success).toBe(true)
|
|
306
|
+
})
|
|
307
|
+
|
|
308
|
+
it('rejects typed object violating string constraints', () => {
|
|
309
|
+
const typedObject = new TypedObjectSchema(
|
|
310
|
+
'com.example.post',
|
|
311
|
+
new ObjectSchema({
|
|
312
|
+
text: new StringSchema({ minLength: 1, maxLength: 300 }),
|
|
313
|
+
}),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
317
|
+
|
|
318
|
+
const result = schema.safeParse({
|
|
319
|
+
$type: 'com.example.post',
|
|
320
|
+
text: '',
|
|
321
|
+
})
|
|
322
|
+
|
|
323
|
+
expect(result.success).toBe(false)
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
it('validates typed object with integer constraints', () => {
|
|
327
|
+
const typedObject = new TypedObjectSchema(
|
|
328
|
+
'com.example.rating',
|
|
329
|
+
new ObjectSchema({
|
|
330
|
+
score: new IntegerSchema({ minimum: 1, maximum: 5 }),
|
|
331
|
+
}),
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
335
|
+
|
|
336
|
+
const result = schema.safeParse({
|
|
337
|
+
$type: 'com.example.rating',
|
|
338
|
+
score: 4,
|
|
339
|
+
})
|
|
340
|
+
|
|
341
|
+
expect(result.success).toBe(true)
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
it('rejects typed object violating integer constraints', () => {
|
|
345
|
+
const typedObject = new TypedObjectSchema(
|
|
346
|
+
'com.example.rating',
|
|
347
|
+
new ObjectSchema({
|
|
348
|
+
score: new IntegerSchema({ minimum: 1, maximum: 5 }),
|
|
349
|
+
}),
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
353
|
+
|
|
354
|
+
const result = schema.safeParse({
|
|
355
|
+
$type: 'com.example.rating',
|
|
356
|
+
score: 10,
|
|
357
|
+
})
|
|
358
|
+
|
|
359
|
+
expect(result.success).toBe(false)
|
|
360
|
+
})
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
describe('multiple validations', () => {
|
|
364
|
+
it('validates multiple inputs correctly', () => {
|
|
365
|
+
const typedObject = new TypedObjectSchema(
|
|
366
|
+
'com.example.user',
|
|
367
|
+
new ObjectSchema({
|
|
368
|
+
name: new StringSchema({ minLength: 2 }),
|
|
369
|
+
}),
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
373
|
+
|
|
374
|
+
const result1 = schema.safeParse({
|
|
375
|
+
$type: 'com.example.user',
|
|
376
|
+
name: 'Alice',
|
|
377
|
+
})
|
|
378
|
+
expect(result1.success).toBe(true)
|
|
379
|
+
|
|
380
|
+
const result2 = schema.safeParse({ $type: 'com.example.user', name: 'A' })
|
|
381
|
+
expect(result2.success).toBe(false)
|
|
382
|
+
|
|
383
|
+
const result3 = schema.safeParse({
|
|
384
|
+
$type: 'com.example.user',
|
|
385
|
+
name: 'Bob',
|
|
386
|
+
})
|
|
387
|
+
expect(result3.success).toBe(true)
|
|
388
|
+
|
|
389
|
+
const result4 = schema.safeParse({ $type: 'com.example.user', name: '' })
|
|
390
|
+
expect(result4.success).toBe(false)
|
|
391
|
+
})
|
|
392
|
+
|
|
393
|
+
it('handles different types of validation failures', () => {
|
|
394
|
+
const typedObject = new TypedObjectSchema(
|
|
395
|
+
'com.example.user',
|
|
396
|
+
new ObjectSchema({
|
|
397
|
+
name: new StringSchema({ minLength: 2 }),
|
|
398
|
+
age: new IntegerSchema({ minimum: 0, maximum: 150 }),
|
|
399
|
+
}),
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
403
|
+
|
|
404
|
+
const result1 = schema.safeParse({
|
|
405
|
+
$type: 'com.example.user',
|
|
406
|
+
name: 'A',
|
|
407
|
+
age: 25,
|
|
408
|
+
})
|
|
409
|
+
expect(result1.success).toBe(false)
|
|
410
|
+
|
|
411
|
+
const result2 = schema.safeParse({
|
|
412
|
+
$type: 'com.example.user',
|
|
413
|
+
name: 'Alice',
|
|
414
|
+
age: 200,
|
|
415
|
+
})
|
|
416
|
+
expect(result2.success).toBe(false)
|
|
417
|
+
|
|
418
|
+
const result3 = schema.safeParse({
|
|
419
|
+
$type: 'com.example.user',
|
|
420
|
+
name: 'Alice',
|
|
421
|
+
age: 25,
|
|
422
|
+
})
|
|
423
|
+
expect(result3.success).toBe(true)
|
|
424
|
+
|
|
425
|
+
const result4 = schema.safeParse({
|
|
426
|
+
$type: 'com.example.user',
|
|
427
|
+
name: 'Alice',
|
|
428
|
+
})
|
|
429
|
+
expect(result4.success).toBe(false)
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
it('validates same input multiple times consistently', () => {
|
|
433
|
+
const typedObject = new TypedObjectSchema(
|
|
434
|
+
'com.example.post',
|
|
435
|
+
new ObjectSchema({
|
|
436
|
+
text: new StringSchema({}),
|
|
437
|
+
}),
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
441
|
+
|
|
442
|
+
const input = { $type: 'com.example.post', text: 'Hello world' }
|
|
443
|
+
|
|
444
|
+
const result1 = schema.safeParse(input)
|
|
445
|
+
const result2 = schema.safeParse(input)
|
|
446
|
+
const result3 = schema.safeParse(input)
|
|
447
|
+
|
|
448
|
+
expect(result1.success).toBe(true)
|
|
449
|
+
expect(result2.success).toBe(true)
|
|
450
|
+
expect(result3.success).toBe(true)
|
|
451
|
+
})
|
|
452
|
+
})
|
|
453
|
+
|
|
454
|
+
describe('edge cases', () => {
|
|
455
|
+
it('handles empty object validation', () => {
|
|
456
|
+
const typedObject = new TypedObjectSchema(
|
|
457
|
+
'com.example.empty',
|
|
458
|
+
new ObjectSchema({}),
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
462
|
+
|
|
463
|
+
const result = schema.safeParse({ $type: 'com.example.empty' })
|
|
464
|
+
expect(result.success).toBe(true)
|
|
465
|
+
if (result.success) {
|
|
466
|
+
expect(result.value.$type).toBe('com.example.empty')
|
|
467
|
+
}
|
|
468
|
+
})
|
|
469
|
+
|
|
470
|
+
it('rejects arrays', () => {
|
|
471
|
+
const typedObject = new TypedObjectSchema(
|
|
472
|
+
'com.example.test',
|
|
473
|
+
new ObjectSchema({
|
|
474
|
+
value: new StringSchema({}),
|
|
475
|
+
}),
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
479
|
+
|
|
480
|
+
const result = schema.safeParse([{ value: 'test' }])
|
|
481
|
+
expect(result.success).toBe(false)
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
it('rejects primitive values', () => {
|
|
485
|
+
const typedObject = new TypedObjectSchema(
|
|
486
|
+
'com.example.test',
|
|
487
|
+
new ObjectSchema({
|
|
488
|
+
value: new StringSchema({}),
|
|
489
|
+
}),
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
493
|
+
|
|
494
|
+
const result1 = schema.safeParse('string')
|
|
495
|
+
expect(result1.success).toBe(false)
|
|
496
|
+
|
|
497
|
+
const result2 = schema.safeParse(123)
|
|
498
|
+
expect(result2.success).toBe(false)
|
|
499
|
+
|
|
500
|
+
const result3 = schema.safeParse(true)
|
|
501
|
+
expect(result3.success).toBe(false)
|
|
502
|
+
})
|
|
503
|
+
|
|
504
|
+
it('handles objects with extra properties', () => {
|
|
505
|
+
const typedObject = new TypedObjectSchema(
|
|
506
|
+
'com.example.user',
|
|
507
|
+
new ObjectSchema({
|
|
508
|
+
name: new StringSchema({}),
|
|
509
|
+
}),
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
513
|
+
|
|
514
|
+
const result = schema.safeParse({
|
|
515
|
+
$type: 'com.example.user',
|
|
516
|
+
name: 'Alice',
|
|
517
|
+
extra: 'property',
|
|
518
|
+
another: 'value',
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
expect(result.success).toBe(true)
|
|
522
|
+
})
|
|
523
|
+
|
|
524
|
+
it('validates with zero values', () => {
|
|
525
|
+
const typedObject = new TypedObjectSchema(
|
|
526
|
+
'com.example.counter',
|
|
527
|
+
new ObjectSchema({
|
|
528
|
+
count: new IntegerSchema({}),
|
|
529
|
+
}),
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
533
|
+
|
|
534
|
+
const result = schema.safeParse({
|
|
535
|
+
$type: 'com.example.counter',
|
|
536
|
+
count: 0,
|
|
537
|
+
})
|
|
538
|
+
expect(result.success).toBe(true)
|
|
539
|
+
})
|
|
540
|
+
|
|
541
|
+
it('validates with empty strings', () => {
|
|
542
|
+
const typedObject = new TypedObjectSchema(
|
|
543
|
+
'com.example.text',
|
|
544
|
+
new ObjectSchema({
|
|
545
|
+
content: new StringSchema({}),
|
|
546
|
+
}),
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
550
|
+
|
|
551
|
+
const result = schema.safeParse({
|
|
552
|
+
$type: 'com.example.text',
|
|
553
|
+
content: '',
|
|
554
|
+
})
|
|
555
|
+
expect(result.success).toBe(true)
|
|
556
|
+
})
|
|
557
|
+
|
|
558
|
+
it('rejects NaN in integer fields', () => {
|
|
559
|
+
const typedObject = new TypedObjectSchema(
|
|
560
|
+
'com.example.number',
|
|
561
|
+
new ObjectSchema({
|
|
562
|
+
value: new IntegerSchema({}),
|
|
563
|
+
}),
|
|
564
|
+
)
|
|
565
|
+
|
|
566
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
567
|
+
|
|
568
|
+
const result = schema.safeParse({
|
|
569
|
+
$type: 'com.example.number',
|
|
570
|
+
value: NaN,
|
|
571
|
+
})
|
|
572
|
+
expect(result.success).toBe(false)
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
it('rejects Infinity in integer fields', () => {
|
|
576
|
+
const typedObject = new TypedObjectSchema(
|
|
577
|
+
'com.example.number',
|
|
578
|
+
new ObjectSchema({
|
|
579
|
+
value: new IntegerSchema({}),
|
|
580
|
+
}),
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
584
|
+
|
|
585
|
+
const result = schema.safeParse({
|
|
586
|
+
$type: 'com.example.number',
|
|
587
|
+
value: Infinity,
|
|
588
|
+
})
|
|
589
|
+
expect(result.success).toBe(false)
|
|
590
|
+
})
|
|
591
|
+
})
|
|
592
|
+
|
|
593
|
+
describe('nested references', () => {
|
|
594
|
+
it('validates through nested TypedRefSchema', () => {
|
|
595
|
+
const typedObject = new TypedObjectSchema(
|
|
596
|
+
'com.example.user',
|
|
597
|
+
new ObjectSchema({
|
|
598
|
+
name: new StringSchema({ minLength: 2 }),
|
|
599
|
+
}),
|
|
600
|
+
)
|
|
601
|
+
|
|
602
|
+
const innerRef = new TypedRefSchema(() => typedObject)
|
|
603
|
+
const outerRef = new TypedRefSchema(() => innerRef.schema)
|
|
604
|
+
|
|
605
|
+
const result = outerRef.safeParse({
|
|
606
|
+
$type: 'com.example.user',
|
|
607
|
+
name: 'Alice',
|
|
608
|
+
})
|
|
609
|
+
expect(result.success).toBe(true)
|
|
610
|
+
if (result.success) {
|
|
611
|
+
expect(result.value.$type).toBe('com.example.user')
|
|
612
|
+
}
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
it('validates with objects containing TypedRef fields', () => {
|
|
616
|
+
const innerTyped = new TypedObjectSchema(
|
|
617
|
+
'com.example.profile',
|
|
618
|
+
new ObjectSchema({
|
|
619
|
+
bio: new StringSchema({}),
|
|
620
|
+
}),
|
|
621
|
+
)
|
|
622
|
+
|
|
623
|
+
const outerTyped = new TypedObjectSchema(
|
|
624
|
+
'com.example.user',
|
|
625
|
+
new ObjectSchema({
|
|
626
|
+
name: new StringSchema({}),
|
|
627
|
+
profile: new TypedRefSchema(() => innerTyped),
|
|
628
|
+
}),
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
const schema = new TypedRefSchema(() => outerTyped)
|
|
632
|
+
|
|
633
|
+
const result = schema.safeParse({
|
|
634
|
+
$type: 'com.example.user',
|
|
635
|
+
name: 'Alice',
|
|
636
|
+
profile: {
|
|
637
|
+
$type: 'com.example.profile',
|
|
638
|
+
bio: 'Software developer',
|
|
639
|
+
},
|
|
640
|
+
})
|
|
641
|
+
|
|
642
|
+
expect(result.success).toBe(true)
|
|
643
|
+
if (result.success) {
|
|
644
|
+
expect(result.value.$type).toBe('com.example.user')
|
|
645
|
+
expect(result.value.profile.$type).toBe('com.example.profile')
|
|
646
|
+
}
|
|
647
|
+
})
|
|
648
|
+
|
|
649
|
+
it('rejects nested objects with wrong $type', () => {
|
|
650
|
+
const innerTyped = new TypedObjectSchema(
|
|
651
|
+
'com.example.profile',
|
|
652
|
+
new ObjectSchema({
|
|
653
|
+
bio: new StringSchema({}),
|
|
654
|
+
}),
|
|
655
|
+
)
|
|
656
|
+
|
|
657
|
+
const outerTyped = new TypedObjectSchema(
|
|
658
|
+
'com.example.user',
|
|
659
|
+
new ObjectSchema({
|
|
660
|
+
name: new StringSchema({}),
|
|
661
|
+
profile: new TypedRefSchema(() => innerTyped),
|
|
662
|
+
}),
|
|
663
|
+
)
|
|
664
|
+
|
|
665
|
+
const schema = new TypedRefSchema(() => outerTyped)
|
|
666
|
+
|
|
667
|
+
const result = schema.safeParse({
|
|
668
|
+
$type: 'com.example.user',
|
|
669
|
+
name: 'Alice',
|
|
670
|
+
profile: {
|
|
671
|
+
$type: 'com.example.wrongtype',
|
|
672
|
+
bio: 'Software developer',
|
|
673
|
+
},
|
|
674
|
+
})
|
|
675
|
+
|
|
676
|
+
expect(result.success).toBe(false)
|
|
677
|
+
})
|
|
678
|
+
})
|
|
679
|
+
|
|
680
|
+
describe('schema property access', () => {
|
|
681
|
+
it('allows direct access to resolved schema', () => {
|
|
682
|
+
const typedObject = new TypedObjectSchema(
|
|
683
|
+
'com.example.test',
|
|
684
|
+
new ObjectSchema({
|
|
685
|
+
value: new StringSchema({}),
|
|
686
|
+
}),
|
|
687
|
+
)
|
|
688
|
+
|
|
689
|
+
const refSchema = new TypedRefSchema(() => typedObject)
|
|
690
|
+
|
|
691
|
+
const resolved = refSchema.schema
|
|
692
|
+
expect(resolved).toBe(typedObject)
|
|
693
|
+
expect(resolved.$type).toBe('com.example.test')
|
|
694
|
+
})
|
|
695
|
+
|
|
696
|
+
it('returns same instance on multiple schema property accesses', () => {
|
|
697
|
+
const typedObject = new TypedObjectSchema(
|
|
698
|
+
'com.example.test',
|
|
699
|
+
new ObjectSchema({
|
|
700
|
+
value: new StringSchema({}),
|
|
701
|
+
}),
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
const refSchema = new TypedRefSchema(() => typedObject)
|
|
705
|
+
|
|
706
|
+
const first = refSchema.schema
|
|
707
|
+
const second = refSchema.schema
|
|
708
|
+
const third = refSchema.schema
|
|
709
|
+
|
|
710
|
+
expect(first).toBe(second)
|
|
711
|
+
expect(second).toBe(third)
|
|
712
|
+
expect(first.$type).toBe('com.example.test')
|
|
713
|
+
})
|
|
714
|
+
|
|
715
|
+
it('resolves schema before validation', () => {
|
|
716
|
+
let resolved = false
|
|
717
|
+
|
|
718
|
+
const refSchema = new TypedRefSchema(() => {
|
|
719
|
+
resolved = true
|
|
720
|
+
return new TypedObjectSchema(
|
|
721
|
+
'com.example.test',
|
|
722
|
+
new ObjectSchema({
|
|
723
|
+
value: new StringSchema({}),
|
|
724
|
+
}),
|
|
725
|
+
)
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
expect(resolved).toBe(false)
|
|
729
|
+
|
|
730
|
+
const schemaValue = refSchema.schema
|
|
731
|
+
expect(resolved).toBe(true)
|
|
732
|
+
expect(schemaValue).toBeDefined()
|
|
733
|
+
expect(schemaValue.$type).toBe('com.example.test')
|
|
734
|
+
})
|
|
735
|
+
})
|
|
736
|
+
|
|
737
|
+
describe('complex object structures', () => {
|
|
738
|
+
it('validates complex nested structure', () => {
|
|
739
|
+
const typedObject = new TypedObjectSchema(
|
|
740
|
+
'com.example.post',
|
|
741
|
+
new ObjectSchema({
|
|
742
|
+
text: new StringSchema({ minLength: 1, maxLength: 300 }),
|
|
743
|
+
createdAt: new StringSchema({ format: 'datetime' }),
|
|
744
|
+
likeCount: new IntegerSchema({ minimum: 0 }),
|
|
745
|
+
}),
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
749
|
+
|
|
750
|
+
const result = schema.safeParse({
|
|
751
|
+
$type: 'com.example.post',
|
|
752
|
+
text: 'Hello world!',
|
|
753
|
+
createdAt: '2023-01-01T00:00:00Z',
|
|
754
|
+
likeCount: 42,
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
expect(result.success).toBe(true)
|
|
758
|
+
if (result.success) {
|
|
759
|
+
expect(result.value.$type).toBe('com.example.post')
|
|
760
|
+
expect(result.value.text).toBe('Hello world!')
|
|
761
|
+
expect(result.value.likeCount).toBe(42)
|
|
762
|
+
}
|
|
763
|
+
})
|
|
764
|
+
|
|
765
|
+
it('validates structure with multiple property types', () => {
|
|
766
|
+
const typedObject = new TypedObjectSchema(
|
|
767
|
+
'com.example.record',
|
|
768
|
+
new ObjectSchema({
|
|
769
|
+
id: new StringSchema({ format: 'nsid' }),
|
|
770
|
+
count: new IntegerSchema({ minimum: 0 }),
|
|
771
|
+
flag: new StringSchema({}),
|
|
772
|
+
}),
|
|
773
|
+
)
|
|
774
|
+
|
|
775
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
776
|
+
|
|
777
|
+
const result = schema.safeParse({
|
|
778
|
+
$type: 'com.example.record',
|
|
779
|
+
id: 'com.example.feed.post',
|
|
780
|
+
count: 100,
|
|
781
|
+
flag: 'active',
|
|
782
|
+
})
|
|
783
|
+
|
|
784
|
+
expect(result.success).toBe(true)
|
|
785
|
+
})
|
|
786
|
+
|
|
787
|
+
it('rejects structure with any invalid property', () => {
|
|
788
|
+
const typedObject = new TypedObjectSchema(
|
|
789
|
+
'com.example.record',
|
|
790
|
+
new ObjectSchema({
|
|
791
|
+
name: new StringSchema({ minLength: 1 }),
|
|
792
|
+
count: new IntegerSchema({ minimum: 0 }),
|
|
793
|
+
}),
|
|
794
|
+
)
|
|
795
|
+
|
|
796
|
+
const schema = new TypedRefSchema(() => typedObject)
|
|
797
|
+
|
|
798
|
+
// Valid name, invalid count
|
|
799
|
+
const result1 = schema.safeParse({
|
|
800
|
+
$type: 'com.example.record',
|
|
801
|
+
name: 'test',
|
|
802
|
+
count: -5,
|
|
803
|
+
})
|
|
804
|
+
expect(result1.success).toBe(false)
|
|
805
|
+
|
|
806
|
+
// Invalid name, valid count
|
|
807
|
+
const result2 = schema.safeParse({
|
|
808
|
+
$type: 'com.example.record',
|
|
809
|
+
name: '',
|
|
810
|
+
count: 5,
|
|
811
|
+
})
|
|
812
|
+
expect(result2.success).toBe(false)
|
|
813
|
+
|
|
814
|
+
// Both invalid
|
|
815
|
+
const result3 = schema.safeParse({
|
|
816
|
+
$type: 'com.example.record',
|
|
817
|
+
name: '',
|
|
818
|
+
count: -5,
|
|
819
|
+
})
|
|
820
|
+
expect(result3.success).toBe(false)
|
|
821
|
+
})
|
|
822
|
+
})
|
|
823
|
+
})
|