@nifrajs/schema 0.1.0-alpha.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 +50 -0
- package/dist/adapter.d.ts +33 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +66 -0
- package/dist/adapter.js.map +1 -0
- package/dist/formats.d.ts +3 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/formats.js +32 -0
- package/dist/formats.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/openapi.d.ts +92 -0
- package/dist/openapi.d.ts.map +1 -0
- package/dist/openapi.js +207 -0
- package/dist/openapi.js.map +1 -0
- package/dist/t.d.ts +34 -0
- package/dist/t.d.ts.map +1 -0
- package/dist/t.js +49 -0
- package/dist/t.js.map +1 -0
- package/package.json +69 -0
- package/src/adapter.ts +78 -0
- package/src/formats.ts +33 -0
- package/src/index.ts +14 -0
- package/src/openapi.ts +358 -0
- package/src/t.ts +70 -0
package/src/t.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ArrayOptions,
|
|
3
|
+
type IntegerOptions,
|
|
4
|
+
type NumberOptions,
|
|
5
|
+
type ObjectOptions,
|
|
6
|
+
type StringOptions,
|
|
7
|
+
type TLiteralValue,
|
|
8
|
+
type TSchema,
|
|
9
|
+
type TUnion,
|
|
10
|
+
Type,
|
|
11
|
+
} from "@sinclair/typebox"
|
|
12
|
+
import { fromTypeBox, type NifraSchema } from "./adapter.ts"
|
|
13
|
+
|
|
14
|
+
type Props = Record<string, NifraSchema>
|
|
15
|
+
|
|
16
|
+
/** Pull each property's raw TypeBox schema out of its `NifraSchema` wrapper. */
|
|
17
|
+
function unwrap<P extends Props>(props: P): { [K in keyof P]: P[K]["jsonSchema"] } {
|
|
18
|
+
const out: Record<string, TSchema> = {}
|
|
19
|
+
// Object.entries → own enumerable string keys only (no prototype walk).
|
|
20
|
+
for (const [key, schema] of Object.entries(props)) out[key] = schema.jsonSchema
|
|
21
|
+
return out as { [K in keyof P]: P[K]["jsonSchema"] }
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The built-in schema builder. Each constructor returns a `NifraSchema` — a
|
|
26
|
+
* Standard Schema whose validated output type flows into `c.body`/`c.query`, and
|
|
27
|
+
* whose `jsonSchema` powers `toOpenAPI`. Options (min/max, length, pattern, …)
|
|
28
|
+
* pass straight through to TypeBox and so become JSON Schema constraints.
|
|
29
|
+
*
|
|
30
|
+
* Composite constructors are generic over the *inner* TypeBox schema `T extends
|
|
31
|
+
* TSchema` (not over `NifraSchema`): reading `.jsonSchema` off a value typed only as
|
|
32
|
+
* `NifraSchema` would erase to the `TSchema` constraint and collapse the output type
|
|
33
|
+
* to `unknown`. Capturing `T` keeps `Static<T>` precise (`string[]`, not
|
|
34
|
+
* `unknown[]`).
|
|
35
|
+
*/
|
|
36
|
+
export const t = {
|
|
37
|
+
string: (options?: StringOptions) => fromTypeBox(Type.String(options)),
|
|
38
|
+
number: (options?: NumberOptions) => fromTypeBox(Type.Number(options)),
|
|
39
|
+
integer: (options?: IntegerOptions) => fromTypeBox(Type.Integer(options)),
|
|
40
|
+
boolean: () => fromTypeBox(Type.Boolean()),
|
|
41
|
+
null: () => fromTypeBox(Type.Null()),
|
|
42
|
+
literal: <const L extends TLiteralValue>(value: L) => fromTypeBox(Type.Literal(value)),
|
|
43
|
+
|
|
44
|
+
// `t.object` REJECTS unknown fields by default (`additionalProperties: false`) — the trust-boundary
|
|
45
|
+
// rule. A body with extra keys fails validation (a 400), so `c.body` never carries attacker-supplied
|
|
46
|
+
// properties (no mass-assignment). Use `t.looseObject` (or pass `{ additionalProperties: true }`) to
|
|
47
|
+
// opt into an open object; an explicit `options.additionalProperties` always wins over the default.
|
|
48
|
+
object: <P extends Props>(props: P, options?: ObjectOptions) =>
|
|
49
|
+
fromTypeBox(Type.Object(unwrap(props), { additionalProperties: false, ...options })),
|
|
50
|
+
/** Like `t.object` but ACCEPTS (and passes through) unknown fields — the explicit opt-out of the
|
|
51
|
+
* strict default. Prefer `t.object` unless you genuinely need an open object. */
|
|
52
|
+
looseObject: <P extends Props>(props: P, options?: ObjectOptions) =>
|
|
53
|
+
fromTypeBox(Type.Object(unwrap(props), { additionalProperties: true, ...options })),
|
|
54
|
+
array: <T extends TSchema>(item: NifraSchema<T>, options?: ArrayOptions) =>
|
|
55
|
+
fromTypeBox(Type.Array(item.jsonSchema, options)),
|
|
56
|
+
/** Marks a property optional inside `t.object`; standalone it is `T | undefined`. */
|
|
57
|
+
optional: <T extends TSchema>(schema: NifraSchema<T>) =>
|
|
58
|
+
fromTypeBox(Type.Optional(schema.jsonSchema)),
|
|
59
|
+
// `const S` captures the argument as a tuple; the explicit return type then maps
|
|
60
|
+
// over that captured tuple (`S[K]["jsonSchema"]`) so the union's `Static` is
|
|
61
|
+
// `A | B`, not `unknown` — the value-level `.map` can't preserve per-element
|
|
62
|
+
// types, so the output type is derived from `S` and the result cast to match
|
|
63
|
+
// (order/length are preserved by `map`, so the tuple shape is sound).
|
|
64
|
+
union: <const S extends readonly NifraSchema[]>(schemas: S) =>
|
|
65
|
+
fromTypeBox(
|
|
66
|
+
Type.Union((schemas as readonly NifraSchema[]).map((schema) => schema.jsonSchema)),
|
|
67
|
+
) as NifraSchema<TUnion<{ -readonly [K in keyof S]: S[K]["jsonSchema"] }>>,
|
|
68
|
+
record: <T extends TSchema>(value: NifraSchema<T>, options?: ObjectOptions) =>
|
|
69
|
+
fromTypeBox(Type.Record(Type.String(), value.jsonSchema, options)),
|
|
70
|
+
} as const
|