@c9up/rune 0.1.6 → 0.1.8
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/dist/MessagesProvider.d.ts +45 -0
- package/dist/MessagesProvider.d.ts.map +1 -0
- package/dist/MessagesProvider.js +77 -0
- package/dist/MessagesProvider.js.map +1 -0
- package/dist/Schema.d.ts +912 -38
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +2841 -219
- package/dist/Schema.js.map +1 -1
- package/dist/date.d.ts +36 -0
- package/dist/date.d.ts.map +1 -0
- package/dist/date.js +275 -0
- package/dist/date.js.map +1 -0
- package/dist/errors.d.ts +42 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +37 -0
- package/dist/errors.js.map +1 -1
- package/dist/formats.d.ts +149 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/formats.js +612 -0
- package/dist/formats.js.map +1 -0
- package/dist/index.d.ts +152 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +181 -2
- package/dist/index.js.map +1 -1
- package/dist/magic.d.ts +30 -0
- package/dist/magic.d.ts.map +1 -0
- package/dist/magic.js +154 -0
- package/dist/magic.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +11 -1
- package/src/MessagesProvider.ts +115 -0
- package/src/Schema.ts +3970 -215
- package/src/date.ts +320 -0
- package/src/errors.ts +59 -0
- package/src/formats.ts +721 -0
- package/src/index.ts +266 -1
- package/src/magic.ts +181 -0
- package/src/types.ts +55 -0
package/dist/Schema.d.ts
CHANGED
|
@@ -3,12 +3,20 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @implements FR38, FR39, FR40, FR41
|
|
5
5
|
*/
|
|
6
|
+
import { type CompareUnit, type DateFormat } from "./date.js";
|
|
7
|
+
import { RuneValidationError } from "./errors.js";
|
|
8
|
+
import { type AlphaOptions, type EmailOptions, type NormalizeEmailOptions, type NormalizeUrlOptions, type UrlOptions, type VatOptions } from "./formats.js";
|
|
9
|
+
import type { MessagesProviderContract } from "./MessagesProvider.js";
|
|
6
10
|
export type ValidationMessageParams = Record<string, string | number | boolean>;
|
|
7
11
|
export type ValidationTranslator = (key: string, params?: ValidationMessageParams) => string | undefined;
|
|
8
12
|
export interface ValidationError {
|
|
9
13
|
field: string;
|
|
10
14
|
rule: string;
|
|
11
15
|
message: string;
|
|
16
|
+
/** Array index when the field is an array item (VineJS parity). */
|
|
17
|
+
index?: number;
|
|
18
|
+
/** Rule metadata carried for reporters/i18n (e.g. `{ min: 3 }`). */
|
|
19
|
+
meta?: Record<string, unknown>;
|
|
12
20
|
}
|
|
13
21
|
/**
|
|
14
22
|
* Field context handed to `.use()` rules — mirrors VineJS's field context. It
|
|
@@ -29,8 +37,26 @@ export interface FieldContext {
|
|
|
29
37
|
meta: Record<string, unknown>;
|
|
30
38
|
/** `true` while no error has been reported for this field yet. */
|
|
31
39
|
isValid: boolean;
|
|
32
|
-
/**
|
|
33
|
-
|
|
40
|
+
/** Last path segment — `city` for `address.city` (VineJS `name`). */
|
|
41
|
+
name: string;
|
|
42
|
+
/** Dotted path with numeric segments replaced by `*` (`tags.*.name`). */
|
|
43
|
+
wildCardPath: string;
|
|
44
|
+
/** `true` when this value sits inside an array. */
|
|
45
|
+
isArrayMember: boolean;
|
|
46
|
+
/** `true` when the value is neither `undefined` nor `null`. */
|
|
47
|
+
isDefined: boolean;
|
|
48
|
+
/** `true` when the value passed its type rule. */
|
|
49
|
+
isValidDataType: boolean;
|
|
50
|
+
/** The full dotted path — same value as {@link field}, VineJS spelling. */
|
|
51
|
+
getFieldPath(): string;
|
|
52
|
+
/** Replace the value under validation (VineJS `mutate`). */
|
|
53
|
+
mutate(newValue: unknown): void;
|
|
54
|
+
/**
|
|
55
|
+
* Report a validation failure. `field` and `args` are optional (VineJS
|
|
56
|
+
* passes four arguments); omitting them reports against this field with no
|
|
57
|
+
* interpolation data.
|
|
58
|
+
*/
|
|
59
|
+
report(message: string, rule: string, field?: string | FieldContext, args?: Record<string, unknown>): void;
|
|
34
60
|
}
|
|
35
61
|
/**
|
|
36
62
|
* A `.use()` rule validator — VineJS shape `(value, options, field)`. Report
|
|
@@ -40,6 +66,13 @@ export type RuleValidator<Options = undefined> = (value: unknown, options: Optio
|
|
|
40
66
|
/** A compiled `.use()` rule produced by {@link createRule}. */
|
|
41
67
|
export interface CompiledRule {
|
|
42
68
|
readonly __rune: "rule";
|
|
69
|
+
/** Run even on `undefined`/`null` (VineJS implicit rules). */
|
|
70
|
+
readonly implicit?: boolean;
|
|
71
|
+
readonly name?: string;
|
|
72
|
+
/** Modifier applied to this field's JSON Schema node. */
|
|
73
|
+
readonly toJSONSchema?: JsonSchemaModifier;
|
|
74
|
+
/** The options the rule was built with, handed to {@link toJSONSchema}. */
|
|
75
|
+
readonly ruleOptions?: unknown;
|
|
43
76
|
run(value: unknown, field: FieldContext): void;
|
|
44
77
|
}
|
|
45
78
|
/**
|
|
@@ -57,8 +90,61 @@ export interface CompiledRule {
|
|
|
57
90
|
* passwordConfirmation: rules.string().use(sameAs('password')),
|
|
58
91
|
* })
|
|
59
92
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Options accepted by {@link createRule} / {@link createAsyncRule} — VineJS
|
|
95
|
+
* `vine.createRule(fn, { implicit, isAsync })`.
|
|
96
|
+
*/
|
|
97
|
+
export interface CreateRuleOptions {
|
|
98
|
+
/**
|
|
99
|
+
* Run the rule even when the value is `undefined` or `null`. Non-implicit
|
|
100
|
+
* rules are skipped on an absent value, which is why a `required`-style
|
|
101
|
+
* custom rule could not be written before.
|
|
102
|
+
*/
|
|
103
|
+
implicit?: boolean;
|
|
104
|
+
/** Rule name reported in errors when the validator does not pass one. */
|
|
105
|
+
name?: string;
|
|
106
|
+
/**
|
|
107
|
+
* VineJS `toJSONSchema?: JsonSchemaModifier` — a FUNCTION receiving the node
|
|
108
|
+
* built so far (plus the rule's options) and returning the modified node.
|
|
109
|
+
* A static fragment could only ever add keys; a modifier can also narrow or
|
|
110
|
+
* replace what the base rules produced.
|
|
111
|
+
*/
|
|
112
|
+
toJSONSchema?: JsonSchemaModifier;
|
|
113
|
+
/**
|
|
114
|
+
* Declare the rule asynchronous (VineJS `{ isAsync: true }`).
|
|
115
|
+
* {@link createAsyncRule} sets it; passing it to {@link createRule} routes
|
|
116
|
+
* the rule to the async builder instead of silently producing a sync rule
|
|
117
|
+
* whose Promise nobody awaits.
|
|
118
|
+
*/
|
|
119
|
+
isAsync?: boolean;
|
|
120
|
+
}
|
|
121
|
+
export declare function createRule(validator: RuleValidator<undefined>, options?: CreateRuleOptions): () => CompiledRule;
|
|
122
|
+
export declare function createRule<Options>(validator: RuleValidator<Options>, options?: CreateRuleOptions): (options: Options) => CompiledRule;
|
|
123
|
+
/**
|
|
124
|
+
* An async `.useAsync()` rule validator — same shape as {@link RuleValidator}
|
|
125
|
+
* but may return a Promise. Runs only under {@link ValidationSchema.validateResultAsync}.
|
|
126
|
+
*/
|
|
127
|
+
export type AsyncRuleValidator<Options = undefined> = (value: unknown, options: Options, field: FieldContext) => void | Promise<void>;
|
|
128
|
+
/** A compiled async rule produced by {@link createAsyncRule}. */
|
|
129
|
+
export interface AsyncCompiledRule {
|
|
130
|
+
readonly __rune: "asyncRule";
|
|
131
|
+
/** Run even on `undefined`/`null` (VineJS implicit rules). */
|
|
132
|
+
readonly implicit?: boolean;
|
|
133
|
+
readonly name?: string;
|
|
134
|
+
/** Modifier applied to this field's JSON Schema node. */
|
|
135
|
+
readonly toJSONSchema?: JsonSchemaModifier;
|
|
136
|
+
/** The options the rule was built with, handed to {@link toJSONSchema}. */
|
|
137
|
+
readonly ruleOptions?: unknown;
|
|
138
|
+
run(value: unknown, field: FieldContext): Promise<void>;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Async counterpart of {@link createRule} — for rules that must await (DB lookups
|
|
142
|
+
* etc.). Attach with `chain.useAsync(rule(options))`; the schema must then be run
|
|
143
|
+
* with `validateResultAsync`. This is how DB-backed `unique`/`exists` rules are built
|
|
144
|
+
* (the validator does the query), keeping rune framework-agnostic.
|
|
145
|
+
*/
|
|
146
|
+
export declare function createAsyncRule(validator: AsyncRuleValidator<undefined>, options?: CreateRuleOptions): () => AsyncCompiledRule;
|
|
147
|
+
export declare function createAsyncRule<Options>(validator: AsyncRuleValidator<Options>, options?: CreateRuleOptions): (options: Options) => AsyncCompiledRule;
|
|
62
148
|
/**
|
|
63
149
|
* Validation result — discriminated union that narrows `data` to the schema's
|
|
64
150
|
* `T` when `valid` is `true`, removing the need for callers to cast or guard
|
|
@@ -77,34 +163,323 @@ export type ValidationResult<T = Record<string, unknown>> = {
|
|
|
77
163
|
export interface ValidateOptions {
|
|
78
164
|
/** Runtime metadata exposed to `.use()` rules via `field.meta` (VineJS parity). */
|
|
79
165
|
meta?: Record<string, unknown>;
|
|
166
|
+
/**
|
|
167
|
+
* VineJS-style messages provider. When supplied, default rule messages are
|
|
168
|
+
* resolved through it (custom `.message()` overrides still win, and the
|
|
169
|
+
* provider takes precedence over a globally bound translator).
|
|
170
|
+
*/
|
|
171
|
+
messagesProvider?: MessagesProviderContract;
|
|
172
|
+
/**
|
|
173
|
+
* VineJS `errorReporter: () => ErrorReporterContract` — a FACTORY returning a
|
|
174
|
+
* reporter, so a transcribed Adonis reporter works as-is. A plain
|
|
175
|
+
* `(error) => void` observer is also accepted.
|
|
176
|
+
*
|
|
177
|
+
* The two are told apart by ARITY (a factory takes no argument), never by
|
|
178
|
+
* calling one speculatively to see what comes back.
|
|
179
|
+
*
|
|
180
|
+
* Either way the reporter OBSERVES: the validation result is never changed by
|
|
181
|
+
* it, so a reporter cannot mask a failure.
|
|
182
|
+
*/
|
|
183
|
+
errorReporter?: ErrorReporterFactory | ((error: ValidationError) => void);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* VineJS `JsonSchemaModifier`: receives the JSON Schema node assembled from the
|
|
187
|
+
* declarative rules and returns the node to use instead.
|
|
188
|
+
*/
|
|
189
|
+
export type JsonSchemaModifier = (node: Record<string, unknown>, options?: unknown) => Record<string, unknown>;
|
|
190
|
+
/** VineJS `ErrorReporterContract`. */
|
|
191
|
+
export interface ErrorReporterContract {
|
|
192
|
+
/** `true` once at least one error has been reported. */
|
|
193
|
+
hasErrors: boolean;
|
|
194
|
+
/** Build the exception a caller may throw. */
|
|
195
|
+
createError(): Error;
|
|
196
|
+
/** Report one failure. */
|
|
197
|
+
report(message: string, rule: string, field: FieldContext | string, args?: Record<string, unknown>): unknown;
|
|
80
198
|
}
|
|
199
|
+
/** A zero-argument factory producing a fresh {@link ErrorReporterContract}. */
|
|
200
|
+
export type ErrorReporterFactory = () => ErrorReporterContract;
|
|
81
201
|
export interface ValidationSchema<T = Record<string, unknown>> {
|
|
82
202
|
fields: Record<string, RuleChain>;
|
|
83
|
-
|
|
203
|
+
/**
|
|
204
|
+
* The object schema the validator was built from — always a chain, so
|
|
205
|
+
* `validator.schema.partial()` / `.pick()` / `.omit()` work as in VineJS
|
|
206
|
+
* whichever form `create()` received. The raw field map stays on
|
|
207
|
+
* {@link fields}.
|
|
208
|
+
*/
|
|
209
|
+
schema: RuleChain;
|
|
210
|
+
/**
|
|
211
|
+
* Standard Schema v1 contract, so a consumer can validate through the
|
|
212
|
+
* vendor-neutral protocol instead of rune's own API.
|
|
213
|
+
*/
|
|
214
|
+
"~standard": {
|
|
215
|
+
version: 1;
|
|
216
|
+
vendor: string;
|
|
217
|
+
/** Standard JSON Schema v1 props (VineJS 4.3+). */
|
|
218
|
+
jsonSchema: {
|
|
219
|
+
input(): Record<string, unknown>;
|
|
220
|
+
output(): Record<string, unknown>;
|
|
221
|
+
};
|
|
222
|
+
validate(value: unknown): Promise<{
|
|
223
|
+
value: T;
|
|
224
|
+
} | {
|
|
225
|
+
issues: ReadonlyArray<{
|
|
226
|
+
message: string;
|
|
227
|
+
path: string[];
|
|
228
|
+
}>;
|
|
229
|
+
}>;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Error reporter for this validator (VineJS `validator.errorReporter`). A
|
|
233
|
+
* per-call option still wins; this wins over the process-wide one.
|
|
234
|
+
*/
|
|
235
|
+
errorReporter: ErrorReporterFactory | ((error: ValidationError) => void) | null;
|
|
236
|
+
/** Introspection of the compiled schema — VineJS `{ schema, refs }` shape. */
|
|
237
|
+
toJSON(): {
|
|
238
|
+
schema: SchemaIntrospection;
|
|
239
|
+
refs: string[];
|
|
240
|
+
};
|
|
241
|
+
/** JSON Schema for the compiled validator (VineJS `toJSONSchema`). */
|
|
242
|
+
toJSONSchema(): Record<string, unknown>;
|
|
243
|
+
/**
|
|
244
|
+
* Validate and return the payload, throwing {@link RuneValidationError} on
|
|
245
|
+
* failure — the VineJS/Adonis contract (`validator.validate(data)`), async
|
|
246
|
+
* so a schema carrying `unique`/`exists` behaves like any other.
|
|
247
|
+
*
|
|
248
|
+
* The never-throwing, synchronous form rune also offers is
|
|
249
|
+
* {@link validateResult}.
|
|
250
|
+
*/
|
|
251
|
+
validate(data: unknown, options?: ValidateOptions): Promise<T>;
|
|
252
|
+
/** Result-based validation (rune superset) — synchronous, never throws. */
|
|
253
|
+
validateResult(data: unknown, options?: ValidateOptions): ValidationResult<T>;
|
|
254
|
+
/** Result-based validation awaiting async rules — never throws. */
|
|
255
|
+
validateResultAsync(data: unknown, options?: ValidateOptions): Promise<ValidationResult<T>>;
|
|
256
|
+
/**
|
|
257
|
+
* Throwing validation (VineJS/Adonis parity). Returns the validated data on
|
|
258
|
+
* success; throws {@link RuneValidationError} (`E_VALIDATION_ERROR`, HTTP 422)
|
|
259
|
+
* with a structured `.messages` array on failure.
|
|
260
|
+
*/
|
|
261
|
+
validateOrThrow(data: unknown, options?: ValidateOptions): T;
|
|
262
|
+
/**
|
|
263
|
+
* Non-throwing validation returning `[error, null] | [null, data]`
|
|
264
|
+
* (VineJS `tryValidate`).
|
|
265
|
+
*/
|
|
266
|
+
tryValidate(data: unknown, options?: ValidateOptions): Promise<[RuneValidationError, null] | [null, T]>;
|
|
267
|
+
/** Synchronous counterpart of {@link tryValidate} (rune superset). */
|
|
268
|
+
tryValidateSync(data: unknown, options?: ValidateOptions): [RuneValidationError, null] | [null, T];
|
|
269
|
+
/** Throwing async validation (see {@link validateResultAsync} + {@link validateOrThrow}). */
|
|
270
|
+
validateOrThrowAsync(data: unknown, options?: ValidateOptions): Promise<T>;
|
|
84
271
|
}
|
|
85
272
|
/** Context threaded through validation so field rules can reach root/parent/meta. */
|
|
86
273
|
interface RunContext {
|
|
87
274
|
data: Record<string, unknown>;
|
|
88
275
|
parent: Record<string, unknown> | unknown[];
|
|
89
276
|
meta: Record<string, unknown>;
|
|
277
|
+
messagesProvider?: MessagesProviderContract;
|
|
278
|
+
errorReporter?: (error: ValidationError) => void;
|
|
90
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* An async rule run deferred by the (synchronous) traversal and awaited by
|
|
282
|
+
* `validateResultAsync`. Collected at EVERY depth — top-level fields, nested object
|
|
283
|
+
* fields and array items alike.
|
|
284
|
+
*/
|
|
285
|
+
interface PendingAsync {
|
|
286
|
+
chain: RuleChain;
|
|
287
|
+
field: string;
|
|
288
|
+
value: unknown;
|
|
289
|
+
ctx: RunContext;
|
|
290
|
+
}
|
|
291
|
+
/** Bind (or clear) the process-wide error reporter. */
|
|
292
|
+
export declare function setGlobalErrorReporter(reporter: ErrorReporterFactory | ((error: ValidationError) => void) | null): void;
|
|
293
|
+
/** Read the process-wide error reporter. */
|
|
294
|
+
export declare function getGlobalErrorReporter(): ErrorReporterFactory | ((error: ValidationError) => void) | null;
|
|
295
|
+
/** Host lookup seam backing `activeUrl()` — see that rule's note on why. */
|
|
296
|
+
export interface HostResolver {
|
|
297
|
+
/** Resolve `true` when the hostname resolves (DNS, or whatever you decide). */
|
|
298
|
+
resolves(hostname: string): Promise<boolean>;
|
|
299
|
+
}
|
|
300
|
+
/** Toggle the global `"" -> null` conversion (VineJS `convertEmptyStringsToNull`). */
|
|
301
|
+
export declare function setConvertEmptyStringsToNull(enabled: boolean): void;
|
|
302
|
+
/** Read the global `"" -> null` conversion flag. */
|
|
303
|
+
export declare function getConvertEmptyStringsToNull(): boolean;
|
|
304
|
+
/** Bind (or clear, with `null`) the resolver backing `activeUrl()`. */
|
|
305
|
+
export declare function bindHostResolver(resolver: HostResolver | null): void;
|
|
306
|
+
/** Bind (or clear) the process-wide messages provider. */
|
|
307
|
+
export declare function setGlobalMessagesProvider(provider: MessagesProviderContract | null): void;
|
|
308
|
+
/** Read the process-wide messages provider. */
|
|
309
|
+
export declare function getGlobalMessagesProvider(): MessagesProviderContract | null;
|
|
310
|
+
/** Bind (or clear, with `null`) the global `rules.date()` output mapper. */
|
|
311
|
+
export declare function setDateTransform(fn: ((value: Date) => unknown) | null): void;
|
|
312
|
+
/**
|
|
313
|
+
* A database lookup seam for the Lucid-style `unique` / `exists` rules.
|
|
314
|
+
*
|
|
315
|
+
* rune stays framework-agnostic, so it never imports a driver: the host binds
|
|
316
|
+
* one resolver at boot (as `bindRosetta` does for translations) and the rules
|
|
317
|
+
* then take Lucid's `{ table, column, where }` options instead of a hand-written
|
|
318
|
+
* callback. The callback form is kept — it is what the resolver is built from.
|
|
319
|
+
*/
|
|
320
|
+
export interface DatabaseResolver {
|
|
321
|
+
/** Resolve `true` when at least one row matches. */
|
|
322
|
+
exists(query: DatabaseLookup): Promise<boolean>;
|
|
323
|
+
}
|
|
324
|
+
/** The lookup handed to a {@link DatabaseResolver} (Lucid `unique`/`exists`). */
|
|
325
|
+
export interface DatabaseLookup {
|
|
326
|
+
table: string;
|
|
327
|
+
column: string;
|
|
328
|
+
value: unknown;
|
|
329
|
+
/** Extra equality filters, e.g. `{ tenant_id: 3 }` (Lucid `where`). */
|
|
330
|
+
where?: Record<string, unknown>;
|
|
331
|
+
/** Rows to ignore, e.g. `{ id: 7 }` when updating (Lucid `whereNot`). */
|
|
332
|
+
whereNot?: Record<string, unknown>;
|
|
333
|
+
}
|
|
334
|
+
/** Bind (or clear, with `null`) the resolver backing `unique()` / `exists()`. */
|
|
335
|
+
export declare function bindDatabase(resolver: DatabaseResolver | null): void;
|
|
336
|
+
/** Options form of `unique()` / `exists()` — Lucid's shape. */
|
|
337
|
+
export interface DatabaseRuleOptions {
|
|
338
|
+
table: string;
|
|
339
|
+
column?: string;
|
|
340
|
+
where?: Record<string, unknown>;
|
|
341
|
+
whereNot?: Record<string, unknown>;
|
|
342
|
+
}
|
|
343
|
+
/** Options accepted by every date comparison (VineJS `{ compare, format }`). */
|
|
344
|
+
export interface DateCompareOptions {
|
|
345
|
+
/** Granularity of the comparison. Defaults to `"day"`, like VineJS. */
|
|
346
|
+
compare?: CompareUnit;
|
|
347
|
+
/** Format used to parse the operand / sibling, when it is a string. */
|
|
348
|
+
format?: string;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* The structural shape `file()` accepts. An Adonis bodyparser `MultipartFile`
|
|
352
|
+
* satisfies it without rune having to know the type.
|
|
353
|
+
*/
|
|
354
|
+
export interface FileLike {
|
|
355
|
+
size: number;
|
|
356
|
+
/**
|
|
357
|
+
* MIME type as REPORTED by the upload. Trust it only with
|
|
358
|
+
* `verifyContent()`, which checks it against the real bytes.
|
|
359
|
+
*/
|
|
360
|
+
type?: string;
|
|
361
|
+
/** Adonis bodyparser's temp path — a byte source for `verifyContent()`. */
|
|
362
|
+
tmpPath?: string;
|
|
363
|
+
/** Alternative byte-source paths. */
|
|
364
|
+
filePath?: string;
|
|
365
|
+
path?: string;
|
|
366
|
+
/** In-memory bytes, when the upload was buffered. */
|
|
367
|
+
buffer?: Uint8Array;
|
|
368
|
+
extname?: string | null;
|
|
369
|
+
clientName?: string;
|
|
370
|
+
name?: string;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Parse a size limit — a byte count, or Adonis's `"2mb"` / `"512kb"` spelling.
|
|
374
|
+
* Throws on an unreadable unit rather than falling back to "unlimited": a cap
|
|
375
|
+
* that silently stops capping is worse than no cap at all.
|
|
376
|
+
*/
|
|
377
|
+
export declare function parseByteSize(size: number | string): number;
|
|
378
|
+
/**
|
|
379
|
+
* What a `parse()` callback receives besides the value — VineJS's
|
|
380
|
+
* `ParseFn = (value, ctx: Pick<FieldContext, 'data' | 'parent' | 'meta'>)`.
|
|
381
|
+
*/
|
|
382
|
+
export type ParseContext = Pick<FieldContext, "data" | "parent" | "meta">;
|
|
383
|
+
/**
|
|
384
|
+
* A conditional set of properties merged into an object (VineJS `vine.group`).
|
|
385
|
+
* The first branch whose predicate matches contributes its shape; `otherwise`
|
|
386
|
+
* is the unconditional fallback.
|
|
387
|
+
*/
|
|
388
|
+
export interface ConditionalGroup {
|
|
389
|
+
readonly __rune: "group";
|
|
390
|
+
branches: ReadonlyArray<{
|
|
391
|
+
predicate: ((data: Record<string, unknown>) => boolean) | null;
|
|
392
|
+
shape: Record<string, RuleChain>;
|
|
393
|
+
}>;
|
|
394
|
+
}
|
|
395
|
+
/** Per-field introspection returned inside `toJSON().schema`. */
|
|
396
|
+
export type SchemaIntrospection = Record<string, {
|
|
397
|
+
rules: string[];
|
|
398
|
+
optional: boolean;
|
|
399
|
+
nullable: boolean;
|
|
400
|
+
}>;
|
|
401
|
+
/** Build a conditional group (VineJS `vine.group([...])`). */
|
|
402
|
+
export declare function group(branches: ReadonlyArray<{
|
|
403
|
+
predicate: ((data: Record<string, unknown>) => boolean) | null;
|
|
404
|
+
shape: Record<string, RuleChain>;
|
|
405
|
+
}>): ConditionalGroup;
|
|
406
|
+
/** A predicate-guarded group branch (`vine.group.if`). */
|
|
407
|
+
export declare function groupIf(predicate: (data: Record<string, unknown>) => boolean, shape: Record<string, RuleChain>): {
|
|
408
|
+
predicate: (data: Record<string, unknown>) => boolean;
|
|
409
|
+
shape: Record<string, RuleChain>;
|
|
410
|
+
};
|
|
411
|
+
/** The unconditional fallback branch (`vine.group.else` / `.otherwise`). */
|
|
412
|
+
export declare function groupElse(shape: Record<string, RuleChain>): {
|
|
413
|
+
predicate: null;
|
|
414
|
+
shape: Record<string, RuleChain>;
|
|
415
|
+
};
|
|
416
|
+
/** A union branch guarded by a predicate — `vine.union.if(...)`. */
|
|
417
|
+
export interface ConditionalBranch {
|
|
418
|
+
/** `null` for an unconditional branch (`union.else`). */
|
|
419
|
+
predicate: ((value: unknown, field: FieldContext) => boolean) | null;
|
|
420
|
+
chain: RuleChain;
|
|
421
|
+
}
|
|
422
|
+
/** What `union()` accepts: a bare chain, or a guarded branch. */
|
|
423
|
+
export type UnionBranch = RuleChain | ConditionalBranch;
|
|
424
|
+
/**
|
|
425
|
+
* Guarded union branch (VineJS `vine.union.if`). The predicate picks the branch;
|
|
426
|
+
* the chosen branch's OWN errors are reported, which is what makes a union
|
|
427
|
+
* diagnosable — "matches nothing" tells the caller nothing about which shape it
|
|
428
|
+
* nearly matched.
|
|
429
|
+
*/
|
|
430
|
+
export declare function unionIf(predicate: (value: unknown, field: FieldContext) => boolean, chain: RuleChain): ConditionalBranch;
|
|
431
|
+
/** Fallback union branch (VineJS `vine.union.else`). */
|
|
432
|
+
export declare function unionElse(chain: RuleChain): ConditionalBranch;
|
|
433
|
+
/** Extract the phantom output type of a chain. */
|
|
434
|
+
type OutputOf<C> = C extends RuleChain<infer O> ? O : never;
|
|
435
|
+
/** Keys whose output includes `undefined` become optional in the inferred shape. */
|
|
436
|
+
type OptionalKeys<S> = {
|
|
437
|
+
[K in keyof S]: undefined extends OutputOf<S[K]> ? K : never;
|
|
438
|
+
}[keyof S];
|
|
439
|
+
/** Flatten an intersection into a single readable object type. */
|
|
440
|
+
type Prettify<T> = {
|
|
441
|
+
[K in keyof T]: T[K];
|
|
442
|
+
} & unknown;
|
|
443
|
+
/**
|
|
444
|
+
* Infer the validated data shape from a schema's field map — the type
|
|
445
|
+
* `result.data` carries once `result.valid === true`. `rules.string()` →
|
|
446
|
+
* `string`, `.optional()` → an optional key, `.nullable()` → `T | null`,
|
|
447
|
+
* `.object(shape)`/`.array(item)` recurse.
|
|
448
|
+
*/
|
|
449
|
+
export type Infer<S> = Prettify<{
|
|
450
|
+
[K in Exclude<keyof S, OptionalKeys<S>>]: OutputOf<S[K]>;
|
|
451
|
+
} & {
|
|
452
|
+
[K in OptionalKeys<S>]?: Exclude<OutputOf<S[K]>, undefined>;
|
|
453
|
+
}>;
|
|
91
454
|
/**
|
|
92
455
|
* Create a validation schema.
|
|
93
456
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
457
|
+
* The field map's rule chains are phantom-typed, so `result.data` is inferred
|
|
458
|
+
* automatically — `schema({ email: rules.string(), age: rules.number() })`
|
|
459
|
+
* types `data` as `{ email: string; age: number }` with no manual generic.
|
|
97
460
|
*
|
|
98
|
-
* const RegisterValidator = schema
|
|
461
|
+
* const RegisterValidator = schema({
|
|
99
462
|
* email: rules.string().email(),
|
|
100
|
-
*
|
|
463
|
+
* age: rules.number().optional(),
|
|
101
464
|
* });
|
|
465
|
+
* // Infer<typeof RegisterValidator> not needed — result.data is typed.
|
|
102
466
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
|
|
467
|
+
* An explicit generic is still accepted for back-compat
|
|
468
|
+
* (`schema<MyType>({ ... })`), overriding inference.
|
|
469
|
+
*/
|
|
470
|
+
export declare function schema<S extends Record<string, RuleChain>>(fields: S, objectChain?: RuleChain): ValidationSchema<Infer<S>>;
|
|
471
|
+
export declare function schema<T = Record<string, unknown>>(fields: Record<string, RuleChain>, objectChain?: RuleChain): ValidationSchema<T>;
|
|
472
|
+
/**
|
|
473
|
+
* VineJS's `vine.create(...)`. Same thing as {@link schema} — the Adonis
|
|
474
|
+
* spelling is provided so a validator reads the same in both frameworks.
|
|
475
|
+
*/
|
|
476
|
+
/**
|
|
477
|
+
* VineJS's `vine.create(...)`. Accepts either a map of fields (rune's native
|
|
478
|
+
* spelling) or the `RuleChain` produced by `rune.object({...})`, because
|
|
479
|
+
* `vine.create(vine.object({...}))` is the form Adonis documents.
|
|
106
480
|
*/
|
|
107
|
-
export declare function
|
|
481
|
+
export declare function create<S extends Record<string, RuleChain>>(fields: S): ValidationSchema<Infer<S>>;
|
|
482
|
+
export declare function create(chain: RuleChain): ValidationSchema;
|
|
108
483
|
export declare function setValidationTranslator(translator?: ValidationTranslator): void;
|
|
109
484
|
export declare function bindRosetta(rosetta: {
|
|
110
485
|
t(key: string, params?: ValidationMessageParams): string;
|
|
@@ -113,43 +488,432 @@ export declare function bindRosetta(rosetta: {
|
|
|
113
488
|
export interface RuleDef {
|
|
114
489
|
name: string;
|
|
115
490
|
param?: number;
|
|
491
|
+
/** Interpolation args exposed to i18n/messages providers (e.g. `{ min: 3 }`). */
|
|
492
|
+
args?: Record<string, unknown>;
|
|
116
493
|
validate: (value: unknown) => boolean;
|
|
117
494
|
message: string;
|
|
495
|
+
/** Set when `.message()` overrode this rule's default text. */
|
|
496
|
+
hasCustomMessage?: boolean;
|
|
497
|
+
/**
|
|
498
|
+
* Keep this rule off the Rust path even though its NAME is in
|
|
499
|
+
* {@link NATIVE_RULES}. Set by options the native engine does not know about
|
|
500
|
+
* (`uuid({ version })`, a callback list for `in` / `notIn`): the engine would
|
|
501
|
+
* run the rule without them and silently answer a different question.
|
|
502
|
+
*/
|
|
503
|
+
tsOnly?: boolean;
|
|
504
|
+
/** Modifier this rule applies to its field's JSON Schema node. */
|
|
505
|
+
toJSONSchema?: JsonSchemaModifier;
|
|
506
|
+
}
|
|
507
|
+
/** A conditional-required condition (VineJS `requiredWhen` family). */
|
|
508
|
+
interface RequiredCondition {
|
|
509
|
+
kind: "exists" | "missing" | "when";
|
|
510
|
+
otherField: string;
|
|
511
|
+
operator?: "=" | "!=" | ">" | "<" | ">=" | "<=" | "in" | "notIn";
|
|
512
|
+
value?: unknown;
|
|
118
513
|
}
|
|
119
|
-
/**
|
|
120
|
-
|
|
514
|
+
/** Phantom brand carrying the inferred output type (never assigned at runtime). */
|
|
515
|
+
declare const OUTPUT: unique symbol;
|
|
516
|
+
/** Rule chain — fluent, phantom-typed validation builder. */
|
|
517
|
+
/**
|
|
518
|
+
* The value list accepted by `in` / `notIn` / `enum` — static, or computed at
|
|
519
|
+
* validation time (VineJS parity).
|
|
520
|
+
*/
|
|
521
|
+
export type AllowedValues = ReadonlyArray<string | number | boolean> | (() => ReadonlyArray<string | number | boolean>);
|
|
522
|
+
export declare class RuleChain<Output = unknown> {
|
|
121
523
|
#private;
|
|
524
|
+
/** Phantom output type — drives {@link Infer}; never read at runtime. */
|
|
525
|
+
readonly [OUTPUT]: Output;
|
|
122
526
|
/** Public read access to rules (for OpenAPI generation, Rust bridge). */
|
|
123
527
|
get rules(): readonly RuleDef[];
|
|
124
528
|
get isOptionalField(): boolean;
|
|
529
|
+
/** Public read access to the `.nullable()` flag (keeps such schemas off the native path). */
|
|
530
|
+
get isNullable(): boolean;
|
|
125
531
|
get transforms(): ReadonlyArray<{
|
|
126
532
|
name: string;
|
|
127
|
-
fn: (value: unknown) => unknown;
|
|
533
|
+
fn: (value: unknown, field: FieldContext) => unknown;
|
|
128
534
|
}>;
|
|
129
535
|
/** Public read access to `.use()` rules (used to keep such schemas off the native path). */
|
|
130
536
|
get useRules(): readonly CompiledRule[];
|
|
131
|
-
/**
|
|
132
|
-
|
|
537
|
+
/** Public read access to async rules (`unique`/`exists`/`useAsync`) — run by `validateResultAsync`. */
|
|
538
|
+
get asyncRules(): readonly AsyncCompiledRule[];
|
|
539
|
+
/**
|
|
540
|
+
* Does this chain — or anything nested under it (object fields, array items) —
|
|
541
|
+
* carry async rules? The schema-level detection used to inspect only the
|
|
542
|
+
* top-level chains, so a nested `unique`/`exists` was invisible: `validate()`
|
|
543
|
+
* did not throw and the async pass never ran the rule, silently accepting
|
|
544
|
+
* an unchecked value.
|
|
545
|
+
*/
|
|
546
|
+
get hasAsyncRulesDeep(): boolean;
|
|
547
|
+
/** Does this object keep keys its shape does not declare? */
|
|
548
|
+
get allowsUnknown(): boolean;
|
|
549
|
+
/** Free-form JSON Schema metadata attached with `meta()`. */
|
|
550
|
+
get metadata(): Record<string, unknown> | null;
|
|
551
|
+
/** The item chain of an `array()`, if declared. */
|
|
552
|
+
get arrayItem(): RuleChain | null;
|
|
553
|
+
/** The positional chains of a `tuple()`, if declared. */
|
|
554
|
+
get tupleItems(): RuleChain[] | null;
|
|
555
|
+
/** The value chain of a `record()`, if declared. */
|
|
556
|
+
get recordValue(): RuleChain | null;
|
|
557
|
+
/** Whether this chain stops at its first failing rule (VineJS `bail`). */
|
|
558
|
+
get bails(): boolean;
|
|
559
|
+
/** Public read access to `.parse()` pre-transforms (kept off the native path). */
|
|
560
|
+
get preTransforms(): ReadonlyArray<(value: unknown, ctx: ParseContext) => unknown>;
|
|
561
|
+
/** Whether this chain carries a `requiredWhen`-family condition. */
|
|
562
|
+
get hasConditionalRequired(): boolean;
|
|
563
|
+
/** Mark field as optional (absent / `undefined` allowed). */
|
|
564
|
+
optional(): RuleChain<Output | undefined>;
|
|
565
|
+
/** Mark field as nullable (`null` allowed, kept in the output). */
|
|
566
|
+
nullable(): RuleChain<Output | null>;
|
|
567
|
+
/** Mark field as both optional and nullable. */
|
|
568
|
+
nullish(): RuleChain<Output | null | undefined>;
|
|
569
|
+
/** Stop at the first failing rule for this field (VineJS bail). */
|
|
570
|
+
bail(enabled?: boolean): this;
|
|
133
571
|
/** Must be an object matching a nested schema. */
|
|
134
|
-
object
|
|
572
|
+
object<Sh extends Record<string, RuleChain>>(shape: Sh): RuleChain<Infer<Sh>>;
|
|
135
573
|
/** Must be an array. Items validated by the provided chain. */
|
|
136
|
-
array(itemChain?:
|
|
574
|
+
array<Item extends RuleChain>(itemChain?: Item): RuleChain<OutputOf<Item>[]>;
|
|
137
575
|
/** Must be a string. */
|
|
138
|
-
string():
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
576
|
+
string(): RuleChain<string>;
|
|
577
|
+
/**
|
|
578
|
+
* Must be a number. Like VineJS, a numeric STRING is coerced (`"32"` → `32`)
|
|
579
|
+
* — HTML form bodies and query strings carry numbers as text, so requiring
|
|
580
|
+
* `typeof v === "number"` rejected the values Adonis accepts. Pass
|
|
581
|
+
* `{ strict: true }` to refuse anything that is not already a number.
|
|
582
|
+
*/
|
|
583
|
+
number(options?: {
|
|
584
|
+
strict?: boolean;
|
|
585
|
+
}): RuleChain<number>;
|
|
586
|
+
/**
|
|
587
|
+
* Must be a boolean. Like VineJS, `"true"`, `"false"`, `"on"`, `"off"`,
|
|
588
|
+
* `"1"`, `"0"`, `1` and `0` are coerced; `{ strict: true }` refuses them.
|
|
589
|
+
*/
|
|
590
|
+
boolean(options?: {
|
|
591
|
+
strict?: boolean;
|
|
592
|
+
}): RuleChain<boolean>;
|
|
593
|
+
/**
|
|
594
|
+
* Must be a date (VineJS `vine.date()`). ISO 8601 by default; pass `formats`
|
|
595
|
+
* for unix timestamps (`x` = ms, `X` = seconds) or a token format such as
|
|
596
|
+
* `DD/MM/YYYY`. Parsing is calendar-strict — `2026-02-31` is rejected.
|
|
597
|
+
*
|
|
598
|
+
* The validated output is a `Date`; bind {@link setDateTransform} to map it
|
|
599
|
+
* to your own type once at boot.
|
|
600
|
+
*/
|
|
601
|
+
date(options?: {
|
|
602
|
+
formats?: DateFormat[];
|
|
603
|
+
}): RuleChain<Date>;
|
|
604
|
+
/** Must be strictly after `operand` (`'today'`, an ISO string, or a `Date`). */
|
|
605
|
+
after(operand: unknown, options?: DateCompareOptions): this;
|
|
606
|
+
/** Must be strictly before `operand`. */
|
|
607
|
+
before(operand: unknown, options?: DateCompareOptions): this;
|
|
608
|
+
/** Must be after `operand`, or equal to it. */
|
|
609
|
+
afterOrEqual(operand: unknown, options?: DateCompareOptions): this;
|
|
610
|
+
/** Must be before `operand`, or equal to it. */
|
|
611
|
+
beforeOrEqual(operand: unknown, options?: DateCompareOptions): this;
|
|
612
|
+
/** Must be after the date held by a sibling field (VineJS `afterField`). */
|
|
613
|
+
afterField(otherField: string, options?: DateCompareOptions): this;
|
|
614
|
+
/** Must be before the date held by a sibling field. */
|
|
615
|
+
beforeField(otherField: string, options?: DateCompareOptions): this;
|
|
616
|
+
/** Must be the same instant as `operand` (VineJS `equals`). */
|
|
617
|
+
equals(operand: unknown, options?: DateCompareOptions): this;
|
|
618
|
+
/** Must be after the sibling's date, or the same instant (VineJS `afterOrSameAs`). */
|
|
619
|
+
afterOrSameAs(otherField: string, options?: DateCompareOptions): this;
|
|
620
|
+
/** Must be before the sibling's date, or the same instant. */
|
|
621
|
+
beforeOrSameAs(otherField: string, options?: DateCompareOptions): this;
|
|
622
|
+
/** Must fall on a Saturday or Sunday (VineJS `weekend`). */
|
|
623
|
+
weekend(): this;
|
|
624
|
+
/** Must fall on a Monday-to-Friday day (VineJS `weekday`). */
|
|
625
|
+
weekday(): this;
|
|
626
|
+
/**
|
|
627
|
+
* Keep keys the object shape does not declare (VineJS
|
|
628
|
+
* `allowUnknownProperties`). Off by default: dropping undeclared keys is what
|
|
629
|
+
* makes a validated payload safe to hand to a mass assignment.
|
|
630
|
+
*/
|
|
631
|
+
allowUnknownProperties(): this;
|
|
632
|
+
/**
|
|
633
|
+
* Convert the object's KEYS to camelCase in the output (VineJS
|
|
634
|
+
* `object.toCamelCase()`), so a snake_case payload hydrates camelCase
|
|
635
|
+
* properties. Distinct from the string `toCamelCase()`, which rewrites a
|
|
636
|
+
* VALUE — that one was never a substitute for this.
|
|
637
|
+
*/
|
|
638
|
+
toCamelCaseKeys(): this;
|
|
639
|
+
/**
|
|
640
|
+
* Merge extra properties into this object's shape (VineJS `merge`). Accepts a
|
|
641
|
+
* plain shape or a {@link ConditionalGroup} whose branch is chosen per
|
|
642
|
+
* payload — `vine.group` in VineJS.
|
|
643
|
+
*/
|
|
644
|
+
merge(extra: Record<string, RuleChain> | ConditionalGroup): this;
|
|
645
|
+
/** The nested shape declared by `object()`, if any (VineJS `getProperties`). */
|
|
646
|
+
getProperties(): Record<string, RuleChain> | null;
|
|
647
|
+
/** Independent copy of this chain (VineJS `clone`). */
|
|
648
|
+
clone(): RuleChain<Output>;
|
|
649
|
+
/**
|
|
650
|
+
* A CLONED subset of the object's properties (VineJS `pick`).
|
|
651
|
+
*
|
|
652
|
+
* Returns a properties record, not a schema — VineJS types it
|
|
653
|
+
* `Pick<Properties, Keys>` precisely so it composes by spread:
|
|
654
|
+
* `rules.any().object({ ...userShape.pick(["id"]) })`. Returning a chain here
|
|
655
|
+
* broke that idiom.
|
|
656
|
+
*/
|
|
657
|
+
pick<K extends string>(keys: readonly K[]): Record<string, RuleChain>;
|
|
658
|
+
/** A cloned copy of the properties EXCLUDING `keys` (VineJS `omit`). */
|
|
659
|
+
omit<K extends string>(keys: readonly K[]): Record<string, RuleChain>;
|
|
660
|
+
/** Make every property of an object shape optional (VineJS `partial`). */
|
|
661
|
+
partial(keys?: readonly string[]): RuleChain<Output>;
|
|
662
|
+
/**
|
|
663
|
+
* Must be an "accepted" value — `true`, `1`, `"1"`, `"on"`, `"yes"`,
|
|
664
|
+
* `"true"` (VineJS `accepted`, for checkbox-style consent fields).
|
|
665
|
+
*/
|
|
666
|
+
accepted(): RuleChain<true>;
|
|
667
|
+
/**
|
|
668
|
+
* Object with arbitrary keys, every value validated by `valueChain`
|
|
669
|
+
* (VineJS `record`).
|
|
670
|
+
*/
|
|
671
|
+
record<Item extends RuleChain>(valueChain: Item): RuleChain<Record<string, OutputOf<Item>>>;
|
|
672
|
+
/**
|
|
673
|
+
* Fixed-length array with a schema per position (VineJS `tuple`). Extra
|
|
674
|
+
* items are rejected — a tuple that silently ignores a trailing element is
|
|
675
|
+
* how unvalidated data slips through.
|
|
676
|
+
*/
|
|
677
|
+
tuple<const Items extends readonly RuleChain[]>(items: Items): RuleChain<{
|
|
678
|
+
[K in keyof Items]: OutputOf<Items[K]>;
|
|
679
|
+
}>;
|
|
680
|
+
/**
|
|
681
|
+
* Value must satisfy at least one of `chains`.
|
|
682
|
+
*
|
|
683
|
+
* Two forms, both supported:
|
|
684
|
+
*
|
|
685
|
+
* - guarded (VineJS parity): `union([rules.union.if(pred, chain), …,
|
|
686
|
+
* rules.union.else(fallback)])` — the predicate SELECTS the branch and
|
|
687
|
+
* that branch's own errors are reported, so a failure says which shape was
|
|
688
|
+
* meant and why it did not fit.
|
|
689
|
+
* - bare chains: tried in order, first match wins, and a total miss reports a
|
|
690
|
+
* single `union` error rather than every losing branch's noise.
|
|
691
|
+
*/
|
|
692
|
+
union(chains: readonly UnionBranch[]): this;
|
|
693
|
+
/**
|
|
694
|
+
* Must be an uploaded file (VineJS/Adonis `vine.file()`).
|
|
695
|
+
*
|
|
696
|
+
* Named deviation: Adonis validates a bodyparser `MultipartFile`, which rune
|
|
697
|
+
* cannot import and stay agnostic. It checks the STRUCTURE instead — any
|
|
698
|
+
* object exposing `size` and a name/extension — so an Adonis MultipartFile
|
|
699
|
+
* satisfies it, and so does any other upload representation.
|
|
700
|
+
*
|
|
701
|
+
* `size` is a byte count; `extnames` are compared lowercase, without the dot.
|
|
702
|
+
*/
|
|
703
|
+
file(options?: {
|
|
704
|
+
size?: number | string;
|
|
705
|
+
extnames?: readonly string[];
|
|
706
|
+
/**
|
|
707
|
+
* Skip the magic-number check. Default `true` — Adonis derives `extname`
|
|
708
|
+
* from the real bytes before validation, so trusting the declaration is
|
|
709
|
+
* NOT the safe default: a `.exe` renamed `.png` satisfies every
|
|
710
|
+
* declarative check, since all of them come from the uploader.
|
|
711
|
+
*/
|
|
712
|
+
verifyContent?: boolean;
|
|
713
|
+
}): RuleChain<FileLike>;
|
|
714
|
+
/**
|
|
715
|
+
* Uploaded file with VineJS `nativeFile` options — `minSize`, `maxSize`,
|
|
716
|
+
* `mimeTypes`. Same structural contract as {@link file}: rune never reads
|
|
717
|
+
* bytes, so the MIME type is the one the upload REPORTS.
|
|
718
|
+
*/
|
|
719
|
+
nativeFile(options?: {
|
|
720
|
+
minSize?: number | string;
|
|
721
|
+
maxSize?: number | string;
|
|
722
|
+
mimeTypes?: readonly string[];
|
|
723
|
+
}): RuleChain<FileLike>;
|
|
724
|
+
/** Minimum upload size (VineJS `nativeFile().minSize()`). */
|
|
725
|
+
minSize(size: number | string): this;
|
|
726
|
+
/** Maximum upload size (VineJS `nativeFile().maxSize()`). */
|
|
727
|
+
maxSize(size: number | string): this;
|
|
728
|
+
/**
|
|
729
|
+
* Allowed MIME types (VineJS `nativeFile().mimeTypes()`). The type is the one
|
|
730
|
+
* the upload REPORTS — rune never reads bytes, see {@link file}.
|
|
731
|
+
*/
|
|
732
|
+
mimeTypes(types: readonly string[]): this;
|
|
733
|
+
/**
|
|
734
|
+
* Verify the file's REAL type against its magic number (Adonis parity).
|
|
735
|
+
*
|
|
736
|
+
* A `.exe` renamed `.jpg` passes every declarative check — size, extension,
|
|
737
|
+
* reported MIME — because all three come from the uploader. This reads the
|
|
738
|
+
* leading bytes and refuses a mismatch.
|
|
739
|
+
*
|
|
740
|
+
* Async by nature (it touches the filesystem), so the schema must run with
|
|
741
|
+
* `validateResultAsync` / `validate`. Needs a byte source on the file object
|
|
742
|
+
* (`buffer`, `tmpPath`, `filePath` or `path`) — an Adonis `MultipartFile`
|
|
743
|
+
* carries `tmpPath`. With NO source it FAILS: a content check that cannot
|
|
744
|
+
* run must never look like one that passed.
|
|
745
|
+
*/
|
|
746
|
+
verifyContent(): this;
|
|
747
|
+
/** Must equal one of `values` (enum). Narrows the output to the union. */
|
|
748
|
+
enum<const V extends readonly (string | number | boolean)[]>(values: V): RuleChain<V[number]>;
|
|
749
|
+
/** Must equal a literal value. */
|
|
750
|
+
literal<V extends string | number | boolean>(value: V): RuleChain<V>;
|
|
751
|
+
/** Minimum length (string) or minimum value (number). Alias of min/minLength. */
|
|
144
752
|
min(n: number): this;
|
|
145
|
-
/** Maximum length (string) or maximum value (number). */
|
|
753
|
+
/** Maximum length (string) or maximum value (number). Alias of max/maxLength. */
|
|
146
754
|
max(n: number): this;
|
|
755
|
+
/** Minimum length for a string or array (VineJS `minLength`). */
|
|
756
|
+
minLength(n: number): this;
|
|
757
|
+
/** Maximum length for a string or array (VineJS `maxLength`). */
|
|
758
|
+
maxLength(n: number): this;
|
|
759
|
+
/** Exact length for a string or array (VineJS `fixedLength`). */
|
|
760
|
+
fixedLength(n: number): this;
|
|
147
761
|
/** Must be a valid email. */
|
|
148
|
-
email(): this;
|
|
149
|
-
/** Must
|
|
762
|
+
email(options?: EmailOptions): this;
|
|
763
|
+
/** Must match a regular expression (TS-only — never dispatched to Rust). */
|
|
764
|
+
regex(pattern: RegExp): this;
|
|
765
|
+
/** Must be a valid URL (TS-only — uses the WHATWG URL parser). */
|
|
766
|
+
url(options?: UrlOptions): this;
|
|
767
|
+
/**
|
|
768
|
+
* The host must actually resolve (VineJS `activeUrl`).
|
|
769
|
+
*
|
|
770
|
+
* The only rule needing the network, which rune cannot do and stay agnostic
|
|
771
|
+
* and zero-dependency — so it runs through a resolver bound once at boot,
|
|
772
|
+
* exactly like `unique()`. Async by nature: run the schema with
|
|
773
|
+
* `validateResultAsync`. Unbound it THROWS, rather than passing a host nobody
|
|
774
|
+
* checked.
|
|
775
|
+
*/
|
|
776
|
+
activeUrl(): this;
|
|
777
|
+
/**
|
|
778
|
+
* Must be a valid UUID, optionally restricted to given versions
|
|
779
|
+
* (VineJS `uuid({ version: [4] })`, versions 1 through 8).
|
|
780
|
+
*/
|
|
781
|
+
uuid(options?: {
|
|
782
|
+
version?: number | number[];
|
|
783
|
+
}): this;
|
|
784
|
+
/** Must be a ULID (VineJS `ulid`). */
|
|
785
|
+
ulid(): this;
|
|
786
|
+
/** Must be a JSON Web Token — three dot-separated base64url segments. */
|
|
787
|
+
jwt(): this;
|
|
788
|
+
/** Must contain only ASCII characters (VineJS `ascii`). */
|
|
789
|
+
ascii(): this;
|
|
790
|
+
/** Must be a CSS hex colour code, with or without the leading `#`. */
|
|
791
|
+
hexCode(): this;
|
|
792
|
+
/** Must be an IP address. Pass `version` to require v4 or v6 specifically. */
|
|
793
|
+
ipAddress(options?: {
|
|
794
|
+
version?: 4 | 6;
|
|
795
|
+
}): this;
|
|
796
|
+
/** Must pass the Luhn checksum (VineJS `creditCard`). */
|
|
797
|
+
creditCard(): this;
|
|
798
|
+
/** Must be an IBAN passing the ISO 13616 mod-97 check. */
|
|
799
|
+
iban(): this;
|
|
800
|
+
/** Must be a `"lat,lng"` pair within the valid ranges. */
|
|
801
|
+
coordinates(): this;
|
|
802
|
+
/**
|
|
803
|
+
* Must be a mobile number in E.164 form. Named deviation from VineJS: rune
|
|
804
|
+
* carries no per-locale numbering plans, so there is no `locale` option.
|
|
805
|
+
*/
|
|
806
|
+
mobile(options?: {
|
|
807
|
+
locale?: string | string[];
|
|
808
|
+
strictMode?: boolean;
|
|
809
|
+
}): this;
|
|
810
|
+
/**
|
|
811
|
+
* Must be a postal code for `countryCode`. Throws for a country rune has no
|
|
812
|
+
* pattern for, rather than accepting the value unchecked.
|
|
813
|
+
*/
|
|
814
|
+
postalCode(options: {
|
|
815
|
+
countryCode: string | string[];
|
|
816
|
+
} | ((field: FieldContext) => {
|
|
817
|
+
countryCode: string | string[];
|
|
818
|
+
})): this;
|
|
819
|
+
/**
|
|
820
|
+
* Must be a valid VAT number (VineJS 4.2 `vat`). Accepts a country list or a
|
|
821
|
+
* callback resolving it per payload.
|
|
822
|
+
*
|
|
823
|
+
* Checksums are run where the country defines a short, well-defined one
|
|
824
|
+
* (BE, DE, NL, IT, PT, LU, CH); the others are FORMAT-only, which is stated
|
|
825
|
+
* rather than implied. An unknown country LEVES rather than accepting the
|
|
826
|
+
* value unchecked.
|
|
827
|
+
*/
|
|
828
|
+
vat(options: VatOptions | ((field: FieldContext) => VatOptions)): this;
|
|
829
|
+
/** Must differ from a sibling field (VineJS `notSameAs`). */
|
|
830
|
+
notSameAs(otherField: string): this;
|
|
831
|
+
/** Array items must be unique — optionally compared on `field` (VineJS `distinct`). */
|
|
832
|
+
distinct(field?: string | string[]): this;
|
|
833
|
+
/** Must be less than or equal to zero (VineJS `nonPositive`). */
|
|
834
|
+
nonPositive(): this;
|
|
835
|
+
/** Array must hold at least one item (VineJS `notEmpty`). */
|
|
836
|
+
notEmpty(): this;
|
|
837
|
+
/** Drop `null`, `undefined` and `""` items before the item rules run. */
|
|
838
|
+
compact(): this;
|
|
839
|
+
/** Number must have no fractional part (VineJS `withoutDecimals`). */
|
|
840
|
+
withoutDecimals(): this;
|
|
841
|
+
/** Must be a passport number for `countryCode`. Throws for an uncovered country. */
|
|
842
|
+
passport(options: {
|
|
843
|
+
countryCode: string | string[];
|
|
844
|
+
}): this;
|
|
845
|
+
/** Lowercase the value (VineJS `toLowerCase`). */
|
|
846
|
+
toLowerCase(): this;
|
|
847
|
+
/** Uppercase the value (VineJS `toUpperCase`). */
|
|
848
|
+
toUpperCase(): this;
|
|
849
|
+
/**
|
|
850
|
+
* VineJS `toCamelCase()`, on both shapes it exists for:
|
|
851
|
+
*
|
|
852
|
+
* - on an `object()` chain it camelCases the object's KEYS
|
|
853
|
+
* (`VineObject.toCamelCase`);
|
|
854
|
+
* - on any other chain it camelCases the string VALUE (`VineString`).
|
|
855
|
+
*
|
|
856
|
+
* One name, because Vine has one name. Dispatching on whether a nested shape
|
|
857
|
+
* was declared is what keeps a transcribed validator behaving the same.
|
|
858
|
+
*/
|
|
859
|
+
toCamelCase(): this;
|
|
860
|
+
/** HTML-escape `& < > " '` (VineJS `escape`). */
|
|
861
|
+
escape(): this;
|
|
862
|
+
/** Normalise an email address (VineJS `normalizeEmail`). */
|
|
863
|
+
normalizeEmail(options?: NormalizeEmailOptions): this;
|
|
864
|
+
/** Normalise a URL (VineJS `normalizeUrl`). */
|
|
865
|
+
normalizeUrl(options?: NormalizeUrlOptions): this;
|
|
866
|
+
/** Must contain only ASCII letters. */
|
|
867
|
+
alpha(options?: AlphaOptions): this;
|
|
868
|
+
/** Must contain only ASCII letters and digits. */
|
|
869
|
+
alphaNumeric(options?: AlphaOptions): this;
|
|
870
|
+
/** String must start with `substring`. */
|
|
871
|
+
startsWith(substring: string): this;
|
|
872
|
+
/** String must end with `substring`. */
|
|
873
|
+
endsWith(substring: string): this;
|
|
874
|
+
/**
|
|
875
|
+
* Value must be one of `values`.
|
|
876
|
+
*
|
|
877
|
+
* VineJS also accepts a callback so the list can be computed at validation
|
|
878
|
+
* time (tenant-scoped roles, values read from config…). A static array is
|
|
879
|
+
* snapshotted; a callback is invoked on every check.
|
|
880
|
+
*/
|
|
881
|
+
in(values: AllowedValues): this;
|
|
882
|
+
/** Value must NOT be one of `values`. */
|
|
883
|
+
notIn(values: AllowedValues): this;
|
|
884
|
+
/** Number must be positive (> 0) and finite. */
|
|
150
885
|
positive(): this;
|
|
886
|
+
/** Number must be negative (< 0) and finite. */
|
|
887
|
+
negative(): this;
|
|
888
|
+
/** Number must be >= 0 and finite. */
|
|
889
|
+
nonNegative(): this;
|
|
890
|
+
/** Number must fall within `[min, max]` (inclusive). */
|
|
891
|
+
range(bounds: [min: number, max: number]): this;
|
|
892
|
+
/** Number must have at most `digits` decimal places (TS-only). */
|
|
893
|
+
decimal(digits: number | [number, number]): this;
|
|
894
|
+
/** Must equal a sibling field (VineJS `sameAs`). Cross-field → TS-only. */
|
|
895
|
+
sameAs(otherField: string): this;
|
|
896
|
+
/** Must equal its `<field>_confirmation` sibling (VineJS `confirmed`). */
|
|
897
|
+
confirmed(options?: {
|
|
898
|
+
as?: string;
|
|
899
|
+
confirmationField?: string;
|
|
900
|
+
}): this;
|
|
901
|
+
/** Required only when `otherField` is present (non-null) — else optional. */
|
|
902
|
+
requiredIfExists(otherField: string): this;
|
|
903
|
+
/** Required only when `otherField` is absent/null — else optional. */
|
|
904
|
+
requiredIfMissing(otherField: string): this;
|
|
905
|
+
/** Required only when `otherField <op> value` holds — else optional. */
|
|
906
|
+
requiredWhen(otherField: string, operator: RequiredCondition["operator"], value: unknown): this;
|
|
151
907
|
/** Trim whitespace (transform). */
|
|
152
908
|
trim(): this;
|
|
909
|
+
/**
|
|
910
|
+
* Post-validation transform changing the output type (VineJS `transform`).
|
|
911
|
+
* `value` is `unknown` — narrow it in the callback (the no-cast rule forbids
|
|
912
|
+
* lying about a dynamically-produced value's static type).
|
|
913
|
+
*/
|
|
914
|
+
transform<U>(fn: (value: unknown, field: FieldContext) => U): RuleChain<U>;
|
|
915
|
+
/** Pre-validation transform of the raw input (VineJS `parse`). */
|
|
916
|
+
parse(fn: (value: unknown, ctx: ParseContext) => unknown): this;
|
|
153
917
|
/** Custom validation rule. */
|
|
154
918
|
custom(name: string, validate: (value: unknown) => boolean, message?: string): this;
|
|
155
919
|
/**
|
|
@@ -157,25 +921,135 @@ export declare class RuleChain {
|
|
|
157
921
|
* receives a {@link FieldContext} with the root `data` and `parent`, so it can
|
|
158
922
|
* validate across fields. Runs after this field's type/value rules.
|
|
159
923
|
*/
|
|
160
|
-
use(rule: CompiledRule): this;
|
|
161
|
-
/**
|
|
924
|
+
use(rule: CompiledRule | AsyncCompiledRule): this;
|
|
925
|
+
/**
|
|
926
|
+
* Attach an async rule (from {@link createAsyncRule}). The schema must then be
|
|
927
|
+
* run with `validateResultAsync` — sync `validate()` throws for such a schema.
|
|
928
|
+
*/
|
|
929
|
+
useAsync(rule: AsyncCompiledRule): this;
|
|
930
|
+
/**
|
|
931
|
+
* DB-backed uniqueness rule (Adonis Lucid `unique`). `check(value, field)`
|
|
932
|
+
* resolves `true` when the value is unique (valid). rune stays agnostic — the
|
|
933
|
+
* check does the query (e.g. against atlas). Requires the async path (`validateResultAsync` / `validate`).
|
|
934
|
+
*
|
|
935
|
+
* rules.string().email().unique(async (value) => {
|
|
936
|
+
* const row = await db.from('users').where('email', value).first()
|
|
937
|
+
* return !row
|
|
938
|
+
* })
|
|
939
|
+
*/
|
|
940
|
+
unique(check: (value: unknown, field: FieldContext) => boolean | Promise<boolean>, message?: string): this;
|
|
941
|
+
unique(options: DatabaseRuleOptions, message?: string): this;
|
|
942
|
+
/**
|
|
943
|
+
* DB-backed existence rule (Adonis Lucid `exists`). `check(value, field)`
|
|
944
|
+
* resolves `true` when a matching row exists (valid). Requires the async path (`validateResultAsync` / `validate`).
|
|
945
|
+
*/
|
|
946
|
+
exists(check: (value: unknown, field: FieldContext) => boolean | Promise<boolean>, message?: string): this;
|
|
947
|
+
exists(options: DatabaseRuleOptions, message?: string): this;
|
|
948
|
+
/**
|
|
949
|
+
* Attach free-form JSON Schema metadata (VineJS `meta()`) — `title`,
|
|
950
|
+
* `description`, `examples`, `deprecated`… Merged verbatim into the field's
|
|
951
|
+
* node by `toJSONSchema()`.
|
|
952
|
+
*/
|
|
953
|
+
meta(metadata: Record<string, unknown>): this;
|
|
954
|
+
/**
|
|
955
|
+
* Set a custom error message for the rule that was just added.
|
|
956
|
+
*
|
|
957
|
+
* "The last rule" spans all three registers: value rules (`#rules`),
|
|
958
|
+
* cross-field `.use()` rules (`sameAs`, `confirmed`, `afterField`,
|
|
959
|
+
* `notSameAs`) and async rules (`unique`, `exists`, `useAsync`). Targeting
|
|
960
|
+
* `#rules` alone silently retargeted the PREVIOUS value rule — or threw
|
|
961
|
+
* `NO_RULE` — whenever the preceding call was a cross-field or async rule.
|
|
962
|
+
*/
|
|
162
963
|
message(msg: string): this;
|
|
163
|
-
/**
|
|
164
|
-
|
|
964
|
+
/**
|
|
965
|
+
* Register a TYPE rule from outside the chain — used by the `optional()` and
|
|
966
|
+
* `null()` factories, which are types in their own right.
|
|
967
|
+
* @internal
|
|
968
|
+
*/
|
|
969
|
+
pushTypeRule(rule: RuleDef): void;
|
|
970
|
+
/** Re-type this chain in place, without cloning. @internal */
|
|
971
|
+
retypeTo<U>(): RuleChain<U>;
|
|
972
|
+
/**
|
|
973
|
+
* Internal: validate a field value and return errors + transformed value.
|
|
974
|
+
*
|
|
975
|
+
* `pending` is the async-rule collector. The traversal itself stays sync (it
|
|
976
|
+
* is shared with `validate()`); when a collector is supplied, every chain in
|
|
977
|
+
* the tree that carries async rules and passed its sync rules records itself
|
|
978
|
+
* for the async path to await. Without it, nested async rules never ran.
|
|
979
|
+
*/
|
|
980
|
+
_validateWithTransform(field: string, rawValue: unknown, ctx?: RunContext, pending?: PendingAsync[]): {
|
|
165
981
|
errors: ValidationError[];
|
|
166
982
|
transformed: unknown;
|
|
167
983
|
};
|
|
984
|
+
/**
|
|
985
|
+
* Run this chain's async rules on the (already sync-validated) value, awaiting
|
|
986
|
+
* each in order. Returns the errors they reported. Used by `validateResultAsync`.
|
|
987
|
+
* @internal
|
|
988
|
+
*/
|
|
989
|
+
_runAsyncRules(field: string, transformed: unknown, ctx: RunContext): Promise<ValidationError[]>;
|
|
168
990
|
/** Internal: validate a field value against all rules. */
|
|
169
991
|
_validate(field: string, value: unknown): ValidationError[];
|
|
170
992
|
/** Internal: apply transforms. */
|
|
171
993
|
_transform(value: unknown): unknown;
|
|
172
994
|
}
|
|
995
|
+
/** No-op alias of {@link schema} — VineJS `vine.compile()` API parity. */
|
|
996
|
+
export declare function compile<T extends ValidationSchema>(s: T): T;
|
|
997
|
+
export declare function compile(chain: RuleChain): ValidationSchema;
|
|
173
998
|
/** Entry point for building rules. */
|
|
174
999
|
export declare const rules: {
|
|
175
|
-
string: () => RuleChain
|
|
176
|
-
number: (
|
|
177
|
-
|
|
178
|
-
|
|
1000
|
+
string: () => RuleChain<string>;
|
|
1001
|
+
number: (options?: {
|
|
1002
|
+
strict?: boolean;
|
|
1003
|
+
}) => RuleChain<number>;
|
|
1004
|
+
boolean: (options?: {
|
|
1005
|
+
strict?: boolean;
|
|
1006
|
+
}) => RuleChain<boolean>;
|
|
1007
|
+
any: () => RuleChain<unknown>;
|
|
1008
|
+
date: (options?: {
|
|
1009
|
+
formats?: DateFormat[];
|
|
1010
|
+
}) => RuleChain<Date>;
|
|
1011
|
+
accepted: () => RuleChain<true>;
|
|
1012
|
+
file: (options?: {
|
|
1013
|
+
size?: number | string;
|
|
1014
|
+
extnames?: readonly string[];
|
|
1015
|
+
verifyContent?: boolean;
|
|
1016
|
+
}) => RuleChain<FileLike>;
|
|
1017
|
+
nativeFile: (options?: {
|
|
1018
|
+
minSize?: number | string;
|
|
1019
|
+
maxSize?: number | string;
|
|
1020
|
+
mimeTypes?: readonly string[];
|
|
1021
|
+
}) => RuleChain<FileLike>;
|
|
1022
|
+
record: <Item extends RuleChain>(valueChain: Item) => RuleChain<Record<string, OutputOf<Item>>>;
|
|
1023
|
+
tuple: <const Items extends readonly RuleChain[]>(items: Items) => RuleChain<{ [K in keyof Items]: OutputOf<Items[K]>; }>;
|
|
1024
|
+
union: ((chains: readonly UnionBranch[]) => RuleChain) & {
|
|
1025
|
+
if: typeof unionIf;
|
|
1026
|
+
else: typeof unionElse;
|
|
1027
|
+
otherwise: typeof unionElse;
|
|
1028
|
+
};
|
|
1029
|
+
/**
|
|
1030
|
+
* Union discriminated by the value's TYPE (VineJS `unionOfTypes`): the first
|
|
1031
|
+
* branch whose own type rule accepts the value wins.
|
|
1032
|
+
*/
|
|
1033
|
+
/**
|
|
1034
|
+
* Make every property of a shape optional (VineJS `vine.helpers.optional`).
|
|
1035
|
+
* A properties TRANSFORMER, like `pick`/`omit` — it returns a record to
|
|
1036
|
+
* spread, not a schema.
|
|
1037
|
+
*/
|
|
1038
|
+
/**
|
|
1039
|
+
* A field that must be ABSENT (VineJS `vine.optional()` → `VineOptional`,
|
|
1040
|
+
* `builder.d.ts:135`). Mostly a `unionOfTypes` branch. Distinct from
|
|
1041
|
+
* `.optional()` on a chain, which relaxes an existing type — this one IS the
|
|
1042
|
+
* type. The properties transformer that used to squat this name moved to
|
|
1043
|
+
* `helpers.optional`, where VineJS keeps it.
|
|
1044
|
+
*/
|
|
1045
|
+
optional: () => RuleChain<undefined>;
|
|
1046
|
+
/** A field that must be `null` (VineJS `vine.null()` → `VineNull`). */
|
|
1047
|
+
null: () => RuleChain<null>;
|
|
1048
|
+
unionOfTypes: (chains: readonly RuleChain[]) => RuleChain;
|
|
1049
|
+
object: <Sh extends Record<string, RuleChain>>(shape: Sh) => RuleChain<Infer<Sh>>;
|
|
1050
|
+
array: <Item extends RuleChain>(item?: Item) => RuleChain<OutputOf<Item>[]>;
|
|
1051
|
+
enum: <const V extends readonly (string | number | boolean)[]>(values: V) => RuleChain<V[number]>;
|
|
1052
|
+
literal: <V extends string | number | boolean>(value: V) => RuleChain<V>;
|
|
179
1053
|
};
|
|
180
1054
|
export {};
|
|
181
1055
|
//# sourceMappingURL=Schema.d.ts.map
|