@orieljs/validation 0.1.0-alpha.5 → 0.1.0-alpha.7
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/NOTICE +7 -0
- package/README.md +34 -0
- package/TRADEMARKS.md +33 -0
- package/dist/index.d.ts +214 -45
- package/dist/index.js +1652 -244
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/NOTICE
CHANGED
|
@@ -7,3 +7,10 @@ This product includes software developed by the Oriel project
|
|
|
7
7
|
Oriel is licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
8
8
|
The Oriel name and logo are not covered by that license; see TRADEMARKS.md
|
|
9
9
|
(https://github.com/orieljs/framework/blob/main/TRADEMARKS.md).
|
|
10
|
+
|
|
11
|
+
@orieljs/support (and @orieljs/framework, which bundles it) includes transliteration data from
|
|
12
|
+
voku/portable-ascii (https://github.com/voku/portable-ascii), Copyright (C) 2019 Lars Moelleken, MIT License.
|
|
13
|
+
|
|
14
|
+
@orieljs/notifications (and @orieljs/framework, which bundles it) includes the HTML and CSS of
|
|
15
|
+
Laravel's default notification mail (laravel/framework, https://github.com/laravel/framework),
|
|
16
|
+
Copyright (c) Taylor Otwell, MIT License.
|
package/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# @orieljs/validation
|
|
2
|
+
|
|
3
|
+
Validation for Oriel: rules for incoming data, form requests and error messages, as Laravel's validation. It is part of `@orieljs/framework`, which every Oriel app already installs, and is re-exported from it. In an app, import it from `@orieljs/framework`; `@orieljs/validation` is also published on its own.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @orieljs/framework
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts title="app/Http/Requests/StorePostRequest.ts"
|
|
10
|
+
import { FormRequest, Rule } from '@orieljs/framework'
|
|
11
|
+
|
|
12
|
+
export class StorePostRequest extends FormRequest {
|
|
13
|
+
rules() {
|
|
14
|
+
return {
|
|
15
|
+
title: 'required|string|max:255',
|
|
16
|
+
slug: ['required', 'alpha_dash', Rule.unique('posts', 'slug')],
|
|
17
|
+
body: 'required|string',
|
|
18
|
+
published_at: 'nullable|date',
|
|
19
|
+
} as const
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
In a controller, `await StorePostRequest.validate()` runs `authorize()` and `rules()` and returns the validated data, typed from the rules: write `rules()` with `as const` and no return type (it may be `async`). A failure sends the user back with the errors and the old input, or answers 422 with JSON. `await request().validate(rules)` and `Validator.make(data, rules)` validate without a class, and `Rule.unique()`, `Rule.exists()`, `Rule.in()` and `Rule.password()` build rule objects.
|
|
25
|
+
|
|
26
|
+
Documentation: https://orieljs.vercel.app/docs/validation
|
|
27
|
+
|
|
28
|
+
Status: early alpha. APIs will change.
|
|
29
|
+
|
|
30
|
+
## License
|
|
31
|
+
|
|
32
|
+
Oriel is open-source software licensed under the Apache License 2.0 (Apache-2.0; see `LICENSE` and `NOTICE`). The Oriel name and logo are trademarks; see `TRADEMARKS.md`.
|
|
33
|
+
|
|
34
|
+
Website: https://orieljs.vercel.app
|
package/TRADEMARKS.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Oriel trademark policy
|
|
2
|
+
|
|
3
|
+
The Oriel code is open source under the Apache License 2.0. The **Oriel name and logo** are not: the license covers
|
|
4
|
+
the code only (section 6 of the license says so), and the name and logo stay with the project. This page explains
|
|
5
|
+
what you can and can't do with them. The goal is simple: people should always be able to tell what is the real Oriel
|
|
6
|
+
and what isn't.
|
|
7
|
+
|
|
8
|
+
## You can, without asking
|
|
9
|
+
|
|
10
|
+
- Use, change, ship and sell the code, as the license allows.
|
|
11
|
+
- Say that your app or package is "built with Oriel", "for Oriel" or "compatible with Oriel".
|
|
12
|
+
- Name a package `oriel-<something>` or `<something>-for-oriel` when it works with Oriel, as long as it is clear that
|
|
13
|
+
it is not official (for example, don't publish it under the `@orieljs` npm scope).
|
|
14
|
+
- Use the name and logo to write about Oriel, teach it, or link to it, in articles, talks, videos and courses.
|
|
15
|
+
- Use the unmodified logo to point to the project, as it is (no recolouring, cropping or
|
|
16
|
+
distortion).
|
|
17
|
+
|
|
18
|
+
## You can't, without written permission
|
|
19
|
+
|
|
20
|
+
- Call a fork, a modified copy or a competing product "Oriel", or anything likely to be confused with it.
|
|
21
|
+
- Use the name or logo as the name, logo or domain of your own product, company or service.
|
|
22
|
+
- Suggest that the Oriel project made, endorses or supports your work when it doesn't.
|
|
23
|
+
- Sell merchandise with the name or logo.
|
|
24
|
+
|
|
25
|
+
## Forks
|
|
26
|
+
|
|
27
|
+
Forks are welcome. Please give yours a different name and logo, keep the `LICENSE` and `NOTICE` files, and say that
|
|
28
|
+
it is based on Oriel.
|
|
29
|
+
|
|
30
|
+
## Questions
|
|
31
|
+
|
|
32
|
+
Open an issue at https://github.com/orieljs/framework or email meeeet.dev@gmail.com. If you're unsure whether a use
|
|
33
|
+
is fine, ask; the answer is usually yes.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { OrielError, ValidationError, Rules, MessageBag, ValidationRule, Validator as Validator$1, ValidationFactory, RuleCallback } from '@orieljs/contracts';
|
|
1
|
+
import { OrielError, ValidationError, Rules, InferValidatedType, MessageBag, ValidationRule, TypedValidationRule, RuleTyping, InValue, UploadedFile, Validator as Validator$1, ValidationFactory, RuleCallback } from '@orieljs/contracts';
|
|
2
|
+
export { InferRuleType, InferValidatedType } from '@orieljs/contracts';
|
|
2
3
|
import * as _orieljs_support from '@orieljs/support';
|
|
3
4
|
import { ServiceProvider } from '@orieljs/support';
|
|
4
5
|
|
|
@@ -41,34 +42,38 @@ declare class InvalidRuleParameterError extends Error implements OrielError {
|
|
|
41
42
|
constructor(rule: string, parameter: string, reason: string);
|
|
42
43
|
}
|
|
43
44
|
|
|
45
|
+
/** The data a FormRequest's validate() returns, typed from its rules(). */
|
|
46
|
+
type ValidatedData<F extends FormRequest> = InferValidatedType<Awaited<ReturnType<F['rules']>>>;
|
|
44
47
|
/**
|
|
45
48
|
* Mirrors Illuminate\Foundation\Http\FormRequest, minus dependency injection by type (Oriel resolves the current
|
|
46
49
|
* request and the ValidationFactory through inject(), never through constructor parameters — see spec §3 rule 5).
|
|
47
50
|
* A subclass only has to implement rules(); authorize()/messages()/attributes() default to Laravel's own defaults.
|
|
48
51
|
*/
|
|
49
52
|
declare abstract class FormRequest {
|
|
50
|
-
|
|
53
|
+
/** May be async, to await something first: `async rules() { const user = await request().user<User>() … }`. */
|
|
54
|
+
abstract rules(): Rules | Promise<Rules>;
|
|
51
55
|
authorize(): boolean | Promise<boolean>;
|
|
52
56
|
messages(): Record<string, string>;
|
|
53
57
|
attributes(): Record<string, string>;
|
|
54
58
|
/**
|
|
55
59
|
* `const data = await StorePostRequest.validate()` (spec §4.3). Resolves the current request and the
|
|
56
60
|
* ValidationFactory from the active container, runs authorize() first (throwing AuthorizationErrorImpl if it
|
|
57
|
-
* returns false), then validates request.all() against rules()/messages()/attributes() and returns the
|
|
58
|
-
*
|
|
61
|
+
* returns false), then validates request.all() against rules()/messages()/attributes() and returns the validated
|
|
62
|
+
* data (or throws the 422 ValidationError — see ValidatorImpl.validated()). The data is typed from rules(): write
|
|
63
|
+
* it without a return type and with `as const` (`return { title: 'required|string' } as const`), so its rule
|
|
64
|
+
* strings keep their text; a rules() typed `Rules` gives `Record<string, unknown>`.
|
|
59
65
|
*/
|
|
60
|
-
static validate<
|
|
66
|
+
static validate<F extends FormRequest>(this: new () => F): Promise<ValidatedData<F>>;
|
|
61
67
|
}
|
|
62
68
|
|
|
63
|
-
/** Humanizes a (possibly dotted) attribute key, e.g. "items.0.product_name" -> "items.0.product name". */
|
|
69
|
+
/** Humanizes a (possibly dotted) attribute key, e.g. "items.0.product_name" -> "items.0.product name" ("colors.*" stays). */
|
|
64
70
|
declare function defaultAttributeName(key: string): string;
|
|
65
71
|
declare function applyReplacements(template: string, replacements: Record<string, string>): string;
|
|
66
|
-
/** Laravel's English lang/en/validation.php, reproduced as closely as possible
|
|
72
|
+
/** Laravel's English lang/en/validation.php, reproduced as closely as possible. */
|
|
67
73
|
declare const DEFAULT_MESSAGES: Record<string, string>;
|
|
68
74
|
|
|
69
75
|
declare class MessageBagImpl implements MessageBag {
|
|
70
76
|
private readonly items;
|
|
71
|
-
/** Not part of the MessageBag contract — used internally by ValidatorImpl and by after() hooks. */
|
|
72
77
|
add(key: string, message: string): void;
|
|
73
78
|
has(key: string): boolean;
|
|
74
79
|
first(key?: string): string | undefined;
|
|
@@ -90,6 +95,17 @@ interface RuleContext {
|
|
|
90
95
|
data: Record<string, unknown>;
|
|
91
96
|
/** Every named rule attached to this field (for size-type resolution: numeric/array/file/string). */
|
|
92
97
|
ruleNames: string[];
|
|
98
|
+
/** The rule key as written, e.g. "items.*.email" (distinct reads every row of it). */
|
|
99
|
+
pattern?: string;
|
|
100
|
+
/**
|
|
101
|
+
* What the rules keep for one validation pass, such as every row a wildcard names: each pass starts with an empty
|
|
102
|
+
* one, so nothing outlives the data it was read from. Absent when a rule runs on its own.
|
|
103
|
+
*/
|
|
104
|
+
cache?: Map<string, unknown>;
|
|
105
|
+
/** The parameters of rule `name` on `field` (a concrete path), or undefined when that field has no such rule. */
|
|
106
|
+
getRule?(field: string, name: string): string[] | undefined;
|
|
107
|
+
/** How a message names `field`: its custom attribute, else the humanized key. */
|
|
108
|
+
displayName?(field: string): string;
|
|
93
109
|
}
|
|
94
110
|
interface BuiltinRule {
|
|
95
111
|
validate(ctx: RuleContext): boolean | Promise<boolean>;
|
|
@@ -103,6 +119,11 @@ interface BuiltinRule {
|
|
|
103
119
|
message?: string;
|
|
104
120
|
/** Runs even when the value is missing, blank, or null under nullable (the required* family, and accepted); a failure stops the field. */
|
|
105
121
|
implicit?: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* An exclude rule (`exclude`, `exclude_if`, …): it always runs, and when validate() returns false the field and its
|
|
124
|
+
* children are skipped from then on and left out of the validated data, with no message.
|
|
125
|
+
*/
|
|
126
|
+
excludes?: boolean;
|
|
106
127
|
}
|
|
107
128
|
type ParsedRule = {
|
|
108
129
|
kind: 'named';
|
|
@@ -112,8 +133,18 @@ type ParsedRule = {
|
|
|
112
133
|
kind: 'object';
|
|
113
134
|
rule: ValidationRule;
|
|
114
135
|
};
|
|
115
|
-
|
|
116
|
-
|
|
136
|
+
/**
|
|
137
|
+
* A rule object that stands for string rules (Rule.requiredIf(), Rule.when(), Rule.array(), …), as Laravel's
|
|
138
|
+
* ValidationRuleParser reads them: the rules expandRules() returns, given the data, take its place.
|
|
139
|
+
*/
|
|
140
|
+
interface ExpandingRule extends ValidationRule {
|
|
141
|
+
expandRules(data: Record<string, unknown>): string | ReadonlyArray<string | ValidationRule>;
|
|
142
|
+
}
|
|
143
|
+
declare function parseRuleSpec(spec: string | ReadonlyArray<string | ValidationRule>, data?: Record<string, unknown>): ParsedRule[];
|
|
144
|
+
/**
|
|
145
|
+
* Laravel's definition of "empty" for the required family (validateRequired()): null, undefined, text that is blank
|
|
146
|
+
* once trimmed, an empty array and an empty plain object (a JSON object is a PHP array). false and 0 are NOT empty.
|
|
147
|
+
*/
|
|
117
148
|
declare function isEmptyValue(value: unknown): boolean;
|
|
118
149
|
/** Duck-types Contracts/Http's UploadedFile without importing @orieljs/http. */
|
|
119
150
|
declare function isUploadedFileLike(value: unknown): value is {
|
|
@@ -126,8 +157,8 @@ declare function isUploadedFileLike(value: unknown): value is {
|
|
|
126
157
|
/**
|
|
127
158
|
* Expands a `*`-wildcard rule pattern (e.g. "items.*.name") into every concrete path present in `data`
|
|
128
159
|
* (e.g. ["items.0.name", "items.1.name"]). A pattern with no `*` is returned unchanged. A `*` segment whose
|
|
129
|
-
* container is missing, not an array and not a plain object expands to nothing for that branch
|
|
130
|
-
*
|
|
160
|
+
* container is missing, not an array and not a plain object expands to nothing for that branch, so every reported
|
|
161
|
+
* error is keyed by a concrete path, never the literal pattern. Object keys in UNSAFE_KEYS are
|
|
131
162
|
* treated as absent, so a JSON body like {"items":{"__proto__":{...}}} never yields a path through the prototype.
|
|
132
163
|
*/
|
|
133
164
|
declare function expandWildcardKeys(pattern: string, data: Record<string, unknown>): string[];
|
|
@@ -141,8 +172,14 @@ declare const builtinRules: Record<string, BuiltinRule>;
|
|
|
141
172
|
* Rule.password() returns the application default (PasswordRule.defaults()). (Laravel's uncompromised() is not
|
|
142
173
|
* ported: it calls an outside service.)
|
|
143
174
|
*/
|
|
144
|
-
declare class PasswordRule implements
|
|
175
|
+
declare class PasswordRule implements TypedValidationRule<{
|
|
176
|
+
value: string;
|
|
177
|
+
}> {
|
|
145
178
|
#private;
|
|
179
|
+
/** A passing value is a string (for the validated data's type); never set at run time. */
|
|
180
|
+
readonly __typing?: {
|
|
181
|
+
value: string;
|
|
182
|
+
};
|
|
146
183
|
constructor(min?: number);
|
|
147
184
|
/** A password rule of at least `size` characters: PasswordRule.min(12).mixedCase(). */
|
|
148
185
|
static min(size: number): PasswordRule;
|
|
@@ -162,7 +199,7 @@ declare class PasswordRule implements ValidationRule {
|
|
|
162
199
|
numbers(): this;
|
|
163
200
|
/** At least one symbol (punctuation, a symbol or a space). */
|
|
164
201
|
symbols(): this;
|
|
165
|
-
validate(
|
|
202
|
+
validate(_attribute: string, value: unknown, fail: (message: string) => void): void;
|
|
166
203
|
}
|
|
167
204
|
|
|
168
205
|
/**
|
|
@@ -171,16 +208,120 @@ declare class PasswordRule implements ValidationRule {
|
|
|
171
208
|
* ("email.unique", "items.*.email.unique", "unique"), custom attributes, then the default text. Called directly
|
|
172
209
|
* as a plain ValidationRule, validate() fails with the default English message.
|
|
173
210
|
*/
|
|
174
|
-
declare abstract class BuiltinRuleObject implements
|
|
211
|
+
declare abstract class BuiltinRuleObject<T extends RuleTyping = Record<never, never>> implements TypedValidationRule<T> {
|
|
175
212
|
abstract readonly ruleName: string;
|
|
176
|
-
|
|
213
|
+
/** What a passing value is, for the validated data's type (`T`); never set at run time. */
|
|
214
|
+
readonly __typing?: T;
|
|
215
|
+
/** `ruleNames`: the field's named rules, when it runs inside a Validator (`Rule.in()` reads `array`). */
|
|
216
|
+
abstract passes(attribute: string, value: unknown, data: Record<string, unknown>, expandedFromWildcard?: boolean, ruleNames?: readonly string[]): boolean | Promise<boolean>;
|
|
217
|
+
/** The parameters its message shows (`:values` of Rule.doesntContain()), as the string rule's would be. */
|
|
218
|
+
messageParameters(): string[];
|
|
177
219
|
validate(attribute: string, value: unknown, fail: (message: string) => void, data: Record<string, unknown>, expandedFromWildcard?: boolean): Promise<void>;
|
|
178
220
|
}
|
|
179
|
-
|
|
221
|
+
/**
|
|
222
|
+
* What `Rule.in(values)` lets through. A list the compiler only knows as `string[]` says nothing: any value whose text
|
|
223
|
+
* is listed passes (the number 1 for '1'), so `string` would be too narrow. A rule string known only as `string` is
|
|
224
|
+
* treated the same way.
|
|
225
|
+
*/
|
|
226
|
+
type InTyping<V> = string extends V ? Record<never, never> : {
|
|
227
|
+
value: InValue<V>;
|
|
228
|
+
each: InValue<V>;
|
|
229
|
+
};
|
|
230
|
+
declare class InRule<V> extends BuiltinRuleObject<InTyping<V>> {
|
|
180
231
|
private readonly values;
|
|
181
232
|
readonly ruleName = "in";
|
|
233
|
+
constructor(values: readonly V[]);
|
|
234
|
+
passes(_attribute: string, value: unknown, _data?: Record<string, unknown>, _expanded?: boolean, ruleNames?: readonly string[]): boolean;
|
|
235
|
+
}
|
|
236
|
+
declare class NotInRule extends BuiltinRuleObject {
|
|
237
|
+
private readonly values;
|
|
238
|
+
readonly ruleName = "not_in";
|
|
182
239
|
constructor(values: readonly unknown[]);
|
|
240
|
+
passes(_attribute: string, value: unknown, _data?: Record<string, unknown>, _expanded?: boolean, ruleNames?: readonly string[]): boolean;
|
|
241
|
+
}
|
|
242
|
+
/** A TypeScript enum, or an `as const` object of string and number values. */
|
|
243
|
+
type EnumLike = Record<string, string | number>;
|
|
244
|
+
/**
|
|
245
|
+
* Laravel's Rule::enum(): one of the enum's values; for a numeric enum, its number or exactly the text of it (a form
|
|
246
|
+
* sends text: `'1'`, not `'1.0'` or `'01'`). only() and except() narrow the values.
|
|
247
|
+
*/
|
|
248
|
+
declare class EnumRule<E extends EnumLike> extends BuiltinRuleObject<{
|
|
249
|
+
value: InValue<E[keyof E]>;
|
|
250
|
+
}> {
|
|
251
|
+
#private;
|
|
252
|
+
private readonly type;
|
|
253
|
+
readonly ruleName = "enum";
|
|
254
|
+
constructor(type: E);
|
|
255
|
+
only(values: E[keyof E] | ReadonlyArray<E[keyof E]>): this;
|
|
256
|
+
except(values: E[keyof E] | ReadonlyArray<E[keyof E]>): this;
|
|
257
|
+
passes(_attribute: string, value: unknown): boolean;
|
|
258
|
+
}
|
|
259
|
+
/** Laravel's Rule::contains() and Rule::doesntContain(): every value is an item of the array, or none is. */
|
|
260
|
+
declare class ContainsRule extends BuiltinRuleObject<{
|
|
261
|
+
value: unknown[];
|
|
262
|
+
}> {
|
|
263
|
+
readonly ruleName: 'contains' | 'doesnt_contain';
|
|
264
|
+
private readonly values;
|
|
265
|
+
constructor(ruleName: 'contains' | 'doesnt_contain', values: readonly unknown[]);
|
|
183
266
|
passes(_attribute: string, value: unknown): boolean;
|
|
267
|
+
messageParameters(): string[];
|
|
268
|
+
}
|
|
269
|
+
/** Rules for the field: a rule string, a list, or a callback given the data that returns one. */
|
|
270
|
+
type RuleSet = string | ReadonlyArray<string | ValidationRule> | ((data: Record<string, unknown>) => string | ReadonlyArray<string | ValidationRule>);
|
|
271
|
+
/**
|
|
272
|
+
* Base for the builders that stand for string rules (Laravel's RequiredIf, ConditionalRules, ArrayRule, Dimensions):
|
|
273
|
+
* the Validator puts the rules expandRules() returns in their place, so they run only inside a Validator.
|
|
274
|
+
*/
|
|
275
|
+
declare abstract class ExpandingRuleObject<T extends RuleTyping = Record<never, never>> implements ExpandingRule, TypedValidationRule<T> {
|
|
276
|
+
readonly __typing?: T;
|
|
277
|
+
abstract expandRules(data: Record<string, unknown>): string | ReadonlyArray<string | ValidationRule>;
|
|
278
|
+
validate(): never;
|
|
279
|
+
}
|
|
280
|
+
/** Rule.requiredIf(), Rule.excludeIf(), Rule.prohibitedIf(): the rule when the condition holds, else nothing. */
|
|
281
|
+
declare class ConditionalRule<T extends RuleTyping = Record<never, never>> extends ExpandingRuleObject<T> {
|
|
282
|
+
private readonly rule;
|
|
283
|
+
private readonly condition;
|
|
284
|
+
constructor(rule: 'required' | 'exclude' | 'prohibited', condition: boolean | (() => boolean));
|
|
285
|
+
expandRules(): string;
|
|
286
|
+
}
|
|
287
|
+
/** Laravel's ConditionalRules (Rule.when() and Rule.unless()): one set of rules or the other, chosen from the data. */
|
|
288
|
+
declare class ConditionalRules extends ExpandingRuleObject {
|
|
289
|
+
private readonly condition;
|
|
290
|
+
private readonly rules;
|
|
291
|
+
private readonly defaultRules;
|
|
292
|
+
private readonly negate;
|
|
293
|
+
constructor(condition: boolean | ((data: Record<string, unknown>) => boolean), rules: RuleSet, defaultRules: RuleSet, negate?: boolean);
|
|
294
|
+
expandRules(data: Record<string, unknown>): string | ReadonlyArray<string | ValidationRule>;
|
|
295
|
+
}
|
|
296
|
+
/** Laravel's Rule::array(): `array`, or `array:a,b` (an object whose keys are among those named). */
|
|
297
|
+
declare class ArrayRule<K extends string> extends ExpandingRuleObject<{
|
|
298
|
+
value: [K] extends [never] ? unknown[] : {
|
|
299
|
+
[P in K]?: unknown;
|
|
300
|
+
};
|
|
301
|
+
}> {
|
|
302
|
+
private readonly keys;
|
|
303
|
+
constructor(keys: readonly K[]);
|
|
304
|
+
expandRules(): string;
|
|
305
|
+
}
|
|
306
|
+
type DimensionConstraints = Partial<Record<'width' | 'height' | 'min_width' | 'min_height' | 'max_width' | 'max_height' | 'ratio', number>>;
|
|
307
|
+
/** Laravel's Rule::dimensions(): the dimensions rule, from an object or fluently (`.maxWidth(1000).ratio(3 / 2)`). */
|
|
308
|
+
declare class DimensionsRule extends ExpandingRuleObject<{
|
|
309
|
+
value: UploadedFile;
|
|
310
|
+
}> {
|
|
311
|
+
#private;
|
|
312
|
+
constructor(constraints: DimensionConstraints);
|
|
313
|
+
width(pixels: number): this;
|
|
314
|
+
height(pixels: number): this;
|
|
315
|
+
minWidth(pixels: number): this;
|
|
316
|
+
minHeight(pixels: number): this;
|
|
317
|
+
maxWidth(pixels: number): this;
|
|
318
|
+
maxHeight(pixels: number): this;
|
|
319
|
+
/** Width over height: `ratio(3 / 2)`. */
|
|
320
|
+
ratio(ratio: number): this;
|
|
321
|
+
/** `dimensions:max_width=1000,ratio=1.5`, Laravel's __toString(). */
|
|
322
|
+
toString(): string;
|
|
323
|
+
expandRules(): string;
|
|
324
|
+
private set;
|
|
184
325
|
}
|
|
185
326
|
declare class UniqueRule extends BuiltinRuleObject {
|
|
186
327
|
private readonly table;
|
|
@@ -208,34 +349,38 @@ declare class ExistsRule extends BuiltinRuleObject {
|
|
|
208
349
|
}
|
|
209
350
|
/** Fluent rule-object builders, for when a plain string rule can't express what's needed (e.g. .ignore()). */
|
|
210
351
|
declare const Rule: {
|
|
211
|
-
in:
|
|
352
|
+
/** One of `values`, compared as text (as `in:a,b`); typed as those values: `Rule.in(['draft', 'publish'])`. */
|
|
353
|
+
in: <const V extends readonly unknown[]>(values: V) => InRule<V[number]>;
|
|
354
|
+
/** None of `values`, compared as text (as `not_in:a,b`). */
|
|
355
|
+
notIn: (values: readonly unknown[]) => NotInRule;
|
|
356
|
+
/** One of a TypeScript enum's values (or an `as const` object's): `Rule.enum(Status)`, `.only([…])`, `.except([…])`. */
|
|
357
|
+
enum: <E extends EnumLike>(type: E) => EnumRule<E>;
|
|
358
|
+
/** An array holding every one of `values`. */
|
|
359
|
+
contains: (values: readonly unknown[]) => ContainsRule;
|
|
360
|
+
/** An array holding none of `values`. */
|
|
361
|
+
doesntContain: (values: readonly unknown[]) => ContainsRule;
|
|
362
|
+
/** `required` when the condition (or the callback) holds. */
|
|
363
|
+
requiredIf: (condition: boolean | (() => boolean)) => ConditionalRule;
|
|
364
|
+
/** `exclude` when the condition (or the callback) holds; the key is optional, as `exclude_if` makes it. */
|
|
365
|
+
excludeIf: (condition: boolean | (() => boolean)) => ConditionalRule<{
|
|
366
|
+
presence: "optional";
|
|
367
|
+
}>;
|
|
368
|
+
/** `prohibited` when the condition (or the callback) holds. */
|
|
369
|
+
prohibitedIf: (condition: boolean | (() => boolean)) => ConditionalRule;
|
|
370
|
+
/** `rules` when the condition (or the callback, given the data) holds, else `defaultRules`. */
|
|
371
|
+
when: (condition: boolean | ((data: Record<string, unknown>) => boolean), rules: RuleSet, defaultRules?: RuleSet) => ConditionalRules;
|
|
372
|
+
/** `rules` unless the condition (or the callback, given the data) holds, else `defaultRules`. */
|
|
373
|
+
unless: (condition: boolean | ((data: Record<string, unknown>) => boolean), rules: RuleSet, defaultRules?: RuleSet) => ConditionalRules;
|
|
374
|
+
/** `array`, or with keys `array:name,email` (an object whose keys are among those named). */
|
|
375
|
+
array: <const K extends string = never>(keys?: readonly K[]) => ArrayRule<K>;
|
|
376
|
+
/** The dimensions rule: `Rule.dimensions().maxWidth(1000).ratio(3 / 2)`, or `Rule.dimensions({ min_width: 100 })`. */
|
|
377
|
+
dimensions: (constraints?: DimensionConstraints) => DimensionsRule;
|
|
212
378
|
unique: (table: string, column?: string) => UniqueRule;
|
|
213
379
|
exists: (table: string, column?: string) => ExistsRule;
|
|
214
380
|
/** Laravel's Password::defaults(): the application's password rule (at least 8 characters unless PasswordRule.defaults() changed it). */
|
|
215
381
|
password: () => PasswordRule;
|
|
216
382
|
};
|
|
217
383
|
|
|
218
|
-
/** See Task 9's writeup in the plan for exactly what this does and doesn't infer. */
|
|
219
|
-
type SplitPipe<S extends string> = S extends `${infer Head}|${infer Tail}` ? Head | SplitPipe<Tail> : S;
|
|
220
|
-
type RuleName<T extends string> = T extends `${infer Name}:${string}` ? Name : T;
|
|
221
|
-
type Names<S extends string> = RuleName<SplitPipe<S>>;
|
|
222
|
-
type BaseType<S extends string> = 'array' extends Names<S> ? unknown[] : 'boolean' extends Names<S> ? boolean : 'integer' extends Names<S> ? number : 'numeric' extends Names<S> ? number : 'email' extends Names<S> ? string : 'url' extends Names<S> ? string : 'uuid' extends Names<S> ? string : 'date' extends Names<S> ? string : 'string' extends Names<S> ? string : unknown;
|
|
223
|
-
/**
|
|
224
|
-
* The inferred type for one rule string, e.g. 'nullable|integer' -> number | null. A non-literal `string` (a rules
|
|
225
|
-
* object declared without `as const`) carries no rule names to read, so it infers unknown: without this guard every
|
|
226
|
-
* `'x' extends string` check would match and the result would wrongly be `unknown[] | null`.
|
|
227
|
-
*/
|
|
228
|
-
type InferRuleType<S extends string> = string extends S ? unknown : 'nullable' extends Names<S> ? BaseType<S> | null : BaseType<S>;
|
|
229
|
-
/**
|
|
230
|
-
* Best-effort: applies InferRuleType to every string-valued rule; array-form (mixed string/object) rules -> unknown.
|
|
231
|
-
* Strips `readonly` (via `-readonly`) so a `Rules` object declared `as const` (the common way to get literal rule
|
|
232
|
-
* strings for inference — see the Task 9 type test) still produces a plain, mutable validated-data shape, not a
|
|
233
|
-
* readonly one; a mapped type otherwise carries the source's readonly modifier over by default.
|
|
234
|
-
*/
|
|
235
|
-
type InferValidatedType<R> = {
|
|
236
|
-
-readonly [K in keyof R]: R[K] extends string ? InferRuleType<R[K]> : unknown;
|
|
237
|
-
};
|
|
238
|
-
|
|
239
384
|
/**
|
|
240
385
|
* Runs each field's rules the way Laravel's Validator does:
|
|
241
386
|
* - a missing key, or a string that is blank after trimming, only runs implicit rules (the required* family and
|
|
@@ -245,7 +390,7 @@ type InferValidatedType<R> = {
|
|
|
245
390
|
* - `sometimes` skips a missing field entirely;
|
|
246
391
|
* - a field stops validating after its first failure under `bail`, or after any implicit rule fails.
|
|
247
392
|
*/
|
|
248
|
-
declare class ValidatorImpl implements Validator$1 {
|
|
393
|
+
declare class ValidatorImpl<R extends Rules = Rules> implements Validator$1<R> {
|
|
249
394
|
private readonly data;
|
|
250
395
|
private readonly rules;
|
|
251
396
|
private readonly customMessages;
|
|
@@ -255,16 +400,40 @@ declare class ValidatorImpl implements Validator$1 {
|
|
|
255
400
|
private bag;
|
|
256
401
|
private ranPromise;
|
|
257
402
|
private readonly afterCallbacks;
|
|
258
|
-
|
|
403
|
+
private parsedRules;
|
|
404
|
+
/** The fields an exclude rule took out (with their children). */
|
|
405
|
+
private readonly excluded;
|
|
406
|
+
/** The same fields as a tree of segment runs from the root, so a lookup reads the field once. */
|
|
407
|
+
private readonly excludedRuns;
|
|
408
|
+
/** What the rules keep while one pass runs (RuleContext.cache); a new pass starts with a new one. */
|
|
409
|
+
private cache;
|
|
410
|
+
constructor(data: Record<string, unknown>, rules: R, customMessages: Record<string, string>, customAttributes: Record<string, string>, registry: Record<string, BuiltinRule>, errorBagName?: string);
|
|
259
411
|
after(callback: (validator: Validator$1) => void | Promise<void>): this;
|
|
260
|
-
/**
|
|
412
|
+
/** Lets an after() hook add a failure. */
|
|
261
413
|
fail(field: string, message: string): void;
|
|
262
414
|
passes(): Promise<boolean>;
|
|
263
415
|
fails(): Promise<boolean>;
|
|
264
416
|
errors(): MessageBagImpl;
|
|
265
|
-
validated<T =
|
|
417
|
+
validated<T = InferValidatedType<R>>(): Promise<T>;
|
|
418
|
+
/** Takes the field (with its children) out of validation and of the validated data. */
|
|
419
|
+
private exclude;
|
|
420
|
+
/**
|
|
421
|
+
* Laravel's shouldBeExcluded(): the field, or one of its parents, was taken out by an exclude rule. The field's
|
|
422
|
+
* segments are followed from the root (so `user` takes out `user.name`, not `username`) and each is read once,
|
|
423
|
+
* however many fields were excluded and however many dots the field holds.
|
|
424
|
+
*/
|
|
425
|
+
private isExcluded;
|
|
266
426
|
private fieldsFor;
|
|
427
|
+
private parsed;
|
|
428
|
+
/** The rule key a concrete field falls under: itself, else the first wildcard key that matches it. */
|
|
429
|
+
private patternOf;
|
|
430
|
+
/** Laravel's getRule(): the parameters of rule `name` on `field`, or undefined when the field has no such rule. */
|
|
431
|
+
private ruleParameters;
|
|
432
|
+
/** Laravel's getDisplayableAttribute(): a custom attribute for the field or its rule key, else the humanized key. */
|
|
433
|
+
private displayName;
|
|
434
|
+
private context;
|
|
267
435
|
private run;
|
|
436
|
+
private passesExcludeRule;
|
|
268
437
|
private runRule;
|
|
269
438
|
/** Custom message (concrete field, then wildcard pattern, then rule name) or the default, with :attribute filled. */
|
|
270
439
|
private failureMessage;
|
|
@@ -272,7 +441,7 @@ declare class ValidatorImpl implements Validator$1 {
|
|
|
272
441
|
|
|
273
442
|
declare class ValidationFactoryImpl implements ValidationFactory {
|
|
274
443
|
private readonly extended;
|
|
275
|
-
make(data: Record<string, unknown>, rules:
|
|
444
|
+
make<const R extends Rules>(data: Record<string, unknown>, rules: R, messages?: Record<string, string>, attributes?: Record<string, string>): ValidatorImpl<R>;
|
|
276
445
|
extend(name: string, callback: RuleCallback, message?: string): void;
|
|
277
446
|
}
|
|
278
447
|
|
|
@@ -283,4 +452,4 @@ declare class ValidationServiceProvider extends ServiceProvider {
|
|
|
283
452
|
register(): void;
|
|
284
453
|
}
|
|
285
454
|
|
|
286
|
-
export { AuthorizationErrorImpl, type BuiltinRule, BuiltinRuleObject, DEFAULT_MESSAGES,
|
|
455
|
+
export { AuthorizationErrorImpl, type BuiltinRule, BuiltinRuleObject, DEFAULT_MESSAGES, type ExpandingRule, FormRequest, InvalidRuleParameterError, MessageBagImpl, type ParsedRule, PasswordRule, Rule, type RuleContext, UnknownValidationRuleError, ValidationErrorImpl, ValidationException, ValidationFactoryImpl, ValidationServiceProvider, Validator, ValidatorImpl, applyReplacements, builtinRules, defaultAttributeName, expandWildcardKeys, isEmptyValue, isUploadedFileLike, parseRuleSpec };
|