@amritk/generate-validators 0.11.11 → 0.11.12
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/AI.md +5 -0
- package/README.md +29 -8
- package/dist/generators/generate-files.js +4 -1
- package/package.json +7 -3
package/AI.md
CHANGED
|
@@ -34,5 +34,10 @@ const files = await buildValidatorSchema(schema, 'Document')
|
|
|
34
34
|
`ValidationResult`, helpers) plus the `index.ts` barrel.
|
|
35
35
|
4. **`NaN` satisfies numeric bounds** (`minimum`/`maximum`/`multipleOf`) — differs
|
|
36
36
|
from Ajv. Draft-07 schemas are auto-upgraded to 2020-12.
|
|
37
|
+
5. **`format` emits no check.** It stays an annotation, like the interpreter's
|
|
38
|
+
default — but *not* like the interpreter run with `{ formats: 'all' }`
|
|
39
|
+
(`@amritk/lint`, `createApi({ formats })`), which rejects strings a generated
|
|
40
|
+
validator accepts. `unevaluatedProperties`/`unevaluatedItems` go the other
|
|
41
|
+
way: unimplemented, so generation **throws** instead of widening the verdict.
|
|
37
42
|
|
|
38
43
|
Only the `.` entry. Install: `bun add @amritk/generate-validators`.
|
package/README.md
CHANGED
|
@@ -23,6 +23,9 @@ Each generated file exports:
|
|
|
23
23
|
|
|
24
24
|
- A TypeScript `type` definition for the schema
|
|
25
25
|
- A `validateFoo(input: unknown, _path?: string): ValidationResult` function
|
|
26
|
+
- An `isFoo(input: unknown): input is Foo` boolean type guard — a single flat
|
|
27
|
+
predicate (no error array, no cold-path call) reaching the same verdict as
|
|
28
|
+
`validateFoo`, for the common "is this valid?" question
|
|
26
29
|
|
|
27
30
|
A shared `validation-result.ts` template and an `index.ts` barrel are emitted alongside the generated files.
|
|
28
31
|
|
|
@@ -81,12 +84,13 @@ if (!result.valid) {
|
|
|
81
84
|
|
|
82
85
|
## API
|
|
83
86
|
|
|
84
|
-
### `buildValidatorSchema(rootSchema, rootTypeName)`
|
|
87
|
+
### `buildValidatorSchema(rootSchema, rootTypeName, typeSuffix?)`
|
|
85
88
|
|
|
86
|
-
| Parameter | Type | Description |
|
|
87
|
-
|
|
88
|
-
| `rootSchema` | `JSONSchema` | The root schema to traverse. `$ref` and `$dynamicRef` are resolved recursively. Draft-07 schemas are upgraded to 2020-12 automatically. |
|
|
89
|
-
| `rootTypeName` | `string` | Name used for the root type (e.g. `"Document"`). |
|
|
89
|
+
| Parameter | Type | Default | Description |
|
|
90
|
+
|:---|:---|:---|:---|
|
|
91
|
+
| `rootSchema` | `JSONSchema` | — | The root schema to traverse. `$ref` and `$dynamicRef` are resolved recursively. Draft-07 schemas are upgraded to 2020-12 automatically. |
|
|
92
|
+
| `rootTypeName` | `string` | — | Name used for the root type (e.g. `"Document"`). |
|
|
93
|
+
| `typeSuffix` | `string` | `''` | Suffix appended to every `$ref`-derived type name (`'Object'` turns `Contact` into `ContactObject`). The root type name is unaffected. |
|
|
90
94
|
|
|
91
95
|
Returns: `Promise<GeneratedFile[]>` where `GeneratedFile = { filename: string; content: string }`.
|
|
92
96
|
|
|
@@ -103,7 +107,17 @@ per-item work (a bare `string[]` is free; a closed object with several fields is
|
|
|
103
107
|
meaningfully slower), which is why array-heavy schemas validate more slowly than
|
|
104
108
|
scalar/object ones.
|
|
105
109
|
|
|
106
|
-
|
|
110
|
+
**`format` emits no check.** JSON Schema treats `format` as an annotation, and so
|
|
111
|
+
does this generator: `{ type: 'string', format: 'uuid' }` produces the `typeof`
|
|
112
|
+
check and nothing more. That matches the interpreter's default, but *not* the
|
|
113
|
+
interpreter run with `{ formats: 'all' }` — as `@amritk/lint` and
|
|
114
|
+
`createApi({ formats })` do — so a generated validator accepts strings those
|
|
115
|
+
reject. Two keywords are handled the other way: `unevaluatedProperties` and
|
|
116
|
+
`unevaluatedItems` are not implemented and **throw at generation time** rather
|
|
117
|
+
than silently widening the verdict, because unlike `format` there is no reading of
|
|
118
|
+
the spec under which ignoring them is correct.
|
|
119
|
+
|
|
120
|
+
One further divergence is worth calling out: **`NaN` satisfies a constrained number.**
|
|
107
121
|
Because the numeric bound checks are the exact negation of the error condition
|
|
108
122
|
(e.g. `!(x < minimum)`), and every comparison against `NaN` is `false`, a `NaN`
|
|
109
123
|
passes `minimum`/`maximum`/`exclusive*`/`multipleOf`. This matches the interpreter
|
|
@@ -144,8 +158,15 @@ the first error rather than collecting a full error list.)
|
|
|
144
158
|
|
|
145
159
|
Preparing a validator costs ~0.3–0.6 ms for mjst codegen and ~0.05–0.2 ms for a
|
|
146
160
|
TypeBox `TypeCompiler` compile, versus ~9–12 ms for an Ajv compile. Every library
|
|
147
|
-
agrees on every verdict; parity is asserted before timing
|
|
148
|
-
|
|
161
|
+
agrees on every verdict; parity is asserted before timing.
|
|
162
|
+
|
|
163
|
+
One caveat on the first two rows: their schemas declare `format` (`uuid`,
|
|
164
|
+
`email`), and Ajv, typia, zod, and TypeBox all check it, while mjst's generated
|
|
165
|
+
validators treat it as an annotation (see [Semantics](#semantics)). So on `small`
|
|
166
|
+
and `order`, mjst is doing slightly less work than the columns beside it — the
|
|
167
|
+
parity samples fail other constraints too, which is why the verdicts still agree.
|
|
168
|
+
The `assert-loose` / `assert-strict` rows carry no `format` and are the
|
|
169
|
+
constraint-for-constraint comparison. Each library is
|
|
149
170
|
timed in an isolated process over a pool of distinct inputs, reporting the median
|
|
150
171
|
of many trials — so the optimiser can't hoist or eliminate the work and the
|
|
151
172
|
numbers stay reproducible. Micro-benchmark figures vary by machine and runtime —
|
|
@@ -8,7 +8,10 @@ const generateValidatorFile = (schema, typeName, options) => {
|
|
|
8
8
|
rootSchema: options?.rootSchema,
|
|
9
9
|
typeSuffix
|
|
10
10
|
});
|
|
11
|
-
const typeDefinition = generateTypeDefinition(schema, typeName, {
|
|
11
|
+
const typeDefinition = generateTypeDefinition(schema, typeName, {
|
|
12
|
+
typeSuffix,
|
|
13
|
+
...options?.rootSchema !== void 0 ? { rootSchema: options.rootSchema } : {}
|
|
14
|
+
});
|
|
12
15
|
const validatorFunction = generateValidatorFunction(schema, typeName, typeSuffix);
|
|
13
16
|
const booleanGuard = generateBooleanGuard(schema, typeName, typeSuffix);
|
|
14
17
|
let result = `import type { ValidationResult, ValidationError } from './validation-result.js'
|
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amritk/generate-validators",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.12",
|
|
4
4
|
"description": "Generate TypeScript validation functions from JSON Schemas.",
|
|
5
5
|
"module": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=20"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "amritk",
|
|
9
13
|
"keywords": [
|
|
@@ -47,10 +51,10 @@
|
|
|
47
51
|
},
|
|
48
52
|
"dependencies": {
|
|
49
53
|
"json-schema-typed": "^8.0.1",
|
|
50
|
-
"@amritk/helpers": "0.
|
|
54
|
+
"@amritk/helpers": "0.14.0"
|
|
51
55
|
},
|
|
52
56
|
"devDependencies": {
|
|
53
|
-
"@amritk/runtime-validators": "0.9.
|
|
57
|
+
"@amritk/runtime-validators": "0.9.1",
|
|
54
58
|
"@ryoppippi/unplugin-typia": "^2.6.5",
|
|
55
59
|
"@scalar/openapi-parser": "^0.26.1",
|
|
56
60
|
"@sinclair/typebox": "^0.34.49",
|