@atproto/lexicon 0.0.4 → 0.2.0
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/dist/blob-refs.d.ts +67 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +12944 -680
- package/dist/index.js.map +4 -4
- package/dist/lexicons.d.ts +6 -4
- package/dist/serialize.d.ts +12 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/lexicons.d.ts +15 -0
- package/dist/src/record/index.d.ts +4 -0
- package/dist/src/record/schema.d.ts +9 -0
- package/dist/src/record/schemas.d.ts +10 -0
- package/dist/src/record/util.d.ts +1 -0
- package/dist/src/record/validation.d.ts +24 -0
- package/dist/src/record/validator.d.ts +17 -0
- package/dist/src/types.d.ts +30268 -0
- package/dist/src/util.d.ts +6 -0
- package/dist/src/validation.d.ts +6 -0
- package/dist/src/validators/blob.d.ts +6 -0
- package/dist/src/validators/complex.d.ts +5 -0
- package/dist/src/validators/primitives.d.ts +9 -0
- package/dist/src/validators/xrpc.d.ts +3 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/types.d.ts +14999 -23510
- package/dist/util.d.ts +6 -1
- package/dist/validation.d.ts +6 -5
- package/dist/validators/blob.d.ts +0 -3
- package/dist/validators/complex.d.ts +2 -2
- package/dist/validators/formats.d.ts +10 -0
- package/dist/validators/primitives.d.ts +2 -2
- package/dist/validators/xrpc.d.ts +1 -1
- package/package.json +13 -4
- package/src/blob-refs.ts +70 -0
- package/src/index.ts +2 -0
- package/src/lexicons.ts +36 -5
- package/src/serialize.ts +93 -0
- package/src/types.ts +306 -180
- package/src/util.ts +64 -5
- package/src/validation.ts +28 -4
- package/src/validators/blob.ts +5 -43
- package/src/validators/complex.ts +31 -32
- package/src/validators/formats.ts +121 -0
- package/src/validators/primitives.ts +114 -67
- package/src/validators/xrpc.ts +29 -29
- package/tests/_scaffolds/lexicons.ts +178 -51
- package/tests/general.test.ts +496 -177
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +3 -1
package/src/types.ts
CHANGED
|
@@ -1,245 +1,364 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { NSID } from '@atproto/nsid'
|
|
3
|
+
import { requiredPropertiesRefinement } from './util'
|
|
3
4
|
|
|
4
5
|
// primitives
|
|
5
6
|
// =
|
|
6
7
|
|
|
7
|
-
export const lexBoolean = z
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
export const lexBoolean = z
|
|
9
|
+
.object({
|
|
10
|
+
type: z.literal('boolean'),
|
|
11
|
+
description: z.string().optional(),
|
|
12
|
+
default: z.boolean().optional(),
|
|
13
|
+
const: z.boolean().optional(),
|
|
14
|
+
})
|
|
15
|
+
.strict()
|
|
13
16
|
export type LexBoolean = z.infer<typeof lexBoolean>
|
|
14
17
|
|
|
15
|
-
export const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
export const lexInteger = z.object({
|
|
27
|
-
type: z.literal('integer'),
|
|
28
|
-
description: z.string().optional(),
|
|
29
|
-
default: z.number().int().optional(),
|
|
30
|
-
minimum: z.number().int().optional(),
|
|
31
|
-
maximum: z.number().int().optional(),
|
|
32
|
-
enum: z.number().int().array().optional(),
|
|
33
|
-
const: z.number().int().optional(),
|
|
34
|
-
})
|
|
18
|
+
export const lexInteger = z
|
|
19
|
+
.object({
|
|
20
|
+
type: z.literal('integer'),
|
|
21
|
+
description: z.string().optional(),
|
|
22
|
+
default: z.number().int().optional(),
|
|
23
|
+
minimum: z.number().int().optional(),
|
|
24
|
+
maximum: z.number().int().optional(),
|
|
25
|
+
enum: z.number().int().array().optional(),
|
|
26
|
+
const: z.number().int().optional(),
|
|
27
|
+
})
|
|
28
|
+
.strict()
|
|
35
29
|
export type LexInteger = z.infer<typeof lexInteger>
|
|
36
30
|
|
|
37
|
-
export const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
export const lexStringFormat = z.enum([
|
|
32
|
+
'datetime',
|
|
33
|
+
'uri',
|
|
34
|
+
'at-uri',
|
|
35
|
+
'did',
|
|
36
|
+
'handle',
|
|
37
|
+
'at-identifier',
|
|
38
|
+
'nsid',
|
|
39
|
+
'cid',
|
|
40
|
+
'language',
|
|
41
|
+
])
|
|
42
|
+
export type LexStringFormat = z.infer<typeof lexStringFormat>
|
|
48
43
|
|
|
49
|
-
export const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
export const lexString = z
|
|
45
|
+
.object({
|
|
46
|
+
type: z.literal('string'),
|
|
47
|
+
format: lexStringFormat.optional(),
|
|
48
|
+
description: z.string().optional(),
|
|
49
|
+
default: z.string().optional(),
|
|
50
|
+
minLength: z.number().int().optional(),
|
|
51
|
+
maxLength: z.number().int().optional(),
|
|
52
|
+
minGraphemes: z.number().int().optional(),
|
|
53
|
+
maxGraphemes: z.number().int().optional(),
|
|
54
|
+
enum: z.string().array().optional(),
|
|
55
|
+
const: z.string().optional(),
|
|
56
|
+
knownValues: z.string().array().optional(),
|
|
57
|
+
})
|
|
58
|
+
.strict()
|
|
59
|
+
export type LexString = z.infer<typeof lexString>
|
|
54
60
|
|
|
55
|
-
export const lexUnknown = z
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
export const lexUnknown = z
|
|
62
|
+
.object({
|
|
63
|
+
type: z.literal('unknown'),
|
|
64
|
+
description: z.string().optional(),
|
|
65
|
+
})
|
|
66
|
+
.strict()
|
|
59
67
|
export type LexUnknown = z.infer<typeof lexUnknown>
|
|
60
68
|
|
|
61
|
-
export const lexPrimitive = z.
|
|
69
|
+
export const lexPrimitive = z.discriminatedUnion('type', [
|
|
62
70
|
lexBoolean,
|
|
63
|
-
lexNumber,
|
|
64
71
|
lexInteger,
|
|
65
72
|
lexString,
|
|
66
|
-
lexDatetime,
|
|
67
73
|
lexUnknown,
|
|
68
74
|
])
|
|
69
75
|
export type LexPrimitive = z.infer<typeof lexPrimitive>
|
|
70
76
|
|
|
77
|
+
// ipld types
|
|
78
|
+
// =
|
|
79
|
+
|
|
80
|
+
export const lexBytes = z
|
|
81
|
+
.object({
|
|
82
|
+
type: z.literal('bytes'),
|
|
83
|
+
description: z.string().optional(),
|
|
84
|
+
maxLength: z.number().optional(),
|
|
85
|
+
minLength: z.number().optional(),
|
|
86
|
+
})
|
|
87
|
+
.strict()
|
|
88
|
+
export type LexBytes = z.infer<typeof lexBytes>
|
|
89
|
+
|
|
90
|
+
export const lexCidLink = z
|
|
91
|
+
.object({
|
|
92
|
+
type: z.literal('cid-link'),
|
|
93
|
+
description: z.string().optional(),
|
|
94
|
+
})
|
|
95
|
+
.strict()
|
|
96
|
+
export type LexCidLink = z.infer<typeof lexCidLink>
|
|
97
|
+
|
|
98
|
+
export const lexIpldType = z.discriminatedUnion('type', [lexBytes, lexCidLink])
|
|
99
|
+
export type LexIpldType = z.infer<typeof lexIpldType>
|
|
100
|
+
|
|
71
101
|
// references
|
|
72
102
|
// =
|
|
73
103
|
|
|
74
|
-
export const lexRef = z
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
104
|
+
export const lexRef = z
|
|
105
|
+
.object({
|
|
106
|
+
type: z.literal('ref'),
|
|
107
|
+
description: z.string().optional(),
|
|
108
|
+
ref: z.string(),
|
|
109
|
+
})
|
|
110
|
+
.strict()
|
|
79
111
|
export type LexRef = z.infer<typeof lexRef>
|
|
80
112
|
|
|
81
|
-
export const lexRefUnion = z
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
113
|
+
export const lexRefUnion = z
|
|
114
|
+
.object({
|
|
115
|
+
type: z.literal('union'),
|
|
116
|
+
description: z.string().optional(),
|
|
117
|
+
refs: z.string().array(),
|
|
118
|
+
closed: z.boolean().optional(),
|
|
119
|
+
})
|
|
120
|
+
.strict()
|
|
87
121
|
export type LexRefUnion = z.infer<typeof lexRefUnion>
|
|
88
122
|
|
|
89
|
-
export const lexRefVariant = z.
|
|
123
|
+
export const lexRefVariant = z.discriminatedUnion('type', [lexRef, lexRefUnion])
|
|
90
124
|
export type LexRefVariant = z.infer<typeof lexRefVariant>
|
|
91
125
|
|
|
92
126
|
// blobs
|
|
93
127
|
// =
|
|
94
128
|
|
|
95
|
-
export const lexBlob = z
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
129
|
+
export const lexBlob = z
|
|
130
|
+
.object({
|
|
131
|
+
type: z.literal('blob'),
|
|
132
|
+
description: z.string().optional(),
|
|
133
|
+
accept: z.string().array().optional(),
|
|
134
|
+
maxSize: z.number().optional(),
|
|
135
|
+
})
|
|
136
|
+
.strict()
|
|
101
137
|
export type LexBlob = z.infer<typeof lexBlob>
|
|
102
138
|
|
|
103
|
-
export const lexImage = z.object({
|
|
104
|
-
type: z.literal('image'),
|
|
105
|
-
description: z.string().optional(),
|
|
106
|
-
accept: z.string().array().optional(),
|
|
107
|
-
maxSize: z.number().optional(),
|
|
108
|
-
maxWidth: z.number().int().optional(),
|
|
109
|
-
maxHeight: z.number().int().optional(),
|
|
110
|
-
})
|
|
111
|
-
export type LexImage = z.infer<typeof lexImage>
|
|
112
|
-
|
|
113
|
-
export const lexVideo = z.object({
|
|
114
|
-
type: z.literal('video'),
|
|
115
|
-
description: z.string().optional(),
|
|
116
|
-
accept: z.string().array().optional(),
|
|
117
|
-
maxSize: z.number().optional(),
|
|
118
|
-
maxWidth: z.number().int().optional(),
|
|
119
|
-
maxHeight: z.number().int().optional(),
|
|
120
|
-
maxLength: z.number().int().optional(),
|
|
121
|
-
})
|
|
122
|
-
export type LexVideo = z.infer<typeof lexVideo>
|
|
123
|
-
|
|
124
|
-
export const lexAudio = z.object({
|
|
125
|
-
type: z.literal('audio'),
|
|
126
|
-
description: z.string().optional(),
|
|
127
|
-
accept: z.string().array().optional(),
|
|
128
|
-
maxSize: z.number().optional(),
|
|
129
|
-
maxLength: z.number().int().optional(),
|
|
130
|
-
})
|
|
131
|
-
export type LexAudio = z.infer<typeof lexAudio>
|
|
132
|
-
|
|
133
|
-
export const lexBlobVariant = z.union([lexBlob, lexImage, lexVideo, lexAudio])
|
|
134
|
-
export type LexBlobVariant = z.infer<typeof lexBlobVariant>
|
|
135
|
-
|
|
136
139
|
// complex types
|
|
137
140
|
// =
|
|
138
141
|
|
|
139
|
-
export const lexArray = z
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
142
|
+
export const lexArray = z
|
|
143
|
+
.object({
|
|
144
|
+
type: z.literal('array'),
|
|
145
|
+
description: z.string().optional(),
|
|
146
|
+
items: z.union([lexPrimitive, lexIpldType, lexBlob, lexRefVariant]),
|
|
147
|
+
minLength: z.number().int().optional(),
|
|
148
|
+
maxLength: z.number().int().optional(),
|
|
149
|
+
})
|
|
150
|
+
.strict()
|
|
146
151
|
export type LexArray = z.infer<typeof lexArray>
|
|
147
152
|
|
|
148
|
-
export const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
export const lexPrimitiveArray = lexArray.merge(
|
|
154
|
+
z
|
|
155
|
+
.object({
|
|
156
|
+
items: lexPrimitive,
|
|
157
|
+
})
|
|
158
|
+
.strict(),
|
|
159
|
+
)
|
|
160
|
+
export type LexPrimitiveArray = z.infer<typeof lexPrimitiveArray>
|
|
161
|
+
|
|
162
|
+
export const lexToken = z
|
|
163
|
+
.object({
|
|
164
|
+
type: z.literal('token'),
|
|
165
|
+
description: z.string().optional(),
|
|
166
|
+
})
|
|
167
|
+
.strict()
|
|
152
168
|
export type LexToken = z.infer<typeof lexToken>
|
|
153
169
|
|
|
154
|
-
export const lexObject = z
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
.
|
|
160
|
-
|
|
161
|
-
|
|
170
|
+
export const lexObject = z
|
|
171
|
+
.object({
|
|
172
|
+
type: z.literal('object'),
|
|
173
|
+
description: z.string().optional(),
|
|
174
|
+
required: z.string().array().optional(),
|
|
175
|
+
nullable: z.string().array().optional(),
|
|
176
|
+
properties: z
|
|
177
|
+
.record(
|
|
178
|
+
z.union([lexRefVariant, lexIpldType, lexArray, lexBlob, lexPrimitive]),
|
|
179
|
+
)
|
|
180
|
+
.optional(),
|
|
181
|
+
})
|
|
182
|
+
.strict()
|
|
183
|
+
.superRefine(requiredPropertiesRefinement)
|
|
162
184
|
export type LexObject = z.infer<typeof lexObject>
|
|
163
185
|
|
|
164
186
|
// xrpc
|
|
165
187
|
// =
|
|
166
188
|
|
|
167
|
-
export const lexXrpcParameters = z
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
189
|
+
export const lexXrpcParameters = z
|
|
190
|
+
.object({
|
|
191
|
+
type: z.literal('params'),
|
|
192
|
+
description: z.string().optional(),
|
|
193
|
+
required: z.string().array().optional(),
|
|
194
|
+
properties: z.record(z.union([lexPrimitive, lexPrimitiveArray])),
|
|
195
|
+
})
|
|
196
|
+
.strict()
|
|
197
|
+
.superRefine(requiredPropertiesRefinement)
|
|
173
198
|
export type LexXrpcParameters = z.infer<typeof lexXrpcParameters>
|
|
174
199
|
|
|
175
|
-
export const lexXrpcBody = z
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
200
|
+
export const lexXrpcBody = z
|
|
201
|
+
.object({
|
|
202
|
+
description: z.string().optional(),
|
|
203
|
+
encoding: z.string(),
|
|
204
|
+
schema: z.union([lexRefVariant, lexObject]).optional(),
|
|
205
|
+
})
|
|
206
|
+
.strict()
|
|
180
207
|
export type LexXrpcBody = z.infer<typeof lexXrpcBody>
|
|
181
208
|
|
|
182
|
-
export const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
209
|
+
export const lexXrpcSubscriptionMessage = z
|
|
210
|
+
.object({
|
|
211
|
+
description: z.string().optional(),
|
|
212
|
+
schema: z.union([lexRefVariant, lexObject]).optional(),
|
|
213
|
+
})
|
|
214
|
+
.strict()
|
|
215
|
+
export type LexXrpcSubscriptionMessage = z.infer<
|
|
216
|
+
typeof lexXrpcSubscriptionMessage
|
|
217
|
+
>
|
|
218
|
+
|
|
219
|
+
export const lexXrpcError = z
|
|
220
|
+
.object({
|
|
221
|
+
name: z.string(),
|
|
222
|
+
description: z.string().optional(),
|
|
223
|
+
})
|
|
224
|
+
.strict()
|
|
186
225
|
export type LexXrpcError = z.infer<typeof lexXrpcError>
|
|
187
226
|
|
|
188
|
-
export const lexXrpcQuery = z
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
227
|
+
export const lexXrpcQuery = z
|
|
228
|
+
.object({
|
|
229
|
+
type: z.literal('query'),
|
|
230
|
+
description: z.string().optional(),
|
|
231
|
+
parameters: lexXrpcParameters.optional(),
|
|
232
|
+
output: lexXrpcBody.optional(),
|
|
233
|
+
errors: lexXrpcError.array().optional(),
|
|
234
|
+
})
|
|
235
|
+
.strict()
|
|
195
236
|
export type LexXrpcQuery = z.infer<typeof lexXrpcQuery>
|
|
196
237
|
|
|
197
|
-
export const lexXrpcProcedure = z
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
238
|
+
export const lexXrpcProcedure = z
|
|
239
|
+
.object({
|
|
240
|
+
type: z.literal('procedure'),
|
|
241
|
+
description: z.string().optional(),
|
|
242
|
+
parameters: lexXrpcParameters.optional(),
|
|
243
|
+
input: lexXrpcBody.optional(),
|
|
244
|
+
output: lexXrpcBody.optional(),
|
|
245
|
+
errors: lexXrpcError.array().optional(),
|
|
246
|
+
})
|
|
247
|
+
.strict()
|
|
205
248
|
export type LexXrpcProcedure = z.infer<typeof lexXrpcProcedure>
|
|
206
249
|
|
|
250
|
+
export const lexXrpcSubscription = z
|
|
251
|
+
.object({
|
|
252
|
+
type: z.literal('subscription'),
|
|
253
|
+
description: z.string().optional(),
|
|
254
|
+
parameters: lexXrpcParameters.optional(),
|
|
255
|
+
message: lexXrpcSubscriptionMessage.optional(),
|
|
256
|
+
errors: lexXrpcError.array().optional(),
|
|
257
|
+
})
|
|
258
|
+
.strict()
|
|
259
|
+
export type LexXrpcSubscription = z.infer<typeof lexXrpcSubscription>
|
|
260
|
+
|
|
207
261
|
// database
|
|
208
262
|
// =
|
|
209
263
|
|
|
210
|
-
export const lexRecord = z
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
264
|
+
export const lexRecord = z
|
|
265
|
+
.object({
|
|
266
|
+
type: z.literal('record'),
|
|
267
|
+
description: z.string().optional(),
|
|
268
|
+
key: z.string().optional(),
|
|
269
|
+
record: lexObject,
|
|
270
|
+
})
|
|
271
|
+
.strict()
|
|
216
272
|
export type LexRecord = z.infer<typeof lexRecord>
|
|
217
273
|
|
|
218
274
|
// core
|
|
219
275
|
// =
|
|
220
276
|
|
|
221
|
-
|
|
222
|
-
|
|
277
|
+
// We need to use `z.custom` here because
|
|
278
|
+
// lexXrpcProperty and lexObject are refined
|
|
279
|
+
// `z.union` would work, but it's too slow
|
|
280
|
+
// see #915 for details
|
|
281
|
+
export const lexUserType = z.custom<
|
|
282
|
+
| LexRecord
|
|
283
|
+
| LexXrpcQuery
|
|
284
|
+
| LexXrpcProcedure
|
|
285
|
+
| LexXrpcSubscription
|
|
286
|
+
| LexBlob
|
|
287
|
+
| LexArray
|
|
288
|
+
| LexToken
|
|
289
|
+
| LexObject
|
|
290
|
+
| LexBoolean
|
|
291
|
+
| LexInteger
|
|
292
|
+
| LexString
|
|
293
|
+
| LexBytes
|
|
294
|
+
| LexCidLink
|
|
295
|
+
| LexUnknown
|
|
296
|
+
>(
|
|
297
|
+
(val) => {
|
|
298
|
+
if (!val || typeof val !== 'object') {
|
|
299
|
+
return
|
|
300
|
+
}
|
|
223
301
|
|
|
224
|
-
|
|
225
|
-
|
|
302
|
+
if (val['type'] === undefined) {
|
|
303
|
+
return
|
|
304
|
+
}
|
|
226
305
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
306
|
+
switch (val['type']) {
|
|
307
|
+
case 'record':
|
|
308
|
+
return lexRecord.parse(val)
|
|
309
|
+
|
|
310
|
+
case 'query':
|
|
311
|
+
return lexXrpcQuery.parse(val)
|
|
312
|
+
case 'procedure':
|
|
313
|
+
return lexXrpcProcedure.parse(val)
|
|
314
|
+
case 'subscription':
|
|
315
|
+
return lexXrpcSubscription.parse(val)
|
|
316
|
+
|
|
317
|
+
case 'blob':
|
|
318
|
+
return lexBlob.parse(val)
|
|
319
|
+
|
|
320
|
+
case 'array':
|
|
321
|
+
return lexArray.parse(val)
|
|
322
|
+
case 'token':
|
|
323
|
+
return lexToken.parse(val)
|
|
324
|
+
case 'object':
|
|
325
|
+
return lexObject.parse(val)
|
|
326
|
+
|
|
327
|
+
case 'boolean':
|
|
328
|
+
return lexBoolean.parse(val)
|
|
329
|
+
case 'integer':
|
|
330
|
+
return lexInteger.parse(val)
|
|
331
|
+
case 'string':
|
|
332
|
+
return lexString.parse(val)
|
|
333
|
+
case 'bytes':
|
|
334
|
+
return lexBytes.parse(val)
|
|
335
|
+
case 'cid-link':
|
|
336
|
+
return lexCidLink.parse(val)
|
|
337
|
+
case 'unknown':
|
|
338
|
+
return lexUnknown.parse(val)
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
(val) => {
|
|
342
|
+
if (!val || typeof val !== 'object') {
|
|
343
|
+
return {
|
|
344
|
+
message: 'Must be an object',
|
|
345
|
+
fatal: true,
|
|
346
|
+
}
|
|
347
|
+
}
|
|
231
348
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
349
|
+
if (val['type'] === undefined) {
|
|
350
|
+
return {
|
|
351
|
+
message: 'Must have a type',
|
|
352
|
+
fatal: true,
|
|
353
|
+
}
|
|
354
|
+
}
|
|
235
355
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
])
|
|
356
|
+
return {
|
|
357
|
+
message: `Invalid type: ${val['type']} must be one of: record, query, procedure, subscription, blob, array, token, object, boolean, integer, string, bytes, cid-link, unknown`,
|
|
358
|
+
fatal: true,
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
)
|
|
243
362
|
export type LexUserType = z.infer<typeof lexUserType>
|
|
244
363
|
|
|
245
364
|
export const lexiconDoc = z
|
|
@@ -252,18 +371,20 @@ export const lexiconDoc = z
|
|
|
252
371
|
description: z.string().optional(),
|
|
253
372
|
defs: z.record(lexUserType),
|
|
254
373
|
})
|
|
255
|
-
.
|
|
374
|
+
.strict()
|
|
375
|
+
.superRefine((doc, ctx) => {
|
|
256
376
|
for (const defId in doc.defs) {
|
|
257
377
|
const def = doc.defs[defId]
|
|
258
378
|
if (
|
|
259
379
|
defId !== 'main' &&
|
|
260
380
|
(def.type === 'record' ||
|
|
261
381
|
def.type === 'procedure' ||
|
|
262
|
-
def.type === 'query'
|
|
382
|
+
def.type === 'query' ||
|
|
383
|
+
def.type === 'subscription')
|
|
263
384
|
) {
|
|
264
385
|
ctx.addIssue({
|
|
265
386
|
code: z.ZodIssueCode.custom,
|
|
266
|
-
message: `Records, procedures, and
|
|
387
|
+
message: `Records, procedures, queries, and subscriptions must be the main definition.`,
|
|
267
388
|
})
|
|
268
389
|
}
|
|
269
390
|
}
|
|
@@ -308,10 +429,15 @@ export class LexiconDocMalformedError extends Error {
|
|
|
308
429
|
}
|
|
309
430
|
}
|
|
310
431
|
|
|
311
|
-
export
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
432
|
+
export type ValidationResult =
|
|
433
|
+
| {
|
|
434
|
+
success: true
|
|
435
|
+
value: unknown
|
|
436
|
+
}
|
|
437
|
+
| {
|
|
438
|
+
success: false
|
|
439
|
+
error: ValidationError
|
|
440
|
+
}
|
|
315
441
|
|
|
316
442
|
export class ValidationError extends Error {}
|
|
317
443
|
export class InvalidLexiconError extends Error {}
|
package/src/util.ts
CHANGED
|
@@ -7,8 +7,13 @@ import {
|
|
|
7
7
|
ValidationResult,
|
|
8
8
|
isDiscriminatedObject,
|
|
9
9
|
} from './types'
|
|
10
|
+
import { z } from 'zod'
|
|
10
11
|
|
|
11
12
|
export function toLexUri(str: string, baseUri?: string): string {
|
|
13
|
+
if (str.split('#').length > 2) {
|
|
14
|
+
throw new Error('Uri can only have one hash segment')
|
|
15
|
+
}
|
|
16
|
+
|
|
12
17
|
if (str.startsWith('lex:')) {
|
|
13
18
|
return str
|
|
14
19
|
}
|
|
@@ -40,7 +45,7 @@ export function validateOneOf(
|
|
|
40
45
|
),
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
|
-
if (!def.refs
|
|
48
|
+
if (!refsContainType(def.refs, value.$type)) {
|
|
44
49
|
if (def.closed) {
|
|
45
50
|
return {
|
|
46
51
|
success: false,
|
|
@@ -49,7 +54,7 @@ export function validateOneOf(
|
|
|
49
54
|
),
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
|
-
return { success: true }
|
|
57
|
+
return { success: true, value }
|
|
53
58
|
} else {
|
|
54
59
|
concreteDefs = toConcreteTypes(lexicons, {
|
|
55
60
|
type: 'ref',
|
|
@@ -88,9 +93,8 @@ export function assertValidOneOf(
|
|
|
88
93
|
mustBeObj = false,
|
|
89
94
|
) {
|
|
90
95
|
const res = validateOneOf(lexicons, path, def, value, mustBeObj)
|
|
91
|
-
if (!res.success)
|
|
92
|
-
|
|
93
|
-
}
|
|
96
|
+
if (!res.success) throw res.error
|
|
97
|
+
return res.value
|
|
94
98
|
}
|
|
95
99
|
|
|
96
100
|
export function toConcreteTypes(
|
|
@@ -105,3 +109,58 @@ export function toConcreteTypes(
|
|
|
105
109
|
return [def]
|
|
106
110
|
}
|
|
107
111
|
}
|
|
112
|
+
|
|
113
|
+
export function requiredPropertiesRefinement<
|
|
114
|
+
ObjectType extends {
|
|
115
|
+
required?: string[]
|
|
116
|
+
properties?: Record<string, unknown>
|
|
117
|
+
},
|
|
118
|
+
>(object: ObjectType, ctx: z.RefinementCtx) {
|
|
119
|
+
// Required fields check
|
|
120
|
+
if (object.required === undefined) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!Array.isArray(object.required)) {
|
|
125
|
+
ctx.addIssue({
|
|
126
|
+
code: z.ZodIssueCode.invalid_type,
|
|
127
|
+
received: typeof object.required,
|
|
128
|
+
expected: 'array',
|
|
129
|
+
})
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (object.properties === undefined) {
|
|
134
|
+
if (object.required.length > 0) {
|
|
135
|
+
ctx.addIssue({
|
|
136
|
+
code: z.ZodIssueCode.custom,
|
|
137
|
+
message: `Required fields defined but no properties defined`,
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
for (const field of object.required) {
|
|
144
|
+
if (object.properties[field] === undefined) {
|
|
145
|
+
ctx.addIssue({
|
|
146
|
+
code: z.ZodIssueCode.custom,
|
|
147
|
+
message: `Required field "${field}" not defined`,
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// to avoid bugs like #0189 this needs to handle both
|
|
154
|
+
// explicit and implicit #main
|
|
155
|
+
const refsContainType = (refs: string[], type: string) => {
|
|
156
|
+
const lexUri = toLexUri(type)
|
|
157
|
+
if (refs.includes(lexUri)) {
|
|
158
|
+
return true
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (lexUri.endsWith('#main')) {
|
|
162
|
+
return refs.includes(lexUri.replace('#main', ''))
|
|
163
|
+
} else {
|
|
164
|
+
return refs.includes(lexUri + '#main')
|
|
165
|
+
}
|
|
166
|
+
}
|