@regle/rules 1.2.2 → 1.3.0-beta.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/README.md +13 -11
- package/dist/regle-rules.d.ts +209 -104
- package/dist/regle-rules.js +1210 -0
- package/dist/regle-rules.min.js +1 -0
- package/package.json +13 -13
- package/dist/regle-rules.min.mjs +0 -1
- package/dist/regle-rules.mjs +0 -1056
|
@@ -0,0 +1,1210 @@
|
|
|
1
|
+
import { InternalRuleType, createRule, unwrapRuleParameters } from "@regle/core";
|
|
2
|
+
import { computed, toValue, unref } from "vue";
|
|
3
|
+
|
|
4
|
+
//#region src/helpers/withMessage.ts
|
|
5
|
+
function withMessage(rule, newMessage) {
|
|
6
|
+
let _type;
|
|
7
|
+
let validator;
|
|
8
|
+
let _active;
|
|
9
|
+
let _params;
|
|
10
|
+
if (typeof rule === "function" && !("_validator" in rule)) {
|
|
11
|
+
_type = InternalRuleType.Inline;
|
|
12
|
+
validator = rule;
|
|
13
|
+
} else ({_type, validator, _active, _params} = rule);
|
|
14
|
+
const newRule = createRule({
|
|
15
|
+
type: _type,
|
|
16
|
+
validator,
|
|
17
|
+
active: _active,
|
|
18
|
+
message: newMessage
|
|
19
|
+
});
|
|
20
|
+
const newParams = [..._params ?? []];
|
|
21
|
+
newRule._params = newParams;
|
|
22
|
+
newRule._message_patched = true;
|
|
23
|
+
if (typeof newRule === "function") {
|
|
24
|
+
if (_params != null) {
|
|
25
|
+
const executedRule = newRule(...newParams);
|
|
26
|
+
executedRule._message_patched = true;
|
|
27
|
+
return executedRule;
|
|
28
|
+
}
|
|
29
|
+
return newRule;
|
|
30
|
+
} else return newRule;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/helpers/withTooltip.ts
|
|
35
|
+
function withTooltip(rule, newTooltip) {
|
|
36
|
+
let _type;
|
|
37
|
+
let validator;
|
|
38
|
+
let _active;
|
|
39
|
+
let _params;
|
|
40
|
+
let _message;
|
|
41
|
+
if (typeof rule === "function" && !("_validator" in rule)) {
|
|
42
|
+
_type = InternalRuleType.Inline;
|
|
43
|
+
validator = rule;
|
|
44
|
+
} else ({_type, validator, _active, _params, _message} = rule);
|
|
45
|
+
const newRule = createRule({
|
|
46
|
+
type: _type,
|
|
47
|
+
validator,
|
|
48
|
+
active: _active,
|
|
49
|
+
message: _message,
|
|
50
|
+
tooltip: newTooltip
|
|
51
|
+
});
|
|
52
|
+
const newParams = [..._params ?? []];
|
|
53
|
+
newRule._params = newParams;
|
|
54
|
+
newRule._tooltip_patched = true;
|
|
55
|
+
if (typeof newRule === "function") {
|
|
56
|
+
const executedRule = newRule(...newParams);
|
|
57
|
+
newRule._tooltip_patched = true;
|
|
58
|
+
return executedRule;
|
|
59
|
+
} else return newRule;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region src/helpers/withAsync.ts
|
|
64
|
+
function withAsync(rule, depsArray) {
|
|
65
|
+
let _type;
|
|
66
|
+
let validator;
|
|
67
|
+
let _params = [];
|
|
68
|
+
let _message = "";
|
|
69
|
+
if (typeof rule === "function") {
|
|
70
|
+
_type = InternalRuleType.Inline;
|
|
71
|
+
validator = async (value, ...params) => {
|
|
72
|
+
return rule(value, ...params);
|
|
73
|
+
};
|
|
74
|
+
_params = [depsArray];
|
|
75
|
+
} else {
|
|
76
|
+
({_type, _message} = rule);
|
|
77
|
+
_params = _params = rule._params?.concat(depsArray);
|
|
78
|
+
validator = async (...args) => rule.validator(args);
|
|
79
|
+
}
|
|
80
|
+
const newRule = createRule({
|
|
81
|
+
type: InternalRuleType.Async,
|
|
82
|
+
validator,
|
|
83
|
+
message: _message
|
|
84
|
+
});
|
|
85
|
+
newRule._params = newRule._params?.concat(_params);
|
|
86
|
+
return newRule(...depsArray ?? []);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
//#endregion
|
|
90
|
+
//#region src/helpers/withParams.ts
|
|
91
|
+
function withParams(rule, depsArray) {
|
|
92
|
+
let _type;
|
|
93
|
+
let validator;
|
|
94
|
+
let _params = [];
|
|
95
|
+
let _message = "";
|
|
96
|
+
if (typeof rule === "function") {
|
|
97
|
+
_type = InternalRuleType.Inline;
|
|
98
|
+
validator = (value, ...params) => {
|
|
99
|
+
return rule(value, ...params);
|
|
100
|
+
};
|
|
101
|
+
_params = [depsArray];
|
|
102
|
+
} else {
|
|
103
|
+
({_type, validator, _message} = rule);
|
|
104
|
+
_params = _params = rule._params?.concat(depsArray);
|
|
105
|
+
}
|
|
106
|
+
const newRule = createRule({
|
|
107
|
+
type: InternalRuleType.Inline,
|
|
108
|
+
validator,
|
|
109
|
+
message: _message
|
|
110
|
+
});
|
|
111
|
+
newRule._params = newRule._params?.concat(_params);
|
|
112
|
+
return newRule(...depsArray);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/helpers/applyIf.ts
|
|
117
|
+
/**
|
|
118
|
+
* The applyIf operator is similar to requiredIf, but it can be used with any rule. It simplifies conditional rule declarations.
|
|
119
|
+
*/
|
|
120
|
+
function applyIf(_condition, rule) {
|
|
121
|
+
let _type;
|
|
122
|
+
let validator;
|
|
123
|
+
let _params = [];
|
|
124
|
+
let _message = "";
|
|
125
|
+
if (typeof rule === "function") {
|
|
126
|
+
_type = InternalRuleType.Inline;
|
|
127
|
+
validator = rule;
|
|
128
|
+
_params = [_condition];
|
|
129
|
+
} else {
|
|
130
|
+
({_type, validator, _message} = rule);
|
|
131
|
+
_params = rule._params?.concat([_condition]);
|
|
132
|
+
}
|
|
133
|
+
function newValidator(value, ...args) {
|
|
134
|
+
const [condition] = unwrapRuleParameters([_condition]);
|
|
135
|
+
if (condition) return validator(value, ...args);
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
function newActive(metadata) {
|
|
139
|
+
const [condition] = unwrapRuleParameters([_condition]);
|
|
140
|
+
return condition;
|
|
141
|
+
}
|
|
142
|
+
const newRule = createRule({
|
|
143
|
+
type: _type,
|
|
144
|
+
validator: newValidator,
|
|
145
|
+
active: newActive,
|
|
146
|
+
message: _message
|
|
147
|
+
});
|
|
148
|
+
const newParams = [..._params ?? []];
|
|
149
|
+
newRule._params = newParams;
|
|
150
|
+
if (typeof newRule === "function") {
|
|
151
|
+
const executedRule = newRule(...newParams);
|
|
152
|
+
return executedRule;
|
|
153
|
+
} else return newRule;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region ../shared/utils/isFile.ts
|
|
158
|
+
/**
|
|
159
|
+
* Server side friendly way of checking for a File
|
|
160
|
+
*/
|
|
161
|
+
function isFile(value) {
|
|
162
|
+
return value?.constructor.name == "File" || value?.constructor.name == "FileList";
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
//#endregion
|
|
166
|
+
//#region ../shared/utils/isEmpty.ts
|
|
167
|
+
/**
|
|
168
|
+
* This is the inverse of isFilled. It will check if the value is in any way empty (including arrays and objects)
|
|
169
|
+
*
|
|
170
|
+
* isEmpty also acts as a type guard.
|
|
171
|
+
*
|
|
172
|
+
* @param value - the target value
|
|
173
|
+
* @param [considerEmptyArrayInvalid=true] - will return false if set to `false`. (default: `true`)
|
|
174
|
+
*/
|
|
175
|
+
function isEmpty(value, considerEmptyArrayInvalid = true) {
|
|
176
|
+
if (value === void 0 || value === null) return true;
|
|
177
|
+
if (value instanceof Date) return isNaN(value.getTime());
|
|
178
|
+
else if (isFile(value)) return value.size <= 0;
|
|
179
|
+
else if (Array.isArray(value)) {
|
|
180
|
+
if (considerEmptyArrayInvalid) return value.length === 0;
|
|
181
|
+
return false;
|
|
182
|
+
} else if (typeof value === "object" && value != null) return Object.keys(value).length === 0;
|
|
183
|
+
return !String(value).length;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
//#endregion
|
|
187
|
+
//#region ../shared/utils/symbol.ts
|
|
188
|
+
const RegleRuleSymbol = Symbol("regle-rule");
|
|
189
|
+
|
|
190
|
+
//#endregion
|
|
191
|
+
//#region ../shared/utils/isDate.ts
|
|
192
|
+
/**
|
|
193
|
+
* This is a useful helper that can check if the provided value is a Date, it is used internally for date rules. This can also check strings.
|
|
194
|
+
*/
|
|
195
|
+
function isDate(value) {
|
|
196
|
+
if (isEmpty(value)) return false;
|
|
197
|
+
try {
|
|
198
|
+
let possibleDate = null;
|
|
199
|
+
if (value instanceof Date) possibleDate = value;
|
|
200
|
+
else if (typeof value === "string") {
|
|
201
|
+
const date$1 = new Date(value);
|
|
202
|
+
if (date$1.toString() === "Invalid Date") return false;
|
|
203
|
+
possibleDate = date$1;
|
|
204
|
+
}
|
|
205
|
+
return !!possibleDate;
|
|
206
|
+
} catch (e) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region ../shared/utils/toDate.ts
|
|
213
|
+
/**
|
|
214
|
+
* This utility will coerce any string, number or Date value into a Date using the Date constructor.
|
|
215
|
+
*/
|
|
216
|
+
function toDate(argument) {
|
|
217
|
+
const argStr = Object.prototype.toString.call(argument);
|
|
218
|
+
if (argument == null) return new Date(NaN);
|
|
219
|
+
else if (argument instanceof Date || typeof argument === "object" && argStr === "[object Date]") return new Date(argument.getTime());
|
|
220
|
+
else if (typeof argument === "number" || argStr === "[object Number]") return new Date(argument);
|
|
221
|
+
else if (typeof argument === "string" || argStr === "[object String]") return new Date(argument);
|
|
222
|
+
else return new Date(NaN);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/helpers/ruleHelpers/isFilled.ts
|
|
227
|
+
/**
|
|
228
|
+
* This is almost a must have for optional fields. It checks if any value you provided is defined (including arrays and objects). You can base your validator result on this.
|
|
229
|
+
*
|
|
230
|
+
* isFilled also acts as a type guard.
|
|
231
|
+
*
|
|
232
|
+
* @param value - the target value
|
|
233
|
+
* @param [considerEmptyArrayInvalid=true] - will return true if set to `false`. (default: `true`)
|
|
234
|
+
*/
|
|
235
|
+
function isFilled(value, considerEmptyArrayInvalid = true) {
|
|
236
|
+
return !isEmpty(typeof value === "string" ? value.trim() : value, considerEmptyArrayInvalid);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/helpers/ruleHelpers/isNumber.ts
|
|
241
|
+
/**
|
|
242
|
+
* This is a type guard that will check if the passed value is a real Number. This also returns false for NaN, so this is better than typeof value === "number".
|
|
243
|
+
*/
|
|
244
|
+
function isNumber(value) {
|
|
245
|
+
if (value == null) return false;
|
|
246
|
+
else if (typeof value !== "number") return false;
|
|
247
|
+
else if (isNaN(value)) return false;
|
|
248
|
+
else return true;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/helpers/ruleHelpers/matchRegex.ts
|
|
253
|
+
/**
|
|
254
|
+
* This utility can take multiple regular expressions as arguments. It checks the input's validity and tests it against the provided regex patterns.
|
|
255
|
+
*/
|
|
256
|
+
function matchRegex(_value, ...expr) {
|
|
257
|
+
if (isEmpty(_value)) return true;
|
|
258
|
+
const value = typeof _value === "number" ? _value.toString() : _value;
|
|
259
|
+
return expr.every((reg) => {
|
|
260
|
+
reg.lastIndex = 0;
|
|
261
|
+
return reg.test(value);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
//#endregion
|
|
266
|
+
//#region src/helpers/ruleHelpers/getSize.ts
|
|
267
|
+
/**
|
|
268
|
+
* This helper will return the length of any data type you pass. It works with strings, arrays, objects and numbers.
|
|
269
|
+
*/
|
|
270
|
+
function getSize(value) {
|
|
271
|
+
const _value = unref(value);
|
|
272
|
+
if (Array.isArray(_value)) return _value.length;
|
|
273
|
+
if (typeof _value === "object") return Object.keys(_value).length;
|
|
274
|
+
if (typeof _value === "number") {
|
|
275
|
+
if (isNaN(_value)) return 0;
|
|
276
|
+
return _value;
|
|
277
|
+
}
|
|
278
|
+
return String(_value).length;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/helpers/ruleHelpers/toNumber.ts
|
|
283
|
+
/**
|
|
284
|
+
* This utility converts any string (or number) into a number using the Number constructor.
|
|
285
|
+
*
|
|
286
|
+
* @returns ⚠️ Warning, returned value can be NaN
|
|
287
|
+
*/
|
|
288
|
+
function toNumber(argument) {
|
|
289
|
+
if (typeof argument === "number") return argument;
|
|
290
|
+
else if (argument != null) {
|
|
291
|
+
if (typeof argument === "string") {
|
|
292
|
+
const isPadded = argument.trim() !== argument;
|
|
293
|
+
if (isPadded) return NaN;
|
|
294
|
+
return +argument;
|
|
295
|
+
}
|
|
296
|
+
return NaN;
|
|
297
|
+
}
|
|
298
|
+
return NaN;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
//#endregion
|
|
302
|
+
//#region src/helpers/and.ts
|
|
303
|
+
/**
|
|
304
|
+
* The and operator combines multiple rules and validates successfully only if all provided rules are valid.
|
|
305
|
+
*/
|
|
306
|
+
function and(...rules) {
|
|
307
|
+
const isAnyRuleAsync = rules.some((rule) => {
|
|
308
|
+
if (typeof rule === "function") return rule.constructor.name === "AsyncFunction";
|
|
309
|
+
else return rule._async;
|
|
310
|
+
});
|
|
311
|
+
const _params = rules.map((rule) => {
|
|
312
|
+
if (typeof rule === "function") return null;
|
|
313
|
+
else {
|
|
314
|
+
const $params = rule._params;
|
|
315
|
+
if (!$params?.length) return [];
|
|
316
|
+
else return $params;
|
|
317
|
+
}
|
|
318
|
+
}).flat().filter((param) => !!param);
|
|
319
|
+
function computeRules(rules$1, value, ...params) {
|
|
320
|
+
const $rules = [];
|
|
321
|
+
let paramIndex = 0;
|
|
322
|
+
for (let rule of rules$1) if (typeof rule === "function") {
|
|
323
|
+
$rules.push(rule(value));
|
|
324
|
+
paramIndex++;
|
|
325
|
+
} else {
|
|
326
|
+
const paramsLength = rule._params?.length ?? 0;
|
|
327
|
+
$rules.push(rule.validator(value, ...params.slice(paramIndex, paramsLength)));
|
|
328
|
+
if (paramsLength) paramIndex += paramsLength;
|
|
329
|
+
}
|
|
330
|
+
return $rules;
|
|
331
|
+
}
|
|
332
|
+
function computeMetadata(results) {
|
|
333
|
+
const isAnyResultMetaData = results?.some((s) => typeof s !== "boolean");
|
|
334
|
+
if (isAnyResultMetaData) return {
|
|
335
|
+
$valid: results.every((result) => {
|
|
336
|
+
if (typeof result === "boolean") return !!result;
|
|
337
|
+
return result.$valid;
|
|
338
|
+
}),
|
|
339
|
+
...results.reduce((acc, result) => {
|
|
340
|
+
if (typeof result === "boolean") return acc;
|
|
341
|
+
const { $valid,...rest } = result;
|
|
342
|
+
return {
|
|
343
|
+
...acc,
|
|
344
|
+
...rest
|
|
345
|
+
};
|
|
346
|
+
}, {})
|
|
347
|
+
};
|
|
348
|
+
else return results.every((result) => !!result);
|
|
349
|
+
}
|
|
350
|
+
let validator;
|
|
351
|
+
if (!!rules.length) validator = isAnyRuleAsync ? async (value, ...params) => {
|
|
352
|
+
const results = await Promise.all(computeRules(rules, value, ...params));
|
|
353
|
+
return computeMetadata(results);
|
|
354
|
+
} : (value, ...params) => {
|
|
355
|
+
const $rules = computeRules(rules, value, ...params);
|
|
356
|
+
return computeMetadata($rules);
|
|
357
|
+
};
|
|
358
|
+
else validator = (value) => {
|
|
359
|
+
return false;
|
|
360
|
+
};
|
|
361
|
+
const newRule = createRule({
|
|
362
|
+
type: "and",
|
|
363
|
+
validator,
|
|
364
|
+
message: "The value does not match all of the provided validators"
|
|
365
|
+
});
|
|
366
|
+
const newParams = [..._params ?? []];
|
|
367
|
+
newRule._params = newParams;
|
|
368
|
+
if (typeof newRule === "function") {
|
|
369
|
+
const executedRule = newRule(...newParams);
|
|
370
|
+
return executedRule;
|
|
371
|
+
} else return newRule;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
//#endregion
|
|
375
|
+
//#region src/helpers/or.ts
|
|
376
|
+
/**
|
|
377
|
+
* The or operator validates successfully if at least one of the provided rules is valid.
|
|
378
|
+
*/
|
|
379
|
+
function or(...rules) {
|
|
380
|
+
const isAnyRuleAsync = rules.some((rule) => {
|
|
381
|
+
if (typeof rule === "function") return rule.constructor.name === "AsyncFunction";
|
|
382
|
+
else return rule._async;
|
|
383
|
+
});
|
|
384
|
+
const _params = rules.map((rule) => {
|
|
385
|
+
if (typeof rule === "function") return null;
|
|
386
|
+
else return rule._params;
|
|
387
|
+
}).flat().filter((param) => !!param);
|
|
388
|
+
function computeRules(rules$1, value, ...params) {
|
|
389
|
+
const $rules = [];
|
|
390
|
+
let paramIndex = 0;
|
|
391
|
+
for (let rule of rules$1) if (typeof rule === "function") {
|
|
392
|
+
$rules.push(rule(value));
|
|
393
|
+
paramIndex++;
|
|
394
|
+
} else {
|
|
395
|
+
const paramsLength = rule._params?.length ?? 0;
|
|
396
|
+
$rules.push(rule.validator(value, ...params.slice(paramIndex, paramsLength)));
|
|
397
|
+
if (paramsLength) paramIndex += paramsLength;
|
|
398
|
+
}
|
|
399
|
+
return $rules;
|
|
400
|
+
}
|
|
401
|
+
function computeMetadata(results) {
|
|
402
|
+
const isAnyResultMetaData = results.some((s) => typeof s !== "boolean");
|
|
403
|
+
if (isAnyResultMetaData) return {
|
|
404
|
+
$valid: results.some((result) => {
|
|
405
|
+
if (typeof result === "boolean") return !!result;
|
|
406
|
+
return result.$valid;
|
|
407
|
+
}),
|
|
408
|
+
...results.reduce((acc, result) => {
|
|
409
|
+
if (typeof result === "boolean") return acc;
|
|
410
|
+
const { $valid,...rest } = result;
|
|
411
|
+
return {
|
|
412
|
+
...acc,
|
|
413
|
+
...rest
|
|
414
|
+
};
|
|
415
|
+
}, {})
|
|
416
|
+
};
|
|
417
|
+
else return results.some((result) => !!result);
|
|
418
|
+
}
|
|
419
|
+
const validator = isAnyRuleAsync ? async (value, ...params) => {
|
|
420
|
+
const results = await Promise.all(computeRules(rules, value, ...params));
|
|
421
|
+
return computeMetadata(results);
|
|
422
|
+
} : (value, ...params) => {
|
|
423
|
+
const $rules = computeRules(rules, value, ...params);
|
|
424
|
+
return computeMetadata($rules);
|
|
425
|
+
};
|
|
426
|
+
const newRule = createRule({
|
|
427
|
+
type: "or",
|
|
428
|
+
validator,
|
|
429
|
+
message: "The value does not match any of the provided validators"
|
|
430
|
+
});
|
|
431
|
+
const newParams = [..._params ?? []];
|
|
432
|
+
newRule._params = newParams;
|
|
433
|
+
if (typeof newRule === "function") {
|
|
434
|
+
const executedRule = newRule(...newParams);
|
|
435
|
+
return executedRule;
|
|
436
|
+
} else return newRule;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
//#endregion
|
|
440
|
+
//#region src/helpers/not.ts
|
|
441
|
+
/**
|
|
442
|
+
* The not operator passes when the provided rule fails and fails when the rule passes. It can be combined with other rules.
|
|
443
|
+
*/
|
|
444
|
+
function not(rule, message) {
|
|
445
|
+
let _type;
|
|
446
|
+
let validator;
|
|
447
|
+
let newValidator;
|
|
448
|
+
let _params;
|
|
449
|
+
let _async;
|
|
450
|
+
if (typeof rule === "function") {
|
|
451
|
+
validator = rule;
|
|
452
|
+
_async = rule.constructor.name === "AsyncFunction";
|
|
453
|
+
} else {
|
|
454
|
+
({_type, validator, _params} = rule);
|
|
455
|
+
_async = rule._async;
|
|
456
|
+
}
|
|
457
|
+
if (_async) newValidator = async (value, ...params) => {
|
|
458
|
+
if (isFilled(value)) {
|
|
459
|
+
const result = await validator(value, ...params);
|
|
460
|
+
return !result;
|
|
461
|
+
}
|
|
462
|
+
return true;
|
|
463
|
+
};
|
|
464
|
+
else newValidator = (value, ...params) => {
|
|
465
|
+
if (isFilled(value)) return !validator(value, ...params);
|
|
466
|
+
return true;
|
|
467
|
+
};
|
|
468
|
+
const newRule = createRule({
|
|
469
|
+
type: "not",
|
|
470
|
+
validator: newValidator,
|
|
471
|
+
message: message ?? "Error"
|
|
472
|
+
});
|
|
473
|
+
const newParams = [..._params ?? []];
|
|
474
|
+
newRule._params = newParams;
|
|
475
|
+
if (typeof newRule === "function") {
|
|
476
|
+
const executedRule = newRule(...newParams);
|
|
477
|
+
return executedRule;
|
|
478
|
+
} else return newRule;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region src/rules/alpha.ts
|
|
483
|
+
const alphaRegex = /^[a-zA-Z]*$/;
|
|
484
|
+
const alphaSymbolRegex = /^[\w.]+$/;
|
|
485
|
+
/**
|
|
486
|
+
* Allows only alphabetic characters.
|
|
487
|
+
*
|
|
488
|
+
* @param [options] - Alpha rules options
|
|
489
|
+
* */
|
|
490
|
+
const alpha = createRule({
|
|
491
|
+
type: "alpha",
|
|
492
|
+
validator(value, options) {
|
|
493
|
+
if (isEmpty(value)) return true;
|
|
494
|
+
if (options?.allowSymbols) return matchRegex(value, alphaSymbolRegex);
|
|
495
|
+
return matchRegex(value, alphaRegex);
|
|
496
|
+
},
|
|
497
|
+
message: "The value is not alphabetical"
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
//#endregion
|
|
501
|
+
//#region src/rules/alphaNum.ts
|
|
502
|
+
const alphaNumRegex = /^[a-zA-Z0-9]*$/;
|
|
503
|
+
const alphaNumSymbolRegex = /^[a-zA-Z0-9_]*$/;
|
|
504
|
+
/**
|
|
505
|
+
* Allows only alphanumeric characters.
|
|
506
|
+
*
|
|
507
|
+
* @param [options] - Alpha rules options
|
|
508
|
+
*/
|
|
509
|
+
const alphaNum = createRule({
|
|
510
|
+
type: "alphaNum",
|
|
511
|
+
validator(value, options) {
|
|
512
|
+
if (isEmpty(value)) return true;
|
|
513
|
+
if (options?.allowSymbols) return matchRegex(value, alphaNumSymbolRegex);
|
|
514
|
+
return matchRegex(value, alphaNumRegex);
|
|
515
|
+
},
|
|
516
|
+
message: "The value must be alpha-numeric"
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region src/rules/between.ts
|
|
521
|
+
/**
|
|
522
|
+
* Checks if a number is in specified bounds. min and max are both inclusive.
|
|
523
|
+
*
|
|
524
|
+
* @param min - the minimum limit
|
|
525
|
+
* @param max - the maximum limit
|
|
526
|
+
*/
|
|
527
|
+
const between = createRule({
|
|
528
|
+
type: "between",
|
|
529
|
+
validator: (value, min, max, options) => {
|
|
530
|
+
const { allowEqual = true } = options ?? {};
|
|
531
|
+
if (isFilled(value) && isFilled(min) && isFilled(max)) {
|
|
532
|
+
const tValue = toNumber(value);
|
|
533
|
+
const tMin = toNumber(min);
|
|
534
|
+
const tMax = toNumber(max);
|
|
535
|
+
if (isNumber(tValue) && isNumber(tMin) && isNumber(tMax)) if (allowEqual) return tValue >= tMin && tValue <= tMax;
|
|
536
|
+
else return tValue > tMin && tValue < tMax;
|
|
537
|
+
console.warn(`[between] Value or parameters aren't numbers, got value: ${value}, min: ${min}, max: ${max}`);
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
return true;
|
|
541
|
+
},
|
|
542
|
+
message: ({ $params: [min, max] }) => {
|
|
543
|
+
return `The value must be between ${min} and ${max}`;
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
//#endregion
|
|
548
|
+
//#region src/rules/boolean.ts
|
|
549
|
+
/**
|
|
550
|
+
* Requires a value to be a native boolean type
|
|
551
|
+
*
|
|
552
|
+
* Mainly used for typing
|
|
553
|
+
*/
|
|
554
|
+
const boolean = createRule({
|
|
555
|
+
type: "boolean",
|
|
556
|
+
validator: (value) => {
|
|
557
|
+
if (isFilled(value)) return typeof value === "boolean";
|
|
558
|
+
return true;
|
|
559
|
+
},
|
|
560
|
+
message: "The value must be a native boolean"
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
//#endregion
|
|
564
|
+
//#region src/rules/checked.ts
|
|
565
|
+
/**
|
|
566
|
+
* Requires a boolean value to be true. This is useful for checkbox inputs.
|
|
567
|
+
*/
|
|
568
|
+
const checked = createRule({
|
|
569
|
+
type: "checked",
|
|
570
|
+
validator: (value) => {
|
|
571
|
+
if (isFilled(value)) return value === true;
|
|
572
|
+
return true;
|
|
573
|
+
},
|
|
574
|
+
message: "The field must be checked"
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
//#endregion
|
|
578
|
+
//#region src/rules/contains.ts
|
|
579
|
+
/**
|
|
580
|
+
* Checks if the string contains the specified substring.
|
|
581
|
+
*
|
|
582
|
+
* @param part - the part the value needs to contain
|
|
583
|
+
*/
|
|
584
|
+
const contains = createRule({
|
|
585
|
+
type: "contains",
|
|
586
|
+
validator(value, part) {
|
|
587
|
+
if (isFilled(value) && isFilled(part)) return value.includes(part);
|
|
588
|
+
return true;
|
|
589
|
+
},
|
|
590
|
+
message({ $params: [part] }) {
|
|
591
|
+
return `The value must contain ${part}`;
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
//#endregion
|
|
596
|
+
//#region src/rules/date.ts
|
|
597
|
+
/**
|
|
598
|
+
* Requires a value to be a native Date constructor
|
|
599
|
+
*
|
|
600
|
+
* Mainly used for typing
|
|
601
|
+
*/
|
|
602
|
+
const date = createRule({
|
|
603
|
+
type: "date",
|
|
604
|
+
validator: (value) => {
|
|
605
|
+
if (isFilled(value)) return value instanceof Date;
|
|
606
|
+
return true;
|
|
607
|
+
},
|
|
608
|
+
message: "The value must be a native Date constructor"
|
|
609
|
+
});
|
|
610
|
+
|
|
611
|
+
//#endregion
|
|
612
|
+
//#region src/utils/getLocale.util.ts
|
|
613
|
+
function getUserLocale() {
|
|
614
|
+
if (navigator.languages != void 0) return navigator.languages[0];
|
|
615
|
+
return navigator.language;
|
|
616
|
+
}
|
|
617
|
+
function formatLocaleDate(date$1) {
|
|
618
|
+
if (date$1) return new Intl.DateTimeFormat(getUserLocale(), { dateStyle: "short" }).format(new Date(date$1));
|
|
619
|
+
return "?";
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
//#endregion
|
|
623
|
+
//#region src/rules/dateAfter.ts
|
|
624
|
+
/**
|
|
625
|
+
* Checks if the date is after the given parameter.
|
|
626
|
+
*
|
|
627
|
+
* @param after - the date to compare to
|
|
628
|
+
* @param options - comparison options
|
|
629
|
+
*/
|
|
630
|
+
const dateAfter = createRule({
|
|
631
|
+
type: "dateAfter",
|
|
632
|
+
validator: (value, after, options) => {
|
|
633
|
+
const { allowEqual = true } = options ?? {};
|
|
634
|
+
if (isFilled(value) && isFilled(after)) {
|
|
635
|
+
if (isDate(value) && isDate(after)) {
|
|
636
|
+
const result = allowEqual ? toDate(value).getTime() >= toDate(after).getTime() : toDate(value).getTime() > toDate(after).getTime();
|
|
637
|
+
if (result) return true;
|
|
638
|
+
return {
|
|
639
|
+
$valid: false,
|
|
640
|
+
error: "date-not-after"
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
return {
|
|
644
|
+
$valid: false,
|
|
645
|
+
error: "value-or-parameter-not-a-date"
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
return true;
|
|
649
|
+
},
|
|
650
|
+
message: ({ $params: [after], error }) => {
|
|
651
|
+
if (error === "value-or-parameter-not-a-date") return "The values must be dates";
|
|
652
|
+
return `The date must be after ${formatLocaleDate(after)}`;
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
//#endregion
|
|
657
|
+
//#region src/rules/dateBefore.ts
|
|
658
|
+
/**
|
|
659
|
+
* Checks if the date is before the given parameter.
|
|
660
|
+
*
|
|
661
|
+
* @param before - the date to compare to
|
|
662
|
+
* @param options - comparison options
|
|
663
|
+
*/
|
|
664
|
+
const dateBefore = createRule({
|
|
665
|
+
type: "dateBefore",
|
|
666
|
+
validator: (value, before, options) => {
|
|
667
|
+
const { allowEqual = true } = options ?? {};
|
|
668
|
+
if (isFilled(value) && isFilled(before)) {
|
|
669
|
+
if (isDate(value) && isDate(before)) {
|
|
670
|
+
const result = allowEqual ? toDate(value).getTime() <= toDate(before).getTime() : toDate(value).getTime() < toDate(before).getTime();
|
|
671
|
+
if (result) return true;
|
|
672
|
+
return {
|
|
673
|
+
$valid: false,
|
|
674
|
+
error: "date-not-before"
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
return {
|
|
678
|
+
$valid: false,
|
|
679
|
+
error: "value-or-parameter-not-a-date"
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
return true;
|
|
683
|
+
},
|
|
684
|
+
message: ({ $params: [before], error }) => {
|
|
685
|
+
if (error === "value-or-parameter-not-a-date") return "The values must be dates";
|
|
686
|
+
return `The date must be before ${formatLocaleDate(before)}`;
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
//#endregion
|
|
691
|
+
//#region src/rules/dateBetween.ts
|
|
692
|
+
/**
|
|
693
|
+
* Checks if the date falls between the specified bounds.
|
|
694
|
+
*
|
|
695
|
+
* @param before - the minimum limit
|
|
696
|
+
* @param after - the maximum limit
|
|
697
|
+
* @param options - comparison options
|
|
698
|
+
*/
|
|
699
|
+
const dateBetween = createRule({
|
|
700
|
+
type: "dateBetween",
|
|
701
|
+
validator: (value, before, after, options) => {
|
|
702
|
+
const { allowEqual = true } = options ?? {};
|
|
703
|
+
if (isDate(value) && isDate(before) && isDate(after)) if (allowEqual) return toDate(value).getTime() >= toDate(before).getTime() && toDate(value).getTime() <= toDate(after).getTime();
|
|
704
|
+
else return toDate(value).getTime() > toDate(before).getTime() && toDate(value).getTime() < toDate(after).getTime();
|
|
705
|
+
return true;
|
|
706
|
+
},
|
|
707
|
+
message: ({ $params: [before, after] }) => {
|
|
708
|
+
return `The date must be between ${formatLocaleDate(before)} and ${formatLocaleDate(after)}`;
|
|
709
|
+
}
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
//#endregion
|
|
713
|
+
//#region src/rules/decimal.ts
|
|
714
|
+
const decimalRegex = /^[-]?\d*(\.\d+)?$/;
|
|
715
|
+
/**
|
|
716
|
+
* Allows positive and negative decimal numbers.
|
|
717
|
+
*/
|
|
718
|
+
const decimal = createRule({
|
|
719
|
+
type: "decimal",
|
|
720
|
+
validator(value) {
|
|
721
|
+
if (isEmpty(value)) return true;
|
|
722
|
+
return matchRegex(value, decimalRegex);
|
|
723
|
+
},
|
|
724
|
+
message: "The value must be decimal"
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
//#endregion
|
|
728
|
+
//#region src/rules/email.ts
|
|
729
|
+
const emailRegex = /^(?:[A-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i;
|
|
730
|
+
/**
|
|
731
|
+
* Validates email addresses. Always verify on the server to ensure the address is real and not already in use.
|
|
732
|
+
*/
|
|
733
|
+
const email = createRule({
|
|
734
|
+
type: "email",
|
|
735
|
+
validator(value) {
|
|
736
|
+
if (isEmpty(value)) return true;
|
|
737
|
+
return matchRegex(value, emailRegex);
|
|
738
|
+
},
|
|
739
|
+
message: "The value must be an valid email address"
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
//#endregion
|
|
743
|
+
//#region src/rules/endsWith.ts
|
|
744
|
+
/**
|
|
745
|
+
* Checks if the string ends with the specified substring.
|
|
746
|
+
*
|
|
747
|
+
* @param part - the value the field must end with
|
|
748
|
+
*/
|
|
749
|
+
const endsWith = createRule({
|
|
750
|
+
type: "endsWith",
|
|
751
|
+
validator(value, part) {
|
|
752
|
+
if (isFilled(value) && isFilled(part)) return value.endsWith(part);
|
|
753
|
+
return true;
|
|
754
|
+
},
|
|
755
|
+
message({ $params: [part] }) {
|
|
756
|
+
return `The value must end with ${part}`;
|
|
757
|
+
}
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
//#endregion
|
|
761
|
+
//#region src/rules/exactLength.ts
|
|
762
|
+
/**
|
|
763
|
+
* Requires the input value to have a strict specified length, inclusive. Works with arrays, objects and strings.
|
|
764
|
+
*
|
|
765
|
+
* @param count - the required length
|
|
766
|
+
*/
|
|
767
|
+
const exactLength = createRule({
|
|
768
|
+
type: "exactLength",
|
|
769
|
+
validator: (value, count) => {
|
|
770
|
+
if (isFilled(value, false) && isFilled(count)) {
|
|
771
|
+
if (isNumber(count)) return getSize(value) === count;
|
|
772
|
+
console.warn(`[minLength] Parameter isn't a number, got parameter: ${count}`);
|
|
773
|
+
return false;
|
|
774
|
+
}
|
|
775
|
+
return true;
|
|
776
|
+
},
|
|
777
|
+
message: ({ $params: [count] }) => {
|
|
778
|
+
return `The value should be exactly ${count} characters long`;
|
|
779
|
+
}
|
|
780
|
+
});
|
|
781
|
+
|
|
782
|
+
//#endregion
|
|
783
|
+
//#region src/rules/exactValue.ts
|
|
784
|
+
/**
|
|
785
|
+
* Requires a field to have a strict numeric value.
|
|
786
|
+
*/
|
|
787
|
+
const exactValue = createRule({
|
|
788
|
+
type: "exactValue",
|
|
789
|
+
validator: (value, count) => {
|
|
790
|
+
if (isFilled(value) && isFilled(count)) {
|
|
791
|
+
if (isNumber(count) && !isNaN(toNumber(value))) return toNumber(value) === count;
|
|
792
|
+
console.warn(`[exactValue] Value or parameter isn't a number, got value: ${value}, parameter: ${count}`);
|
|
793
|
+
return true;
|
|
794
|
+
}
|
|
795
|
+
return true;
|
|
796
|
+
},
|
|
797
|
+
message: ({ $params: [count] }) => {
|
|
798
|
+
return `The value must be equal to ${count}`;
|
|
799
|
+
}
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
//#endregion
|
|
803
|
+
//#region src/rules/hexadecimal.ts
|
|
804
|
+
const hexadecimalRegex = /^[a-fA-F0-9]*$/;
|
|
805
|
+
/**
|
|
806
|
+
* Allows only hexadecimal values.
|
|
807
|
+
*/
|
|
808
|
+
const hexadecimal = createRule({
|
|
809
|
+
type: "hexadecimal",
|
|
810
|
+
validator(value) {
|
|
811
|
+
if (isEmpty(value)) return true;
|
|
812
|
+
return matchRegex(value, hexadecimalRegex);
|
|
813
|
+
},
|
|
814
|
+
message: "The value must be hexadecimal"
|
|
815
|
+
});
|
|
816
|
+
|
|
817
|
+
//#endregion
|
|
818
|
+
//#region src/rules/integer.ts
|
|
819
|
+
const integerRegex = /(^[0-9]*$)|(^-[0-9]+$)/;
|
|
820
|
+
/**
|
|
821
|
+
* Allows only integers (positive and negative).
|
|
822
|
+
*/
|
|
823
|
+
const integer = createRule({
|
|
824
|
+
type: "integer",
|
|
825
|
+
validator(value) {
|
|
826
|
+
if (isEmpty(value)) return true;
|
|
827
|
+
return matchRegex(value, integerRegex);
|
|
828
|
+
},
|
|
829
|
+
message: "The value must be an integer"
|
|
830
|
+
});
|
|
831
|
+
|
|
832
|
+
//#endregion
|
|
833
|
+
//#region src/rules/ipv4Address.ts
|
|
834
|
+
function nibbleValid(nibble) {
|
|
835
|
+
if (nibble.length > 3 || nibble.length === 0) return false;
|
|
836
|
+
if (nibble[0] === "0" && nibble !== "0") return false;
|
|
837
|
+
if (!nibble.match(/^\d+$/)) return false;
|
|
838
|
+
const numeric$1 = +nibble | 0;
|
|
839
|
+
return numeric$1 >= 0 && numeric$1 <= 255;
|
|
840
|
+
}
|
|
841
|
+
/**
|
|
842
|
+
* Validates IPv4 addresses in dotted decimal notation 127.0.0.1.
|
|
843
|
+
*/
|
|
844
|
+
const ipv4Address = createRule({
|
|
845
|
+
type: "ipv4Address",
|
|
846
|
+
validator(value) {
|
|
847
|
+
if (isEmpty(value)) return true;
|
|
848
|
+
if (typeof value !== "string") return false;
|
|
849
|
+
const nibbles = value.split(".");
|
|
850
|
+
return nibbles.length === 4 && nibbles.every(nibbleValid);
|
|
851
|
+
},
|
|
852
|
+
message: "The value is not a valid IPv4 address"
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
//#endregion
|
|
856
|
+
//#region src/rules/literal.ts
|
|
857
|
+
/**
|
|
858
|
+
* Allow only one possible literal value
|
|
859
|
+
*/
|
|
860
|
+
function literal(literal$1) {
|
|
861
|
+
const params = computed(() => toValue(literal$1));
|
|
862
|
+
const rule = withMessage(withParams((value, literal$2) => {
|
|
863
|
+
if (isFilled(value) && isFilled(literal$2)) return literal$2 === value;
|
|
864
|
+
return true;
|
|
865
|
+
}, [params]), ({ $params: [literal$2] }) => `Value should be ${literal$2}.`);
|
|
866
|
+
return rule;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
//#endregion
|
|
870
|
+
//#region src/rules/macAddress.ts
|
|
871
|
+
/**
|
|
872
|
+
* Validates MAC addresses. Call as a function to specify a custom separator (e.g., ':' or an empty string for 00ff1122334455).
|
|
873
|
+
*
|
|
874
|
+
* @param separator - the custom separator
|
|
875
|
+
*/
|
|
876
|
+
const macAddress = createRule({
|
|
877
|
+
type: "macAddress",
|
|
878
|
+
validator(value, separator = ":") {
|
|
879
|
+
if (isEmpty(value)) return true;
|
|
880
|
+
if (typeof value !== "string") return false;
|
|
881
|
+
const parts = typeof separator === "string" && separator !== "" ? value.split(separator) : value.length === 12 || value.length === 16 ? value.match(/.{2}/g) : null;
|
|
882
|
+
return parts !== null && (parts.length === 6 || parts.length === 8) && parts.every(hexValid);
|
|
883
|
+
},
|
|
884
|
+
message: "The value is not a valid MAC Address"
|
|
885
|
+
});
|
|
886
|
+
const hexValid = (hex) => hex.toLowerCase().match(/^[0-9a-f]{2}$/);
|
|
887
|
+
|
|
888
|
+
//#endregion
|
|
889
|
+
//#region src/rules/maxLength.ts
|
|
890
|
+
/**
|
|
891
|
+
* Requires the input value to have a maximum specified length, inclusive. Works with arrays, objects and strings.
|
|
892
|
+
*
|
|
893
|
+
* @param max - the maximum length
|
|
894
|
+
* @param options - comparison options
|
|
895
|
+
*/
|
|
896
|
+
const maxLength = createRule({
|
|
897
|
+
type: "maxLength",
|
|
898
|
+
validator: (value, count, options) => {
|
|
899
|
+
const { allowEqual = true } = options ?? {};
|
|
900
|
+
if (isFilled(value, false) && isFilled(count)) {
|
|
901
|
+
if (isNumber(count)) if (allowEqual) return getSize(value) <= count;
|
|
902
|
+
else return getSize(value) < count;
|
|
903
|
+
console.warn(`[maxLength] Value or parameter isn't a number, got value: ${value}, parameter: ${count}`);
|
|
904
|
+
return false;
|
|
905
|
+
}
|
|
906
|
+
return true;
|
|
907
|
+
},
|
|
908
|
+
message: ({ $value, $params: [count] }) => {
|
|
909
|
+
if (Array.isArray($value)) return `This list should have maximum ${count} items`;
|
|
910
|
+
return `The value length should not exceed ${count}`;
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
|
|
914
|
+
//#endregion
|
|
915
|
+
//#region src/rules/maxValue.ts
|
|
916
|
+
/**
|
|
917
|
+
* Requires a field to have a specified maximum numeric value.
|
|
918
|
+
*
|
|
919
|
+
* @param max - the maximum value
|
|
920
|
+
* @param options - comparison options
|
|
921
|
+
*/
|
|
922
|
+
const maxValue = createRule({
|
|
923
|
+
type: "maxValue",
|
|
924
|
+
validator: (value, count, options) => {
|
|
925
|
+
const { allowEqual = true } = options ?? {};
|
|
926
|
+
if (isFilled(value) && isFilled(count)) {
|
|
927
|
+
if (isNumber(count) && !isNaN(toNumber(value))) if (allowEqual) return toNumber(value) <= count;
|
|
928
|
+
else return toNumber(value) < count;
|
|
929
|
+
console.warn(`[maxValue] Value or parameter isn't a number, got value: ${value}, parameter: ${count}`);
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
932
|
+
return true;
|
|
933
|
+
},
|
|
934
|
+
message: ({ $params: [count, options] }) => {
|
|
935
|
+
const { allowEqual = true } = options ?? {};
|
|
936
|
+
if (allowEqual) return `The value must be less than or equal to ${count}`;
|
|
937
|
+
else return `The value must be less than ${count}`;
|
|
938
|
+
}
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
//#endregion
|
|
942
|
+
//#region src/rules/minLength.ts
|
|
943
|
+
/**
|
|
944
|
+
* Requires the input value to have a minimum specified length, inclusive. Works with arrays, objects and strings.
|
|
945
|
+
*
|
|
946
|
+
* @param min - the minimum value
|
|
947
|
+
* @param options - comparison options
|
|
948
|
+
*/
|
|
949
|
+
const minLength = createRule({
|
|
950
|
+
type: "minLength",
|
|
951
|
+
validator: (value, count, options) => {
|
|
952
|
+
const { allowEqual = true } = options ?? {};
|
|
953
|
+
if (isFilled(value, false) && isFilled(count)) {
|
|
954
|
+
if (isNumber(count)) if (allowEqual) return getSize(value) >= count;
|
|
955
|
+
else return getSize(value) > count;
|
|
956
|
+
console.warn(`[minLength] Parameter isn't a number, got parameter: ${count}`);
|
|
957
|
+
return false;
|
|
958
|
+
}
|
|
959
|
+
return true;
|
|
960
|
+
},
|
|
961
|
+
message: ({ $value, $params: [count] }) => {
|
|
962
|
+
if (Array.isArray($value)) return `The list should have at least ${count} items`;
|
|
963
|
+
return `The value length should be at least ${count}`;
|
|
964
|
+
}
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
//#endregion
|
|
968
|
+
//#region src/rules/minValue.ts
|
|
969
|
+
/**
|
|
970
|
+
* Requires a field to have a specified minimum numeric value.
|
|
971
|
+
*
|
|
972
|
+
* @param count - the minimum count
|
|
973
|
+
* @param options - comparison options
|
|
974
|
+
*/
|
|
975
|
+
const minValue = createRule({
|
|
976
|
+
type: "minValue",
|
|
977
|
+
validator: (value, count, options) => {
|
|
978
|
+
const { allowEqual = true } = options ?? {};
|
|
979
|
+
if (isFilled(value) && isFilled(count)) {
|
|
980
|
+
if (isNumber(count) && !isNaN(toNumber(value))) if (allowEqual) return toNumber(value) >= count;
|
|
981
|
+
else return toNumber(value) > count;
|
|
982
|
+
console.warn(`[minValue] Value or parameter isn't a number, got value: ${value}, parameter: ${count}`);
|
|
983
|
+
return true;
|
|
984
|
+
}
|
|
985
|
+
return true;
|
|
986
|
+
},
|
|
987
|
+
message: ({ $params: [count, options] }) => {
|
|
988
|
+
const { allowEqual = true } = options ?? {};
|
|
989
|
+
if (allowEqual) return `The value must be greater than or equal to ${count}`;
|
|
990
|
+
else return `The value must be greater than ${count}`;
|
|
991
|
+
}
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
//#endregion
|
|
995
|
+
//#region src/rules/nativeEnum.ts
|
|
996
|
+
function getValidEnumValues(obj) {
|
|
997
|
+
const validKeys = Object.keys(obj).filter((k) => typeof obj[obj[k]] !== "number");
|
|
998
|
+
const filtered = {};
|
|
999
|
+
for (const k of validKeys) filtered[k] = obj[k];
|
|
1000
|
+
return Object.values(filtered);
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Validate against a native Typescript enum value.
|
|
1004
|
+
*/
|
|
1005
|
+
function nativeEnum(enumLike) {
|
|
1006
|
+
const params = computed(() => toValue(enumLike));
|
|
1007
|
+
const rule = withMessage(withParams((value, enumLike$1) => {
|
|
1008
|
+
if (isFilled(value) && !isEmpty(enumLike$1)) {
|
|
1009
|
+
const validValues = getValidEnumValues(enumLike$1);
|
|
1010
|
+
return validValues.includes(value);
|
|
1011
|
+
}
|
|
1012
|
+
return true;
|
|
1013
|
+
}, [params]), ({ $params: [enumLike$1] }) => `The value should be one of those options: ${Object.values(enumLike$1).join(", ")}.`);
|
|
1014
|
+
return rule;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
//#endregion
|
|
1018
|
+
//#region src/rules/number.ts
|
|
1019
|
+
/**
|
|
1020
|
+
* Requires a value to be a native number type
|
|
1021
|
+
*
|
|
1022
|
+
* Mainly used for typing
|
|
1023
|
+
*/
|
|
1024
|
+
const number = createRule({
|
|
1025
|
+
type: "number",
|
|
1026
|
+
validator: (value) => {
|
|
1027
|
+
if (isFilled(value)) return isNumber(value);
|
|
1028
|
+
return true;
|
|
1029
|
+
},
|
|
1030
|
+
message: "The value must be a native number"
|
|
1031
|
+
});
|
|
1032
|
+
|
|
1033
|
+
//#endregion
|
|
1034
|
+
//#region src/rules/numeric.ts
|
|
1035
|
+
const numericRegex = /^\d*(\.\d+)?$/;
|
|
1036
|
+
/**
|
|
1037
|
+
* Allows only numeric values (including numeric strings).
|
|
1038
|
+
*/
|
|
1039
|
+
const numeric = createRule({
|
|
1040
|
+
type: "numeric",
|
|
1041
|
+
validator(value) {
|
|
1042
|
+
if (isEmpty(value)) return true;
|
|
1043
|
+
return matchRegex(value, numericRegex);
|
|
1044
|
+
},
|
|
1045
|
+
message: "The value must be numeric"
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
//#endregion
|
|
1049
|
+
//#region src/rules/oneOf.ts
|
|
1050
|
+
/**
|
|
1051
|
+
* Allow only one of the values from a fixed Array of possible entries.
|
|
1052
|
+
*/
|
|
1053
|
+
function oneOf(options) {
|
|
1054
|
+
const params = computed(() => toValue(options));
|
|
1055
|
+
const rule = withMessage(withParams((value, options$1) => {
|
|
1056
|
+
if (isFilled(value) && isFilled(options$1, false)) return options$1.includes(value);
|
|
1057
|
+
return true;
|
|
1058
|
+
}, [params]), ({ $params: [options$1] }) => `The value should be one of those options: ${options$1.join(", ")}.`);
|
|
1059
|
+
return rule;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
//#endregion
|
|
1063
|
+
//#region src/rules/regex.ts
|
|
1064
|
+
/**
|
|
1065
|
+
* Checks if the value matches one or more regular expressions.
|
|
1066
|
+
*/
|
|
1067
|
+
const regex = createRule({
|
|
1068
|
+
type: "regex",
|
|
1069
|
+
validator(value, regexp) {
|
|
1070
|
+
if (isFilled(value)) {
|
|
1071
|
+
const filteredRegexp = Array.isArray(regexp) ? regexp : [regexp];
|
|
1072
|
+
return matchRegex(value, ...filteredRegexp);
|
|
1073
|
+
}
|
|
1074
|
+
return true;
|
|
1075
|
+
},
|
|
1076
|
+
message: "The value does not match the required pattern"
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
//#endregion
|
|
1080
|
+
//#region src/rules/required.ts
|
|
1081
|
+
/**
|
|
1082
|
+
* Requires non-empty data. Checks for empty arrays and strings containing only whitespaces.
|
|
1083
|
+
*/
|
|
1084
|
+
const required = createRule({
|
|
1085
|
+
type: "required",
|
|
1086
|
+
validator: (value) => {
|
|
1087
|
+
return isFilled(value);
|
|
1088
|
+
},
|
|
1089
|
+
message: "This field is required"
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
//#endregion
|
|
1093
|
+
//#region src/rules/requiredIf.ts
|
|
1094
|
+
/**
|
|
1095
|
+
* Requires non-empty data, only if provided data property, ref, or a function resolves to true.
|
|
1096
|
+
*
|
|
1097
|
+
* @param condition - the condition to enable the required rule
|
|
1098
|
+
*/
|
|
1099
|
+
const requiredIf = createRule({
|
|
1100
|
+
type: "required",
|
|
1101
|
+
validator(value, condition) {
|
|
1102
|
+
if (condition) return isFilled(value);
|
|
1103
|
+
return true;
|
|
1104
|
+
},
|
|
1105
|
+
message: "This field is required",
|
|
1106
|
+
active({ $params: [condition] }) {
|
|
1107
|
+
return condition;
|
|
1108
|
+
}
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
//#endregion
|
|
1112
|
+
//#region src/rules/requiredUnless.ts
|
|
1113
|
+
/**
|
|
1114
|
+
* Requires non-empty data, only if provided data property, ref, or a function resolves to false.
|
|
1115
|
+
*
|
|
1116
|
+
* @param condition - the condition to disable the required rule
|
|
1117
|
+
*/
|
|
1118
|
+
const requiredUnless = createRule({
|
|
1119
|
+
type: "required",
|
|
1120
|
+
validator(value, condition) {
|
|
1121
|
+
if (!condition) return isFilled(value);
|
|
1122
|
+
return true;
|
|
1123
|
+
},
|
|
1124
|
+
message: "This field is required",
|
|
1125
|
+
active({ $params: [condition] }) {
|
|
1126
|
+
return !condition;
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1130
|
+
//#endregion
|
|
1131
|
+
//#region src/rules/sameAs.ts
|
|
1132
|
+
/**
|
|
1133
|
+
* Checks if the value matches the specified property or ref.
|
|
1134
|
+
*/
|
|
1135
|
+
const sameAs = createRule({
|
|
1136
|
+
type: "sameAs",
|
|
1137
|
+
validator(value, target, otherName) {
|
|
1138
|
+
if (isEmpty(value)) return true;
|
|
1139
|
+
return value === target;
|
|
1140
|
+
},
|
|
1141
|
+
message({ $params: [_, otherName = "other"] }) {
|
|
1142
|
+
return `The value must be equal to the ${otherName} value`;
|
|
1143
|
+
}
|
|
1144
|
+
});
|
|
1145
|
+
|
|
1146
|
+
//#endregion
|
|
1147
|
+
//#region src/rules/startsWith.ts
|
|
1148
|
+
/**
|
|
1149
|
+
* Checks if the string starts with the specified substring.
|
|
1150
|
+
*
|
|
1151
|
+
* @private part - the value the field must start with
|
|
1152
|
+
*/
|
|
1153
|
+
const startsWith = createRule({
|
|
1154
|
+
type: "startsWith",
|
|
1155
|
+
validator(value, part) {
|
|
1156
|
+
if (isFilled(value) && isFilled(part)) return value.startsWith(part);
|
|
1157
|
+
return true;
|
|
1158
|
+
},
|
|
1159
|
+
message({ $params: [part] }) {
|
|
1160
|
+
return `The value must end with ${part}`;
|
|
1161
|
+
}
|
|
1162
|
+
});
|
|
1163
|
+
|
|
1164
|
+
//#endregion
|
|
1165
|
+
//#region src/rules/string.ts
|
|
1166
|
+
/**
|
|
1167
|
+
* Requires a value to be a native string type
|
|
1168
|
+
*
|
|
1169
|
+
* Mainly used for typing
|
|
1170
|
+
*/
|
|
1171
|
+
const string = createRule({
|
|
1172
|
+
type: "string",
|
|
1173
|
+
validator: (value) => {
|
|
1174
|
+
if (isFilled(value)) return typeof value === "string";
|
|
1175
|
+
return true;
|
|
1176
|
+
},
|
|
1177
|
+
message: "The value must be a string"
|
|
1178
|
+
});
|
|
1179
|
+
|
|
1180
|
+
//#endregion
|
|
1181
|
+
//#region src/rules/type.ts
|
|
1182
|
+
/**
|
|
1183
|
+
* Define the input type of a rule. No runtime validation.
|
|
1184
|
+
*
|
|
1185
|
+
* Override any input type set by other rules.
|
|
1186
|
+
*/
|
|
1187
|
+
function type() {
|
|
1188
|
+
return () => true;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
//#endregion
|
|
1192
|
+
//#region src/rules/url.ts
|
|
1193
|
+
/**
|
|
1194
|
+
* Regex taken from {@link https://gist.github.com/dperini/729294}
|
|
1195
|
+
*/
|
|
1196
|
+
const urlRegex = /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i;
|
|
1197
|
+
/**
|
|
1198
|
+
* Validates URLs.
|
|
1199
|
+
*/
|
|
1200
|
+
const url = createRule({
|
|
1201
|
+
type: "url",
|
|
1202
|
+
validator(value) {
|
|
1203
|
+
if (isEmpty(value)) return true;
|
|
1204
|
+
return matchRegex(value, urlRegex);
|
|
1205
|
+
},
|
|
1206
|
+
message: "The value is not a valid URL address"
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
//#endregion
|
|
1210
|
+
export { alpha, alphaNum, and, applyIf, between, boolean, checked, contains, date, dateAfter, dateBefore, dateBetween, decimal, email, endsWith, exactLength, exactValue, getSize, hexadecimal, integer, ipv4Address, isDate, isEmpty, isFilled, isNumber, literal, macAddress, matchRegex, maxLength, maxValue, minLength, minValue, nativeEnum, not, number, numeric, oneOf, or, regex, required, requiredIf, requiredUnless, sameAs, startsWith, string, toDate, toNumber, type, url, withAsync, withMessage, withParams, withTooltip };
|