@atproto/lexicon 0.7.3 → 0.7.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 +16 -0
- package/dist/lexicons.d.ts +1 -1
- package/dist/lexicons.d.ts.map +1 -1
- package/dist/lexicons.js.map +1 -1
- package/dist/serialize.d.ts +1 -1
- package/dist/serialize.d.ts.map +1 -1
- package/dist/serialize.js +8 -7
- package/dist/serialize.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validation.d.ts +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1 -0
- package/dist/validation.js.map +1 -1
- package/dist/validators/blob.d.ts +1 -1
- package/dist/validators/blob.d.ts.map +1 -1
- package/dist/validators/blob.js +1 -0
- package/dist/validators/blob.js.map +1 -1
- package/dist/validators/complex.d.ts +1 -1
- package/dist/validators/complex.d.ts.map +1 -1
- package/dist/validators/complex.js +2 -1
- package/dist/validators/complex.js.map +1 -1
- package/dist/validators/formats.d.ts +1 -1
- package/dist/validators/formats.d.ts.map +1 -1
- package/dist/validators/formats.js.map +1 -1
- package/dist/validators/primitives.d.ts +1 -1
- package/dist/validators/primitives.d.ts.map +1 -1
- package/dist/validators/primitives.js +2 -1
- package/dist/validators/primitives.js.map +1 -1
- package/dist/validators/xrpc.d.ts +1 -1
- package/dist/validators/xrpc.d.ts.map +1 -1
- package/dist/validators/xrpc.js +3 -2
- package/dist/validators/xrpc.js.map +1 -1
- package/package.json +18 -13
- package/jest.config.cjs +0 -21
- package/src/blob-refs.ts +0 -65
- package/src/index.ts +0 -4
- package/src/lexicons.ts +0 -253
- package/src/serialize.ts +0 -102
- package/src/types.ts +0 -483
- package/src/util.ts +0 -58
- package/src/validation.ts +0 -84
- package/src/validators/blob.ts +0 -19
- package/src/validators/complex.ts +0 -212
- package/src/validators/formats.ts +0 -72
- package/src/validators/primitives.ts +0 -416
- package/src/validators/xrpc.ts +0 -53
- package/tests/_scaffolds/lexicons.ts +0 -545
- package/tests/general.test.ts +0 -1243
- package/tsconfig.build.json +0 -8
- package/tsconfig.build.tsbuildinfo +0 -1
- package/tsconfig.json +0 -7
- package/tsconfig.tests.json +0 -7
|
@@ -1,416 +0,0 @@
|
|
|
1
|
-
import { CID } from 'multiformats/cid'
|
|
2
|
-
import { graphemeLen, utf8Len } from '@atproto/common-web'
|
|
3
|
-
import { Lexicons } from '../lexicons.js'
|
|
4
|
-
import {
|
|
5
|
-
LexBoolean,
|
|
6
|
-
LexBytes,
|
|
7
|
-
LexInteger,
|
|
8
|
-
LexString,
|
|
9
|
-
LexUserType,
|
|
10
|
-
ValidationError,
|
|
11
|
-
ValidationResult,
|
|
12
|
-
} from '../types.js'
|
|
13
|
-
import * as formats from './formats.js'
|
|
14
|
-
|
|
15
|
-
export function validate(
|
|
16
|
-
lexicons: Lexicons,
|
|
17
|
-
path: string,
|
|
18
|
-
def: LexUserType,
|
|
19
|
-
value: unknown,
|
|
20
|
-
): ValidationResult {
|
|
21
|
-
switch (def.type) {
|
|
22
|
-
case 'boolean':
|
|
23
|
-
return boolean(lexicons, path, def, value)
|
|
24
|
-
case 'integer':
|
|
25
|
-
return integer(lexicons, path, def, value)
|
|
26
|
-
case 'string':
|
|
27
|
-
return string(lexicons, path, def, value)
|
|
28
|
-
case 'bytes':
|
|
29
|
-
return bytes(lexicons, path, def, value)
|
|
30
|
-
case 'cid-link':
|
|
31
|
-
return cidLink(lexicons, path, def, value)
|
|
32
|
-
case 'unknown':
|
|
33
|
-
return unknown(lexicons, path, def, value)
|
|
34
|
-
default:
|
|
35
|
-
return {
|
|
36
|
-
success: false,
|
|
37
|
-
error: new ValidationError(`Unexpected lexicon type: ${def.type}`),
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function boolean(
|
|
43
|
-
lexicons: Lexicons,
|
|
44
|
-
path: string,
|
|
45
|
-
def: LexUserType,
|
|
46
|
-
value: unknown,
|
|
47
|
-
): ValidationResult {
|
|
48
|
-
def = def as LexBoolean
|
|
49
|
-
|
|
50
|
-
// type
|
|
51
|
-
const type = typeof value
|
|
52
|
-
if (type === 'undefined') {
|
|
53
|
-
if (typeof def.default === 'boolean') {
|
|
54
|
-
return { success: true, value: def.default }
|
|
55
|
-
}
|
|
56
|
-
return {
|
|
57
|
-
success: false,
|
|
58
|
-
error: new ValidationError(`${path} must be a boolean`),
|
|
59
|
-
}
|
|
60
|
-
} else if (type !== 'boolean') {
|
|
61
|
-
return {
|
|
62
|
-
success: false,
|
|
63
|
-
error: new ValidationError(`${path} must be a boolean`),
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// const
|
|
68
|
-
if (typeof def.const === 'boolean') {
|
|
69
|
-
if (value !== def.const) {
|
|
70
|
-
return {
|
|
71
|
-
success: false,
|
|
72
|
-
error: new ValidationError(`${path} must be ${def.const}`),
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return { success: true, value }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function integer(
|
|
81
|
-
lexicons: Lexicons,
|
|
82
|
-
path: string,
|
|
83
|
-
def: LexUserType,
|
|
84
|
-
value: unknown,
|
|
85
|
-
): ValidationResult {
|
|
86
|
-
def = def as LexInteger
|
|
87
|
-
|
|
88
|
-
// type
|
|
89
|
-
const type = typeof value
|
|
90
|
-
if (type === 'undefined') {
|
|
91
|
-
if (typeof def.default === 'number') {
|
|
92
|
-
return { success: true, value: def.default }
|
|
93
|
-
}
|
|
94
|
-
return {
|
|
95
|
-
success: false,
|
|
96
|
-
error: new ValidationError(`${path} must be an integer`),
|
|
97
|
-
}
|
|
98
|
-
} else if (!Number.isInteger(value)) {
|
|
99
|
-
return {
|
|
100
|
-
success: false,
|
|
101
|
-
error: new ValidationError(`${path} must be an integer`),
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// const
|
|
106
|
-
if (typeof def.const === 'number') {
|
|
107
|
-
if (value !== def.const) {
|
|
108
|
-
return {
|
|
109
|
-
success: false,
|
|
110
|
-
error: new ValidationError(`${path} must be ${def.const}`),
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// enum
|
|
116
|
-
if (Array.isArray(def.enum)) {
|
|
117
|
-
if (!def.enum.includes(value as number)) {
|
|
118
|
-
return {
|
|
119
|
-
success: false,
|
|
120
|
-
error: new ValidationError(
|
|
121
|
-
`${path} must be one of (${def.enum.join('|')})`,
|
|
122
|
-
),
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// maximum
|
|
128
|
-
if (typeof def.maximum === 'number') {
|
|
129
|
-
if ((value as number) > def.maximum) {
|
|
130
|
-
return {
|
|
131
|
-
success: false,
|
|
132
|
-
error: new ValidationError(
|
|
133
|
-
`${path} can not be greater than ${def.maximum}`,
|
|
134
|
-
),
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// minimum
|
|
140
|
-
if (typeof def.minimum === 'number') {
|
|
141
|
-
if ((value as number) < def.minimum) {
|
|
142
|
-
return {
|
|
143
|
-
success: false,
|
|
144
|
-
error: new ValidationError(
|
|
145
|
-
`${path} can not be less than ${def.minimum}`,
|
|
146
|
-
),
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return { success: true, value }
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function string(
|
|
155
|
-
lexicons: Lexicons,
|
|
156
|
-
path: string,
|
|
157
|
-
def: LexUserType,
|
|
158
|
-
value: unknown,
|
|
159
|
-
): ValidationResult<string> {
|
|
160
|
-
def = def as LexString
|
|
161
|
-
|
|
162
|
-
// type
|
|
163
|
-
if (typeof value === 'undefined') {
|
|
164
|
-
if (typeof def.default === 'string') {
|
|
165
|
-
return { success: true, value: def.default }
|
|
166
|
-
}
|
|
167
|
-
return {
|
|
168
|
-
success: false,
|
|
169
|
-
error: new ValidationError(`${path} must be a string`),
|
|
170
|
-
}
|
|
171
|
-
} else if (typeof value !== 'string') {
|
|
172
|
-
return {
|
|
173
|
-
success: false,
|
|
174
|
-
error: new ValidationError(`${path} must be a string`),
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
// const
|
|
179
|
-
if (typeof def.const === 'string') {
|
|
180
|
-
if (value !== def.const) {
|
|
181
|
-
return {
|
|
182
|
-
success: false,
|
|
183
|
-
error: new ValidationError(`${path} must be ${def.const}`),
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// enum
|
|
189
|
-
if (Array.isArray(def.enum)) {
|
|
190
|
-
if (!def.enum.includes(value as string)) {
|
|
191
|
-
return {
|
|
192
|
-
success: false,
|
|
193
|
-
error: new ValidationError(
|
|
194
|
-
`${path} must be one of (${def.enum.join('|')})`,
|
|
195
|
-
),
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// maxLength and minLength
|
|
201
|
-
if (typeof def.minLength === 'number' || typeof def.maxLength === 'number') {
|
|
202
|
-
// If the JavaScript string length * 3 is below the maximum limit,
|
|
203
|
-
// its UTF8 length (which <= .length * 3) will also be below.
|
|
204
|
-
if (typeof def.minLength === 'number' && value.length * 3 < def.minLength) {
|
|
205
|
-
return {
|
|
206
|
-
success: false,
|
|
207
|
-
error: new ValidationError(
|
|
208
|
-
`${path} must not be shorter than ${def.minLength} characters`,
|
|
209
|
-
),
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// If the JavaScript string length * 3 is within the maximum limit,
|
|
214
|
-
// its UTF8 length (which <= .length * 3) will also be within.
|
|
215
|
-
// When there's no minimal length, this lets us skip the UTF8 length check.
|
|
216
|
-
let canSkipUtf8LenChecks = false
|
|
217
|
-
if (
|
|
218
|
-
typeof def.minLength === 'undefined' &&
|
|
219
|
-
typeof def.maxLength === 'number' &&
|
|
220
|
-
value.length * 3 <= def.maxLength
|
|
221
|
-
) {
|
|
222
|
-
canSkipUtf8LenChecks = true
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
if (!canSkipUtf8LenChecks) {
|
|
226
|
-
const len = utf8Len(value)
|
|
227
|
-
|
|
228
|
-
if (typeof def.maxLength === 'number') {
|
|
229
|
-
if (len > def.maxLength) {
|
|
230
|
-
return {
|
|
231
|
-
success: false,
|
|
232
|
-
error: new ValidationError(
|
|
233
|
-
`${path} must not be longer than ${def.maxLength} characters`,
|
|
234
|
-
),
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (typeof def.minLength === 'number') {
|
|
240
|
-
if (len < def.minLength) {
|
|
241
|
-
return {
|
|
242
|
-
success: false,
|
|
243
|
-
error: new ValidationError(
|
|
244
|
-
`${path} must not be shorter than ${def.minLength} characters`,
|
|
245
|
-
),
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// maxGraphemes and minGraphemes
|
|
253
|
-
if (
|
|
254
|
-
typeof def.maxGraphemes === 'number' ||
|
|
255
|
-
typeof def.minGraphemes === 'number'
|
|
256
|
-
) {
|
|
257
|
-
let needsMaxGraphemesCheck = false
|
|
258
|
-
let needsMinGraphemesCheck = false
|
|
259
|
-
|
|
260
|
-
if (typeof def.maxGraphemes === 'number') {
|
|
261
|
-
if (value.length <= def.maxGraphemes) {
|
|
262
|
-
// If the JavaScript string length (UTF-16) is within the maximum limit,
|
|
263
|
-
// its grapheme length (which <= .length) will also be within.
|
|
264
|
-
needsMaxGraphemesCheck = false
|
|
265
|
-
} else {
|
|
266
|
-
needsMaxGraphemesCheck = true
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
if (typeof def.minGraphemes === 'number') {
|
|
271
|
-
if (value.length < def.minGraphemes) {
|
|
272
|
-
// If the JavaScript string length (UTF-16) is below the minimal limit,
|
|
273
|
-
// its grapheme length (which <= .length) will also be below.
|
|
274
|
-
// Fail early.
|
|
275
|
-
return {
|
|
276
|
-
success: false,
|
|
277
|
-
error: new ValidationError(
|
|
278
|
-
`${path} must not be shorter than ${def.minGraphemes} graphemes`,
|
|
279
|
-
),
|
|
280
|
-
}
|
|
281
|
-
} else {
|
|
282
|
-
needsMinGraphemesCheck = true
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (needsMaxGraphemesCheck || needsMinGraphemesCheck) {
|
|
287
|
-
const len = graphemeLen(value)
|
|
288
|
-
|
|
289
|
-
if (typeof def.maxGraphemes === 'number') {
|
|
290
|
-
if (len > def.maxGraphemes) {
|
|
291
|
-
return {
|
|
292
|
-
success: false,
|
|
293
|
-
error: new ValidationError(
|
|
294
|
-
`${path} must not be longer than ${def.maxGraphemes} graphemes`,
|
|
295
|
-
),
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (typeof def.minGraphemes === 'number') {
|
|
301
|
-
if (len < def.minGraphemes) {
|
|
302
|
-
return {
|
|
303
|
-
success: false,
|
|
304
|
-
error: new ValidationError(
|
|
305
|
-
`${path} must not be shorter than ${def.minGraphemes} graphemes`,
|
|
306
|
-
),
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
if (typeof def.format === 'string') {
|
|
314
|
-
switch (def.format) {
|
|
315
|
-
case 'datetime':
|
|
316
|
-
return formats.datetime(path, value)
|
|
317
|
-
case 'uri':
|
|
318
|
-
return formats.uri(path, value)
|
|
319
|
-
case 'at-uri':
|
|
320
|
-
return formats.atUri(path, value)
|
|
321
|
-
case 'did':
|
|
322
|
-
return formats.did(path, value)
|
|
323
|
-
case 'handle':
|
|
324
|
-
return formats.handle(path, value)
|
|
325
|
-
case 'at-identifier':
|
|
326
|
-
return formats.atIdentifier(path, value)
|
|
327
|
-
case 'nsid':
|
|
328
|
-
return formats.nsid(path, value)
|
|
329
|
-
case 'cid':
|
|
330
|
-
return formats.cid(path, value)
|
|
331
|
-
case 'language':
|
|
332
|
-
return formats.language(path, value)
|
|
333
|
-
case 'tid':
|
|
334
|
-
return formats.tid(path, value)
|
|
335
|
-
case 'record-key':
|
|
336
|
-
return formats.recordKey(path, value)
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return { success: true, value }
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function bytes(
|
|
344
|
-
lexicons: Lexicons,
|
|
345
|
-
path: string,
|
|
346
|
-
def: LexUserType,
|
|
347
|
-
value: unknown,
|
|
348
|
-
): ValidationResult {
|
|
349
|
-
def = def as LexBytes
|
|
350
|
-
|
|
351
|
-
if (!value || !(value instanceof Uint8Array)) {
|
|
352
|
-
return {
|
|
353
|
-
success: false,
|
|
354
|
-
error: new ValidationError(`${path} must be a byte array`),
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// maxLength
|
|
359
|
-
if (typeof def.maxLength === 'number') {
|
|
360
|
-
if (value.byteLength > def.maxLength) {
|
|
361
|
-
return {
|
|
362
|
-
success: false,
|
|
363
|
-
error: new ValidationError(
|
|
364
|
-
`${path} must not be larger than ${def.maxLength} bytes`,
|
|
365
|
-
),
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// minLength
|
|
371
|
-
if (typeof def.minLength === 'number') {
|
|
372
|
-
if (value.byteLength < def.minLength) {
|
|
373
|
-
return {
|
|
374
|
-
success: false,
|
|
375
|
-
error: new ValidationError(
|
|
376
|
-
`${path} must not be smaller than ${def.minLength} bytes`,
|
|
377
|
-
),
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
return { success: true, value }
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function cidLink(
|
|
386
|
-
lexicons: Lexicons,
|
|
387
|
-
path: string,
|
|
388
|
-
def: LexUserType,
|
|
389
|
-
value: unknown,
|
|
390
|
-
): ValidationResult {
|
|
391
|
-
if (CID.asCID(value) === null) {
|
|
392
|
-
return {
|
|
393
|
-
success: false,
|
|
394
|
-
error: new ValidationError(`${path} must be a CID`),
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return { success: true, value }
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function unknown(
|
|
402
|
-
lexicons: Lexicons,
|
|
403
|
-
path: string,
|
|
404
|
-
def: LexUserType,
|
|
405
|
-
value: unknown,
|
|
406
|
-
): ValidationResult {
|
|
407
|
-
// type
|
|
408
|
-
if (!value || typeof value !== 'object') {
|
|
409
|
-
return {
|
|
410
|
-
success: false,
|
|
411
|
-
error: new ValidationError(`${path} must be an object`),
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
return { success: true, value }
|
|
416
|
-
}
|
package/src/validators/xrpc.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { Lexicons } from '../lexicons.js'
|
|
2
|
-
import {
|
|
3
|
-
LexXrpcParameters,
|
|
4
|
-
ValidationError,
|
|
5
|
-
ValidationResult,
|
|
6
|
-
} from '../types.js'
|
|
7
|
-
import { array } from './complex.js'
|
|
8
|
-
import * as PrimitiveValidators from './primitives.js'
|
|
9
|
-
|
|
10
|
-
export function params(
|
|
11
|
-
lexicons: Lexicons,
|
|
12
|
-
path: string,
|
|
13
|
-
def: LexXrpcParameters,
|
|
14
|
-
val: unknown,
|
|
15
|
-
): ValidationResult<Record<string, unknown>> {
|
|
16
|
-
// type
|
|
17
|
-
const value = val && typeof val === 'object' ? val : {}
|
|
18
|
-
|
|
19
|
-
const requiredProps = new Set(def.required ?? [])
|
|
20
|
-
|
|
21
|
-
// properties
|
|
22
|
-
let resultValue = value as Record<string, unknown>
|
|
23
|
-
if (typeof def.properties === 'object') {
|
|
24
|
-
for (const key in def.properties) {
|
|
25
|
-
const propDef = def.properties[key]
|
|
26
|
-
const validated =
|
|
27
|
-
propDef.type === 'array'
|
|
28
|
-
? array(lexicons, key, propDef, value[key])
|
|
29
|
-
: PrimitiveValidators.validate(lexicons, key, propDef, value[key])
|
|
30
|
-
const propValue = validated.success ? validated.value : value[key]
|
|
31
|
-
const propIsUndefined = typeof propValue === 'undefined'
|
|
32
|
-
// Return error for bad validation, giving required rule precedence
|
|
33
|
-
if (propIsUndefined && requiredProps.has(key)) {
|
|
34
|
-
return {
|
|
35
|
-
success: false,
|
|
36
|
-
error: new ValidationError(`${path} must have the property "${key}"`),
|
|
37
|
-
}
|
|
38
|
-
} else if (!propIsUndefined && !validated.success) {
|
|
39
|
-
return validated
|
|
40
|
-
}
|
|
41
|
-
// Adjust value based on e.g. applied defaults, cloning shallowly if there was a changed value
|
|
42
|
-
if (propValue !== value[key]) {
|
|
43
|
-
if (resultValue === value) {
|
|
44
|
-
// Lazy shallow clone
|
|
45
|
-
resultValue = { ...value }
|
|
46
|
-
}
|
|
47
|
-
resultValue[key] = propValue
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return { success: true, value: resultValue }
|
|
53
|
-
}
|