@atproto/lex-schema 0.0.2 → 0.0.4
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 +75 -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 +7 -3
- 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 +10 -46
- 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 +19 -123
- 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,592 @@
|
|
|
1
|
+
import { UnknownObjectSchema } from './unknown-object.js'
|
|
2
|
+
|
|
3
|
+
describe('UnknownObjectSchema', () => {
|
|
4
|
+
describe('basic validation', () => {
|
|
5
|
+
const schema = new UnknownObjectSchema()
|
|
6
|
+
|
|
7
|
+
it('accepts empty plain objects', () => {
|
|
8
|
+
const result = schema.safeParse({})
|
|
9
|
+
expect(result.success).toBe(true)
|
|
10
|
+
if (result.success) {
|
|
11
|
+
expect(result.value).toEqual({})
|
|
12
|
+
}
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('accepts plain objects with string values', () => {
|
|
16
|
+
const obj = { key: 'value', name: 'test' }
|
|
17
|
+
const result = schema.safeParse(obj)
|
|
18
|
+
expect(result.success).toBe(true)
|
|
19
|
+
if (result.success) {
|
|
20
|
+
expect(result.value).toEqual(obj)
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('accepts plain objects with number values', () => {
|
|
25
|
+
const obj = { count: 42, total: 100 }
|
|
26
|
+
const result = schema.safeParse(obj)
|
|
27
|
+
expect(result.success).toBe(true)
|
|
28
|
+
if (result.success) {
|
|
29
|
+
expect(result.value).toEqual(obj)
|
|
30
|
+
}
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('accepts plain objects with boolean values', () => {
|
|
34
|
+
const obj = { enabled: true, visible: false }
|
|
35
|
+
const result = schema.safeParse(obj)
|
|
36
|
+
expect(result.success).toBe(true)
|
|
37
|
+
if (result.success) {
|
|
38
|
+
expect(result.value).toEqual(obj)
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('accepts plain objects with null values', () => {
|
|
43
|
+
const obj = { value: null, optional: null }
|
|
44
|
+
const result = schema.safeParse(obj)
|
|
45
|
+
expect(result.success).toBe(true)
|
|
46
|
+
if (result.success) {
|
|
47
|
+
expect(result.value).toEqual(obj)
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('accepts nested plain objects', () => {
|
|
52
|
+
const obj = {
|
|
53
|
+
nested: {
|
|
54
|
+
deep: {
|
|
55
|
+
value: 'test',
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
const result = schema.safeParse(obj)
|
|
60
|
+
expect(result.success).toBe(true)
|
|
61
|
+
if (result.success) {
|
|
62
|
+
expect(result.value).toEqual(obj)
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('accepts plain objects with array values', () => {
|
|
67
|
+
const obj = {
|
|
68
|
+
items: [1, 2, 3],
|
|
69
|
+
names: ['alice', 'bob'],
|
|
70
|
+
}
|
|
71
|
+
const result = schema.safeParse(obj)
|
|
72
|
+
expect(result.success).toBe(true)
|
|
73
|
+
if (result.success) {
|
|
74
|
+
expect(result.value).toEqual(obj)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('accepts plain objects with mixed value types', () => {
|
|
79
|
+
const obj = {
|
|
80
|
+
string: 'value',
|
|
81
|
+
number: 42,
|
|
82
|
+
boolean: true,
|
|
83
|
+
null: null,
|
|
84
|
+
array: [1, 'two', 3],
|
|
85
|
+
nested: { key: 'value' },
|
|
86
|
+
}
|
|
87
|
+
const result = schema.safeParse(obj)
|
|
88
|
+
expect(result.success).toBe(true)
|
|
89
|
+
if (result.success) {
|
|
90
|
+
expect(result.value).toEqual(obj)
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
it('accepts plain objects with Uint8Array values', () => {
|
|
95
|
+
const obj = {
|
|
96
|
+
bytes: new Uint8Array([1, 2, 3, 4]),
|
|
97
|
+
data: new Uint8Array([255, 0, 128]),
|
|
98
|
+
}
|
|
99
|
+
const result = schema.safeParse(obj)
|
|
100
|
+
expect(result.success).toBe(true)
|
|
101
|
+
if (result.success) {
|
|
102
|
+
expect(result.value).toEqual(obj)
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe('rejects non-plain-objects', () => {
|
|
108
|
+
const schema = new UnknownObjectSchema()
|
|
109
|
+
|
|
110
|
+
it('rejects strings', () => {
|
|
111
|
+
const result = schema.safeParse('not an object')
|
|
112
|
+
expect(result.success).toBe(false)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('rejects numbers', () => {
|
|
116
|
+
const result = schema.safeParse(42)
|
|
117
|
+
expect(result.success).toBe(false)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
it('rejects booleans', () => {
|
|
121
|
+
const result = schema.safeParse(true)
|
|
122
|
+
expect(result.success).toBe(false)
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
it('rejects null', () => {
|
|
126
|
+
const result = schema.safeParse(null)
|
|
127
|
+
expect(result.success).toBe(false)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('rejects undefined', () => {
|
|
131
|
+
const result = schema.safeParse(undefined)
|
|
132
|
+
expect(result.success).toBe(false)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
it('rejects arrays', () => {
|
|
136
|
+
const result = schema.safeParse([1, 2, 3])
|
|
137
|
+
expect(result.success).toBe(false)
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('rejects empty arrays', () => {
|
|
141
|
+
const result = schema.safeParse([])
|
|
142
|
+
expect(result.success).toBe(false)
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
it('rejects Date objects', () => {
|
|
146
|
+
const result = schema.safeParse(new Date())
|
|
147
|
+
expect(result.success).toBe(false)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('rejects RegExp objects', () => {
|
|
151
|
+
const result = schema.safeParse(/test/gi)
|
|
152
|
+
expect(result.success).toBe(false)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('rejects Map objects', () => {
|
|
156
|
+
const result = schema.safeParse(new Map([['key', 'value']]))
|
|
157
|
+
expect(result.success).toBe(false)
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
it('rejects Set objects', () => {
|
|
161
|
+
const result = schema.safeParse(new Set([1, 2, 3]))
|
|
162
|
+
expect(result.success).toBe(false)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('rejects WeakMap objects', () => {
|
|
166
|
+
const result = schema.safeParse(new WeakMap())
|
|
167
|
+
expect(result.success).toBe(false)
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('rejects WeakSet objects', () => {
|
|
171
|
+
const result = schema.safeParse(new WeakSet())
|
|
172
|
+
expect(result.success).toBe(false)
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
it('rejects Error objects', () => {
|
|
176
|
+
const result = schema.safeParse(new Error('test'))
|
|
177
|
+
expect(result.success).toBe(false)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
it('rejects Promise objects', () => {
|
|
181
|
+
const result = schema.safeParse(Promise.resolve(42))
|
|
182
|
+
expect(result.success).toBe(false)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('rejects functions', () => {
|
|
186
|
+
const result = schema.safeParse(() => 'test')
|
|
187
|
+
expect(result.success).toBe(false)
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
it('rejects Symbol', () => {
|
|
191
|
+
const result = schema.safeParse(Symbol('test'))
|
|
192
|
+
expect(result.success).toBe(false)
|
|
193
|
+
})
|
|
194
|
+
|
|
195
|
+
it('rejects BigInt', () => {
|
|
196
|
+
const result = schema.safeParse(BigInt(123))
|
|
197
|
+
expect(result.success).toBe(false)
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
it('rejects class instances', () => {
|
|
201
|
+
class TestClass {
|
|
202
|
+
constructor(public value: string) {}
|
|
203
|
+
}
|
|
204
|
+
const result = schema.safeParse(new TestClass('test'))
|
|
205
|
+
expect(result.success).toBe(false)
|
|
206
|
+
})
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
describe('rejects invalid value types', () => {
|
|
210
|
+
const schema = new UnknownObjectSchema()
|
|
211
|
+
|
|
212
|
+
it('rejects objects with floating point numbers', () => {
|
|
213
|
+
const result = schema.safeParse({ value: 3.14 })
|
|
214
|
+
expect(result.success).toBe(false)
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
it('rejects objects with NaN values', () => {
|
|
218
|
+
const result = schema.safeParse({ value: NaN })
|
|
219
|
+
expect(result.success).toBe(false)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
it('rejects objects with Infinity values', () => {
|
|
223
|
+
const result = schema.safeParse({ value: Infinity })
|
|
224
|
+
expect(result.success).toBe(false)
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
it('rejects objects with -Infinity values', () => {
|
|
228
|
+
const result = schema.safeParse({ value: -Infinity })
|
|
229
|
+
expect(result.success).toBe(false)
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
it('rejects objects with undefined values', () => {
|
|
233
|
+
const result = schema.safeParse({ value: undefined })
|
|
234
|
+
expect(result.success).toBe(false)
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
it('rejects objects with function values', () => {
|
|
238
|
+
const result = schema.safeParse({ fn: () => 'test' })
|
|
239
|
+
expect(result.success).toBe(false)
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
it('rejects objects with Symbol values', () => {
|
|
243
|
+
const result = schema.safeParse({ sym: Symbol('test') })
|
|
244
|
+
expect(result.success).toBe(false)
|
|
245
|
+
})
|
|
246
|
+
|
|
247
|
+
it('rejects objects with BigInt values', () => {
|
|
248
|
+
const result = schema.safeParse({ big: BigInt(123) })
|
|
249
|
+
expect(result.success).toBe(false)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
it('rejects objects with Date values', () => {
|
|
253
|
+
const result = schema.safeParse({ date: new Date() })
|
|
254
|
+
expect(result.success).toBe(false)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('rejects objects with RegExp values', () => {
|
|
258
|
+
const result = schema.safeParse({ pattern: /test/i })
|
|
259
|
+
expect(result.success).toBe(false)
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
it('rejects objects with Map values', () => {
|
|
263
|
+
const result = schema.safeParse({ map: new Map() })
|
|
264
|
+
expect(result.success).toBe(false)
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
it('rejects objects with Set values', () => {
|
|
268
|
+
const result = schema.safeParse({ set: new Set() })
|
|
269
|
+
expect(result.success).toBe(false)
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('rejects objects with Error values', () => {
|
|
273
|
+
const result = schema.safeParse({ error: new Error('test') })
|
|
274
|
+
expect(result.success).toBe(false)
|
|
275
|
+
})
|
|
276
|
+
|
|
277
|
+
it('rejects objects with Promise values', () => {
|
|
278
|
+
const result = schema.safeParse({ promise: Promise.resolve(1) })
|
|
279
|
+
expect(result.success).toBe(false)
|
|
280
|
+
})
|
|
281
|
+
|
|
282
|
+
it('rejects objects with class instance values', () => {
|
|
283
|
+
class TestClass {}
|
|
284
|
+
const result = schema.safeParse({ instance: new TestClass() })
|
|
285
|
+
expect(result.success).toBe(false)
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
describe('rejects invalid nested values', () => {
|
|
290
|
+
const schema = new UnknownObjectSchema()
|
|
291
|
+
|
|
292
|
+
it('rejects deeply nested invalid values', () => {
|
|
293
|
+
const result = schema.safeParse({
|
|
294
|
+
nested: {
|
|
295
|
+
deep: {
|
|
296
|
+
invalid: 3.14,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
})
|
|
300
|
+
expect(result.success).toBe(false)
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
it('rejects arrays with invalid values', () => {
|
|
304
|
+
const result = schema.safeParse({
|
|
305
|
+
items: [1, 2, 3.14],
|
|
306
|
+
})
|
|
307
|
+
expect(result.success).toBe(false)
|
|
308
|
+
})
|
|
309
|
+
|
|
310
|
+
it('rejects arrays with undefined values', () => {
|
|
311
|
+
const result = schema.safeParse({
|
|
312
|
+
items: [1, undefined, 3],
|
|
313
|
+
})
|
|
314
|
+
expect(result.success).toBe(false)
|
|
315
|
+
})
|
|
316
|
+
|
|
317
|
+
it('rejects nested arrays with invalid values', () => {
|
|
318
|
+
const result = schema.safeParse({
|
|
319
|
+
matrix: [
|
|
320
|
+
[1, 2],
|
|
321
|
+
[3, 4.5],
|
|
322
|
+
],
|
|
323
|
+
})
|
|
324
|
+
expect(result.success).toBe(false)
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
it('rejects mixed valid and invalid keys', () => {
|
|
328
|
+
const result = schema.safeParse({
|
|
329
|
+
valid: 'string',
|
|
330
|
+
invalid: Infinity,
|
|
331
|
+
})
|
|
332
|
+
expect(result.success).toBe(false)
|
|
333
|
+
})
|
|
334
|
+
})
|
|
335
|
+
|
|
336
|
+
describe('edge cases', () => {
|
|
337
|
+
const schema = new UnknownObjectSchema()
|
|
338
|
+
|
|
339
|
+
it('accepts objects with numeric string keys', () => {
|
|
340
|
+
const obj = { '0': 'zero', '1': 'one', '2': 'two' }
|
|
341
|
+
const result = schema.safeParse(obj)
|
|
342
|
+
expect(result.success).toBe(true)
|
|
343
|
+
if (result.success) {
|
|
344
|
+
expect(result.value).toEqual(obj)
|
|
345
|
+
}
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
it('accepts objects with special string keys', () => {
|
|
349
|
+
const obj = {
|
|
350
|
+
'with spaces': 'value',
|
|
351
|
+
'with-dashes': 'value',
|
|
352
|
+
'with.dots': 'value',
|
|
353
|
+
with_underscores: 'value',
|
|
354
|
+
}
|
|
355
|
+
const result = schema.safeParse(obj)
|
|
356
|
+
expect(result.success).toBe(true)
|
|
357
|
+
if (result.success) {
|
|
358
|
+
expect(result.value).toEqual(obj)
|
|
359
|
+
}
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
it('accepts objects with empty string keys', () => {
|
|
363
|
+
const obj = { '': 'empty key value' }
|
|
364
|
+
const result = schema.safeParse(obj)
|
|
365
|
+
expect(result.success).toBe(true)
|
|
366
|
+
if (result.success) {
|
|
367
|
+
expect(result.value).toEqual(obj)
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
it('accepts objects with zero values', () => {
|
|
372
|
+
const obj = { count: 0, index: 0 }
|
|
373
|
+
const result = schema.safeParse(obj)
|
|
374
|
+
expect(result.success).toBe(true)
|
|
375
|
+
if (result.success) {
|
|
376
|
+
expect(result.value).toEqual(obj)
|
|
377
|
+
}
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
it('accepts objects with negative integer values', () => {
|
|
381
|
+
const obj = { temperature: -10, balance: -500 }
|
|
382
|
+
const result = schema.safeParse(obj)
|
|
383
|
+
expect(result.success).toBe(true)
|
|
384
|
+
if (result.success) {
|
|
385
|
+
expect(result.value).toEqual(obj)
|
|
386
|
+
}
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
it('accepts objects with empty string values', () => {
|
|
390
|
+
const obj = { name: '', description: '' }
|
|
391
|
+
const result = schema.safeParse(obj)
|
|
392
|
+
expect(result.success).toBe(true)
|
|
393
|
+
if (result.success) {
|
|
394
|
+
expect(result.value).toEqual(obj)
|
|
395
|
+
}
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
it('accepts objects with empty array values', () => {
|
|
399
|
+
const obj = { items: [], tags: [] }
|
|
400
|
+
const result = schema.safeParse(obj)
|
|
401
|
+
expect(result.success).toBe(true)
|
|
402
|
+
if (result.success) {
|
|
403
|
+
expect(result.value).toEqual(obj)
|
|
404
|
+
}
|
|
405
|
+
})
|
|
406
|
+
|
|
407
|
+
it('accepts objects with empty nested objects', () => {
|
|
408
|
+
const obj = { config: {}, metadata: {} }
|
|
409
|
+
const result = schema.safeParse(obj)
|
|
410
|
+
expect(result.success).toBe(true)
|
|
411
|
+
if (result.success) {
|
|
412
|
+
expect(result.value).toEqual(obj)
|
|
413
|
+
}
|
|
414
|
+
})
|
|
415
|
+
|
|
416
|
+
it('accepts objects with empty Uint8Array values', () => {
|
|
417
|
+
const obj = { data: new Uint8Array([]) }
|
|
418
|
+
const result = schema.safeParse(obj)
|
|
419
|
+
expect(result.success).toBe(true)
|
|
420
|
+
if (result.success) {
|
|
421
|
+
expect(result.value).toEqual(obj)
|
|
422
|
+
}
|
|
423
|
+
})
|
|
424
|
+
|
|
425
|
+
it('accepts deeply nested structures', () => {
|
|
426
|
+
const obj = {
|
|
427
|
+
level1: {
|
|
428
|
+
level2: {
|
|
429
|
+
level3: {
|
|
430
|
+
level4: {
|
|
431
|
+
level5: {
|
|
432
|
+
value: 'deep',
|
|
433
|
+
array: [1, 2, [3, 4, [5]]],
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
}
|
|
440
|
+
const result = schema.safeParse(obj)
|
|
441
|
+
expect(result.success).toBe(true)
|
|
442
|
+
if (result.success) {
|
|
443
|
+
expect(result.value).toEqual(obj)
|
|
444
|
+
}
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
it('accepts complex nested arrays and objects', () => {
|
|
448
|
+
const obj = {
|
|
449
|
+
matrix: [
|
|
450
|
+
[1, 2],
|
|
451
|
+
[3, 4],
|
|
452
|
+
[5, 6],
|
|
453
|
+
],
|
|
454
|
+
nested: {
|
|
455
|
+
arrays: [[['deep']]],
|
|
456
|
+
mixed: [{ a: 1 }, { b: 2 }],
|
|
457
|
+
},
|
|
458
|
+
}
|
|
459
|
+
const result = schema.safeParse(obj)
|
|
460
|
+
expect(result.success).toBe(true)
|
|
461
|
+
if (result.success) {
|
|
462
|
+
expect(result.value).toEqual(obj)
|
|
463
|
+
}
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
it('accepts objects with null prototype', () => {
|
|
467
|
+
const obj = Object.create(null)
|
|
468
|
+
obj.key = 'value'
|
|
469
|
+
obj.count = 42
|
|
470
|
+
const result = schema.safeParse(obj)
|
|
471
|
+
expect(result.success).toBe(true)
|
|
472
|
+
if (result.success) {
|
|
473
|
+
expect(result.value).toBe(obj)
|
|
474
|
+
}
|
|
475
|
+
})
|
|
476
|
+
|
|
477
|
+
it('accepts objects with $type property', () => {
|
|
478
|
+
const obj = { $type: 'app.bsky.feed.post', text: 'Hello' }
|
|
479
|
+
const result = schema.safeParse(obj)
|
|
480
|
+
expect(result.success).toBe(true)
|
|
481
|
+
if (result.success) {
|
|
482
|
+
expect(result.value).toEqual(obj)
|
|
483
|
+
}
|
|
484
|
+
})
|
|
485
|
+
|
|
486
|
+
it('accepts objects with various special characters in keys', () => {
|
|
487
|
+
const obj = {
|
|
488
|
+
'@mention': 'user',
|
|
489
|
+
'#hashtag': 'tag',
|
|
490
|
+
'!important': 'flag',
|
|
491
|
+
'key:value': 'pair',
|
|
492
|
+
}
|
|
493
|
+
const result = schema.safeParse(obj)
|
|
494
|
+
expect(result.success).toBe(true)
|
|
495
|
+
if (result.success) {
|
|
496
|
+
expect(result.value).toEqual(obj)
|
|
497
|
+
}
|
|
498
|
+
})
|
|
499
|
+
})
|
|
500
|
+
|
|
501
|
+
describe('large objects', () => {
|
|
502
|
+
const schema = new UnknownObjectSchema()
|
|
503
|
+
|
|
504
|
+
it('accepts objects with many keys', () => {
|
|
505
|
+
const obj: Record<string, number> = {}
|
|
506
|
+
for (let i = 0; i < 100; i++) {
|
|
507
|
+
obj[`key${i}`] = i
|
|
508
|
+
}
|
|
509
|
+
const result = schema.safeParse(obj)
|
|
510
|
+
expect(result.success).toBe(true)
|
|
511
|
+
if (result.success) {
|
|
512
|
+
expect(result.value).toEqual(obj)
|
|
513
|
+
}
|
|
514
|
+
})
|
|
515
|
+
|
|
516
|
+
it('accepts objects with large arrays', () => {
|
|
517
|
+
const obj = {
|
|
518
|
+
numbers: Array.from({ length: 1000 }, (_, i) => i),
|
|
519
|
+
}
|
|
520
|
+
const result = schema.safeParse(obj)
|
|
521
|
+
expect(result.success).toBe(true)
|
|
522
|
+
if (result.success) {
|
|
523
|
+
expect(result.value).toEqual(obj)
|
|
524
|
+
}
|
|
525
|
+
})
|
|
526
|
+
|
|
527
|
+
it('accepts objects with large Uint8Array values', () => {
|
|
528
|
+
const obj = {
|
|
529
|
+
data: new Uint8Array(1000).fill(0),
|
|
530
|
+
}
|
|
531
|
+
const result = schema.safeParse(obj)
|
|
532
|
+
expect(result.success).toBe(true)
|
|
533
|
+
if (result.success) {
|
|
534
|
+
expect(result.value).toEqual(obj)
|
|
535
|
+
}
|
|
536
|
+
})
|
|
537
|
+
})
|
|
538
|
+
|
|
539
|
+
describe('preservation of input', () => {
|
|
540
|
+
const schema = new UnknownObjectSchema()
|
|
541
|
+
|
|
542
|
+
it('preserves the original object reference', () => {
|
|
543
|
+
const input = { key: 'value', count: 42 }
|
|
544
|
+
const result = schema.safeParse(input)
|
|
545
|
+
|
|
546
|
+
if (result.success) {
|
|
547
|
+
expect(result.value).toBe(input)
|
|
548
|
+
} else {
|
|
549
|
+
throw new Error('Expected validation to succeed')
|
|
550
|
+
}
|
|
551
|
+
})
|
|
552
|
+
|
|
553
|
+
it('preserves nested object references', () => {
|
|
554
|
+
const nested = { inner: 'value' }
|
|
555
|
+
const input = { outer: nested }
|
|
556
|
+
const result = schema.safeParse(input)
|
|
557
|
+
|
|
558
|
+
if (result.success) {
|
|
559
|
+
expect(result.value).toBe(input)
|
|
560
|
+
expect(result.value.outer).toBe(nested)
|
|
561
|
+
} else {
|
|
562
|
+
throw new Error('Expected validation to succeed')
|
|
563
|
+
}
|
|
564
|
+
})
|
|
565
|
+
|
|
566
|
+
it('preserves array references in object values', () => {
|
|
567
|
+
const arr = [1, 2, 3]
|
|
568
|
+
const input = { items: arr }
|
|
569
|
+
const result = schema.safeParse(input)
|
|
570
|
+
|
|
571
|
+
if (result.success) {
|
|
572
|
+
expect(result.value).toBe(input)
|
|
573
|
+
expect(result.value.items).toBe(arr)
|
|
574
|
+
} else {
|
|
575
|
+
throw new Error('Expected validation to succeed')
|
|
576
|
+
}
|
|
577
|
+
})
|
|
578
|
+
|
|
579
|
+
it('preserves Uint8Array references in object values', () => {
|
|
580
|
+
const bytes = new Uint8Array([1, 2, 3])
|
|
581
|
+
const input = { data: bytes }
|
|
582
|
+
const result = schema.safeParse(input)
|
|
583
|
+
|
|
584
|
+
if (result.success) {
|
|
585
|
+
expect(result.value).toBe(input)
|
|
586
|
+
expect(result.value.data).toBe(bytes)
|
|
587
|
+
} else {
|
|
588
|
+
throw new Error('Expected validation to succeed')
|
|
589
|
+
}
|
|
590
|
+
})
|
|
591
|
+
})
|
|
592
|
+
})
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { LexMap, isLexMap } from '@atproto/lex-data'
|
|
2
|
-
import {
|
|
2
|
+
import { Schema, ValidationResult, ValidatorContext } from '../validation'
|
|
3
3
|
|
|
4
4
|
export type { LexMap }
|
|
5
5
|
export type UnknownObjectOutput = LexMap
|
|
6
6
|
|
|
7
|
-
export class UnknownObjectSchema extends
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
override validateInContext(
|
|
7
|
+
export class UnknownObjectSchema extends Schema<UnknownObjectOutput> {
|
|
8
|
+
validateInContext(
|
|
11
9
|
input: unknown,
|
|
12
10
|
ctx: ValidatorContext,
|
|
13
11
|
): ValidationResult<UnknownObjectOutput> {
|