ata-validator 0.17.5 → 0.18.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/CHANGELOG.md +6 -0
- package/README.md +30 -0
- package/index.d.ts +74 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
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.0 - 2026-05-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `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.
|
|
10
|
+
|
|
5
11
|
## 0.17.5 - 2026-05-25
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/README.md
CHANGED
|
@@ -180,6 +180,36 @@ const v = new Validator(userSchema)
|
|
|
180
180
|
|
|
181
181
|
The exported `JSONSchema` type is also available directly if you want to annotate a schema yourself. Custom and vendor keywords are allowed, so exotic schemas still type-check. Requires TypeScript >= 5.0.
|
|
182
182
|
|
|
183
|
+
#### Extracting the type: `Infer`
|
|
184
|
+
|
|
185
|
+
Because `defineSchema` leaves the schema as a plain object, you can pull a TypeScript type straight out of it with `Infer`, with no second type declaration to keep in sync.
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import { defineSchema, type Infer } from 'ata-validator'
|
|
189
|
+
|
|
190
|
+
const event = defineSchema({
|
|
191
|
+
$defs: {
|
|
192
|
+
Point: { type: 'object', properties: { x: { type: 'number' }, y: { type: 'number' } }, required: ['x', 'y'] },
|
|
193
|
+
},
|
|
194
|
+
type: 'object',
|
|
195
|
+
properties: {
|
|
196
|
+
kind: { enum: ['click', 'scroll'] },
|
|
197
|
+
at: { $ref: '#/$defs/Point' },
|
|
198
|
+
path: { type: 'array', prefixItems: [{ type: 'string' }, { type: 'integer' }] },
|
|
199
|
+
},
|
|
200
|
+
required: ['kind', 'at'],
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
type Event = Infer<typeof event>
|
|
204
|
+
// {
|
|
205
|
+
// kind: 'click' | 'scroll'
|
|
206
|
+
// at: { x: number; y: number }
|
|
207
|
+
// path?: [string, number]
|
|
208
|
+
// }
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
`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. `new Validator(schema)` carries the same type, so a successful `validate` narrows `result.data` without a manual annotation. An external or unresolvable `$ref` resolves to `unknown` rather than erroring.
|
|
212
|
+
|
|
183
213
|
### Cross-Schema `$ref`
|
|
184
214
|
|
|
185
215
|
```javascript
|
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.0",
|
|
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",
|