schiva 0.1.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/LICENSE +21 -0
- package/README.md +166 -0
- package/package.json +45 -0
- package/src/closed-schema.js +11 -0
- package/src/compile.js +742 -0
- package/src/deep-equal.js +59 -0
- package/src/index.js +13 -0
- package/src/json-schema-refs.js +170 -0
- package/src/json-schema.js +420 -0
- package/src/schema.js +230 -0
- package/src/types/all-of.js +62 -0
- package/src/types/any-of.js +63 -0
- package/src/types/any.js +32 -0
- package/src/types/array-of.js +137 -0
- package/src/types/boolean.js +43 -0
- package/src/types/code-point-length.js +32 -0
- package/src/types/conditional.js +48 -0
- package/src/types/enum.js +51 -0
- package/src/types/float.js +84 -0
- package/src/types/has-duplicates.js +21 -0
- package/src/types/index.js +39 -0
- package/src/types/integer.js +45 -0
- package/src/types/never.js +36 -0
- package/src/types/not.js +49 -0
- package/src/types/obj.js +58 -0
- package/src/types/one-of.js +69 -0
- package/src/types/ref.js +49 -0
- package/src/types/string.js +86 -0
- package/src/types/validate-type.js +98 -0
- package/src/types/values.js +46 -0
- package/src/types/when.js +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jesús Seijas
|
|
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,166 @@
|
|
|
1
|
+
# schiva
|
|
2
|
+
|
|
3
|
+
Fast schema validation for JavaScript. Describe data with a small schema DSL or with JSON Schema (draft-07), and
|
|
4
|
+
schiva compiles it into a JavaScript function generated for that schema, so validating is several times faster than
|
|
5
|
+
walking the schema for every value.
|
|
6
|
+
|
|
7
|
+
- Passes the whole draft-07 [JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite)
|
|
8
|
+
(929 of 929 tests), including `$ref` to other documents.
|
|
9
|
+
- Readable error messages with the path of each field: `lines[12].price must be a number`.
|
|
10
|
+
- Three modes: every error, the first error only, or just `true`/`false`.
|
|
11
|
+
- No dependencies. Unknown or unsupported keywords throw instead of being silently ignored.
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install schiva
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
const { ClosedSchema, String, Integer, ArrayOf } = require('schiva');
|
|
21
|
+
|
|
22
|
+
const person = new ClosedSchema({
|
|
23
|
+
id: String(),
|
|
24
|
+
age: Integer({ min: 18 }),
|
|
25
|
+
tags: ArrayOf({ type: String(), isMandatory: false }),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Compile once, when the program starts:
|
|
29
|
+
const validatePerson = person.compile();
|
|
30
|
+
|
|
31
|
+
validatePerson({ id: 'x', age: 20 }); // []
|
|
32
|
+
validatePerson({ id: 1, age: 10, extra: 1 });
|
|
33
|
+
// ['id must be a string', 'age must be at least 18', 'Unexpected key: extra']
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
With JSON Schema:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
const { compileJsonSchema } = require('schiva');
|
|
40
|
+
|
|
41
|
+
const validate = compileJsonSchema({
|
|
42
|
+
type: 'object',
|
|
43
|
+
required: ['id'],
|
|
44
|
+
properties: { id: { type: 'string', pattern: '^[A-Z]+$' } },
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
validate({ id: 'AB' }); // []
|
|
48
|
+
validate({ id: 'ab' }); // ['id does not match the required pattern']
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Modes
|
|
52
|
+
|
|
53
|
+
`compile(options)` (on schemas and on every type) and `compileJsonSchema(json, options)` return a function:
|
|
54
|
+
|
|
55
|
+
| Option | The function returns | Use it when |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| (none) | every error message, `[]` when valid | messages are shown or logged |
|
|
58
|
+
| `{ allErrors: false }` | only the first error message, `[]` when valid | one message is enough; stops at the first failing check |
|
|
59
|
+
| `{ errors: false }` | `true` or `false` | only validity matters; builds no messages |
|
|
60
|
+
|
|
61
|
+
Schemas and types also have `validate(value)`, which checks without compiling (10 to 25 times slower), and
|
|
62
|
+
`isValid(value)`.
|
|
63
|
+
|
|
64
|
+
## Compile once
|
|
65
|
+
|
|
66
|
+
The compiled function is a snapshot of the schema: changes made to the schema or its types afterwards (such as
|
|
67
|
+
`.optional()`, `.nullable()` or setting their fields) are not seen. Compile after building the schema, and compile
|
|
68
|
+
again if it changes. Compiling takes about 0.1 ms for a schema of moderate size, so compile when the program starts
|
|
69
|
+
(or cache the function), not for every value.
|
|
70
|
+
|
|
71
|
+
The generated code uses `new Function`, so it does not run where code generation is forbidden (for example with a
|
|
72
|
+
strict Content Security Policy).
|
|
73
|
+
|
|
74
|
+
## Schema DSL
|
|
75
|
+
|
|
76
|
+
A `Schema` takes an object whose keys are the expected properties. Plain objects inside it become nested schemas.
|
|
77
|
+
|
|
78
|
+
```js
|
|
79
|
+
const { Schema, String, Float, Enum } = require('schiva');
|
|
80
|
+
|
|
81
|
+
const order = new Schema(
|
|
82
|
+
{
|
|
83
|
+
id: String({ pattern: /^ORD-\d{8}$/ }),
|
|
84
|
+
status: Enum({ options: ['draft', 'placed'] }),
|
|
85
|
+
customer: { name: String({ min: 1 }), email: String({ isMandatory: false }) },
|
|
86
|
+
total: Float({ min: 0 }),
|
|
87
|
+
},
|
|
88
|
+
{ isOpen: false }
|
|
89
|
+
);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Every type takes `isMandatory` (default `true`: `undefined` is an error) and `isNullable` (default `false`: `null` is
|
|
93
|
+
an error), and has `.optional()`, `.required()`, `.nullable()` and `.notNull()`.
|
|
94
|
+
|
|
95
|
+
| Type | Options |
|
|
96
|
+
|---|---|
|
|
97
|
+
| `String` | `min`, `max` (length), `pattern` (RegExp), `allowEmpty`, `countCodePoints` |
|
|
98
|
+
| `Integer`, `Float` | `min`, `max`, `exclusiveMin`, `exclusiveMax`, `multipleOf` |
|
|
99
|
+
| `Boolean`, `Any`, `Never` | |
|
|
100
|
+
| `Enum` | `options` (strings) |
|
|
101
|
+
| `Values`, `Const(value)` | `values`: allowed values, compared deeply |
|
|
102
|
+
| `ArrayOf` | `type` (one type, or an array of types for a tuple), `min`, `max`, `unique`, `contains`, `additionalType` |
|
|
103
|
+
| `AnyOf`, `AllOf`, `OneOf` | `types` |
|
|
104
|
+
| `Not` | `type` |
|
|
105
|
+
| `Conditional` | `ifType`, `thenType`, `elseType` |
|
|
106
|
+
| `When` | `jsonType` (`object`, `array`, `string`, `number`), `type`: checks only values of that JSON type |
|
|
107
|
+
| `Ref` | `target`, for recursive schemas |
|
|
108
|
+
|
|
109
|
+
Schema options: `isOpen` (default `true`; `ClosedSchema` sets it to `false` and rejects unknown keys),
|
|
110
|
+
`additionalType`, `patternTypes` (`[{ pattern, type }]`), `propertyNameType`, `minProperties`, `maxProperties`,
|
|
111
|
+
`dependencies` (`[{ key, required: [...] }]` or `[{ key, type }]`), `isMandatory`, `isNullable`.
|
|
112
|
+
|
|
113
|
+
Short helpers are also exported: `str`, `int`, `float`, `bool`, `arrOf`, `obj`, `any`, `anyOf`, `allOf`, `oneOf`,
|
|
114
|
+
`not`, `enumt`, and optional versions prefixed with `o` (`ostr`, `oint`...).
|
|
115
|
+
|
|
116
|
+
Declared keys are read as own properties only, so `{}.toString` or a key added to `Object.prototype` never counts as
|
|
117
|
+
present.
|
|
118
|
+
|
|
119
|
+
## JSON Schema
|
|
120
|
+
|
|
121
|
+
`fromJsonSchema(json, options)` converts a JSON Schema (draft-07) into the same types, and
|
|
122
|
+
`compileJsonSchema(json, options)` compiles it. Every validation keyword of draft-07 is supported, along with
|
|
123
|
+
`definitions` and `$ref` (JSON pointers, `$id` base URIs and anchors, recursive schemas). String lengths count Unicode
|
|
124
|
+
code points, as the specification says.
|
|
125
|
+
|
|
126
|
+
References to other documents resolve against the documents given in `options.schemas`, as `{ uri: schema }` or as an
|
|
127
|
+
array of schemas with `$id`. Nothing is loaded from the network, and a reference that cannot be resolved throws when
|
|
128
|
+
compiling:
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
const validateOrder = compileJsonSchema(orderSchema, {
|
|
132
|
+
schemas: { 'https://example.com/schemas/address.json': addressSchema },
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
To validate schemas against the draft-07 meta-schema, register it in `schemas` (ajv ships a copy as
|
|
137
|
+
`ajv/dist/refs/json-schema-draft-07.json`).
|
|
138
|
+
|
|
139
|
+
## Types of your own
|
|
140
|
+
|
|
141
|
+
Classes that extend `ValidateType` (or a built-in type) with their own `validate()` or `isValid()` keep working when
|
|
142
|
+
compiled: the generated code calls them for their part of the schema.
|
|
143
|
+
|
|
144
|
+
## Speed
|
|
145
|
+
|
|
146
|
+
Compared with ajv and the other validators of
|
|
147
|
+
[json-schema-benchmark](https://github.com/ebdrup/json-schema-benchmark), each measurement in its own process
|
|
148
|
+
(see `bench/`):
|
|
149
|
+
|
|
150
|
+
| | schiva | ajv | @exodus/schemasafe |
|
|
151
|
+
|---|---|---|---|
|
|
152
|
+
| Test suite, tests passed | **929** of 929 | 921 (8 wrong) | 905 |
|
|
153
|
+
| Test suite, first error (runs/sec) | **118k** | 62k | 99k |
|
|
154
|
+
| Test suite, all errors (runs/sec) | **88k** | 54k | 65k |
|
|
155
|
+
| Order with 20 lines, valid, first error (validations/sec) | **2.26M** | 0.76M | 0.54M |
|
|
156
|
+
| Order with 20 lines, invalid, all errors (validations/sec) | **1.86M** | 0.43M | 0.32M |
|
|
157
|
+
| Compiling a schema (per sec) | **10k** | 0.2k | 0.8k |
|
|
158
|
+
|
|
159
|
+
```sh
|
|
160
|
+
pnpm run bench # every validator in its own process (about 8 minutes)
|
|
161
|
+
pnpm run bench:quick # every validator in one process (about a minute)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "schiva",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Fast schema validation for JavaScript: a schema DSL and JSON Schema (draft-07), compiled to generated code",
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"files": [
|
|
8
|
+
"src"
|
|
9
|
+
],
|
|
10
|
+
"keywords": [
|
|
11
|
+
"schema",
|
|
12
|
+
"validation",
|
|
13
|
+
"validator",
|
|
14
|
+
"json-schema",
|
|
15
|
+
"draft-07",
|
|
16
|
+
"compiler",
|
|
17
|
+
"fast"
|
|
18
|
+
],
|
|
19
|
+
"author": "Jesús Seijas <jseijas@gmail.com>",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
26
|
+
"@eslint/js": "^9.39.2",
|
|
27
|
+
"eslint": "^9.39.2",
|
|
28
|
+
"eslint-config-prettier": "^10.1.8",
|
|
29
|
+
"eslint-plugin-jest": "^29.12.1",
|
|
30
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
31
|
+
"globals": "^17.0.0",
|
|
32
|
+
"jest": "^30.2.0",
|
|
33
|
+
"prettier": "^3.8.0"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"lint": "eslint .",
|
|
40
|
+
"lintfix": "eslint --fix .",
|
|
41
|
+
"test": "eslint . && jest --silent --coverage .",
|
|
42
|
+
"bench": "cd bench && pnpm install && pnpm start",
|
|
43
|
+
"bench:quick": "cd bench && pnpm install && pnpm run quick"
|
|
44
|
+
}
|
|
45
|
+
}
|