@atproto/lex-schema 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/LICENSE.txt +1 -1
- package/dist/core/$type.d.ts +11 -0
- package/dist/core/$type.d.ts.map +1 -1
- package/dist/core/$type.js +4 -0
- package/dist/core/$type.js.map +1 -1
- package/dist/core/schema.d.ts +31 -24
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +38 -8
- package/dist/core/schema.js.map +1 -1
- package/dist/core/string-format.d.ts +35 -35
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js +49 -91
- package/dist/core/string-format.js.map +1 -1
- package/dist/core/validation-issue.js +1 -1
- package/dist/core/validation-issue.js.map +1 -1
- package/dist/core/validator.d.ts +53 -32
- package/dist/core/validator.d.ts.map +1 -1
- package/dist/core/validator.js +18 -22
- package/dist/core/validator.js.map +1 -1
- package/dist/external.d.ts +0 -85
- package/dist/external.d.ts.map +1 -1
- package/dist/external.js +0 -164
- package/dist/external.js.map +1 -1
- package/dist/helpers.d.ts +10 -5
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +3 -3
- package/dist/helpers.js.map +1 -1
- package/dist/schema/array.d.ts +9 -5
- package/dist/schema/array.d.ts.map +1 -1
- package/dist/schema/array.js +14 -5
- package/dist/schema/array.js.map +1 -1
- package/dist/schema/blob.d.ts +9 -7
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +9 -5
- package/dist/schema/blob.js.map +1 -1
- package/dist/schema/boolean.d.ts +3 -7
- package/dist/schema/boolean.d.ts.map +1 -1
- package/dist/schema/boolean.js +6 -7
- package/dist/schema/boolean.js.map +1 -1
- package/dist/schema/bytes.d.ts +3 -2
- package/dist/schema/bytes.d.ts.map +1 -1
- package/dist/schema/bytes.js +7 -3
- package/dist/schema/bytes.js.map +1 -1
- package/dist/schema/cid.d.ts +10 -8
- package/dist/schema/cid.d.ts.map +1 -1
- package/dist/schema/cid.js +5 -1
- package/dist/schema/cid.js.map +1 -1
- package/dist/schema/custom.d.ts +6 -5
- package/dist/schema/custom.d.ts.map +1 -1
- package/dist/schema/custom.js +10 -4
- package/dist/schema/custom.js.map +1 -1
- package/dist/schema/dict.d.ts +8 -8
- package/dist/schema/dict.d.ts.map +1 -1
- package/dist/schema/dict.js +11 -2
- package/dist/schema/dict.js.map +1 -1
- package/dist/schema/discriminated-union.d.ts +21 -14
- package/dist/schema/discriminated-union.d.ts.map +1 -1
- package/dist/schema/discriminated-union.js +7 -0
- package/dist/schema/discriminated-union.js.map +1 -1
- package/dist/schema/enum.d.ts +7 -9
- package/dist/schema/enum.d.ts.map +1 -1
- package/dist/schema/enum.js +8 -4
- package/dist/schema/enum.js.map +1 -1
- package/dist/schema/integer.d.ts +5 -5
- package/dist/schema/integer.d.ts.map +1 -1
- package/dist/schema/integer.js +9 -5
- package/dist/schema/integer.js.map +1 -1
- package/dist/schema/intersection.d.ts +4 -4
- package/dist/schema/intersection.d.ts.map +1 -1
- package/dist/schema/intersection.js +5 -0
- package/dist/schema/intersection.js.map +1 -1
- package/dist/schema/literal.d.ts +6 -9
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +7 -4
- package/dist/schema/literal.js.map +1 -1
- package/dist/schema/never.d.ts +3 -2
- package/dist/schema/never.d.ts.map +1 -1
- package/dist/schema/never.js +5 -1
- package/dist/schema/never.js.map +1 -1
- package/dist/schema/null.d.ts +4 -3
- package/dist/schema/null.d.ts.map +1 -1
- package/dist/schema/null.js +6 -4
- package/dist/schema/null.js.map +1 -1
- package/dist/schema/nullable.d.ts +6 -5
- package/dist/schema/nullable.d.ts.map +1 -1
- package/dist/schema/nullable.js +9 -5
- package/dist/schema/nullable.js.map +1 -1
- package/dist/schema/object.d.ts +10 -8
- package/dist/schema/object.d.ts.map +1 -1
- package/dist/schema/object.js +11 -3
- package/dist/schema/object.js.map +1 -1
- package/dist/schema/optional.d.ts +7 -5
- package/dist/schema/optional.d.ts.map +1 -1
- package/dist/schema/optional.js +14 -6
- package/dist/schema/optional.js.map +1 -1
- package/dist/schema/params.d.ts +24 -13
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +47 -25
- package/dist/schema/params.js.map +1 -1
- package/dist/schema/payload.d.ts +12 -9
- package/dist/schema/payload.d.ts.map +1 -1
- package/dist/schema/payload.js +11 -0
- package/dist/schema/payload.js.map +1 -1
- package/dist/schema/permission-set.d.ts +1 -0
- package/dist/schema/permission-set.d.ts.map +1 -1
- package/dist/schema/permission-set.js +5 -0
- package/dist/schema/permission-set.js.map +1 -1
- package/dist/schema/permission.d.ts +6 -5
- package/dist/schema/permission.d.ts.map +1 -1
- package/dist/schema/permission.js +5 -0
- package/dist/schema/permission.js.map +1 -1
- package/dist/schema/procedure.d.ts +2 -1
- package/dist/schema/procedure.d.ts.map +1 -1
- package/dist/schema/procedure.js +5 -0
- package/dist/schema/procedure.js.map +1 -1
- package/dist/schema/query.d.ts +2 -1
- package/dist/schema/query.d.ts.map +1 -1
- package/dist/schema/query.js +5 -0
- package/dist/schema/query.js.map +1 -1
- package/dist/schema/record.d.ts +48 -30
- package/dist/schema/record.d.ts.map +1 -1
- package/dist/schema/record.js +12 -9
- package/dist/schema/record.js.map +1 -1
- package/dist/schema/ref.d.ts +9 -6
- package/dist/schema/ref.d.ts.map +1 -1
- package/dist/schema/ref.js +9 -16
- package/dist/schema/ref.js.map +1 -1
- package/dist/schema/refine.d.ts +4 -4
- package/dist/schema/refine.d.ts.map +1 -1
- package/dist/schema/refine.js.map +1 -1
- package/dist/schema/regexp.d.ts +4 -3
- package/dist/schema/regexp.d.ts.map +1 -1
- package/dist/schema/regexp.js +5 -0
- package/dist/schema/regexp.js.map +1 -1
- package/dist/schema/string.d.ts +7 -8
- package/dist/schema/string.d.ts.map +1 -1
- package/dist/schema/string.js +13 -19
- package/dist/schema/string.js.map +1 -1
- package/dist/schema/subscription.d.ts +2 -1
- package/dist/schema/subscription.d.ts.map +1 -1
- package/dist/schema/subscription.js +5 -0
- package/dist/schema/subscription.js.map +1 -1
- package/dist/schema/token.d.ts +6 -5
- package/dist/schema/token.d.ts.map +1 -1
- package/dist/schema/token.js +5 -0
- package/dist/schema/token.js.map +1 -1
- package/dist/schema/typed-object.d.ts +43 -26
- package/dist/schema/typed-object.d.ts.map +1 -1
- package/dist/schema/typed-object.js +6 -3
- package/dist/schema/typed-object.js.map +1 -1
- package/dist/schema/typed-ref.d.ts +16 -25
- package/dist/schema/typed-ref.d.ts.map +1 -1
- package/dist/schema/typed-ref.js +7 -17
- package/dist/schema/typed-ref.js.map +1 -1
- package/dist/schema/typed-union.d.ts +9 -21
- package/dist/schema/typed-union.d.ts.map +1 -1
- package/dist/schema/typed-union.js +15 -11
- package/dist/schema/typed-union.js.map +1 -1
- package/dist/schema/union.d.ts +6 -6
- package/dist/schema/union.d.ts.map +1 -1
- package/dist/schema/union.js +7 -5
- package/dist/schema/union.js.map +1 -1
- package/dist/schema/unknown-object.d.ts +5 -4
- package/dist/schema/unknown-object.d.ts.map +1 -1
- package/dist/schema/unknown-object.js +5 -1
- package/dist/schema/unknown-object.js.map +1 -1
- package/dist/schema/unknown.d.ts +3 -2
- package/dist/schema/unknown.d.ts.map +1 -1
- package/dist/schema/unknown.js +5 -1
- package/dist/schema/unknown.js.map +1 -1
- package/dist/schema/with-default.d.ts +9 -0
- package/dist/schema/with-default.d.ts.map +1 -0
- package/dist/schema/with-default.js +27 -0
- package/dist/schema/with-default.js.map +1 -0
- package/dist/schema.d.ts +2 -2
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +2 -4
- package/dist/schema.js.map +1 -1
- package/dist/util/assertion-util.d.ts +0 -6
- package/dist/util/assertion-util.d.ts.map +1 -1
- package/dist/util/assertion-util.js +0 -28
- package/dist/util/assertion-util.js.map +1 -1
- package/dist/util/memoize.d.ts +2 -2
- package/dist/util/memoize.d.ts.map +1 -1
- package/dist/util/memoize.js +23 -39
- package/dist/util/memoize.js.map +1 -1
- package/package.json +3 -3
- package/src/core/$type.test.ts +20 -0
- package/src/core/$type.ts +30 -0
- package/src/core/schema.ts +86 -38
- package/src/core/string-format.ts +119 -158
- package/src/core/validation-issue.ts +1 -1
- package/src/core/validator.ts +93 -53
- package/src/external.ts +0 -404
- package/src/helpers.test.ts +22 -21
- package/src/helpers.ts +14 -14
- package/src/schema/array.test.ts +38 -40
- package/src/schema/array.ts +35 -13
- package/src/schema/blob.test.ts +21 -21
- package/src/schema/blob.ts +19 -17
- package/src/schema/boolean.test.ts +9 -8
- package/src/schema/boolean.ts +7 -13
- package/src/schema/bytes.test.ts +13 -13
- package/src/schema/bytes.ts +13 -8
- package/src/schema/cid.test.ts +3 -3
- package/src/schema/cid.ts +15 -13
- package/src/schema/custom.test.ts +26 -26
- package/src/schema/custom.ts +20 -13
- package/src/schema/dict.test.ts +21 -39
- package/src/schema/dict.ts +28 -19
- package/src/schema/discriminated-union.test.ts +128 -128
- package/src/schema/discriminated-union.ts +45 -26
- package/src/schema/enum.test.ts +17 -16
- package/src/schema/enum.ts +16 -16
- package/src/schema/integer.test.ts +22 -21
- package/src/schema/integer.ts +12 -9
- package/src/schema/intersection.test.ts +10 -10
- package/src/schema/intersection.ts +17 -14
- package/src/schema/literal.test.ts +35 -34
- package/src/schema/literal.ts +12 -15
- package/src/schema/never.test.ts +5 -5
- package/src/schema/never.ts +7 -2
- package/src/schema/null.test.ts +3 -3
- package/src/schema/null.ts +9 -9
- package/src/schema/nullable.test.ts +31 -42
- package/src/schema/nullable.ts +17 -9
- package/src/schema/object.test.ts +10 -12
- package/src/schema/object.ts +27 -18
- package/src/schema/optional.test.ts +21 -28
- package/src/schema/optional.ts +27 -10
- package/src/schema/params.test.ts +471 -47
- package/src/schema/params.ts +72 -38
- package/src/schema/payload.test.ts +150 -156
- package/src/schema/payload.ts +35 -19
- package/src/schema/permission-set.test.ts +206 -273
- package/src/schema/permission-set.ts +8 -0
- package/src/schema/permission.test.ts +177 -177
- package/src/schema/permission.ts +13 -5
- package/src/schema/procedure.test.ts +183 -242
- package/src/schema/procedure.ts +18 -5
- package/src/schema/query.test.ts +186 -200
- package/src/schema/query.ts +16 -4
- package/src/schema/record.test.ts +121 -101
- package/src/schema/record.ts +74 -40
- package/src/schema/ref.test.ts +101 -118
- package/src/schema/ref.ts +33 -28
- package/src/schema/refine.test.ts +28 -28
- package/src/schema/refine.ts +23 -20
- package/src/schema/regexp.test.ts +29 -33
- package/src/schema/regexp.ts +11 -7
- package/src/schema/string.test.ts +35 -35
- package/src/schema/string.ts +24 -33
- package/src/schema/subscription.test.ts +259 -387
- package/src/schema/subscription.ts +16 -4
- package/src/schema/token.test.ts +47 -324
- package/src/schema/token.ts +14 -7
- package/src/schema/typed-object.test.ts +98 -81
- package/src/schema/typed-object.ts +68 -33
- package/src/schema/typed-ref.test.ts +206 -234
- package/src/schema/typed-ref.ts +40 -42
- package/src/schema/typed-union.test.ts +40 -64
- package/src/schema/typed-union.ts +36 -58
- package/src/schema/union.test.ts +17 -27
- package/src/schema/union.ts +20 -16
- package/src/schema/unknown-object.test.ts +8 -8
- package/src/schema/unknown-object.ts +9 -7
- package/src/schema/unknown.test.ts +4 -4
- package/src/schema/unknown.ts +7 -5
- package/src/schema/with-default.ts +35 -0
- package/src/schema.ts +2 -6
- package/src/util/assertion-util.ts +0 -39
- package/src/util/memoize.ts +26 -46
- package/dist/schema/_parameters.d.ts +0 -17
- package/dist/schema/_parameters.d.ts.map +0 -1
- package/dist/schema/_parameters.js +0 -20
- package/dist/schema/_parameters.js.map +0 -1
- package/src/schema/_parameters.test.ts +0 -417
- package/src/schema/_parameters.ts +0 -26
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest'
|
|
2
2
|
import { IssueCustom } from '../core.js'
|
|
3
|
-
import {
|
|
3
|
+
import { custom } from './custom.js'
|
|
4
4
|
|
|
5
5
|
describe('CustomSchema', () => {
|
|
6
6
|
describe('basic validation', () => {
|
|
7
7
|
it('validates input that passes custom assertion', () => {
|
|
8
|
-
const schema =
|
|
8
|
+
const schema = custom(
|
|
9
9
|
(input): input is string => typeof input === 'string',
|
|
10
10
|
'Must be a string',
|
|
11
11
|
)
|
|
@@ -17,7 +17,7 @@ describe('CustomSchema', () => {
|
|
|
17
17
|
})
|
|
18
18
|
|
|
19
19
|
it('rejects input that fails custom assertion', () => {
|
|
20
|
-
const schema =
|
|
20
|
+
const schema = custom(
|
|
21
21
|
(input): input is string => typeof input === 'string',
|
|
22
22
|
'Must be a string',
|
|
23
23
|
)
|
|
@@ -26,7 +26,7 @@ describe('CustomSchema', () => {
|
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
it('includes custom message in error', () => {
|
|
29
|
-
const schema =
|
|
29
|
+
const schema = custom(
|
|
30
30
|
(input): input is string => typeof input === 'string',
|
|
31
31
|
'Custom error message',
|
|
32
32
|
)
|
|
@@ -45,7 +45,7 @@ describe('CustomSchema', () => {
|
|
|
45
45
|
age: number
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
const schema =
|
|
48
|
+
const schema = custom((input): input is User => {
|
|
49
49
|
return (
|
|
50
50
|
typeof input === 'object' &&
|
|
51
51
|
input !== null &&
|
|
@@ -65,7 +65,7 @@ describe('CustomSchema', () => {
|
|
|
65
65
|
age: number
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
const schema =
|
|
68
|
+
const schema = custom((input): input is User => {
|
|
69
69
|
return (
|
|
70
70
|
typeof input === 'object' &&
|
|
71
71
|
input !== null &&
|
|
@@ -80,7 +80,7 @@ describe('CustomSchema', () => {
|
|
|
80
80
|
})
|
|
81
81
|
|
|
82
82
|
it('validates arrays with specific element types', () => {
|
|
83
|
-
const schema =
|
|
83
|
+
const schema = custom((input): input is number[] => {
|
|
84
84
|
return (
|
|
85
85
|
Array.isArray(input) &&
|
|
86
86
|
input.every((item) => typeof item === 'number')
|
|
@@ -92,7 +92,7 @@ describe('CustomSchema', () => {
|
|
|
92
92
|
})
|
|
93
93
|
|
|
94
94
|
it('rejects arrays with mixed types', () => {
|
|
95
|
-
const schema =
|
|
95
|
+
const schema = custom((input): input is number[] => {
|
|
96
96
|
return (
|
|
97
97
|
Array.isArray(input) &&
|
|
98
98
|
input.every((item) => typeof item === 'number')
|
|
@@ -106,7 +106,7 @@ describe('CustomSchema', () => {
|
|
|
106
106
|
|
|
107
107
|
describe('custom context usage', () => {
|
|
108
108
|
it('can add custom issues through context', () => {
|
|
109
|
-
const schema =
|
|
109
|
+
const schema = custom((input, ctx): input is string => {
|
|
110
110
|
if (typeof input !== 'string') {
|
|
111
111
|
ctx.addIssue({
|
|
112
112
|
code: 'invalid_type',
|
|
@@ -125,7 +125,7 @@ describe('CustomSchema', () => {
|
|
|
125
125
|
|
|
126
126
|
it('accesses path from context', () => {
|
|
127
127
|
let capturedPath: any[] = []
|
|
128
|
-
const schema =
|
|
128
|
+
const schema = custom((input, ctx): input is string => {
|
|
129
129
|
capturedPath = [...ctx.path]
|
|
130
130
|
return typeof input === 'string'
|
|
131
131
|
}, 'Must be a string')
|
|
@@ -135,7 +135,7 @@ describe('CustomSchema', () => {
|
|
|
135
135
|
})
|
|
136
136
|
|
|
137
137
|
it('validates with custom path', () => {
|
|
138
|
-
const schema =
|
|
138
|
+
const schema = custom(
|
|
139
139
|
(input): input is string => typeof input === 'string',
|
|
140
140
|
'Must be a string',
|
|
141
141
|
'customField',
|
|
@@ -149,7 +149,7 @@ describe('CustomSchema', () => {
|
|
|
149
149
|
})
|
|
150
150
|
|
|
151
151
|
it('validates with array of paths', () => {
|
|
152
|
-
const schema =
|
|
152
|
+
const schema = custom(
|
|
153
153
|
(input): input is string => typeof input === 'string',
|
|
154
154
|
'Must be a string',
|
|
155
155
|
['nested', 'field'],
|
|
@@ -166,7 +166,7 @@ describe('CustomSchema', () => {
|
|
|
166
166
|
|
|
167
167
|
describe('business logic validation', () => {
|
|
168
168
|
it('validates email format', () => {
|
|
169
|
-
const schema =
|
|
169
|
+
const schema = custom((input): input is string => {
|
|
170
170
|
return (
|
|
171
171
|
typeof input === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input)
|
|
172
172
|
)
|
|
@@ -180,7 +180,7 @@ describe('CustomSchema', () => {
|
|
|
180
180
|
})
|
|
181
181
|
|
|
182
182
|
it('validates password strength', () => {
|
|
183
|
-
const schema =
|
|
183
|
+
const schema = custom((input): input is string => {
|
|
184
184
|
if (typeof input !== 'string') return false
|
|
185
185
|
return (
|
|
186
186
|
input.length >= 8 &&
|
|
@@ -198,7 +198,7 @@ describe('CustomSchema', () => {
|
|
|
198
198
|
})
|
|
199
199
|
|
|
200
200
|
it('validates age range', () => {
|
|
201
|
-
const schema =
|
|
201
|
+
const schema = custom((input): input is number => {
|
|
202
202
|
return typeof input === 'number' && input >= 18 && input <= 120
|
|
203
203
|
}, 'Age must be between 18 and 120')
|
|
204
204
|
|
|
@@ -213,7 +213,7 @@ describe('CustomSchema', () => {
|
|
|
213
213
|
})
|
|
214
214
|
|
|
215
215
|
it('validates positive numbers', () => {
|
|
216
|
-
const schema =
|
|
216
|
+
const schema = custom((input): input is number => {
|
|
217
217
|
return typeof input === 'number' && input > 0
|
|
218
218
|
}, 'Must be a positive number')
|
|
219
219
|
|
|
@@ -230,7 +230,7 @@ describe('CustomSchema', () => {
|
|
|
230
230
|
|
|
231
231
|
describe('edge cases', () => {
|
|
232
232
|
it('handles null input', () => {
|
|
233
|
-
const schema =
|
|
233
|
+
const schema = custom(
|
|
234
234
|
(input): input is null => input === null,
|
|
235
235
|
'Must be null',
|
|
236
236
|
)
|
|
@@ -243,7 +243,7 @@ describe('CustomSchema', () => {
|
|
|
243
243
|
})
|
|
244
244
|
|
|
245
245
|
it('handles undefined input', () => {
|
|
246
|
-
const schema =
|
|
246
|
+
const schema = custom(
|
|
247
247
|
(input): input is undefined => input === undefined,
|
|
248
248
|
'Must be undefined',
|
|
249
249
|
)
|
|
@@ -256,7 +256,7 @@ describe('CustomSchema', () => {
|
|
|
256
256
|
})
|
|
257
257
|
|
|
258
258
|
it('handles empty string', () => {
|
|
259
|
-
const schema =
|
|
259
|
+
const schema = custom(
|
|
260
260
|
(input): input is string =>
|
|
261
261
|
typeof input === 'string' && input.length > 0,
|
|
262
262
|
'Must be a non-empty string',
|
|
@@ -270,7 +270,7 @@ describe('CustomSchema', () => {
|
|
|
270
270
|
})
|
|
271
271
|
|
|
272
272
|
it('handles empty array', () => {
|
|
273
|
-
const schema =
|
|
273
|
+
const schema = custom(
|
|
274
274
|
(input): input is any[] => Array.isArray(input) && input.length > 0,
|
|
275
275
|
'Must be a non-empty array',
|
|
276
276
|
)
|
|
@@ -288,7 +288,7 @@ describe('CustomSchema', () => {
|
|
|
288
288
|
metadata: { count: number }
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
-
const schema =
|
|
291
|
+
const schema = custom((input): input is ComplexType => {
|
|
292
292
|
if (typeof input !== 'object' || input === null) return false
|
|
293
293
|
const obj = input as any
|
|
294
294
|
return (
|
|
@@ -325,7 +325,7 @@ describe('CustomSchema', () => {
|
|
|
325
325
|
it('correctly narrows union types', () => {
|
|
326
326
|
type StringOrNumber = string | number
|
|
327
327
|
|
|
328
|
-
const schema =
|
|
328
|
+
const schema = custom(
|
|
329
329
|
(input): input is string => typeof input === 'string',
|
|
330
330
|
'Must be a string',
|
|
331
331
|
)
|
|
@@ -347,7 +347,7 @@ describe('CustomSchema', () => {
|
|
|
347
347
|
| { type: 'circle'; radius: number }
|
|
348
348
|
| { type: 'rectangle'; width: number; height: number }
|
|
349
349
|
|
|
350
|
-
const circleSchema =
|
|
350
|
+
const circleSchema = custom((input): input is Shape => {
|
|
351
351
|
return (
|
|
352
352
|
typeof input === 'object' &&
|
|
353
353
|
input !== null &&
|
|
@@ -380,13 +380,13 @@ describe('CustomSchema', () => {
|
|
|
380
380
|
return typeof input === 'string'
|
|
381
381
|
})
|
|
382
382
|
|
|
383
|
-
|
|
383
|
+
custom(assertion as any, 'Must be a string').safeParse('test')
|
|
384
384
|
|
|
385
385
|
expect(assertion).toHaveBeenCalledTimes(1)
|
|
386
386
|
})
|
|
387
387
|
|
|
388
388
|
it('provides addIssue method in context', () => {
|
|
389
|
-
const schema =
|
|
389
|
+
const schema = custom((input, ctx): input is string => {
|
|
390
390
|
ctx.addIssue(new IssueCustom(ctx.path, input, 'This is a custom issue'))
|
|
391
391
|
return false
|
|
392
392
|
}, 'Must be a string')
|
|
@@ -403,7 +403,7 @@ describe('CustomSchema', () => {
|
|
|
403
403
|
})
|
|
404
404
|
|
|
405
405
|
it('provides path array in context', () => {
|
|
406
|
-
const schema =
|
|
406
|
+
const schema = custom((input, ctx): input is string => {
|
|
407
407
|
expect(Array.isArray(ctx.path)).toBe(true)
|
|
408
408
|
return typeof input === 'string'
|
|
409
409
|
}, 'Must be a string')
|
package/src/schema/custom.ts
CHANGED
|
@@ -3,8 +3,7 @@ import {
|
|
|
3
3
|
IssueCustom,
|
|
4
4
|
PropertyKey,
|
|
5
5
|
Schema,
|
|
6
|
-
|
|
7
|
-
ValidatorContext,
|
|
6
|
+
ValidationContext,
|
|
8
7
|
} from '../core.js'
|
|
9
8
|
|
|
10
9
|
export type CustomAssertionContext = {
|
|
@@ -12,27 +11,35 @@ export type CustomAssertionContext = {
|
|
|
12
11
|
addIssue(issue: Issue): void
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
export type CustomAssertion<
|
|
14
|
+
export type CustomAssertion<TValue> = (
|
|
16
15
|
this: null,
|
|
17
16
|
input: unknown,
|
|
18
17
|
ctx: CustomAssertionContext,
|
|
19
|
-
) => input is
|
|
18
|
+
) => input is TValue
|
|
20
19
|
|
|
21
|
-
export class CustomSchema<
|
|
20
|
+
export class CustomSchema<const TValue = unknown> extends Schema<TValue> {
|
|
22
21
|
constructor(
|
|
23
|
-
private readonly assertion: CustomAssertion<
|
|
22
|
+
private readonly assertion: CustomAssertion<TValue>,
|
|
24
23
|
private readonly message: string,
|
|
25
24
|
private readonly path?: PropertyKey | readonly PropertyKey[],
|
|
26
25
|
) {
|
|
27
26
|
super()
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
validateInContext(
|
|
31
|
-
input
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return ctx.issue(new IssueCustom(path, input, this.message))
|
|
29
|
+
validateInContext(input: unknown, ctx: ValidationContext) {
|
|
30
|
+
if (!this.assertion.call(null, input, ctx)) {
|
|
31
|
+
const path = ctx.concatPath(this.path)
|
|
32
|
+
return ctx.issue(new IssueCustom(path, input, this.message))
|
|
33
|
+
}
|
|
34
|
+
return ctx.success(input as TValue)
|
|
37
35
|
}
|
|
38
36
|
}
|
|
37
|
+
|
|
38
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
39
|
+
export function custom<TValue>(
|
|
40
|
+
assertion: CustomAssertion<TValue>,
|
|
41
|
+
message: string,
|
|
42
|
+
path?: PropertyKey | readonly PropertyKey[],
|
|
43
|
+
) {
|
|
44
|
+
return new CustomSchema<TValue>(assertion, message, path)
|
|
45
|
+
}
|
package/src/schema/dict.test.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
2
|
+
import { boolean } from './boolean.js'
|
|
3
|
+
import { dict } from './dict.js'
|
|
4
|
+
import { enumSchema } from './enum.js'
|
|
5
|
+
import { integer } from './integer.js'
|
|
6
|
+
import { string } from './string.js'
|
|
7
7
|
|
|
8
8
|
describe('DictSchema', () => {
|
|
9
|
-
const schema =
|
|
9
|
+
const schema = dict(string(), integer())
|
|
10
10
|
|
|
11
11
|
it('validates plain objects with valid keys and values', () => {
|
|
12
12
|
const result = schema.safeParse({
|
|
@@ -59,10 +59,7 @@ describe('DictSchema', () => {
|
|
|
59
59
|
})
|
|
60
60
|
|
|
61
61
|
it('validates with enum key schema', () => {
|
|
62
|
-
const enumKeySchema =
|
|
63
|
-
new EnumSchema(['tag1', 'tag2', 'tag3']),
|
|
64
|
-
new BooleanSchema({}),
|
|
65
|
-
)
|
|
62
|
+
const enumKeySchema = dict(enumSchema(['tag1', 'tag2', 'tag3']), boolean())
|
|
66
63
|
|
|
67
64
|
const result = enumKeySchema.safeParse({
|
|
68
65
|
tag1: true,
|
|
@@ -73,10 +70,7 @@ describe('DictSchema', () => {
|
|
|
73
70
|
})
|
|
74
71
|
|
|
75
72
|
it('rejects invalid keys with enum key schema', () => {
|
|
76
|
-
const enumKeySchema =
|
|
77
|
-
new EnumSchema(['tag1', 'tag2']),
|
|
78
|
-
new BooleanSchema({}),
|
|
79
|
-
)
|
|
73
|
+
const enumKeySchema = dict(enumSchema(['tag1', 'tag2']), boolean())
|
|
80
74
|
|
|
81
75
|
const result = enumKeySchema.safeParse({
|
|
82
76
|
tag1: true,
|
|
@@ -86,10 +80,7 @@ describe('DictSchema', () => {
|
|
|
86
80
|
})
|
|
87
81
|
|
|
88
82
|
it('validates nested dict schemas', () => {
|
|
89
|
-
const nestedSchema =
|
|
90
|
-
new StringSchema({}),
|
|
91
|
-
new DictSchema(new StringSchema({}), new IntegerSchema({})),
|
|
92
|
-
)
|
|
83
|
+
const nestedSchema = dict(string(), dict(string(), integer()))
|
|
93
84
|
|
|
94
85
|
const result = nestedSchema.safeParse({
|
|
95
86
|
group1: { count: 10, total: 20 },
|
|
@@ -99,9 +90,9 @@ describe('DictSchema', () => {
|
|
|
99
90
|
})
|
|
100
91
|
|
|
101
92
|
it('validates with string key schema constraints', () => {
|
|
102
|
-
const constrainedKeySchema =
|
|
103
|
-
|
|
104
|
-
|
|
93
|
+
const constrainedKeySchema = dict(
|
|
94
|
+
string({ minLength: 3, maxLength: 10 }),
|
|
95
|
+
integer(),
|
|
105
96
|
)
|
|
106
97
|
|
|
107
98
|
const result = constrainedKeySchema.safeParse({
|
|
@@ -112,10 +103,7 @@ describe('DictSchema', () => {
|
|
|
112
103
|
})
|
|
113
104
|
|
|
114
105
|
it('rejects keys that do not meet key schema constraints', () => {
|
|
115
|
-
const constrainedKeySchema =
|
|
116
|
-
new StringSchema({ minLength: 3 }),
|
|
117
|
-
new IntegerSchema({}),
|
|
118
|
-
)
|
|
106
|
+
const constrainedKeySchema = dict(string({ minLength: 3 }), integer())
|
|
119
107
|
|
|
120
108
|
const result = constrainedKeySchema.safeParse({
|
|
121
109
|
ab: 1, // too short
|
|
@@ -124,9 +112,9 @@ describe('DictSchema', () => {
|
|
|
124
112
|
})
|
|
125
113
|
|
|
126
114
|
it('validates with value schema constraints', () => {
|
|
127
|
-
const constrainedValueSchema =
|
|
128
|
-
|
|
129
|
-
|
|
115
|
+
const constrainedValueSchema = dict(
|
|
116
|
+
string(),
|
|
117
|
+
integer({ minimum: 0, maximum: 100 }),
|
|
130
118
|
)
|
|
131
119
|
|
|
132
120
|
const result = constrainedValueSchema.safeParse({
|
|
@@ -137,9 +125,9 @@ describe('DictSchema', () => {
|
|
|
137
125
|
})
|
|
138
126
|
|
|
139
127
|
it('rejects values that do not meet value schema constraints', () => {
|
|
140
|
-
const constrainedValueSchema =
|
|
141
|
-
|
|
142
|
-
|
|
128
|
+
const constrainedValueSchema = dict(
|
|
129
|
+
string(),
|
|
130
|
+
integer({ minimum: 0, maximum: 100 }),
|
|
143
131
|
)
|
|
144
132
|
|
|
145
133
|
const result = constrainedValueSchema.safeParse({
|
|
@@ -149,10 +137,7 @@ describe('DictSchema', () => {
|
|
|
149
137
|
})
|
|
150
138
|
|
|
151
139
|
it('validates dict with string values', () => {
|
|
152
|
-
const stringValueSchema =
|
|
153
|
-
new StringSchema({}),
|
|
154
|
-
new StringSchema({}),
|
|
155
|
-
)
|
|
140
|
+
const stringValueSchema = dict(string(), string())
|
|
156
141
|
|
|
157
142
|
const result = stringValueSchema.safeParse({
|
|
158
143
|
name: 'Alice',
|
|
@@ -163,10 +148,7 @@ describe('DictSchema', () => {
|
|
|
163
148
|
})
|
|
164
149
|
|
|
165
150
|
it('validates dict with boolean values', () => {
|
|
166
|
-
const booleanValueSchema =
|
|
167
|
-
new StringSchema({}),
|
|
168
|
-
new BooleanSchema({}),
|
|
169
|
-
)
|
|
151
|
+
const booleanValueSchema = dict(string(), boolean())
|
|
170
152
|
|
|
171
153
|
const result = booleanValueSchema.safeParse({
|
|
172
154
|
enabled: true,
|
package/src/schema/dict.ts
CHANGED
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
import { isPlainObject } from '@atproto/lex-data'
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
InferInput,
|
|
4
|
+
InferOutput,
|
|
4
5
|
Schema,
|
|
5
|
-
|
|
6
|
+
ValidationContext,
|
|
6
7
|
Validator,
|
|
7
|
-
ValidatorContext,
|
|
8
8
|
} from '../core.js'
|
|
9
9
|
|
|
10
|
-
export type DictSchemaOutput<
|
|
11
|
-
KeySchema extends Validator<string>,
|
|
12
|
-
ValueSchema extends Validator,
|
|
13
|
-
> = Record<Infer<KeySchema>, Infer<ValueSchema>>
|
|
14
|
-
|
|
15
10
|
/**
|
|
16
11
|
* @note There is no dictionary in Lexicon schemas. This is a custom extension
|
|
17
12
|
* to allow map-like objects when using the lex library programmatically (i.e.
|
|
18
13
|
* not code generated from a lexicon schema).
|
|
19
14
|
*/
|
|
20
15
|
export class DictSchema<
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
> extends Schema<
|
|
16
|
+
const TKey extends Validator<string> = any,
|
|
17
|
+
const TValue extends Validator = any,
|
|
18
|
+
> extends Schema<
|
|
19
|
+
Record<InferInput<TKey>, InferInput<TValue>>,
|
|
20
|
+
Record<InferInput<TKey>, InferOutput<TValue>>
|
|
21
|
+
> {
|
|
24
22
|
constructor(
|
|
25
|
-
readonly keySchema:
|
|
26
|
-
readonly valueSchema:
|
|
23
|
+
readonly keySchema: TKey,
|
|
24
|
+
readonly valueSchema: TValue,
|
|
27
25
|
) {
|
|
28
26
|
super()
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
validateInContext(
|
|
32
30
|
input: unknown,
|
|
33
|
-
ctx:
|
|
31
|
+
ctx: ValidationContext,
|
|
34
32
|
options?: { ignoredKeys?: { has(k: string): boolean } },
|
|
35
|
-
)
|
|
33
|
+
) {
|
|
36
34
|
if (!isPlainObject(input)) {
|
|
37
35
|
return ctx.issueInvalidType(input, 'dict')
|
|
38
36
|
}
|
|
@@ -54,14 +52,25 @@ export class DictSchema<
|
|
|
54
52
|
const valueResult = ctx.validateChild(input, key, this.valueSchema)
|
|
55
53
|
if (!valueResult.success) return valueResult
|
|
56
54
|
|
|
57
|
-
if (valueResult.value
|
|
55
|
+
if (!Object.is(valueResult.value, input[key])) {
|
|
56
|
+
if (ctx.options.mode === 'validate') {
|
|
57
|
+
// In "validate" mode, we can't modify the input, so we issue an error
|
|
58
|
+
return ctx.issueInvalidPropertyValue(input, key, [valueResult.value])
|
|
59
|
+
}
|
|
60
|
+
|
|
58
61
|
copy ??= { ...input }
|
|
59
62
|
copy[key] = valueResult.value
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
65
|
|
|
63
|
-
return ctx.success(
|
|
64
|
-
(copy ?? input) as DictSchemaOutput<KeySchema, ValueSchema>,
|
|
65
|
-
)
|
|
66
|
+
return ctx.success(copy ?? input)
|
|
66
67
|
}
|
|
67
68
|
}
|
|
69
|
+
|
|
70
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
71
|
+
export function dict<
|
|
72
|
+
const TKey extends Validator<string>,
|
|
73
|
+
const TValue extends Validator,
|
|
74
|
+
>(key: TKey, value: TValue) {
|
|
75
|
+
return new DictSchema<TKey, TValue>(key, value)
|
|
76
|
+
}
|