@azure-net/kit 5.0.4 → 5.1.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/dist/delivery/injectable-dependencies/AsyncHelpers.js +5 -3
- package/dist/delivery/schema/Schema.d.ts +3 -1
- package/dist/delivery/schema/Schema.js +3 -0
- package/dist/delivery/schema/rules/Rules.d.ts +40 -6
- package/dist/delivery/schema/rules/Rules.js +183 -57
- package/dist/delivery/schema/rules/messages/En.js +28 -3
- package/dist/delivery/schema/rules/messages/Ru.js +28 -3
- package/dist/delivery/schema/rules/messages/Types.d.ts +28 -3
- package/dist/delivery/schema/rules/messages/WithI18n.js +28 -3
- package/dist/external/edges/_edges.d.ts +1 -1
- package/dist/external/edges/_edges.js +1 -1
- package/dist/infra/http-service/HttpServiceInstance.js +16 -8
- package/dist/plugin/AzureNetPlugin.d.ts +0 -2
- package/dist/plugin/AzureNetPlugin.js +43 -244
- package/dist/shared/app/App.d.ts +3 -5
- package/dist/shared/app/App.js +6 -16
- package/dist/shared/app/middleware/ClientMiddleware.js +12 -11
- package/dist/shared/boundary-provider/Provider.js +0 -8
- package/dist/svelte/active-form/ActiveForm.svelte.js +43 -23
- package/dist/svelte/async-signal/AsyncSignal.svelte.js +22 -14
- package/package.json +5 -14
|
@@ -2,17 +2,18 @@ import { createErrorHandler } from './ErrorHandler.js';
|
|
|
2
2
|
import {} from '../../shared/app-error/AppError.js';
|
|
3
3
|
import { BROWSER } from '../../external/tools/index.js';
|
|
4
4
|
import { RequestContext } from '../../external/edges/ServerContext.js';
|
|
5
|
-
const HANDLER_CONTEXT_KEY = '__azureNetAsyncHelperErrorParser__';
|
|
6
5
|
export class AsyncHelperError extends Error {
|
|
7
6
|
}
|
|
8
7
|
export const createAsyncHelpers = () => {
|
|
9
8
|
const defaultErrorParser = createErrorHandler();
|
|
9
|
+
const handlerContextKey = Symbol('azureNetAsyncHelperErrorParser');
|
|
10
10
|
let clientErrorParser;
|
|
11
11
|
const getErrorParser = () => {
|
|
12
12
|
if (BROWSER)
|
|
13
13
|
return clientErrorParser ?? defaultErrorParser;
|
|
14
14
|
try {
|
|
15
|
-
|
|
15
|
+
const data = RequestContext.current().data;
|
|
16
|
+
return data[handlerContextKey] ?? defaultErrorParser;
|
|
16
17
|
}
|
|
17
18
|
catch {
|
|
18
19
|
return defaultErrorParser;
|
|
@@ -24,7 +25,8 @@ export const createAsyncHelpers = () => {
|
|
|
24
25
|
clientErrorParser = parser;
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
|
-
RequestContext.current().data
|
|
28
|
+
const data = RequestContext.current().data;
|
|
29
|
+
data[handlerContextKey] = parser;
|
|
28
30
|
};
|
|
29
31
|
const normalizeError = (err) => (err instanceof Error ? err : new Error(String(err)));
|
|
30
32
|
const prepareErrors = async (error, retry) => {
|
|
@@ -16,10 +16,12 @@ export type ValidationMessage = string | {
|
|
|
16
16
|
key: string;
|
|
17
17
|
vars?: Record<string, unknown>;
|
|
18
18
|
};
|
|
19
|
+
export declare const SKIP_REMAINING_VALIDATION: unique symbol;
|
|
20
|
+
export type ValidationControl = typeof SKIP_REMAINING_VALIDATION;
|
|
19
21
|
export interface ValidationErrorsMap {
|
|
20
22
|
[key: string]: ValidationMessage | ValidationErrorsMap;
|
|
21
23
|
}
|
|
22
|
-
export type ValidationResult = ValidationMessage | ValidationErrorsMap | ValidationErrorsMap[] | undefined;
|
|
24
|
+
export type ValidationResult = ValidationMessage | ValidationErrorsMap | ValidationErrorsMap[] | ValidationControl | undefined;
|
|
23
25
|
export type ValidationRuleResult<CurrentValue, ListValues = unknown, CurrentKey = string> = (params: ValidationParams<CurrentValue, ListValues, CurrentKey>) => ValidationResult;
|
|
24
26
|
type ValidationErrors<Errors> = Errors extends ReadonlyArray<infer U> ? ValidationErrors<U>[] : IsAtomic<Errors> extends true ? ValidationMessage : Errors extends object ? {
|
|
25
27
|
[K in keyof Errors]?: ValidationErrors<Errors[K]>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FormDataUtil } from '../../external/tools/index.js';
|
|
2
2
|
import { AzureNetKitInternalError } from '../../shared/app-error/AppError.js';
|
|
3
|
+
export const SKIP_REMAINING_VALIDATION = Symbol('skipRemainingValidation');
|
|
3
4
|
export class SchemaFail extends Error {
|
|
4
5
|
_errors;
|
|
5
6
|
data;
|
|
@@ -92,6 +93,8 @@ class SchemaBuilderImpl {
|
|
|
92
93
|
listValues: _preparedData,
|
|
93
94
|
key: key
|
|
94
95
|
});
|
|
96
|
+
if (failMessage === SKIP_REMAINING_VALIDATION)
|
|
97
|
+
break;
|
|
95
98
|
if (failMessage) {
|
|
96
99
|
setByPath(_errors, key, failMessage);
|
|
97
100
|
_isValid = false;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { BaseValidationMessages } from './messages/Types.js';
|
|
2
2
|
import type { ValidationParams, ValidationRuleResult } from '../index.js';
|
|
3
|
+
type ValidationMessageOverride<T> = T extends (...args: never[]) => unknown ? T : Partial<T>;
|
|
3
4
|
export type ValidationRuleParams<T extends keyof BaseValidationMessages, D = object> = D & {
|
|
4
|
-
message?: BaseValidationMessages[T]
|
|
5
|
+
message?: ValidationMessageOverride<BaseValidationMessages[T]>;
|
|
5
6
|
};
|
|
6
7
|
export type LengthParams = {
|
|
7
8
|
length?: {
|
|
@@ -15,6 +16,35 @@ export type RangeParams = {
|
|
|
15
16
|
max?: number;
|
|
16
17
|
};
|
|
17
18
|
};
|
|
19
|
+
export type DateRangeParams = {
|
|
20
|
+
range?: {
|
|
21
|
+
min?: Date | string;
|
|
22
|
+
max?: Date | string;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export type PatternParams = {
|
|
26
|
+
regexp: RegExp;
|
|
27
|
+
};
|
|
28
|
+
export type UrlParams = {
|
|
29
|
+
protocols?: string[];
|
|
30
|
+
allowRelative?: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type FileParams = {
|
|
33
|
+
maxSize?: number;
|
|
34
|
+
mimeTypes?: string[];
|
|
35
|
+
extensions?: string[];
|
|
36
|
+
};
|
|
37
|
+
export type EmailParams = {
|
|
38
|
+
trim?: boolean;
|
|
39
|
+
maxLength?: number;
|
|
40
|
+
allowedDomains?: string[];
|
|
41
|
+
blockedDomains?: string[];
|
|
42
|
+
};
|
|
43
|
+
export type PhoneParams = {
|
|
44
|
+
requireCountryCode?: boolean;
|
|
45
|
+
minDigits?: number;
|
|
46
|
+
maxDigits?: number;
|
|
47
|
+
};
|
|
18
48
|
type ArrayItemRules<Context> = ValidationRuleResult<Context>[] | Record<string, ValidationRuleResult<Context>[]>;
|
|
19
49
|
type ArrayParams<Context> = LengthParams & {
|
|
20
50
|
schema?: ArrayItemRules<Context>;
|
|
@@ -47,17 +77,21 @@ export declare const createRules: <M extends BaseValidationMessages>(validationM
|
|
|
47
77
|
boolean: <T = unknown, D_6 = unknown>(params?: ValidationRuleParams<"boolean", {
|
|
48
78
|
expected?: boolean;
|
|
49
79
|
}>) => ValidationRuleResult<T, D_6>;
|
|
50
|
-
email: <T = unknown, D_7 = unknown>(params?: ValidationRuleParams<"email">) => ValidationRuleResult<T, D_7>;
|
|
80
|
+
email: <T = unknown, D_7 = unknown>(params?: ValidationRuleParams<"email", EmailParams>) => ValidationRuleResult<T, D_7>;
|
|
51
81
|
finite: <T = unknown, D_8 = unknown>(params?: ValidationRuleParams<"finite", RangeParams & {
|
|
52
82
|
maxDigitsAfterDot?: number;
|
|
53
83
|
}>) => ValidationRuleResult<T, D_8>;
|
|
54
84
|
lettersOnly: <T = unknown, D_9 = unknown>(params?: ValidationRuleParams<"lettersOnly", {
|
|
55
85
|
whiteSpaces?: boolean;
|
|
56
86
|
}>) => ValidationRuleResult<T, D_9>;
|
|
57
|
-
phone: <T = unknown, D_10 = unknown>(params?: ValidationRuleParams<"phone">) => ValidationRuleResult<T, D_10>;
|
|
58
|
-
date: <T = unknown, D_11 = unknown>(params?: ValidationRuleParams<"date">) => ValidationRuleResult<T, D_11>;
|
|
59
|
-
|
|
87
|
+
phone: <T = unknown, D_10 = unknown>(params?: ValidationRuleParams<"phone", PhoneParams>) => ValidationRuleResult<T, D_10>;
|
|
88
|
+
date: <T = unknown, D_11 = unknown>(params?: ValidationRuleParams<"date", DateRangeParams>) => ValidationRuleResult<T, D_11>;
|
|
89
|
+
condition: <T = unknown, D_12 = unknown, K = string>(predicate: (params: ValidationParams<T, D_12, K>) => boolean) => ValidationRuleResult<T, D_12, K>;
|
|
90
|
+
pattern: <T = unknown, D_13 = unknown>(params: ValidationRuleParams<"pattern", PatternParams>) => ValidationRuleResult<T, D_13>;
|
|
91
|
+
url: <T = unknown, D_14 = unknown>(params?: ValidationRuleParams<"url", UrlParams>) => ValidationRuleResult<T, D_14>;
|
|
92
|
+
file: <T = unknown, D_15 = unknown>(params?: ValidationRuleParams<"file", FileParams>) => ValidationRuleResult<T, D_15>;
|
|
93
|
+
allowedOnly: <T = unknown, D_16 = unknown>(params?: ValidationRuleParams<"allowedOnly", {
|
|
60
94
|
allowed?: unknown[];
|
|
61
|
-
}>) => ValidationRuleResult<T,
|
|
95
|
+
}>) => ValidationRuleResult<T, D_16>;
|
|
62
96
|
};
|
|
63
97
|
export {};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { DateUtil } from '../../../external/tools/index.js';
|
|
1
|
+
import { DateUtil, ObjectUtil } from '../../../external/tools/index.js';
|
|
2
|
+
import { SKIP_REMAINING_VALIDATION } from '../Schema.js';
|
|
2
3
|
/**
|
|
3
4
|
*
|
|
4
5
|
* @param validationMessages - BaseValidationMessages
|
|
@@ -9,6 +10,98 @@ export const createRules = (validationMessages) => {
|
|
|
9
10
|
const checkVal = (val) => {
|
|
10
11
|
return val !== undefined && val !== null;
|
|
11
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Checks a value against a regular expression.
|
|
15
|
+
*/
|
|
16
|
+
const pattern = (params) => {
|
|
17
|
+
const { regexp, message = validationMessages.pattern } = params;
|
|
18
|
+
return ({ val }) => {
|
|
19
|
+
if (!checkVal(val))
|
|
20
|
+
return undefined;
|
|
21
|
+
if (typeof val !== 'string')
|
|
22
|
+
return message();
|
|
23
|
+
regexp.lastIndex = 0;
|
|
24
|
+
const matches = regexp.test(val);
|
|
25
|
+
regexp.lastIndex = 0;
|
|
26
|
+
return matches ? undefined : message();
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Checks absolute URLs and, when enabled, relative URL paths.
|
|
31
|
+
*/
|
|
32
|
+
const url = (params) => {
|
|
33
|
+
const { protocols, allowRelative = false, message } = {
|
|
34
|
+
...params,
|
|
35
|
+
message: { ...validationMessages.url, ...params?.message }
|
|
36
|
+
};
|
|
37
|
+
const normalizedProtocols = protocols?.map((protocol) => protocol.toLowerCase().replace(/:$/, '')).filter(Boolean);
|
|
38
|
+
return ({ val }) => {
|
|
39
|
+
if (!checkVal(val))
|
|
40
|
+
return undefined;
|
|
41
|
+
if (typeof val !== 'string' || !val.length)
|
|
42
|
+
return message.base();
|
|
43
|
+
let parsed;
|
|
44
|
+
let relative = false;
|
|
45
|
+
try {
|
|
46
|
+
parsed = new URL(val);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
if (!allowRelative || !val.startsWith('/') || val.startsWith('//'))
|
|
50
|
+
return message.base();
|
|
51
|
+
parsed = new URL(val, 'https://azure-net.local');
|
|
52
|
+
relative = true;
|
|
53
|
+
}
|
|
54
|
+
if (!relative && normalizedProtocols?.length && !normalizedProtocols.includes(parsed.protocol.slice(0, -1).toLowerCase())) {
|
|
55
|
+
return message.protocol(normalizedProtocols.join(', '));
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Checks one or multiple File/Blob values and optional size, MIME type and extension constraints.
|
|
62
|
+
*/
|
|
63
|
+
const file = (params) => {
|
|
64
|
+
const { maxSize, mimeTypes, extensions, message } = {
|
|
65
|
+
...params,
|
|
66
|
+
message: { ...validationMessages.file, ...params?.message }
|
|
67
|
+
};
|
|
68
|
+
const normalizedMimeTypes = mimeTypes?.map((mimeType) => mimeType.trim().toLowerCase()).filter(Boolean);
|
|
69
|
+
const normalizedExtensions = extensions?.map((extension) => extension.trim().toLowerCase().replace(/^\./, '')).filter(Boolean);
|
|
70
|
+
const isBlobLike = (value) => typeof value === 'object' &&
|
|
71
|
+
value !== null &&
|
|
72
|
+
typeof value.size === 'number' &&
|
|
73
|
+
typeof value.type === 'string' &&
|
|
74
|
+
typeof value.arrayBuffer === 'function';
|
|
75
|
+
const matchesMimeType = (actual, expected) => {
|
|
76
|
+
if (expected === '*/*')
|
|
77
|
+
return true;
|
|
78
|
+
if (expected.endsWith('/*'))
|
|
79
|
+
return actual.startsWith(expected.slice(0, -1));
|
|
80
|
+
return actual === expected;
|
|
81
|
+
};
|
|
82
|
+
return ({ val }) => {
|
|
83
|
+
if (!checkVal(val))
|
|
84
|
+
return undefined;
|
|
85
|
+
const rawFiles = Array.isArray(val) ? val : typeof FileList !== 'undefined' && val instanceof FileList ? Array.from(val) : [val];
|
|
86
|
+
if (!rawFiles.length || !rawFiles.every(isBlobLike))
|
|
87
|
+
return message.base();
|
|
88
|
+
for (const currentFile of rawFiles) {
|
|
89
|
+
if (maxSize !== undefined && currentFile.size > maxSize)
|
|
90
|
+
return message.maxSize(maxSize);
|
|
91
|
+
const mimeType = currentFile.type.toLowerCase();
|
|
92
|
+
if (normalizedMimeTypes?.length && !normalizedMimeTypes.some((allowed) => matchesMimeType(mimeType, allowed))) {
|
|
93
|
+
return message.mimeType(normalizedMimeTypes.join(', '));
|
|
94
|
+
}
|
|
95
|
+
if (normalizedExtensions?.length) {
|
|
96
|
+
const fileName = currentFile.name?.toLowerCase() ?? '';
|
|
97
|
+
const extension = fileName.includes('.') ? (fileName.split('.').pop() ?? '') : '';
|
|
98
|
+
if (!normalizedExtensions.includes(extension))
|
|
99
|
+
return message.extension(normalizedExtensions.join(', '));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
};
|
|
104
|
+
};
|
|
12
105
|
/**
|
|
13
106
|
*
|
|
14
107
|
* @param params - ValidationRuleParams<'string', LengthParams>
|
|
@@ -136,6 +229,8 @@ export const createRules = (validationMessages) => {
|
|
|
136
229
|
listValues,
|
|
137
230
|
key: `${key}[${index}]`
|
|
138
231
|
});
|
|
232
|
+
if (fail === SKIP_REMAINING_VALIDATION)
|
|
233
|
+
break;
|
|
139
234
|
if (fail) {
|
|
140
235
|
itemErrors['_error'] = fail;
|
|
141
236
|
break;
|
|
@@ -156,6 +251,8 @@ export const createRules = (validationMessages) => {
|
|
|
156
251
|
listValues,
|
|
157
252
|
key: `${key}[${index}].${fieldKey}`
|
|
158
253
|
});
|
|
254
|
+
if (fail === SKIP_REMAINING_VALIDATION)
|
|
255
|
+
break;
|
|
159
256
|
if (fail) {
|
|
160
257
|
itemErrors[fieldKey] = fail;
|
|
161
258
|
break;
|
|
@@ -176,73 +273,109 @@ export const createRules = (validationMessages) => {
|
|
|
176
273
|
};
|
|
177
274
|
/**
|
|
178
275
|
*
|
|
179
|
-
* @param params - ValidationRuleParams<'phone'>
|
|
276
|
+
* @param params - ValidationRuleParams<'phone', PhoneParams>
|
|
180
277
|
* @returns ValidationRuleResult<T, D>
|
|
181
278
|
* @description Checks if the value is a phone number and if it is valid.
|
|
182
279
|
*/
|
|
183
280
|
const phone = (params) => {
|
|
184
|
-
const {
|
|
281
|
+
const { requireCountryCode = false, minDigits = 7, maxDigits = 15, message } = {
|
|
282
|
+
...params,
|
|
283
|
+
message: { ...validationMessages.phone, ...params?.message }
|
|
284
|
+
};
|
|
185
285
|
return ({ val }) => {
|
|
186
286
|
if (checkVal(val)) {
|
|
187
287
|
const rawVal = String(val).trim();
|
|
188
288
|
if (!rawVal) {
|
|
189
|
-
return message();
|
|
289
|
+
return message.base();
|
|
190
290
|
}
|
|
191
291
|
if (!/^[\d+\s().-]+$/.test(rawVal)) {
|
|
192
|
-
return message();
|
|
292
|
+
return message.base();
|
|
193
293
|
}
|
|
194
294
|
const normalized = rawVal.replace(/[\s().-]/g, '');
|
|
195
295
|
if (!normalized) {
|
|
196
|
-
return message();
|
|
296
|
+
return message.base();
|
|
197
297
|
}
|
|
198
298
|
const plusCount = (normalized.match(/\+/g) ?? []).length;
|
|
199
299
|
if (plusCount > 1 || (plusCount === 1 && !normalized.startsWith('+'))) {
|
|
200
|
-
return message();
|
|
300
|
+
return message.base();
|
|
201
301
|
}
|
|
202
302
|
const hasInternationalPrefix = normalized.startsWith('+');
|
|
203
303
|
const digitsOnly = hasInternationalPrefix ? normalized.slice(1) : normalized;
|
|
204
304
|
if (!/^\d+$/.test(digitsOnly)) {
|
|
205
|
-
return message();
|
|
206
|
-
}
|
|
207
|
-
if (hasInternationalPrefix) {
|
|
208
|
-
return /^[1-9]\d{6,14}$/.test(digitsOnly) ? undefined : message();
|
|
305
|
+
return message.base();
|
|
209
306
|
}
|
|
210
|
-
|
|
307
|
+
if (requireCountryCode && !hasInternationalPrefix)
|
|
308
|
+
return message.countryCode();
|
|
309
|
+
if (hasInternationalPrefix && digitsOnly.startsWith('0'))
|
|
310
|
+
return message.base();
|
|
311
|
+
if (digitsOnly.length < minDigits)
|
|
312
|
+
return params?.minDigits === undefined ? message.base() : message.minDigits(minDigits);
|
|
313
|
+
if (digitsOnly.length > maxDigits)
|
|
314
|
+
return params?.maxDigits === undefined ? message.base() : message.maxDigits(maxDigits);
|
|
315
|
+
return undefined;
|
|
211
316
|
}
|
|
212
317
|
return undefined;
|
|
213
318
|
};
|
|
214
319
|
};
|
|
215
320
|
/**
|
|
216
321
|
*
|
|
217
|
-
* @param params - ValidationRuleParams<'date'>
|
|
322
|
+
* @param params - ValidationRuleParams<'date', DateRangeParams>
|
|
218
323
|
* @returns ValidationRuleResult<T, D>
|
|
219
324
|
* @description Checks if the value is a valid date.
|
|
220
325
|
*/
|
|
221
326
|
const date = (params) => {
|
|
222
|
-
const { message } = { ...params, message:
|
|
327
|
+
const { message, range } = { ...params, message: { ...validationMessages.date, ...params?.message } };
|
|
223
328
|
return ({ val }) => {
|
|
224
|
-
if (checkVal(val))
|
|
225
|
-
return
|
|
226
|
-
|
|
329
|
+
if (!checkVal(val))
|
|
330
|
+
return undefined;
|
|
331
|
+
if (!(val instanceof Date || typeof val === 'string') || !DateUtil.isDate(val))
|
|
332
|
+
return message.base();
|
|
333
|
+
if (range?.min !== undefined && DateUtil.isBefore(val, range.min))
|
|
334
|
+
return message.min(range.min);
|
|
335
|
+
if (range?.max !== undefined && DateUtil.isAfter(val, range.max))
|
|
336
|
+
return message.max(range.max);
|
|
227
337
|
return undefined;
|
|
228
338
|
};
|
|
229
339
|
};
|
|
340
|
+
/**
|
|
341
|
+
* Stops validation of the current field when the predicate returns false.
|
|
342
|
+
*/
|
|
343
|
+
const condition = (predicate) => {
|
|
344
|
+
return (params) => (predicate(params) ? undefined : SKIP_REMAINING_VALIDATION);
|
|
345
|
+
};
|
|
230
346
|
/**
|
|
231
347
|
*
|
|
232
|
-
* @param params - ValidationRuleParams<'email'>
|
|
348
|
+
* @param params - ValidationRuleParams<'email', EmailParams>
|
|
233
349
|
* @returns ValidationRuleResult<T, D>
|
|
234
350
|
* @description Checks if the value is a valid email address.
|
|
235
351
|
*/
|
|
236
352
|
const email = (params) => {
|
|
237
|
-
const {
|
|
353
|
+
const { trim = false, maxLength, allowedDomains, blockedDomains, message } = {
|
|
354
|
+
...params,
|
|
355
|
+
message: { ...validationMessages.email, ...params?.message }
|
|
356
|
+
};
|
|
357
|
+
const normalizeDomain = (domain) => domain.trim().toLowerCase().replace(/^@/, '');
|
|
358
|
+
const normalizedAllowedDomains = allowedDomains?.map(normalizeDomain).filter(Boolean);
|
|
359
|
+
const normalizedBlockedDomains = blockedDomains?.map(normalizeDomain).filter(Boolean);
|
|
238
360
|
const emailRegExp =
|
|
239
361
|
// eslint-disable-next-line no-control-regex
|
|
240
362
|
/^(?:[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;
|
|
241
363
|
return ({ val }) => {
|
|
242
|
-
if (checkVal(val))
|
|
243
|
-
|
|
244
|
-
|
|
364
|
+
if (!checkVal(val))
|
|
365
|
+
return undefined;
|
|
366
|
+
if (typeof val !== 'string')
|
|
367
|
+
return message.base();
|
|
368
|
+
const emailValue = trim ? val.trim() : val;
|
|
369
|
+
if (!emailRegExp.test(emailValue))
|
|
370
|
+
return message.base();
|
|
371
|
+
if (maxLength !== undefined && emailValue.length > maxLength)
|
|
372
|
+
return message.maxLength(maxLength);
|
|
373
|
+
const domain = normalizeDomain(emailValue.slice(emailValue.lastIndexOf('@') + 1));
|
|
374
|
+
if (normalizedAllowedDomains?.length && !normalizedAllowedDomains.includes(domain)) {
|
|
375
|
+
return message.allowedDomain(normalizedAllowedDomains.join(', '));
|
|
245
376
|
}
|
|
377
|
+
if (normalizedBlockedDomains?.length && normalizedBlockedDomains.includes(domain))
|
|
378
|
+
return message.blockedDomain(domain);
|
|
246
379
|
return undefined;
|
|
247
380
|
};
|
|
248
381
|
};
|
|
@@ -295,23 +428,10 @@ export const createRules = (validationMessages) => {
|
|
|
295
428
|
const sameAs = (params) => {
|
|
296
429
|
const { message, key } = { ...params, message: params?.message ?? validationMessages.sameAs };
|
|
297
430
|
return ({ val, listValues }) => {
|
|
298
|
-
if (checkVal(val))
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
return message(String(key));
|
|
303
|
-
}
|
|
304
|
-
try {
|
|
305
|
-
return JSON.stringify(val) === JSON.stringify(listValues[key]) ? undefined : message(String(key));
|
|
306
|
-
}
|
|
307
|
-
catch {
|
|
308
|
-
return 'Parsing error';
|
|
309
|
-
}
|
|
310
|
-
default:
|
|
311
|
-
return String(val ?? '') === String(listValues?.[key] ?? '') ? undefined : message(String(key));
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return undefined;
|
|
431
|
+
if (!checkVal(val))
|
|
432
|
+
return undefined;
|
|
433
|
+
const comparedValue = listValues?.[key];
|
|
434
|
+
return ObjectUtil.equals(val, comparedValue) ? undefined : message(String(key));
|
|
315
435
|
};
|
|
316
436
|
};
|
|
317
437
|
/**
|
|
@@ -323,23 +443,10 @@ export const createRules = (validationMessages) => {
|
|
|
323
443
|
const notSameAs = (params) => {
|
|
324
444
|
const { message, key } = { ...params, message: params?.message ?? validationMessages.notSameAs };
|
|
325
445
|
return ({ val, listValues }) => {
|
|
326
|
-
if (checkVal(val))
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
return message(String(key));
|
|
331
|
-
}
|
|
332
|
-
try {
|
|
333
|
-
return JSON.stringify(val) !== JSON.stringify(listValues[key]) ? undefined : message(String(key));
|
|
334
|
-
}
|
|
335
|
-
catch {
|
|
336
|
-
return 'Parsing error';
|
|
337
|
-
}
|
|
338
|
-
default:
|
|
339
|
-
return String(val) === String(listValues?.[key]) ? undefined : message(String(key));
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
return undefined;
|
|
446
|
+
if (!checkVal(val))
|
|
447
|
+
return undefined;
|
|
448
|
+
const comparedValue = listValues?.[key];
|
|
449
|
+
return ObjectUtil.equals(val, comparedValue) ? message(String(key)) : undefined;
|
|
343
450
|
};
|
|
344
451
|
};
|
|
345
452
|
/**
|
|
@@ -403,5 +510,24 @@ export const createRules = (validationMessages) => {
|
|
|
403
510
|
return undefined;
|
|
404
511
|
};
|
|
405
512
|
};
|
|
406
|
-
return {
|
|
513
|
+
return {
|
|
514
|
+
string,
|
|
515
|
+
number,
|
|
516
|
+
required,
|
|
517
|
+
password,
|
|
518
|
+
notSameAs,
|
|
519
|
+
sameAs,
|
|
520
|
+
array,
|
|
521
|
+
boolean,
|
|
522
|
+
email,
|
|
523
|
+
finite,
|
|
524
|
+
lettersOnly,
|
|
525
|
+
phone,
|
|
526
|
+
date,
|
|
527
|
+
condition,
|
|
528
|
+
pattern,
|
|
529
|
+
url,
|
|
530
|
+
file,
|
|
531
|
+
allowedOnly
|
|
532
|
+
};
|
|
407
533
|
};
|
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
export const validationMessagesEn = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
pattern: () => 'Invalid field format',
|
|
3
|
+
url: {
|
|
4
|
+
base: () => 'Invalid URL format',
|
|
5
|
+
protocol: (value) => `URL protocol must be one of: ${value}`
|
|
6
|
+
},
|
|
7
|
+
file: {
|
|
8
|
+
base: () => 'This field must contain a file',
|
|
9
|
+
maxSize: (value) => `File size must not exceed ${value} bytes`,
|
|
10
|
+
mimeType: (value) => `File type must be one of: ${value}`,
|
|
11
|
+
extension: (value) => `File extension must be one of: ${value}`
|
|
12
|
+
},
|
|
13
|
+
date: {
|
|
14
|
+
base: () => 'Invalid date format',
|
|
15
|
+
min: (value) => `The date must be on or after ${value instanceof Date ? value.toISOString() : value}`,
|
|
16
|
+
max: (value) => `The date must be on or before ${value instanceof Date ? value.toISOString() : value}`
|
|
17
|
+
},
|
|
18
|
+
phone: {
|
|
19
|
+
base: () => 'Invalid phone number format',
|
|
20
|
+
countryCode: () => 'Phone number must include an international country code',
|
|
21
|
+
minDigits: (value) => `Phone number must contain at least ${value} digits`,
|
|
22
|
+
maxDigits: (value) => `Phone number must contain at most ${value} digits`
|
|
23
|
+
},
|
|
24
|
+
email: {
|
|
25
|
+
base: () => 'Invalid email address',
|
|
26
|
+
maxLength: (value) => `Email address must not exceed ${value} characters`,
|
|
27
|
+
allowedDomain: (value) => `Email domain must be one of: ${value}`,
|
|
28
|
+
blockedDomain: (value) => `Email domain is not allowed: ${value}`
|
|
29
|
+
},
|
|
5
30
|
required: () => 'This field is required',
|
|
6
31
|
lettersOnly: (whiteSpaces) => `This field may contain letters only${whiteSpaces ? '' : ' and must not contain spaces'}`,
|
|
7
32
|
allowedOnly: (value) => value && value.length ? `This field may contain only one of the following values: ${value}` : 'This field has no allowed values',
|
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
export const validationMessagesRu = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
pattern: () => 'Значение не соответствует требуемому формату',
|
|
3
|
+
url: {
|
|
4
|
+
base: () => 'Неверный формат URL',
|
|
5
|
+
protocol: (value) => `Протокол URL должен быть одним из: ${value}`
|
|
6
|
+
},
|
|
7
|
+
file: {
|
|
8
|
+
base: () => 'Поле должно содержать файл',
|
|
9
|
+
maxSize: (value) => `Размер файла не должен превышать ${value} байт`,
|
|
10
|
+
mimeType: (value) => `Тип файла должен быть одним из: ${value}`,
|
|
11
|
+
extension: (value) => `Расширение файла должно быть одним из: ${value}`
|
|
12
|
+
},
|
|
13
|
+
date: {
|
|
14
|
+
base: () => 'Неверный формат даты',
|
|
15
|
+
min: (value) => `Дата должна быть не раньше ${value instanceof Date ? value.toISOString() : value}`,
|
|
16
|
+
max: (value) => `Дата должна быть не позже ${value instanceof Date ? value.toISOString() : value}`
|
|
17
|
+
},
|
|
18
|
+
phone: {
|
|
19
|
+
base: () => 'Неверный формат номера телефона',
|
|
20
|
+
countryCode: () => 'Номер телефона должен содержать международный код страны',
|
|
21
|
+
minDigits: (value) => `Номер телефона должен содержать не менее ${value} цифр`,
|
|
22
|
+
maxDigits: (value) => `Номер телефона должен содержать не более ${value} цифр`
|
|
23
|
+
},
|
|
24
|
+
email: {
|
|
25
|
+
base: () => 'Невалидный email',
|
|
26
|
+
maxLength: (value) => `Email не должен быть длиннее ${value} символов`,
|
|
27
|
+
allowedDomain: (value) => `Домен email должен быть одним из: ${value}`,
|
|
28
|
+
blockedDomain: (value) => `Домен email запрещен: ${value}`
|
|
29
|
+
},
|
|
5
30
|
required: () => 'Поле обязательно к заполнению',
|
|
6
31
|
lettersOnly: (whiteSpaces) => `Поле может содержать только буквы ${whiteSpaces ? '' : 'и не должно содержать пробелы'}`,
|
|
7
32
|
allowedOnly: (value) => value && value.length ? `Поле может содержать только одно из следующих значений:: ${value}` : 'Поле не имеет допустимых значений',
|
|
@@ -1,8 +1,33 @@
|
|
|
1
1
|
import type { ValidationMessage } from '../../index.js';
|
|
2
2
|
export type BaseValidationMessages = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
pattern: () => ValidationMessage;
|
|
4
|
+
url: {
|
|
5
|
+
base: () => ValidationMessage;
|
|
6
|
+
protocol: (value: string) => ValidationMessage;
|
|
7
|
+
};
|
|
8
|
+
file: {
|
|
9
|
+
base: () => ValidationMessage;
|
|
10
|
+
maxSize: (value: number) => ValidationMessage;
|
|
11
|
+
mimeType: (value: string) => ValidationMessage;
|
|
12
|
+
extension: (value: string) => ValidationMessage;
|
|
13
|
+
};
|
|
14
|
+
date: {
|
|
15
|
+
base: () => ValidationMessage;
|
|
16
|
+
min: (value: Date | string) => ValidationMessage;
|
|
17
|
+
max: (value: Date | string) => ValidationMessage;
|
|
18
|
+
};
|
|
19
|
+
phone: {
|
|
20
|
+
base: () => ValidationMessage;
|
|
21
|
+
countryCode: () => ValidationMessage;
|
|
22
|
+
minDigits: (value: number) => ValidationMessage;
|
|
23
|
+
maxDigits: (value: number) => ValidationMessage;
|
|
24
|
+
};
|
|
25
|
+
email: {
|
|
26
|
+
base: () => ValidationMessage;
|
|
27
|
+
maxLength: (value: number) => ValidationMessage;
|
|
28
|
+
allowedDomain: (value: string) => ValidationMessage;
|
|
29
|
+
blockedDomain: (value: string) => ValidationMessage;
|
|
30
|
+
};
|
|
6
31
|
required: () => ValidationMessage;
|
|
7
32
|
lettersOnly: (whiteSpaces: boolean) => ValidationMessage;
|
|
8
33
|
allowedOnly: (allowed: string) => ValidationMessage;
|
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
export const validationMessagesI18n = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
pattern: () => 'validation.pattern',
|
|
3
|
+
url: {
|
|
4
|
+
base: () => 'validation.url',
|
|
5
|
+
protocol: (value) => ({ key: 'validation.urlProtocol', vars: { value } })
|
|
6
|
+
},
|
|
7
|
+
file: {
|
|
8
|
+
base: () => 'validation.file',
|
|
9
|
+
maxSize: (value) => ({ key: 'validation.fileMaxSize', vars: { value } }),
|
|
10
|
+
mimeType: (value) => ({ key: 'validation.fileMimeType', vars: { value } }),
|
|
11
|
+
extension: (value) => ({ key: 'validation.fileExtension', vars: { value } })
|
|
12
|
+
},
|
|
13
|
+
date: {
|
|
14
|
+
base: () => 'validation.date',
|
|
15
|
+
min: (value) => ({ key: 'validation.dateMin', vars: { value: value instanceof Date ? value.toISOString() : value } }),
|
|
16
|
+
max: (value) => ({ key: 'validation.dateMax', vars: { value: value instanceof Date ? value.toISOString() : value } })
|
|
17
|
+
},
|
|
18
|
+
phone: {
|
|
19
|
+
base: () => 'validation.phone',
|
|
20
|
+
countryCode: () => 'validation.phoneCountryCode',
|
|
21
|
+
minDigits: (value) => ({ key: 'validation.phoneMinDigits', vars: { value } }),
|
|
22
|
+
maxDigits: (value) => ({ key: 'validation.phoneMaxDigits', vars: { value } })
|
|
23
|
+
},
|
|
24
|
+
email: {
|
|
25
|
+
base: () => 'validation.email',
|
|
26
|
+
maxLength: (value) => ({ key: 'validation.emailMaxLength', vars: { value } }),
|
|
27
|
+
allowedDomain: (value) => ({ key: 'validation.emailAllowedDomain', vars: { value } }),
|
|
28
|
+
blockedDomain: (value) => ({ key: 'validation.emailBlockedDomain', vars: { value } })
|
|
29
|
+
},
|
|
5
30
|
required: () => 'validation.required',
|
|
6
31
|
lettersOnly: (whiteSpaces) => (whiteSpaces ? 'validation.lettersOnlyWithWhiteSpaces' : 'validation.lettersOnly'),
|
|
7
32
|
allowedOnly: (value) => ({ key: value && value.length ? 'validation.allowedOnly.base' : 'validation.allowedOnly.nothing', vars: { value } }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { edgesHandle,
|
|
1
|
+
export { edgesHandle, edgesHandleRaw } from '@azure-net/edges/server';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { edgesHandle,
|
|
1
|
+
export { edgesHandle, edgesHandleRaw } from '@azure-net/edges/server';
|