@deepseek-ai/schemastery 3.18.1-rc.1
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/LICENSE +21 -0
- package/README.md +389 -0
- package/lib/index.cjs +596 -0
- package/lib/index.mjs +596 -0
- package/lib/types/index.d.ts +200 -0
- package/lib/types/index.d.ts.map +1 -0
- package/package.json +39 -0
- package/src/index.ts +902 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-present Shigma
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# Schemastery
|
|
2
|
+
|
|
3
|
+
[](https://codecov.io/gh/shigma/schemastery)
|
|
4
|
+
[](https://www.npmjs.com/package/schemastery)
|
|
5
|
+
[](https://www.npmjs.com/package/schemastery)
|
|
6
|
+
[](https://github.com/shigma/schemastery/blob/master/LICENSE)
|
|
7
|
+
|
|
8
|
+
Type Driven Schema Validator.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Lightweight.** Much smaller than other validation libraries.
|
|
13
|
+
- **Easy to use.** You can use any schema as a function or constructor directly.
|
|
14
|
+
- **Powerful.** Schemastery supports some advanced types such as `union`, `intersect` and `transform`.
|
|
15
|
+
- **Extensible.** You can create your own schema types via `Schema.extend()`.
|
|
16
|
+
- **Serializable.** Schema objects can be serialized into JSON and then be hydrated in another environment.
|
|
17
|
+
|
|
18
|
+
## Basic Examples
|
|
19
|
+
|
|
20
|
+
### use as validator (JavaScript)
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const Schema = require('schemastery')
|
|
24
|
+
|
|
25
|
+
const validate = Schema.number().default(10)
|
|
26
|
+
|
|
27
|
+
validate(0) // 0
|
|
28
|
+
validate(null) // 10
|
|
29
|
+
validate('') // TypeError
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### use as constructor (TypeScript)
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import Schema from 'schemastery'
|
|
36
|
+
|
|
37
|
+
interface Config {
|
|
38
|
+
foo: Record<string, string>
|
|
39
|
+
bar: string[]
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const Config = Schema.object({
|
|
43
|
+
foo: Schema.dict(Schema.string()).default({}),
|
|
44
|
+
bar: Schema.array(Schema.string()).default([]),
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
// config is an instance of Config
|
|
48
|
+
// in this case, that is { foo: {}, bar: [] }
|
|
49
|
+
const config = new Config()
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## General Types
|
|
53
|
+
|
|
54
|
+
### Schema.any()
|
|
55
|
+
|
|
56
|
+
Assert that the value is of any type.
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
const validate = Schema.any()
|
|
60
|
+
|
|
61
|
+
validate() // undefined
|
|
62
|
+
validate(0) // 0
|
|
63
|
+
validate({}) // {}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Schema.never()
|
|
67
|
+
|
|
68
|
+
Assert that the value is nullable.
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
const validate = Schema.never()
|
|
72
|
+
|
|
73
|
+
validate() // undefined
|
|
74
|
+
validate(0) // TypeError
|
|
75
|
+
validate({}) // TypeError
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Schema.const(value)
|
|
79
|
+
|
|
80
|
+
Assert that the value is equal to the given constant.
|
|
81
|
+
|
|
82
|
+
```js
|
|
83
|
+
const validate = Schema.const(10)
|
|
84
|
+
|
|
85
|
+
validate(10) // 10
|
|
86
|
+
validate(0) // TypeError
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Schema.number()
|
|
90
|
+
|
|
91
|
+
Assert that the value is a number.
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
const validate = Schema.number()
|
|
95
|
+
|
|
96
|
+
validate() // undefined
|
|
97
|
+
validate(1) // 1
|
|
98
|
+
validate('') // TypeError
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Schema.string()
|
|
102
|
+
|
|
103
|
+
Assert that the value is a string.
|
|
104
|
+
|
|
105
|
+
```js
|
|
106
|
+
const validate = Schema.string()
|
|
107
|
+
|
|
108
|
+
validate() // undefined
|
|
109
|
+
validate(0) // TypeError
|
|
110
|
+
validate('foo') // 'foo'
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Schema.boolean()
|
|
114
|
+
|
|
115
|
+
Assert that the value is a boolean.
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
const validate = Schema.boolean()
|
|
119
|
+
|
|
120
|
+
validate() // undefined
|
|
121
|
+
validate(0) // TypeError
|
|
122
|
+
validate(true) // true
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Schema.is(constructor)
|
|
126
|
+
|
|
127
|
+
Assert that the value is an instance of the given constructor.
|
|
128
|
+
|
|
129
|
+
```js
|
|
130
|
+
const validate = Schema.is(RegExp)
|
|
131
|
+
|
|
132
|
+
validate() // undefined
|
|
133
|
+
validate(/foo/) // /foo/
|
|
134
|
+
validate('foo') // TypeError
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Schema.array(inner)
|
|
138
|
+
|
|
139
|
+
Assert that the value is an array of `inner`. The default value will be `[]` if not specified.
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
const validate = Schema.array(Schema.number())
|
|
143
|
+
|
|
144
|
+
validate() // []
|
|
145
|
+
validate(0) // TypeError
|
|
146
|
+
validate([0, 1]) // [0, 1]
|
|
147
|
+
validate([0, '1']) // TypeError
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Schema.dict(inner)
|
|
151
|
+
|
|
152
|
+
Assert that the value is a dictionary of `inner`. The default value will be `{}` if not specified.
|
|
153
|
+
|
|
154
|
+
```js
|
|
155
|
+
const validate = Schema.dict(Schema.number())
|
|
156
|
+
|
|
157
|
+
validate() // {}
|
|
158
|
+
validate(0) // TypeError
|
|
159
|
+
validate({ a: 0, b: 1 }) // { a: 0, b: 1 }
|
|
160
|
+
validate({ a: 0, b: '1' }) // TypeError
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Schema.tuple(list)
|
|
164
|
+
|
|
165
|
+
Assert that the value is a tuple whose each element is of corresponding subtype. The default value will be `[]` if not specified.
|
|
166
|
+
|
|
167
|
+
```js
|
|
168
|
+
const validate = Schema.tuple([
|
|
169
|
+
Schema.number(),
|
|
170
|
+
Schema.string(),
|
|
171
|
+
])
|
|
172
|
+
|
|
173
|
+
validate() // []
|
|
174
|
+
validate([0]) // { a: 0 }
|
|
175
|
+
validate([0, 1]) // TypeError
|
|
176
|
+
validate([0, '1']) // [0, '1']
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Schema.object(dict)
|
|
180
|
+
|
|
181
|
+
Assert that the value is an object whose each property is of corresponding subtype. The default value will be `{}` if not specified.
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
const validate = Schema.object({
|
|
185
|
+
a: Schema.number(),
|
|
186
|
+
b: Schema.string(),
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
validate() // {}
|
|
190
|
+
validate({ a: 0 }) // { a: 0 }
|
|
191
|
+
validate({ a: 0, b: 1 }) // TypeError
|
|
192
|
+
validate({ a: 0, b: '1' }) // { a: 0, b: '1' }
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Schema.union(list)
|
|
196
|
+
|
|
197
|
+
Assert that the value is one of the specified types.
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
const validate = Schema.union([
|
|
201
|
+
Schema.number(),
|
|
202
|
+
Schema.string(),
|
|
203
|
+
])
|
|
204
|
+
|
|
205
|
+
validate() // undefined
|
|
206
|
+
validate(0) // 0
|
|
207
|
+
validate('1') // '1'
|
|
208
|
+
validate(true) // TypeError
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Schema.intersect(list)
|
|
212
|
+
|
|
213
|
+
Assert that the value should match each specified type.
|
|
214
|
+
|
|
215
|
+
```js
|
|
216
|
+
const validate = Schema.intersect([
|
|
217
|
+
Schema.object({ a: Schema.string().required() }),
|
|
218
|
+
Schema.object({ b: Schema.number().default(0) }),
|
|
219
|
+
])
|
|
220
|
+
|
|
221
|
+
validate() // TypeError
|
|
222
|
+
validate({ a: '' }) // { a: '', b: 0 }
|
|
223
|
+
validate({ a: '', b: 1 }) // { a: '', b: 1 }
|
|
224
|
+
validate({ a: '', b: '2' }) // TypeError
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Schema.transform(inner, callback)
|
|
228
|
+
|
|
229
|
+
Assert that the value is of the specified subtype and then transformed by `callback`.
|
|
230
|
+
|
|
231
|
+
```js
|
|
232
|
+
const validate = Schema.transform(Schema.number().default(0), n => n + 1)
|
|
233
|
+
|
|
234
|
+
validate() // 1
|
|
235
|
+
validate('0') // TypeError
|
|
236
|
+
validate(10) // 11
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Instance Methods
|
|
240
|
+
|
|
241
|
+
Note: `default` and `required` are mutually exclusive.
|
|
242
|
+
|
|
243
|
+
### schema.required()
|
|
244
|
+
|
|
245
|
+
Assert that the value is not nullable.
|
|
246
|
+
|
|
247
|
+
### schema.default(value)
|
|
248
|
+
|
|
249
|
+
Set the fallback value when nullable.
|
|
250
|
+
|
|
251
|
+
### schema.description(text)
|
|
252
|
+
|
|
253
|
+
Set the description of the schema.
|
|
254
|
+
|
|
255
|
+
### schema.simplify(value)
|
|
256
|
+
|
|
257
|
+
Normalize a value by removing parts that are equal to schema defaults. This is
|
|
258
|
+
useful when storing user configuration and keeping persisted files compact.
|
|
259
|
+
|
|
260
|
+
```js
|
|
261
|
+
const Config = Schema.object({
|
|
262
|
+
foo: Schema.string().default(''),
|
|
263
|
+
bar: Schema.number().default(0),
|
|
264
|
+
})
|
|
265
|
+
|
|
266
|
+
Config.simplify({ foo: '', bar: 1 }) // { bar: 1 }
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Validation Options
|
|
270
|
+
|
|
271
|
+
All schemas are callable. The second argument accepts validation options:
|
|
272
|
+
|
|
273
|
+
```js
|
|
274
|
+
const Config = Schema.object({
|
|
275
|
+
foo: Schema.number(),
|
|
276
|
+
})
|
|
277
|
+
|
|
278
|
+
Config({ foo: '1' }, { autofix: true }) // {}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
- `autofix`: remove invalid object properties where possible.
|
|
282
|
+
- `ignore`: skip validation for selected values and schema nodes.
|
|
283
|
+
- `path`: provide an initial path for nested validation errors.
|
|
284
|
+
|
|
285
|
+
## Shorthand Syntax
|
|
286
|
+
|
|
287
|
+
Some shorthand syntax is available for inner types.
|
|
288
|
+
|
|
289
|
+
- `undefined` -> `Schema.any()`
|
|
290
|
+
- `String` -> `Schema.string()`
|
|
291
|
+
- `Number` -> `Schema.number()`
|
|
292
|
+
- `Boolean` -> `Schema.boolean()`
|
|
293
|
+
- `1` -> `Schema.const(1)` (only for primitive types)
|
|
294
|
+
- `Date` -> `Schema.is(Date)`
|
|
295
|
+
|
|
296
|
+
```js
|
|
297
|
+
Schema.array(String) // Schema.array(Schema.string())
|
|
298
|
+
Schema.dict(RegExp) // Schema.dict(Schema.is(RegExp))
|
|
299
|
+
Schema.union([1, 2]) // Schema.union([Schema.const(1), Schema.const(2)])
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
You can also use `Schema.from()` to get the inferred schema from a shorthand value.
|
|
303
|
+
|
|
304
|
+
```js
|
|
305
|
+
Schema.from() // Schema.any()
|
|
306
|
+
Schema.from(Date) // Schema.is(Date)
|
|
307
|
+
Schema.from('foo') // Schema.const('foo')
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## Advanced Examples
|
|
311
|
+
|
|
312
|
+
Here are some examples which demonstrate how to define advanced types.
|
|
313
|
+
|
|
314
|
+
### Enumeration
|
|
315
|
+
|
|
316
|
+
```js
|
|
317
|
+
const Enum = Schema.union(['red', 'blue'])
|
|
318
|
+
|
|
319
|
+
Enum('red') // 'red'
|
|
320
|
+
Enum('blue') // 'blue'
|
|
321
|
+
Enum('green') // TypeError
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### ToString
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
const ToString = Schema.transform(Schema.any(), v => String(v))
|
|
328
|
+
|
|
329
|
+
ToString('') // ''
|
|
330
|
+
ToString(0) // '0'
|
|
331
|
+
ToString({}) // '{}'
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Listable
|
|
335
|
+
|
|
336
|
+
```js
|
|
337
|
+
const Listable = Schema.union([
|
|
338
|
+
Schema.array(Number),
|
|
339
|
+
Schema.transform(Number, n => [n]),
|
|
340
|
+
]).default([])
|
|
341
|
+
|
|
342
|
+
Listable() // []
|
|
343
|
+
Listable(0) // [0]
|
|
344
|
+
Listable([1, 2]) // [1, 2]
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Alias
|
|
348
|
+
|
|
349
|
+
```js
|
|
350
|
+
const Config = Schema.dict(Number, Schema.union([
|
|
351
|
+
'foo',
|
|
352
|
+
Schema.transform('bar', () => 'foo'),
|
|
353
|
+
]))
|
|
354
|
+
|
|
355
|
+
Config({ foo: 1 }) // { foo: 1 }
|
|
356
|
+
Config({ bar: 2 }) // { foo: 2 }
|
|
357
|
+
Config({ bar: '3' }) // TypeError
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Extensibility
|
|
361
|
+
|
|
362
|
+
Custom schema types are registered with `Schema.extend(type, resolve)`. A
|
|
363
|
+
resolver receives the input value, schema node, validation options, and a strict
|
|
364
|
+
flag. Return `[value]` for accepted input, or `[value, adapted]` when the caller
|
|
365
|
+
should write an adapted value back to the source object.
|
|
366
|
+
|
|
367
|
+
```js
|
|
368
|
+
Schema.extend('trimmed', (data, schema, options) => {
|
|
369
|
+
if (typeof data !== 'string') {
|
|
370
|
+
throw new Schema.ValidationError(`expected string but got ${data}`, options)
|
|
371
|
+
}
|
|
372
|
+
return [data.trim()]
|
|
373
|
+
})
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Serializability
|
|
377
|
+
|
|
378
|
+
```js
|
|
379
|
+
const schema1 = Schema.object({
|
|
380
|
+
foo: Schema.string(),
|
|
381
|
+
bar: Schema.number(),
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
// should have the same effect as schema1
|
|
385
|
+
const schema2 = new Schema(JSON.parse(JSON.stringify(schema1)))
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
Schemastery also exposes the Standard Schema `~standard` property, so compatible
|
|
389
|
+
tools can validate values without depending on Schemastery-specific APIs.
|