@uniflowed/validator 0.0.0-alpha.10

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/json-schema.js ADDED
@@ -0,0 +1,307 @@
1
+ // @flow
2
+ //
3
+ // `@uniflowed/validator/json-schema`: a schema as a document somebody else can
4
+ // read.
5
+ //
6
+ // const { schema, unrepresentable } = toJsonSchema(Account);
7
+ // // { $schema: "…/2020-12/schema", type: "object", properties: { … } }
8
+ //
9
+ // The roadmap calls this "schema exports", and it is the reason `schema.js`
10
+ // makes every schema carry a [`Description`] beside its parse function. A
11
+ // closure cannot be read: a schema that was *only* the four lines that check a
12
+ // value can be run and can never be published, documented, handed to an
13
+ // OpenAPI generator, or turned into types for a consumer written in another
14
+ // language. The description is the readable half, and this module is the first
15
+ // consumer of it.
16
+ //
17
+ // # What "unrepresentable" means, and why it is a return value
18
+ //
19
+ // JSON Schema describes JSON. `map`, `set`, `bigint`, `date`, `instance` and
20
+ // `custom` describe values that JSON does not have, and `check` describes a
21
+ // predicate no declarative format can express. A converter has three options
22
+ // for those: throw, lie, or say so. Throwing makes one `Date` field fatal for a
23
+ // document that is otherwise fine. Lying — emitting `{}` and moving on — is
24
+ // what makes an exported schema quietly weaker than the one the application
25
+ // runs.
26
+ //
27
+ // So this says so. The node becomes `{}`, which accepts anything and is
28
+ // therefore *never wrong*, only imprecise, and the place it happened is
29
+ // reported in `unrepresentable` with the path to it. A caller that wants the
30
+ // strict behaviour asserts the list is empty; a caller documenting an API that
31
+ // happens to have one `Date` in it gets its document.
32
+ //
33
+ // # The exported document describes the input, not the output
34
+ //
35
+ // `pipe(string(), transform(Number))` exports as `{ "type": "string" }`. That
36
+ // is the whole point of a JSON Schema: it validates what arrives on the wire,
37
+ // and what arrives is the input. `InferOutput` is for the code on this side of
38
+ // the boundary; the document is for the code on the other side, which has
39
+ // never heard of the transform.
40
+ //
41
+ // The consequence is easy to get wrong, and this module got it wrong first: a
42
+ // step *after* a transform constrains the output, not the input.
43
+ // `pipe(string(), transform(Number), min(18))` must not export as `{ "type":
44
+ // "string", "minimum": 18 }`, which would ask a consumer to compare a string
45
+ // against a number. It exports as `{ "type": "string" }`, and `min after a
46
+ // transform` is reported as unrepresentable — because the schema does reject
47
+ // `"5"` and the document does not, and that is exactly what the list is for.
48
+ //
49
+ // `fallback` follows the same rule to its conclusion: a fallback accepts every
50
+ // value, so it exports as `{}`. Nothing is lost that JSON Schema could have
51
+ // held.
52
+ //
53
+ // # Recursion
54
+ //
55
+ // A `lazy` schema is a cycle, and the description of one is a thunk rather
56
+ // than a value for exactly that reason. Each `lazy` carries an identity, and
57
+ // the walk keeps a table from that identity to a name under `$defs`: the first
58
+ // visit converts the body, and every visit after it emits a `$ref`. A comment
59
+ // tree comes out as one definition and a reference to it, which is what JSON
60
+ // Schema is for.
61
+ //
62
+ // # What this is not, yet
63
+ //
64
+ // `uf prepare` lists a `GenerateValidatorTypes` step, and there is no code
65
+ // behind it — no crate reads a schema and writes a `.js.flow`. This module is
66
+ // the half that can exist without one: a description a generator would read,
67
+ // and a converter proving the description is complete enough to build
68
+ // something from. When that step is implemented it should consume
69
+ // [`describe`], not re-derive a shape from the source.
70
+
71
+ import type { Path } from "./issue.js";
72
+ import { put } from "./plain-object.js";
73
+ import type { Constraint, Description, Schema } from "./schema.js";
74
+ import { describe } from "./schema.js";
75
+
76
+ /** One node of a JSON Schema document. */
77
+ export type JsonSchemaNode = { readonly [string]: mixed, ... };
78
+
79
+ /** Somewhere the document is less precise than the schema it came from. */
80
+ export type Unrepresentable = {|
81
+ readonly path: Path,
82
+ readonly kind: string,
83
+ |};
84
+
85
+ /** A JSON Schema document, and everything JSON Schema could not say. */
86
+ export type JsonSchemaExport = {|
87
+ readonly schema: JsonSchemaNode,
88
+ readonly unrepresentable: $ReadOnlyArray<Unrepresentable>,
89
+ |};
90
+
91
+ const DIALECT = "https://json-schema.org/draft/2020-12/schema";
92
+
93
+ /** `left` with `right`'s keywords on top, written prototype-safely. */
94
+ function merge(left: JsonSchemaNode, right: JsonSchemaNode): JsonSchemaNode {
95
+ const out: { [string]: mixed, ... } = {};
96
+ for (const key of Object.keys(left)) {
97
+ put(out, key, left[key]);
98
+ }
99
+ for (const key of Object.keys(right)) {
100
+ put(out, key, right[key]);
101
+ }
102
+ return out;
103
+ }
104
+
105
+ /**
106
+ * Whether a field may be absent.
107
+ *
108
+ * `optional`, `nullish` and a default all mean the key can be missing, and any
109
+ * of them may be wrapped in the steps of a pipeline — `pipe(optional(string()),
110
+ * …)` is an `optional` under a `constrained` — so the wrappers are unwrapped
111
+ * before the question is asked. `nullable` is not here: `null` is a value, and
112
+ * a key holding it is present.
113
+ */
114
+ function mayBeAbsent(description: Description): boolean {
115
+ return match (description) {
116
+ {kind: "optional", inner: _} => true,
117
+ {kind: "nullish", inner: _} => true,
118
+ {kind: "default", inner: _} => true,
119
+ {kind: "fallback", inner: _} => true,
120
+ {kind: "constrained", inner: const inner, constraint: _} => mayBeAbsent(inner),
121
+ {kind: "transformed", inner: const inner} => mayBeAbsent(inner),
122
+ _ => false,
123
+ };
124
+ }
125
+
126
+ /**
127
+ * Whether a description is of a value some step already changed.
128
+ *
129
+ * Only the spine of pipeline wrappers is followed. A transform *inside* an
130
+ * object's field does not make the object transformed: the field's own node is
131
+ * where that is handled.
132
+ */
133
+ function describesTransformedValue(description: Description): boolean {
134
+ return match (description) {
135
+ {kind: "transformed", inner: _} => true,
136
+ {kind: "constrained", inner: const inner, constraint: _} => describesTransformedValue(inner),
137
+ _ => false,
138
+ };
139
+ }
140
+
141
+ /** What to call a constraint in the `unrepresentable` list. */
142
+ function labelFor(constraint: Constraint): string {
143
+ return constraint.kind === "opaque" ? `check ${constraint.label}` : constraint.kind;
144
+ }
145
+
146
+ /** The JSON Schema keywords one `pipe` step contributes, if any. */
147
+ function keywordsFor(constraint: Constraint): JsonSchemaNode {
148
+ return match (constraint) {
149
+ {kind: "minLength", value: const value} => { minLength: value },
150
+ {kind: "maxLength", value: const value} => { maxLength: value },
151
+ {kind: "length", value: const value} => { minLength: value, maxLength: value },
152
+ {kind: "minItems", value: const value} => { minItems: value },
153
+ {kind: "maxItems", value: const value} => { maxItems: value },
154
+ {kind: "min", value: const value} => { minimum: value },
155
+ {kind: "max", value: const value} => { maximum: value },
156
+ {kind: "integer"} => { type: "integer" },
157
+ {kind: "multipleOf", value: const value} => { multipleOf: value },
158
+ {kind: "pattern", source: const source} => { pattern: source },
159
+ {kind: "format", name: const name} => { format: name },
160
+ {kind: "brand", name: const name} => { title: name },
161
+ {kind: "opaque", label: _} => {},
162
+ };
163
+ }
164
+
165
+ /**
166
+ * Convert `schema` to a JSON Schema document.
167
+ *
168
+ * The walk keeps three pieces of state — the definitions a recursive schema
169
+ * needs, the names already given out, and the places JSON Schema could not
170
+ * say what the schema meant — which is why it is a closure over a converter
171
+ * rather than a free function.
172
+ */
173
+ export function toJsonSchema(schema: Schema<mixed, mixed>): JsonSchemaExport {
174
+ const definitions: { [string]: JsonSchemaNode, ... } = {};
175
+ const names = new Map<symbol, string>();
176
+ const unrepresentable: Array<Unrepresentable> = [];
177
+
178
+ function unsupported(kind: string, path: Path): JsonSchemaNode {
179
+ unrepresentable.push({ path: path.slice(), kind });
180
+ return {};
181
+ }
182
+
183
+ function object(
184
+ entries: $ReadOnlyArray<[string, Description]>,
185
+ unknownKeys: "strip" | "reject" | "keep",
186
+ path: Path,
187
+ ): JsonSchemaNode {
188
+ const properties: { [string]: JsonSchemaNode, ... } = {};
189
+ const required: Array<string> = [];
190
+ for (const [key, inner] of entries) {
191
+ put(properties, key, convert(inner, path.concat(key)));
192
+ if (!mayBeAbsent(inner)) {
193
+ required.push(key);
194
+ }
195
+ }
196
+ const base = { type: "object", properties, required };
197
+ return unknownKeys === "reject" ? merge(base, { additionalProperties: false }) : base;
198
+ }
199
+
200
+ function recursive(id: symbol, inner: () => Description, path: Path): JsonSchemaNode {
201
+ const already = names.get(id);
202
+ if (already != null) {
203
+ return { $ref: `#/$defs/${already}` };
204
+ }
205
+ const name = `definition${String(names.size)}`;
206
+ names.set(id, name);
207
+ put(definitions, name, convert(inner(), path));
208
+ return { $ref: `#/$defs/${name}` };
209
+ }
210
+
211
+ function convert(description: Description, path: Path): JsonSchemaNode {
212
+ return match (description) {
213
+ {kind: "unknown"} => {},
214
+ {kind: "never"} => { not: {} },
215
+ {kind: "string"} => { type: "string" },
216
+ {kind: "number"} => { type: "number" },
217
+ {kind: "boolean"} => { type: "boolean" },
218
+ {kind: "null"} => { type: "null" },
219
+ {kind: "bigint"} => unsupported("bigint", path),
220
+ {kind: "undefined"} => unsupported("undefined", path),
221
+ {kind: "date"} => unsupported("date", path),
222
+ {kind: "instance", name: const name} => unsupported(`instance ${name}`, path),
223
+ {kind: "custom", name: const name} => unsupported(`custom ${name}`, path),
224
+ {kind: "map", key: _, value: _} => unsupported("map", path),
225
+ {kind: "set", item: _} => unsupported("set", path),
226
+ {kind: "literal", value: const value} => { const: value },
227
+ {kind: "enum", values: const values} => { enum: values.slice() },
228
+ {kind: "array", item: const item} =>
229
+ {
230
+ type: "array",
231
+ items: convert(item, path.concat("*")),
232
+ },
233
+ {kind: "tuple", items: const items} =>
234
+ {
235
+ type: "array",
236
+ prefixItems: items.map((item, index) => convert(item, path.concat(String(index)))),
237
+ minItems: items.length,
238
+ maxItems: items.length,
239
+ },
240
+ {kind: "record", value: const value} =>
241
+ {
242
+ type: "object",
243
+ additionalProperties: convert(value, path.concat("*")),
244
+ },
245
+ {kind: "object", entries: const entries, unknownKeys: const unknownKeys} =>
246
+ object(entries, unknownKeys, path),
247
+ {kind: "union", options: const options} =>
248
+ {
249
+ anyOf: options.map((option) => convert(option, path)),
250
+ },
251
+ {kind: "variant", key: _, branches: const branches} =>
252
+ {
253
+ oneOf: branches.map(([, branch]) => convert(branch, path)),
254
+ },
255
+ {kind: "intersect", parts: const parts} =>
256
+ {
257
+ allOf: parts.map((part) => convert(part, path)),
258
+ },
259
+ {kind: "optional", inner: const inner} => convert(inner, path),
260
+ {kind: "default", inner: const inner} => convert(inner, path),
261
+ {kind: "nullable", inner: const inner} =>
262
+ {
263
+ anyOf: [convert(inner, path), { type: "null" }],
264
+ },
265
+ {kind: "nullish", inner: const inner} =>
266
+ {
267
+ anyOf: [convert(inner, path), { type: "null" }],
268
+ },
269
+ {kind: "fallback", inner: _} => {},
270
+ {kind: "transformed", inner: const inner} => convert(inner, path),
271
+ {kind: "lazy", id: const id, inner: const inner} => recursive(id, inner, path),
272
+ {kind: "constrained", inner: const inner, constraint: const constraint} =>
273
+ constrained(inner, constraint, path),
274
+ };
275
+ }
276
+
277
+ /**
278
+ * A pipeline step's keywords on top of what it refined.
279
+ *
280
+ * Two of them contribute nothing. A `check`'s predicate is a closure, and a
281
+ * step that sits above a `transform` is about the output rather than the
282
+ * input this document describes. Both leave the node alone and add a line
283
+ * saying the document is looser than the schema at that path.
284
+ */
285
+ function constrained(inner: Description, constraint: Constraint, path: Path): JsonSchemaNode {
286
+ const node = convert(inner, path);
287
+ if (describesTransformedValue(inner)) {
288
+ unrepresentable.push({
289
+ path: path.slice(),
290
+ kind: `${labelFor(constraint)} after a transform`,
291
+ });
292
+ return node;
293
+ }
294
+ if (constraint.kind === "opaque") {
295
+ unrepresentable.push({ path: path.slice(), kind: labelFor(constraint) });
296
+ return node;
297
+ }
298
+ return merge(node, keywordsFor(constraint));
299
+ }
300
+
301
+ const root = convert(describe(schema), []);
302
+ const document =
303
+ Object.keys(definitions).length === 0
304
+ ? merge({ $schema: DIALECT }, root)
305
+ : merge(merge({ $schema: DIALECT }, root), { $defs: definitions });
306
+ return { schema: document, unrepresentable };
307
+ }
package/lazy.js ADDED
@@ -0,0 +1,93 @@
1
+ // @flow
2
+ //
3
+ // `@uniflowed/validator/lazy`: a schema that does not exist yet.
4
+ //
5
+ // A comment has replies, and a reply is a comment. There is no order in which
6
+ // to write that down, because the initialiser of `Comment` would have to name
7
+ // `Comment`, and at that moment it is still `undefined`. So the schema is
8
+ // wrapped in a function, and the function is not called until the first parse:
9
+ //
10
+ // type Comment = {| text: string, replies: $ReadOnlyArray<Comment> |};
11
+ //
12
+ // const Comment: Schema<Comment> = lazy(() =>
13
+ // object({ text: string(), replies: array(Comment) }),
14
+ // );
15
+ //
16
+ // The annotation is the other half, and it is not optional. Flow will infer
17
+ // the type of almost every schema in this package, but it will not solve a
18
+ // type that mentions itself; the `Schema<Comment>` on the binding is where the
19
+ // cycle is cut, and `infer.js` says so among the other limits.
20
+ //
21
+ // # Why the result is memoised
22
+ //
23
+ // Without it, every node of the tree calls `build()` and gets a fresh object
24
+ // graph — a thousand-comment thread would construct a thousand schemas, none
25
+ // of which is reused, on a parse that should have allocated nothing. With it,
26
+ // recursion costs one closure for the whole schema.
27
+ //
28
+ // # Why there are two of these
29
+ //
30
+ // Everything else in the package works out whether it is asynchronous when it
31
+ // is built: `object` asks its fields, `array` asks its item. A lazy schema
32
+ // cannot ask, because the thing it would ask does not exist yet, and building
33
+ // it to find out is the infinite loop the laziness was there to avoid.
34
+ //
35
+ // So the answer is declared instead of discovered. [`lazy`] is synchronous and
36
+ // [`lazyAsync`] is not, and a recursive schema with a `checkAsync` anywhere
37
+ // inside it must use the second — otherwise the objects and arrays above it
38
+ // build their synchronous halves, and the first `await` that never happens
39
+ // surfaces as a thrown "use safeParseAsync" from the middle of a parse rather
40
+ // than as a type the caller could have seen.
41
+
42
+ import type { Description, Schema } from "./schema.js";
43
+ import { describe, makeAsyncSchema, makeSchema, run, runAsync } from "./schema.js";
44
+
45
+ /** Build once, then hand back the same schema for the life of the process. */
46
+ function memoise<TOutput, TInput>(
47
+ build: () => Schema<TOutput, TInput>,
48
+ ): () => Schema<TOutput, TInput> {
49
+ let built: null | Schema<TOutput, TInput> = null;
50
+ return () => {
51
+ const already = built;
52
+ if (already != null) {
53
+ return already;
54
+ }
55
+ const made = build();
56
+ built = made;
57
+ return made;
58
+ };
59
+ }
60
+
61
+ /**
62
+ * A synchronous schema built on first use.
63
+ *
64
+ * `id` is what a converter keys its definitions on: `json-schema.js` sees the
65
+ * same symbol every time it walks back around the cycle, which is how a
66
+ * recursive schema becomes a `$ref` rather than a stack overflow.
67
+ */
68
+ export function lazy<TOutput, TInput = mixed>(
69
+ build: () => Schema<TOutput, TInput>,
70
+ ): Schema<TOutput, TInput> {
71
+ const resolve = memoise(build);
72
+ const id = Symbol("lazy");
73
+ const description = (): Description => ({
74
+ kind: "lazy",
75
+ id,
76
+ inner: () => describe(resolve()),
77
+ });
78
+ return makeSchema((value, path) => run(resolve(), value, path), description);
79
+ }
80
+
81
+ /** A recursive schema with an asynchronous step somewhere inside it. */
82
+ export function lazyAsync<TOutput, TInput = mixed>(
83
+ build: () => Schema<TOutput, TInput>,
84
+ ): Schema<TOutput, TInput> {
85
+ const resolve = memoise(build);
86
+ const id = Symbol("lazyAsync");
87
+ const description = (): Description => ({
88
+ kind: "lazy",
89
+ id,
90
+ inner: () => describe(resolve()),
91
+ });
92
+ return makeAsyncSchema((value, path) => runAsync(resolve(), value, path), description);
93
+ }
package/namespace.js ADDED
@@ -0,0 +1,229 @@
1
+ // @flow
2
+ //
3
+ // `@uniflowed/validator/namespace`: every builder under one name.
4
+ //
5
+ // import { v } from "@uniflowed/validator";
6
+ // const Account = v.object({ email: v.pipe(v.string(), v.email()) });
7
+ //
8
+ // The named exports are the primary surface. This is the convenience alias,
9
+ // for the many schemas that mention a dozen builders and would otherwise open
10
+ // with a dozen-line import, and for readers coming from Valibot who already
11
+ // write `v.` in front of everything.
12
+ //
13
+ // # Why it is a module of its own
14
+ //
15
+ // Because it is the one module that has to import all of them, and a package
16
+ // whose entry point did that would make every application carry every check.
17
+ // Here it is reached through a single named re-export from `index.js`, which a
18
+ // bundler drops when nothing reads `v`; a project that imports
19
+ // `@uniflowed/validator/primitive` directly never resolves this file at all.
20
+ //
21
+ // # Why it is typed with `typeof`
22
+ //
23
+ // So the two surfaces cannot drift. Each field's type is the exported
24
+ // function's own, which means adding a builder and forgetting to list it here
25
+ // is a missing property rather than a silently different signature, and
26
+ // renaming one is an error at this file rather than a surprise at a call site.
27
+
28
+ import {
29
+ email,
30
+ endsWith,
31
+ includes,
32
+ integer,
33
+ isoDate,
34
+ length,
35
+ max,
36
+ maxItems,
37
+ maxLength,
38
+ min,
39
+ minItems,
40
+ minLength,
41
+ multipleOf,
42
+ nonEmpty,
43
+ regex,
44
+ startsWith,
45
+ toLowerCase,
46
+ toUpperCase,
47
+ trim,
48
+ url,
49
+ uuid,
50
+ } from "./action.js";
51
+ import { array, map, record, set, tuple } from "./collection.js";
52
+ import { flatten } from "./issue.js";
53
+ import { toJsonSchema } from "./json-schema.js";
54
+ import { lazy, lazyAsync } from "./lazy.js";
55
+ import { looseObject, object, partial, strictObject } from "./object.js";
56
+ import { fallback, nullable, nullish, optional, withDefault } from "./optional.js";
57
+ import {
58
+ is,
59
+ parse,
60
+ parseAsync,
61
+ parser,
62
+ safeParse,
63
+ safeParseAsync,
64
+ useValidation,
65
+ } from "./parse.js";
66
+ import { brand, check, checkAsync, pipe, refine, transform, transformAsync } from "./pipe.js";
67
+ import {
68
+ bigint,
69
+ boolean,
70
+ custom,
71
+ date,
72
+ enum_,
73
+ instance,
74
+ literal,
75
+ never,
76
+ null_,
77
+ number,
78
+ string,
79
+ undefined_,
80
+ unknown,
81
+ } from "./primitive.js";
82
+ import { describe, isAsync } from "./schema.js";
83
+ import { intersect, union, variant } from "./union.js";
84
+
85
+ export const v: {
86
+ readonly string: typeof string,
87
+ readonly number: typeof number,
88
+ readonly bigint: typeof bigint,
89
+ readonly boolean: typeof boolean,
90
+ readonly unknown: typeof unknown,
91
+ readonly never: typeof never,
92
+ readonly null: typeof null_,
93
+ readonly undefined: typeof undefined_,
94
+ readonly literal: typeof literal,
95
+ readonly enum: typeof enum_,
96
+ readonly date: typeof date,
97
+ readonly instance: typeof instance,
98
+ readonly custom: typeof custom,
99
+ readonly object: typeof object,
100
+ readonly strictObject: typeof strictObject,
101
+ readonly looseObject: typeof looseObject,
102
+ readonly partial: typeof partial,
103
+ readonly array: typeof array,
104
+ readonly tuple: typeof tuple,
105
+ readonly record: typeof record,
106
+ readonly map: typeof map,
107
+ readonly set: typeof set,
108
+ readonly union: typeof union,
109
+ readonly variant: typeof variant,
110
+ readonly intersect: typeof intersect,
111
+ readonly optional: typeof optional,
112
+ readonly nullable: typeof nullable,
113
+ readonly nullish: typeof nullish,
114
+ readonly withDefault: typeof withDefault,
115
+ readonly fallback: typeof fallback,
116
+ readonly lazy: typeof lazy,
117
+ readonly lazyAsync: typeof lazyAsync,
118
+ readonly pipe: typeof pipe,
119
+ readonly check: typeof check,
120
+ readonly checkAsync: typeof checkAsync,
121
+ readonly transform: typeof transform,
122
+ readonly transformAsync: typeof transformAsync,
123
+ readonly brand: typeof brand,
124
+ readonly refine: typeof refine,
125
+ readonly minLength: typeof minLength,
126
+ readonly maxLength: typeof maxLength,
127
+ readonly length: typeof length,
128
+ readonly nonEmpty: typeof nonEmpty,
129
+ readonly startsWith: typeof startsWith,
130
+ readonly endsWith: typeof endsWith,
131
+ readonly includes: typeof includes,
132
+ readonly regex: typeof regex,
133
+ readonly email: typeof email,
134
+ readonly url: typeof url,
135
+ readonly uuid: typeof uuid,
136
+ readonly isoDate: typeof isoDate,
137
+ readonly trim: typeof trim,
138
+ readonly toLowerCase: typeof toLowerCase,
139
+ readonly toUpperCase: typeof toUpperCase,
140
+ readonly min: typeof min,
141
+ readonly max: typeof max,
142
+ readonly integer: typeof integer,
143
+ readonly multipleOf: typeof multipleOf,
144
+ readonly minItems: typeof minItems,
145
+ readonly maxItems: typeof maxItems,
146
+ readonly parse: typeof parse,
147
+ readonly safeParse: typeof safeParse,
148
+ readonly parseAsync: typeof parseAsync,
149
+ readonly safeParseAsync: typeof safeParseAsync,
150
+ readonly is: typeof is,
151
+ readonly parser: typeof parser,
152
+ readonly useValidation: typeof useValidation,
153
+ readonly describe: typeof describe,
154
+ readonly isAsync: typeof isAsync,
155
+ readonly flatten: typeof flatten,
156
+ readonly toJsonSchema: typeof toJsonSchema,
157
+ } = {
158
+ string,
159
+ number,
160
+ bigint,
161
+ boolean,
162
+ unknown,
163
+ never,
164
+ null: null_,
165
+ undefined: undefined_,
166
+ literal,
167
+ enum: enum_,
168
+ date,
169
+ instance,
170
+ custom,
171
+ object,
172
+ strictObject,
173
+ looseObject,
174
+ partial,
175
+ array,
176
+ tuple,
177
+ record,
178
+ map,
179
+ set,
180
+ union,
181
+ variant,
182
+ intersect,
183
+ optional,
184
+ nullable,
185
+ nullish,
186
+ withDefault,
187
+ fallback,
188
+ lazy,
189
+ lazyAsync,
190
+ pipe,
191
+ check,
192
+ checkAsync,
193
+ transform,
194
+ transformAsync,
195
+ brand,
196
+ refine,
197
+ minLength,
198
+ maxLength,
199
+ length,
200
+ nonEmpty,
201
+ startsWith,
202
+ endsWith,
203
+ includes,
204
+ regex,
205
+ email,
206
+ url,
207
+ uuid,
208
+ isoDate,
209
+ trim,
210
+ toLowerCase,
211
+ toUpperCase,
212
+ min,
213
+ max,
214
+ integer,
215
+ multipleOf,
216
+ minItems,
217
+ maxItems,
218
+ parse,
219
+ safeParse,
220
+ parseAsync,
221
+ safeParseAsync,
222
+ is,
223
+ parser,
224
+ useValidation,
225
+ describe,
226
+ isAsync,
227
+ flatten,
228
+ toJsonSchema,
229
+ };