@h3ravel/validation 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +74 -0
- package/dist/env.d.ts +1 -0
- package/dist/index.cjs +648 -0
- package/dist/index.d.ts +340 -0
- package/dist/index.js +642 -0
- package/package.json +82 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
let simple_body_validator = require("simple-body-validator");
|
|
2
|
+
let __h3ravel_support = require("@h3ravel/support");
|
|
3
|
+
let __h3ravel_foundation = require("@h3ravel/foundation");
|
|
4
|
+
|
|
5
|
+
//#region src/ImplicitRule.ts
|
|
6
|
+
var ImplicitRule = class extends simple_body_validator.ImplicitRule {
|
|
7
|
+
rules = [];
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/Providers/ValidationServiceProvider.ts
|
|
12
|
+
/**
|
|
13
|
+
* Service provider for Validation utilities
|
|
14
|
+
*/
|
|
15
|
+
var ValidationServiceProvider = class {
|
|
16
|
+
registeredCommands;
|
|
17
|
+
static priority = 895;
|
|
18
|
+
constructor(app) {
|
|
19
|
+
this.app = app;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Register URL services in the container
|
|
23
|
+
*/
|
|
24
|
+
register() {}
|
|
25
|
+
/**
|
|
26
|
+
* Boot URL services
|
|
27
|
+
*/
|
|
28
|
+
boot() {}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/ValidationRule.ts
|
|
33
|
+
var ValidationRule = class extends simple_body_validator.Rule {
|
|
34
|
+
rules = [];
|
|
35
|
+
passing = false;
|
|
36
|
+
/**
|
|
37
|
+
* Set the data under validation.
|
|
38
|
+
*/
|
|
39
|
+
setData(_data) {
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
passes(value, attribute) {
|
|
43
|
+
this.passing = true;
|
|
44
|
+
this.validate(attribute, value, (message) => {
|
|
45
|
+
this.message = message;
|
|
46
|
+
this.passing = false;
|
|
47
|
+
});
|
|
48
|
+
return this.passing;
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/Rules/ExtendedRules.ts
|
|
54
|
+
var ExtendedRules = class extends ValidationRule {
|
|
55
|
+
/**
|
|
56
|
+
* The validator instance.
|
|
57
|
+
*/
|
|
58
|
+
validator;
|
|
59
|
+
setValidator(validator) {
|
|
60
|
+
this.validator = validator;
|
|
61
|
+
return this;
|
|
62
|
+
}
|
|
63
|
+
rules = [
|
|
64
|
+
{
|
|
65
|
+
name: "hex",
|
|
66
|
+
validator: (value) => {
|
|
67
|
+
if (typeof value !== "string") return false;
|
|
68
|
+
return /^[0-9a-fA-F]+$/.test(value.replace("#", ""));
|
|
69
|
+
},
|
|
70
|
+
message: "The :attribute must be a valid hexadecimal string."
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "includes",
|
|
74
|
+
validator: (value, parameters = []) => {
|
|
75
|
+
if (value == null) return false;
|
|
76
|
+
if (Array.isArray(value)) return parameters.some((param) => value.includes(param));
|
|
77
|
+
if (typeof value === "string") return parameters.some((param) => value.includes(param));
|
|
78
|
+
return false;
|
|
79
|
+
},
|
|
80
|
+
message: "The :attribute must include one of the following values: :values."
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "not_includes",
|
|
84
|
+
validator: (value, parameters = []) => {
|
|
85
|
+
if (value == null) return true;
|
|
86
|
+
if (Array.isArray(value)) return parameters.every((param) => !value.includes(param));
|
|
87
|
+
if (typeof value === "string") return parameters.every((param) => !value.includes(param));
|
|
88
|
+
return true;
|
|
89
|
+
},
|
|
90
|
+
message: "The :attribute must not include any of the following values: :values."
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "datetime",
|
|
94
|
+
validator: (value, parameters = [], attr) => {
|
|
95
|
+
if (typeof value !== "string") return false;
|
|
96
|
+
const [format] = parameters;
|
|
97
|
+
if (!format) return !isNaN(Date.parse(value));
|
|
98
|
+
try {
|
|
99
|
+
return new __h3ravel_support.DateTime(value, format, true).isValid();
|
|
100
|
+
} catch {
|
|
101
|
+
return !isNaN(Date.parse(value));
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
message: "The :attribute must be a valid date matching the format :format."
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "exists",
|
|
108
|
+
validator: async (value, parameters = []) => {
|
|
109
|
+
const [tab, column, ignore] = parameters;
|
|
110
|
+
try {
|
|
111
|
+
const { DB } = await import("@h3ravel/database");
|
|
112
|
+
const [conn, table] = tab.split(".");
|
|
113
|
+
const query = DB.instance(table && conn ? conn : "default").table(table && conn ? table : conn);
|
|
114
|
+
if (ignore) query.whereNot(column, ignore);
|
|
115
|
+
return await query.where(column, value).exists();
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
message: "The :attribute does not exist."
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "unique",
|
|
124
|
+
validator: async (value, parameters = []) => {
|
|
125
|
+
const [tab, column, ignore] = parameters;
|
|
126
|
+
try {
|
|
127
|
+
const { DB } = await import("@h3ravel/database");
|
|
128
|
+
const [conn, table] = tab.split(".");
|
|
129
|
+
const query = DB.instance(table && conn ? conn : "default").table(table && conn ? table : conn);
|
|
130
|
+
if (ignore) query.whereNot(column, ignore);
|
|
131
|
+
return !await query.where(column, value).exists();
|
|
132
|
+
} catch {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
message: "The :attribute does not exist."
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
validate() {}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/utilities/MessageBag.ts
|
|
144
|
+
var MessageBag = class {
|
|
145
|
+
/**
|
|
146
|
+
* All of the registered messages.
|
|
147
|
+
*/
|
|
148
|
+
messages = {};
|
|
149
|
+
/**
|
|
150
|
+
* Default format for message output.
|
|
151
|
+
*/
|
|
152
|
+
format = ":message";
|
|
153
|
+
/**
|
|
154
|
+
* Create a new message bag instance.
|
|
155
|
+
*/
|
|
156
|
+
constructor(messages = {}) {
|
|
157
|
+
for (const [key, value] of Object.entries(messages)) {
|
|
158
|
+
const arr = Array.isArray(value) ? value : [value];
|
|
159
|
+
this.messages[key] = Array.from(new Set(arr));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get all message keys.
|
|
164
|
+
*/
|
|
165
|
+
keys() {
|
|
166
|
+
return Object.keys(this.messages);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Add a message.
|
|
170
|
+
*/
|
|
171
|
+
add(key, message) {
|
|
172
|
+
if (this.isUnique(key, message)) {
|
|
173
|
+
if (!this.messages[key]) this.messages[key] = [];
|
|
174
|
+
this.messages[key].push(message);
|
|
175
|
+
}
|
|
176
|
+
return this;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Add a message conditionally.
|
|
180
|
+
*/
|
|
181
|
+
addIf(condition, key, message) {
|
|
182
|
+
return condition ? this.add(key, message) : this;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check uniqueness of key/message pair.
|
|
186
|
+
*/
|
|
187
|
+
isUnique(key, message) {
|
|
188
|
+
return !this.messages[key] || !this.messages[key].includes(message);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Merge another message source into this one.
|
|
192
|
+
*/
|
|
193
|
+
merge(messages) {
|
|
194
|
+
const incoming = messages.getMessageBag?.()?.getMessages?.() ?? messages;
|
|
195
|
+
for (const [key, list] of Object.entries(incoming)) {
|
|
196
|
+
if (!this.messages[key]) this.messages[key] = [];
|
|
197
|
+
this.messages[key].push(...list);
|
|
198
|
+
this.messages[key] = Array.from(new Set(this.messages[key]));
|
|
199
|
+
}
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Determine if messages exist for all given keys.
|
|
204
|
+
*/
|
|
205
|
+
has(key) {
|
|
206
|
+
if (this.isEmpty()) return false;
|
|
207
|
+
if (key == null) return this.any();
|
|
208
|
+
return (Array.isArray(key) ? key : [key]).every((k) => this.first(k) !== "");
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Determine if messages exist for any given key.
|
|
212
|
+
*/
|
|
213
|
+
hasAny(keys = []) {
|
|
214
|
+
if (this.isEmpty()) return false;
|
|
215
|
+
return (Array.isArray(keys) ? keys : [keys]).some((k) => this.has(k));
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Determine if messages don't exist for given keys.
|
|
219
|
+
*/
|
|
220
|
+
missing(key) {
|
|
221
|
+
const keys = Array.isArray(key) ? key : [key];
|
|
222
|
+
return !this.hasAny(keys);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Get the first message for a given key.
|
|
226
|
+
*/
|
|
227
|
+
first(key = null, format = null) {
|
|
228
|
+
const messages = key == null ? this.all(format) : this.get(key, format);
|
|
229
|
+
const firstMessage = Array.isArray(messages) ? messages[0] ?? "" : "";
|
|
230
|
+
return Array.isArray(firstMessage) ? firstMessage[0] ?? "" : firstMessage;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get all messages for a given key.
|
|
234
|
+
*/
|
|
235
|
+
get(key, format = null) {
|
|
236
|
+
if (this.messages[key]) return this.transform(this.messages[key], this.checkFormat(format), key);
|
|
237
|
+
if (key.includes("*")) return this.getMessagesForWildcardKey(key, format);
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Wildcard key match.
|
|
242
|
+
*/
|
|
243
|
+
getMessagesForWildcardKey(key, format) {
|
|
244
|
+
const regex = /* @__PURE__ */ new RegExp("^" + key.replace(/\*/g, ".*") + "$");
|
|
245
|
+
const result = {};
|
|
246
|
+
for (const [messageKey, messages] of Object.entries(this.messages)) if (regex.test(messageKey)) result[messageKey] = this.transform(messages, this.checkFormat(format), messageKey);
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Get all messages.
|
|
251
|
+
*/
|
|
252
|
+
all(format = null) {
|
|
253
|
+
const fmt = this.checkFormat(format);
|
|
254
|
+
const all = [];
|
|
255
|
+
for (const [key, messages] of Object.entries(this.messages)) all.push(...this.transform(messages, fmt, key));
|
|
256
|
+
return all;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Get unique messages.
|
|
260
|
+
*/
|
|
261
|
+
unique(format = null) {
|
|
262
|
+
return Array.from(new Set(this.all(format)));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Remove messages for a key.
|
|
266
|
+
*/
|
|
267
|
+
forget(key) {
|
|
268
|
+
delete this.messages[key];
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Format an array of messages.
|
|
273
|
+
*/
|
|
274
|
+
transform(messages, format, messageKey) {
|
|
275
|
+
if (format === ":message") return messages;
|
|
276
|
+
return messages.map((m) => format.replace(":message", m).replace(":key", messageKey));
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get proper format string.
|
|
280
|
+
*/
|
|
281
|
+
checkFormat(format) {
|
|
282
|
+
return format || this.format;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Get raw messages.
|
|
286
|
+
*/
|
|
287
|
+
messagesRaw() {
|
|
288
|
+
return this.messages;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Alias for messagesRaw().
|
|
292
|
+
*/
|
|
293
|
+
getMessages() {
|
|
294
|
+
return this.messagesRaw();
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Return message bag instance.
|
|
298
|
+
*/
|
|
299
|
+
getMessageBag() {
|
|
300
|
+
return this;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Get format string.
|
|
304
|
+
*/
|
|
305
|
+
getFormat() {
|
|
306
|
+
return this.format;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Set default message format.
|
|
310
|
+
*/
|
|
311
|
+
setFormat(format = ":message") {
|
|
312
|
+
this.format = format;
|
|
313
|
+
return this;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Empty checks.
|
|
317
|
+
*/
|
|
318
|
+
isEmpty() {
|
|
319
|
+
return !this.any();
|
|
320
|
+
}
|
|
321
|
+
isNotEmpty() {
|
|
322
|
+
return this.any();
|
|
323
|
+
}
|
|
324
|
+
any() {
|
|
325
|
+
return this.count() > 0;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Count total messages.
|
|
329
|
+
*/
|
|
330
|
+
count() {
|
|
331
|
+
return Object.values(this.messages).reduce((sum, list) => sum + list.length, 0);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Array & JSON conversions.
|
|
335
|
+
*/
|
|
336
|
+
toArray() {
|
|
337
|
+
return this.getMessages();
|
|
338
|
+
}
|
|
339
|
+
jsonSerialize() {
|
|
340
|
+
return this.toArray();
|
|
341
|
+
}
|
|
342
|
+
toJson(options = 0) {
|
|
343
|
+
return JSON.stringify(this.jsonSerialize(), null, options ? 2 : void 0);
|
|
344
|
+
}
|
|
345
|
+
toPrettyJson() {
|
|
346
|
+
return JSON.stringify(this.jsonSerialize(), null, 2);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* String representation.
|
|
350
|
+
*/
|
|
351
|
+
toString() {
|
|
352
|
+
return this.toJson();
|
|
353
|
+
}
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
//#endregion
|
|
357
|
+
//#region src/Validator.ts
|
|
358
|
+
(0, simple_body_validator.register)("telephone", function(value) {
|
|
359
|
+
return /^\d{3}-\d{3}-\d{4}$/.test(value);
|
|
360
|
+
});
|
|
361
|
+
var Validator = class Validator {
|
|
362
|
+
#messages;
|
|
363
|
+
#after = [];
|
|
364
|
+
data;
|
|
365
|
+
rules;
|
|
366
|
+
_errors;
|
|
367
|
+
passing = false;
|
|
368
|
+
executed = false;
|
|
369
|
+
instance;
|
|
370
|
+
errorBagName = "default";
|
|
371
|
+
registeredCustomRules = [new ExtendedRules()];
|
|
372
|
+
shouldStopOnFirstFailure = false;
|
|
373
|
+
constructor(data, rules, messages = {}) {
|
|
374
|
+
this.data = data;
|
|
375
|
+
this.rules = rules;
|
|
376
|
+
this.#messages = messages;
|
|
377
|
+
this._errors = new MessageBag();
|
|
378
|
+
this.bindServices();
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Validate the data and return the instance
|
|
382
|
+
*/
|
|
383
|
+
static make(data, rules, messages = {}) {
|
|
384
|
+
return new Validator(data, rules, messages);
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Run the validator and store results.
|
|
388
|
+
*/
|
|
389
|
+
async passes() {
|
|
390
|
+
if (this.executed) return this._errors.isEmpty();
|
|
391
|
+
const exec = await this.execute();
|
|
392
|
+
for (const after of this.#after) after();
|
|
393
|
+
return exec.passing;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Opposite of passes()
|
|
397
|
+
*/
|
|
398
|
+
async fails() {
|
|
399
|
+
return !await this.passes();
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Throw if validation fails, else return executed data
|
|
403
|
+
*
|
|
404
|
+
* @throws ValidationException if validation fails
|
|
405
|
+
*/
|
|
406
|
+
async validate() {
|
|
407
|
+
if (!await this.passes()) throw new ValidationException(this, JSON.stringify(this._errors.toArray()));
|
|
408
|
+
return this.validatedData();
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Run the validator's rules against its data.
|
|
412
|
+
* @param bagName
|
|
413
|
+
* @returns
|
|
414
|
+
*/
|
|
415
|
+
async validateWithBag(bagName) {
|
|
416
|
+
this.errorBagName = bagName;
|
|
417
|
+
return this.validate();
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Stop validation on first failure.
|
|
421
|
+
*/
|
|
422
|
+
stopOnFirstFailure() {
|
|
423
|
+
this.shouldStopOnFirstFailure = true;
|
|
424
|
+
return this;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Get the data that passed validation.
|
|
428
|
+
*/
|
|
429
|
+
validatedData() {
|
|
430
|
+
const validKeys = Object.keys(this.rules);
|
|
431
|
+
const clean = {};
|
|
432
|
+
for (const key of validKeys) if (this.data[key] !== void 0) clean[key] = this.data[key];
|
|
433
|
+
return clean;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Return all validated input.
|
|
437
|
+
*/
|
|
438
|
+
validated() {
|
|
439
|
+
return Object.fromEntries(Object.entries(this.data).filter(([key]) => key in this.rules));
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Return a portion of validated input
|
|
443
|
+
*/
|
|
444
|
+
safe() {
|
|
445
|
+
const validated = this.validated();
|
|
446
|
+
return {
|
|
447
|
+
only: (keys) => Object.fromEntries(Object.entries(validated).filter(([key]) => keys.includes(key))),
|
|
448
|
+
except: (keys) => Object.fromEntries(Object.entries(validated).filter(([key]) => !keys.includes(key)))
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Get the message container for the validator.
|
|
453
|
+
*/
|
|
454
|
+
async messages() {
|
|
455
|
+
if (!this.#messages) await this.passes();
|
|
456
|
+
return this.#messages;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Add an after validation callback.
|
|
460
|
+
*
|
|
461
|
+
* @param callback
|
|
462
|
+
*/
|
|
463
|
+
after(callback) {
|
|
464
|
+
if (Array.isArray(callback)) for (const rule of callback) this.#after.push(() => rule.toString().startsWith("class") ? new rule(this) : rule(this));
|
|
465
|
+
else if (typeof callback === "function") this.#after.push(() => callback(this));
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Get all errors.
|
|
470
|
+
*/
|
|
471
|
+
errors() {
|
|
472
|
+
return this._errors;
|
|
473
|
+
}
|
|
474
|
+
errorBag() {
|
|
475
|
+
return this.errorBagName;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Reset validator with new data.
|
|
479
|
+
*/
|
|
480
|
+
setData(data) {
|
|
481
|
+
this.data = data;
|
|
482
|
+
this.executed = false;
|
|
483
|
+
return this;
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Set validation rules.
|
|
487
|
+
*/
|
|
488
|
+
setRules(rules) {
|
|
489
|
+
this.rules = rules;
|
|
490
|
+
this.executed = false;
|
|
491
|
+
return this;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Add a single rule to existing rules.
|
|
495
|
+
*/
|
|
496
|
+
addRule(key, rule) {
|
|
497
|
+
this.rules[key] = rule;
|
|
498
|
+
return this;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Merge additional rules.
|
|
502
|
+
*/
|
|
503
|
+
mergeRules(rules) {
|
|
504
|
+
this.rules = {
|
|
505
|
+
...this.rules,
|
|
506
|
+
...rules
|
|
507
|
+
};
|
|
508
|
+
return this;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Get current data.
|
|
512
|
+
*/
|
|
513
|
+
getData() {
|
|
514
|
+
return this.data;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Get current rules.
|
|
518
|
+
*/
|
|
519
|
+
getRules() {
|
|
520
|
+
return this.rules;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Bind all required services here.
|
|
524
|
+
*/
|
|
525
|
+
bindServices() {
|
|
526
|
+
/**
|
|
527
|
+
* Register all custom rules
|
|
528
|
+
*/
|
|
529
|
+
for (const reged of this.registeredCustomRules) if (reged instanceof ValidationRule) {
|
|
530
|
+
if (reged.setData) reged.setData(this.data);
|
|
531
|
+
if (reged.setValidator) reged.setValidator(this);
|
|
532
|
+
for (const rule of reged.rules) {
|
|
533
|
+
(0, simple_body_validator.register)(rule.name, rule.validator);
|
|
534
|
+
if (rule.message) (0, simple_body_validator.setTranslationObject)({ en: { [rule.name]: rule.message } });
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
return this;
|
|
538
|
+
}
|
|
539
|
+
async execute() {
|
|
540
|
+
const instance = (0, simple_body_validator.make)().setData(this.data).setRules(this.rules).setCustomMessages(this.#messages).stopOnFirstFailure(this.shouldStopOnFirstFailure);
|
|
541
|
+
this.passing = await instance.validateAsync();
|
|
542
|
+
this.executed = true;
|
|
543
|
+
this.instance = instance;
|
|
544
|
+
if (!this.passing) this._errors = new MessageBag(instance.errors().all());
|
|
545
|
+
return this;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
549
|
+
//#endregion
|
|
550
|
+
//#region src/ValidationException.ts
|
|
551
|
+
var ValidationException = class ValidationException extends __h3ravel_foundation.UnprocessableEntityHttpException {
|
|
552
|
+
validator;
|
|
553
|
+
response;
|
|
554
|
+
status = 422;
|
|
555
|
+
errorBag = "default";
|
|
556
|
+
redirectTo;
|
|
557
|
+
constructor(validator, response$1 = null, errorBag = "default") {
|
|
558
|
+
super(ValidationException.summarize(validator));
|
|
559
|
+
this.name = "ValidationException";
|
|
560
|
+
this.validator = validator;
|
|
561
|
+
this.response = response$1;
|
|
562
|
+
this.errorBag = errorBag;
|
|
563
|
+
Object.setPrototypeOf(this, ValidationException.prototype);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Send a custom response body for this exception
|
|
567
|
+
*
|
|
568
|
+
* @param request
|
|
569
|
+
* @returns
|
|
570
|
+
*/
|
|
571
|
+
toResponse(request) {
|
|
572
|
+
if (!request.expectsJson()) {
|
|
573
|
+
session().flash("_errors", this.errors());
|
|
574
|
+
session().flash("_old", request.all());
|
|
575
|
+
return response().setCharset("utf-8").redirect(request.getHeader("referer") || "/", 302);
|
|
576
|
+
}
|
|
577
|
+
return {
|
|
578
|
+
message: this.message,
|
|
579
|
+
errors: this.errors()
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Create a new validation exception from a plain array of messages.
|
|
584
|
+
*/
|
|
585
|
+
static withMessages(messages) {
|
|
586
|
+
const validator = new Validator({}, {});
|
|
587
|
+
const bag = new MessageBag();
|
|
588
|
+
for (const [key, value] of Object.entries(messages)) {
|
|
589
|
+
const list = Array.isArray(value) ? value : [value];
|
|
590
|
+
for (const message of list) bag.add(key, message);
|
|
591
|
+
}
|
|
592
|
+
validator._errors = bag;
|
|
593
|
+
return new ValidationException(validator);
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Create a readable summary message from the validation errors.
|
|
597
|
+
*/
|
|
598
|
+
static summarize(validator) {
|
|
599
|
+
const messages = validator.errors().all();
|
|
600
|
+
if (!messages.length || typeof messages[0] !== "string") return "The given data was invalid.";
|
|
601
|
+
let message = messages.shift();
|
|
602
|
+
const count = messages.length;
|
|
603
|
+
if (count > 0) message += ` (and ${count} more ${__h3ravel_support.Str.plural("error", count)})`;
|
|
604
|
+
return message;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Get all of the validation error messages.
|
|
608
|
+
*/
|
|
609
|
+
errors() {
|
|
610
|
+
return this.validator.errors().getMessages();
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Set the HTTP status code to be used for the response.
|
|
614
|
+
*/
|
|
615
|
+
setStatus(status) {
|
|
616
|
+
this.status = status;
|
|
617
|
+
return this;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Set the error bag on the exception.
|
|
621
|
+
*/
|
|
622
|
+
setErrorBag(errorBag) {
|
|
623
|
+
this.errorBag = errorBag;
|
|
624
|
+
return this;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Set the URL to redirect to on a validation error.
|
|
628
|
+
*/
|
|
629
|
+
setRedirectTo(url) {
|
|
630
|
+
this.redirectTo = url;
|
|
631
|
+
return this;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Get the underlying response instance.
|
|
635
|
+
*/
|
|
636
|
+
getResponse() {
|
|
637
|
+
return this.response;
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
|
|
641
|
+
//#endregion
|
|
642
|
+
exports.ExtendedRules = ExtendedRules;
|
|
643
|
+
exports.ImplicitRule = ImplicitRule;
|
|
644
|
+
exports.MessageBag = MessageBag;
|
|
645
|
+
exports.ValidationException = ValidationException;
|
|
646
|
+
exports.ValidationRule = ValidationRule;
|
|
647
|
+
exports.ValidationServiceProvider = ValidationServiceProvider;
|
|
648
|
+
exports.Validator = Validator;
|