ata-validator 0.17.5 → 0.18.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/CHANGELOG.md +12 -0
- package/README.md +49 -28
- package/index.browser.mjs +1 -1
- package/index.d.ts +74 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to ata-validator are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/), and this project adheres to semantic versioning.
|
|
4
4
|
|
|
5
|
+
## 0.18.1 - 2026-05-26
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- The browser entry (`index.browser.mjs`) re-exports `toTypeScript`, so the inferred TypeScript type for a schema can be generated client-side (for example in a web playground) alongside `Validator.toStandaloneModule()`. Pure re-export, no runtime change.
|
|
10
|
+
|
|
11
|
+
## 0.18.0 - 2026-05-25
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- `Infer<S>` resolves the shapes 0.17.0 left as `unknown`. `anyOf` and `oneOf` map to unions, `allOf` to an intersection, `prefixItems` to a tuple, and a `$ref` to a local `#/$defs/...` or `#/definitions/...` entry resolves to the referenced type, including recursive references. An external or otherwise unresolvable `$ref` still resolves to `unknown` rather than erroring. `new Validator(schema)` carries the wider inference, so handlers narrow `result.data` for these schemas with no manual annotation, and the same applies to the Fastify type provider that builds on `Infer`. Pure `.d.ts` change, no runtime impact.
|
|
16
|
+
|
|
5
17
|
## 0.17.5 - 2026-05-25
|
|
6
18
|
|
|
7
19
|
### Fixed
|
package/README.md
CHANGED
|
@@ -127,58 +127,79 @@ v.countValid(ndjson); // number
|
|
|
127
127
|
|
|
128
128
|
### Type-safe schemas
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
ata infers TypeScript types straight from plain JSON Schema. Write the schema once with `defineSchema`, and both runtime validation and the static type come from it, with no builder DSL and no second type declaration to keep in sync.
|
|
131
131
|
|
|
132
132
|
```ts
|
|
133
|
-
import {
|
|
134
|
-
import { Validator } from 'ata-validator'
|
|
133
|
+
import { defineSchema, Validator } from 'ata-validator'
|
|
135
134
|
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
135
|
+
const userSchema = defineSchema({
|
|
136
|
+
type: 'object',
|
|
137
|
+
properties: {
|
|
138
|
+
id: { type: 'integer', minimum: 1 },
|
|
139
|
+
role: { type: 'string', enum: ['admin', 'user'] },
|
|
140
|
+
},
|
|
141
|
+
required: ['id'],
|
|
140
142
|
})
|
|
141
143
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const v = new Validator<User>(UserSchema)
|
|
145
|
-
|
|
146
|
-
if (v.isValidObject(data)) {
|
|
147
|
-
// data is narrowed to User, no cast needed
|
|
148
|
-
console.log(data.name)
|
|
149
|
-
}
|
|
150
|
-
|
|
144
|
+
const v = new Validator(userSchema)
|
|
151
145
|
const result = v.validate(data)
|
|
152
146
|
if (result.valid) {
|
|
153
|
-
|
|
147
|
+
result.data.id // number
|
|
148
|
+
result.data.role // 'admin' | 'user' | undefined
|
|
154
149
|
} else {
|
|
155
150
|
// result.errors: ValidationError[]
|
|
156
151
|
}
|
|
157
152
|
```
|
|
158
153
|
|
|
159
|
-
|
|
154
|
+
`defineSchema` returns the schema untouched at runtime; in TypeScript it gives keyword autocomplete and an error when a value has the wrong shape, with no `as const` needed. `new Validator(schema)` carries the inferred type, so a successful `validate` narrows `result.data` with no manual annotation.
|
|
160
155
|
|
|
161
|
-
####
|
|
156
|
+
#### Extracting the type: `Infer`
|
|
162
157
|
|
|
163
|
-
|
|
158
|
+
You can also pull the type out directly with `Infer`, with no second declaration to keep in sync.
|
|
164
159
|
|
|
165
160
|
```ts
|
|
166
|
-
import { defineSchema,
|
|
161
|
+
import { defineSchema, type Infer } from 'ata-validator'
|
|
167
162
|
|
|
168
|
-
const
|
|
163
|
+
const event = defineSchema({
|
|
164
|
+
$defs: {
|
|
165
|
+
Point: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } }, required: ['x', 'y'] },
|
|
166
|
+
},
|
|
169
167
|
type: 'object',
|
|
170
168
|
properties: {
|
|
171
|
-
|
|
172
|
-
|
|
169
|
+
kind: { enum: ['click', 'scroll'] },
|
|
170
|
+
at: { $ref: '#/$defs/Point' },
|
|
171
|
+
path: { type: 'array', prefixItems: [{ type: 'string' }, { type: 'integer' }] },
|
|
173
172
|
},
|
|
174
|
-
required: ['
|
|
173
|
+
required: ['kind', 'at'],
|
|
175
174
|
})
|
|
176
175
|
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
type Event = Infer<typeof event>
|
|
177
|
+
// {
|
|
178
|
+
// kind: 'click' | 'scroll'
|
|
179
|
+
// at: { x: number; y: number }
|
|
180
|
+
// path?: [string, number]
|
|
181
|
+
// }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`Infer` resolves `const`/`enum` to literals, `anyOf`/`oneOf` to unions, `allOf` to intersections, `prefixItems` to tuples, and local `$ref` into `#/$defs` or `#/definitions`, including recursive references. An external or unresolvable `$ref` resolves to `unknown` rather than erroring. The exported `JSONSchema` type is available if you want to annotate a schema by hand; custom and vendor keywords are allowed. Requires TypeScript >= 5.0.
|
|
185
|
+
|
|
186
|
+
#### Composes with TypeBox, Zod, or your own types
|
|
187
|
+
|
|
188
|
+
`Validator<T>` is generic, so if you already author schemas with a library, pass the type and ata narrows to it. No library-specific assumption.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { Type, type Static } from '@sinclair/typebox'
|
|
192
|
+
import { Validator } from 'ata-validator'
|
|
193
|
+
|
|
194
|
+
const UserSchema = Type.Object({
|
|
195
|
+
id: Type.Integer({ minimum: 1 }),
|
|
196
|
+
name: Type.String({ minLength: 1 }),
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
const v = new Validator<Static<typeof UserSchema>>(UserSchema)
|
|
179
200
|
```
|
|
180
201
|
|
|
181
|
-
The
|
|
202
|
+
The same works with Zod-from-JSON-Schema, Valibot, or a hand-written `type User = {...}` alongside a JSON Schema literal.
|
|
182
203
|
|
|
183
204
|
### Cross-Schema `$ref`
|
|
184
205
|
|
package/index.browser.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// Browser ESM entry — same code, native addon stubbed out by bundler via "browser" field.
|
|
2
2
|
import mod from './index.js';
|
|
3
|
-
export const { Validator, validate, version, createPaddedBuffer, SIMDJSON_PADDING, renderPretty, renderCompact, renderJSON } = mod;
|
|
3
|
+
export const { Validator, validate, version, createPaddedBuffer, SIMDJSON_PADDING, renderPretty, renderCompact, renderJSON, toTypeScript } = mod;
|
|
4
4
|
export default mod;
|
package/index.d.ts
CHANGED
|
@@ -177,26 +177,55 @@ type RequiredKeys<S> = S extends { required: infer R }
|
|
|
177
177
|
: never
|
|
178
178
|
: never;
|
|
179
179
|
|
|
180
|
+
/** Collapse a union of types into their intersection (used for `allOf`). */
|
|
181
|
+
type UnionToIntersection<U> =
|
|
182
|
+
(U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;
|
|
183
|
+
|
|
184
|
+
/** The root `$defs`/`definitions` map, threaded through inference for `$ref` resolution. */
|
|
185
|
+
type RootDefs<S> = S extends { $defs: infer D }
|
|
186
|
+
? D
|
|
187
|
+
: S extends { definitions: infer D }
|
|
188
|
+
? D
|
|
189
|
+
: {};
|
|
190
|
+
|
|
191
|
+
/** Extract the definition name from a local `#/$defs/...` or `#/definitions/...` pointer. */
|
|
192
|
+
type RefName<R> = R extends `#/$defs/${infer N}`
|
|
193
|
+
? N
|
|
194
|
+
: R extends `#/definitions/${infer N}`
|
|
195
|
+
? N
|
|
196
|
+
: never;
|
|
197
|
+
|
|
198
|
+
/** Resolve a `$ref` against the root defs map; external/unresolvable refs -> unknown. */
|
|
199
|
+
type ResolveRef<R, D> = [RefName<R>] extends [never]
|
|
200
|
+
? unknown
|
|
201
|
+
: RefName<R> extends keyof D
|
|
202
|
+
? InferWith<D[RefName<R>], D>
|
|
203
|
+
: unknown;
|
|
204
|
+
|
|
180
205
|
/** Object shape: required keys are required, all other declared keys optional. */
|
|
181
|
-
type InferObject<S> = S extends { properties: infer P }
|
|
206
|
+
type InferObject<S, D> = S extends { properties: infer P }
|
|
182
207
|
? Simplify<
|
|
183
|
-
{ [K in keyof P as K extends RequiredKeys<S> ? K : never]:
|
|
184
|
-
{ [K in keyof P as K extends RequiredKeys<S> ? never : K]?:
|
|
208
|
+
{ [K in keyof P as K extends RequiredKeys<S> ? K : never]: InferWith<P[K], D> } &
|
|
209
|
+
{ [K in keyof P as K extends RequiredKeys<S> ? never : K]?: InferWith<P[K], D> }
|
|
185
210
|
>
|
|
186
211
|
: Record<string, unknown>;
|
|
187
212
|
|
|
188
|
-
/** Array shape: `
|
|
189
|
-
type InferArray<S> = S extends {
|
|
190
|
-
?
|
|
191
|
-
?
|
|
192
|
-
:
|
|
193
|
-
:
|
|
213
|
+
/** Array shape: `prefixItems` -> tuple; `items` (single schema) -> element type; otherwise unknown[]. */
|
|
214
|
+
type InferArray<S, D> = S extends { prefixItems: infer P }
|
|
215
|
+
? P extends ReadonlyArray<unknown>
|
|
216
|
+
? { -readonly [K in keyof P]: InferWith<P[K], D> }
|
|
217
|
+
: unknown[]
|
|
218
|
+
: S extends { items: infer I }
|
|
219
|
+
? I extends ReadonlyArray<unknown>
|
|
220
|
+
? unknown[]
|
|
221
|
+
: InferWith<I, D>[]
|
|
222
|
+
: unknown[];
|
|
194
223
|
|
|
195
224
|
/** Map a single JSON Schema type name (+ its schema) to a TS type. */
|
|
196
|
-
type InferByTypeName<N, S> = N extends 'object'
|
|
197
|
-
? InferObject<S>
|
|
225
|
+
type InferByTypeName<N, S, D> = N extends 'object'
|
|
226
|
+
? InferObject<S, D>
|
|
198
227
|
: N extends 'array'
|
|
199
|
-
? InferArray<S>
|
|
228
|
+
? InferArray<S, D>
|
|
200
229
|
: N extends 'string'
|
|
201
230
|
? string
|
|
202
231
|
: N extends 'number'
|
|
@@ -209,28 +238,46 @@ type InferByTypeName<N, S> = N extends 'object'
|
|
|
209
238
|
? null
|
|
210
239
|
: unknown;
|
|
211
240
|
|
|
241
|
+
/** Core inference with the root defs map `D` threaded for `$ref` resolution. */
|
|
242
|
+
type InferWith<S, D> = S extends { $ref: infer R }
|
|
243
|
+
? ResolveRef<R, D>
|
|
244
|
+
: S extends { const: infer C }
|
|
245
|
+
? C
|
|
246
|
+
: S extends { enum: infer E }
|
|
247
|
+
? E extends ReadonlyArray<infer U>
|
|
248
|
+
? U
|
|
249
|
+
: unknown
|
|
250
|
+
: S extends { allOf: infer A }
|
|
251
|
+
? A extends ReadonlyArray<unknown>
|
|
252
|
+
? Simplify<UnionToIntersection<{ [K in keyof A]: InferWith<A[K], D> }[number]>>
|
|
253
|
+
: unknown
|
|
254
|
+
: S extends { anyOf: infer A }
|
|
255
|
+
? A extends ReadonlyArray<unknown>
|
|
256
|
+
? { [K in keyof A]: InferWith<A[K], D> }[number]
|
|
257
|
+
: unknown
|
|
258
|
+
: S extends { oneOf: infer A }
|
|
259
|
+
? A extends ReadonlyArray<unknown>
|
|
260
|
+
? { [K in keyof A]: InferWith<A[K], D> }[number]
|
|
261
|
+
: unknown
|
|
262
|
+
: S extends { type: infer T }
|
|
263
|
+
? T extends ReadonlyArray<infer N>
|
|
264
|
+
? InferByTypeName<N, S, D>
|
|
265
|
+
: InferByTypeName<T, S, D>
|
|
266
|
+
: unknown;
|
|
267
|
+
|
|
212
268
|
/**
|
|
213
|
-
* Infer the TypeScript data type a JSON Schema literal describes
|
|
269
|
+
* Infer the TypeScript data type a JSON Schema literal describes.
|
|
214
270
|
*
|
|
215
271
|
* Handles: primitives, `type` arrays (union), `const`, `enum`, objects
|
|
216
|
-
* (`properties` + `required` -> required/optional keys),
|
|
217
|
-
* (`
|
|
218
|
-
* `
|
|
272
|
+
* (`properties` + `required` -> required/optional keys), arrays (`items`),
|
|
273
|
+
* tuples (`prefixItems`), `anyOf`/`oneOf` (union), `allOf` (intersection),
|
|
274
|
+
* and `$ref` to local `#/$defs/...` or `#/definitions/...`. External or
|
|
275
|
+
* unresolvable `$ref` resolves to `unknown` rather than erroring.
|
|
219
276
|
*
|
|
220
277
|
* Pair with {@link defineSchema}:
|
|
221
278
|
* `const s = defineSchema({...}); type T = Infer<typeof s>;`
|
|
222
279
|
*/
|
|
223
|
-
export type Infer<S> = S
|
|
224
|
-
? C
|
|
225
|
-
: S extends { enum: infer E }
|
|
226
|
-
? E extends ReadonlyArray<infer U>
|
|
227
|
-
? U
|
|
228
|
-
: unknown
|
|
229
|
-
: S extends { type: infer T }
|
|
230
|
-
? T extends ReadonlyArray<infer N>
|
|
231
|
-
? InferByTypeName<N, S>
|
|
232
|
-
: InferByTypeName<T, S>
|
|
233
|
-
: unknown;
|
|
280
|
+
export type Infer<S> = InferWith<S, RootDefs<S>>;
|
|
234
281
|
|
|
235
282
|
export type ValidationResult<T = unknown> =
|
|
236
283
|
| { valid: true; data: T; errors: ValidationError[] }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ata-validator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "JSON Schema validation with first-class TypeScript and zero runtime cost. AOT compile to per-schema ESM modules with zero validator dependency. Generic Validator<T> for TypeBox/Zod/Valibot composition. Optional runtime API. Standard Schema V1 compatible.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.mjs",
|