@reformer/core 1.0.0-beta.3
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 +53 -0
- package/dist/behaviors.d.ts +2 -0
- package/dist/behaviors.js +230 -0
- package/dist/core/behavior/behavior-applicator.d.ts +71 -0
- package/dist/core/behavior/behavior-applicator.js +92 -0
- package/dist/core/behavior/behavior-context.d.ts +29 -0
- package/dist/core/behavior/behavior-context.js +38 -0
- package/dist/core/behavior/behavior-registry.d.ts +97 -0
- package/dist/core/behavior/behavior-registry.js +198 -0
- package/dist/core/behavior/behaviors/compute-from.d.ts +41 -0
- package/dist/core/behavior/behaviors/compute-from.js +84 -0
- package/dist/core/behavior/behaviors/copy-from.d.ts +31 -0
- package/dist/core/behavior/behaviors/copy-from.js +64 -0
- package/dist/core/behavior/behaviors/enable-when.d.ts +49 -0
- package/dist/core/behavior/behaviors/enable-when.js +81 -0
- package/dist/core/behavior/behaviors/index.d.ts +11 -0
- package/dist/core/behavior/behaviors/index.js +11 -0
- package/dist/core/behavior/behaviors/reset-when.d.ts +51 -0
- package/dist/core/behavior/behaviors/reset-when.js +63 -0
- package/dist/core/behavior/behaviors/revalidate-when.d.ts +30 -0
- package/dist/core/behavior/behaviors/revalidate-when.js +51 -0
- package/dist/core/behavior/behaviors/sync-fields.d.ts +28 -0
- package/dist/core/behavior/behaviors/sync-fields.js +66 -0
- package/dist/core/behavior/behaviors/transform-value.d.ts +120 -0
- package/dist/core/behavior/behaviors/transform-value.js +110 -0
- package/dist/core/behavior/behaviors/watch-field.d.ts +35 -0
- package/dist/core/behavior/behaviors/watch-field.js +56 -0
- package/dist/core/behavior/compose-behavior.d.ts +106 -0
- package/dist/core/behavior/compose-behavior.js +166 -0
- package/dist/core/behavior/create-field-path.d.ts +20 -0
- package/dist/core/behavior/create-field-path.js +69 -0
- package/dist/core/behavior/index.d.ts +12 -0
- package/dist/core/behavior/index.js +17 -0
- package/dist/core/behavior/types.d.ts +152 -0
- package/dist/core/behavior/types.js +7 -0
- package/dist/core/context/form-context-impl.d.ts +29 -0
- package/dist/core/context/form-context-impl.js +37 -0
- package/dist/core/factories/index.d.ts +6 -0
- package/dist/core/factories/index.js +6 -0
- package/dist/core/factories/node-factory.d.ts +209 -0
- package/dist/core/factories/node-factory.js +281 -0
- package/dist/core/nodes/array-node.d.ts +308 -0
- package/dist/core/nodes/array-node.js +534 -0
- package/dist/core/nodes/field-node.d.ts +269 -0
- package/dist/core/nodes/field-node.js +510 -0
- package/dist/core/nodes/form-node.d.ts +342 -0
- package/dist/core/nodes/form-node.js +343 -0
- package/dist/core/nodes/group-node/field-registry.d.ts +191 -0
- package/dist/core/nodes/group-node/field-registry.js +215 -0
- package/dist/core/nodes/group-node/index.d.ts +11 -0
- package/dist/core/nodes/group-node/index.js +11 -0
- package/dist/core/nodes/group-node/proxy-builder.d.ts +71 -0
- package/dist/core/nodes/group-node/proxy-builder.js +161 -0
- package/dist/core/nodes/group-node/state-manager.d.ts +184 -0
- package/dist/core/nodes/group-node/state-manager.js +265 -0
- package/dist/core/nodes/group-node.d.ts +494 -0
- package/dist/core/nodes/group-node.js +770 -0
- package/dist/core/types/deep-schema.d.ts +78 -0
- package/dist/core/types/deep-schema.js +11 -0
- package/dist/core/types/field-path.d.ts +42 -0
- package/dist/core/types/field-path.js +4 -0
- package/dist/core/types/form-context.d.ts +83 -0
- package/dist/core/types/form-context.js +25 -0
- package/dist/core/types/group-node-proxy.d.ts +135 -0
- package/dist/core/types/group-node-proxy.js +31 -0
- package/dist/core/types/index.d.ts +163 -0
- package/dist/core/types/index.js +4 -0
- package/dist/core/types/validation-schema.d.ts +104 -0
- package/dist/core/types/validation-schema.js +10 -0
- package/dist/core/utils/create-form.d.ts +61 -0
- package/dist/core/utils/create-form.js +24 -0
- package/dist/core/utils/debounce.d.ts +160 -0
- package/dist/core/utils/debounce.js +197 -0
- package/dist/core/utils/error-handler.d.ts +180 -0
- package/dist/core/utils/error-handler.js +226 -0
- package/dist/core/utils/field-path-navigator.d.ts +240 -0
- package/dist/core/utils/field-path-navigator.js +374 -0
- package/dist/core/utils/index.d.ts +14 -0
- package/dist/core/utils/index.js +14 -0
- package/dist/core/utils/registry-helpers.d.ts +50 -0
- package/dist/core/utils/registry-helpers.js +79 -0
- package/dist/core/utils/registry-stack.d.ts +69 -0
- package/dist/core/utils/registry-stack.js +86 -0
- package/dist/core/utils/resources.d.ts +41 -0
- package/dist/core/utils/resources.js +69 -0
- package/dist/core/utils/subscription-manager.d.ts +180 -0
- package/dist/core/utils/subscription-manager.js +214 -0
- package/dist/core/utils/type-guards.d.ts +116 -0
- package/dist/core/utils/type-guards.js +169 -0
- package/dist/core/validation/core/apply-when.d.ts +28 -0
- package/dist/core/validation/core/apply-when.js +41 -0
- package/dist/core/validation/core/apply.d.ts +63 -0
- package/dist/core/validation/core/apply.js +38 -0
- package/dist/core/validation/core/index.d.ts +8 -0
- package/dist/core/validation/core/index.js +8 -0
- package/dist/core/validation/core/validate-async.d.ts +42 -0
- package/dist/core/validation/core/validate-async.js +45 -0
- package/dist/core/validation/core/validate-tree.d.ts +35 -0
- package/dist/core/validation/core/validate-tree.js +37 -0
- package/dist/core/validation/core/validate.d.ts +32 -0
- package/dist/core/validation/core/validate.js +38 -0
- package/dist/core/validation/field-path.d.ts +43 -0
- package/dist/core/validation/field-path.js +147 -0
- package/dist/core/validation/index.d.ts +21 -0
- package/dist/core/validation/index.js +33 -0
- package/dist/core/validation/validate-form.d.ts +85 -0
- package/dist/core/validation/validate-form.js +152 -0
- package/dist/core/validation/validation-applicator.d.ts +89 -0
- package/dist/core/validation/validation-applicator.js +217 -0
- package/dist/core/validation/validation-context.d.ts +47 -0
- package/dist/core/validation/validation-context.js +75 -0
- package/dist/core/validation/validation-registry.d.ts +156 -0
- package/dist/core/validation/validation-registry.js +298 -0
- package/dist/core/validation/validators/array-validators.d.ts +63 -0
- package/dist/core/validation/validators/array-validators.js +86 -0
- package/dist/core/validation/validators/date.d.ts +38 -0
- package/dist/core/validation/validators/date.js +117 -0
- package/dist/core/validation/validators/email.d.ts +44 -0
- package/dist/core/validation/validators/email.js +60 -0
- package/dist/core/validation/validators/index.d.ts +14 -0
- package/dist/core/validation/validators/index.js +14 -0
- package/dist/core/validation/validators/max-length.d.ts +45 -0
- package/dist/core/validation/validators/max-length.js +60 -0
- package/dist/core/validation/validators/max.d.ts +45 -0
- package/dist/core/validation/validators/max.js +60 -0
- package/dist/core/validation/validators/min-length.d.ts +45 -0
- package/dist/core/validation/validators/min-length.js +60 -0
- package/dist/core/validation/validators/min.d.ts +45 -0
- package/dist/core/validation/validators/min.js +60 -0
- package/dist/core/validation/validators/number.d.ts +38 -0
- package/dist/core/validation/validators/number.js +90 -0
- package/dist/core/validation/validators/pattern.d.ts +47 -0
- package/dist/core/validation/validators/pattern.js +62 -0
- package/dist/core/validation/validators/phone.d.ts +34 -0
- package/dist/core/validation/validators/phone.js +58 -0
- package/dist/core/validation/validators/required.d.ts +48 -0
- package/dist/core/validation/validators/required.js +69 -0
- package/dist/core/validation/validators/url.d.ts +29 -0
- package/dist/core/validation/validators/url.js +55 -0
- package/dist/create-field-path-CdPF3lIK.js +704 -0
- package/dist/hooks/useFormControl.d.ts +48 -0
- package/dist/hooks/useFormControl.js +298 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +8 -0
- package/dist/node-factory-D7DOnSSN.js +3200 -0
- package/dist/validators.d.ts +2 -0
- package/dist/validators.js +298 -0
- package/llms.txt +847 -0
- package/package.json +86 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Guards - централизованные функции проверки типов узлов
|
|
3
|
+
*
|
|
4
|
+
* Устраняет дублирование между form-node.ts, validation-applicator.ts и validation-context.ts
|
|
5
|
+
*
|
|
6
|
+
* @group Utilities
|
|
7
|
+
* @category Type Guards
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* import { isFieldNode, isGroupNode } from '@/core/utils/type-guards';
|
|
12
|
+
*
|
|
13
|
+
* if (isFieldNode(node)) {
|
|
14
|
+
* // TypeScript знает, что node это FieldNode
|
|
15
|
+
* node.validators;
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Проверить, является ли значение любым FormNode
|
|
21
|
+
*
|
|
22
|
+
* Проверяет базовые свойства, общие для всех типов узлов
|
|
23
|
+
*
|
|
24
|
+
* @group Utilities
|
|
25
|
+
* @category Type Guards
|
|
26
|
+
*
|
|
27
|
+
* @param value - Значение для проверки
|
|
28
|
+
* @returns true если value является FormNode
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* if (isFormNode(value)) {
|
|
33
|
+
* value.setValue(newValue);
|
|
34
|
+
* value.validate();
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function isFormNode(value) {
|
|
39
|
+
if (value === null || value === undefined) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
return (typeof value === 'object' &&
|
|
43
|
+
'value' in value &&
|
|
44
|
+
'setValue' in value &&
|
|
45
|
+
'getValue' in value &&
|
|
46
|
+
'validate' in value);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Проверить, является ли значение FieldNode (примитивное поле)
|
|
50
|
+
*
|
|
51
|
+
* FieldNode представляет примитивное поле формы (string, number, boolean и т.д.)
|
|
52
|
+
* и имеет валидаторы, но не имеет вложенных полей или элементов массива
|
|
53
|
+
*
|
|
54
|
+
* @group Utilities
|
|
55
|
+
* @category Type Guards
|
|
56
|
+
*
|
|
57
|
+
* @param value - Значение для проверки
|
|
58
|
+
* @returns true если value является FieldNode
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* if (isFieldNode(node)) {
|
|
63
|
+
* node.validators; // OK
|
|
64
|
+
* node.asyncValidators; // OK
|
|
65
|
+
* node.markAsTouched(); // OK
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export function isFieldNode(value) {
|
|
70
|
+
if (value === null || value === undefined) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return (isFormNode(value) &&
|
|
74
|
+
'validators' in value &&
|
|
75
|
+
'asyncValidators' in value &&
|
|
76
|
+
// FieldNode имеет markAsTouched метод
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
|
+
typeof value.markAsTouched === 'function' &&
|
|
79
|
+
// У FieldNode нет fields или items
|
|
80
|
+
!('fields' in value) &&
|
|
81
|
+
!('items' in value));
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Проверить, является ли значение GroupNode (объект с вложенными полями)
|
|
85
|
+
*
|
|
86
|
+
* GroupNode представляет объект с вложенными полями формы
|
|
87
|
+
* и имеет методы для применения validation/behavior схем
|
|
88
|
+
*
|
|
89
|
+
* @param value - Значение для проверки
|
|
90
|
+
* @returns true если value является GroupNode
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* if (isGroupNode(node)) {
|
|
95
|
+
* node.applyValidationSchema(schema); // OK
|
|
96
|
+
* node.getFieldByPath('user.email'); // OK
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export function isGroupNode(value) {
|
|
101
|
+
if (value === null || value === undefined) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
return (isFormNode(value) &&
|
|
105
|
+
'applyValidationSchema' in value &&
|
|
106
|
+
'applyBehaviorSchema' in value &&
|
|
107
|
+
'getFieldByPath' in value &&
|
|
108
|
+
// GroupNode НЕ имеет items/push/removeAt (это ArrayNode)
|
|
109
|
+
!('items' in value) &&
|
|
110
|
+
!('push' in value) &&
|
|
111
|
+
!('removeAt' in value));
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Проверить, является ли значение ArrayNode (массив форм)
|
|
115
|
+
*
|
|
116
|
+
* ArrayNode представляет массив вложенных форм (обычно GroupNode)
|
|
117
|
+
* и имеет array-like методы (push, removeAt, at)
|
|
118
|
+
*
|
|
119
|
+
* @param value - Значение для проверки
|
|
120
|
+
* @returns true если value является ArrayNode
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* if (isArrayNode(node)) {
|
|
125
|
+
* node.push(); // OK - добавить элемент
|
|
126
|
+
* node.removeAt(0); // OK - удалить элемент
|
|
127
|
+
* const item = node.at(0); // OK - получить элемент
|
|
128
|
+
* }
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
export function isArrayNode(value) {
|
|
132
|
+
if (value === null || value === undefined) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
return (isFormNode(value) &&
|
|
136
|
+
'items' in value &&
|
|
137
|
+
'length' in value &&
|
|
138
|
+
'push' in value &&
|
|
139
|
+
'removeAt' in value &&
|
|
140
|
+
'at' in value &&
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
142
|
+
typeof value.push === 'function' &&
|
|
143
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
144
|
+
typeof value.removeAt === 'function');
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Получить тип узла как строку (для отладки)
|
|
148
|
+
*
|
|
149
|
+
* Полезно для логирования и отладки
|
|
150
|
+
*
|
|
151
|
+
* @param node - Узел для проверки
|
|
152
|
+
* @returns Строковое название типа узла
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```typescript
|
|
156
|
+
* console.log('Node type:', getNodeType(node)); // "FieldNode" | "GroupNode" | "ArrayNode" | "FormNode" | "Unknown"
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
export function getNodeType(node) {
|
|
160
|
+
if (isFieldNode(node))
|
|
161
|
+
return 'FieldNode';
|
|
162
|
+
if (isGroupNode(node))
|
|
163
|
+
return 'GroupNode';
|
|
164
|
+
if (isArrayNode(node))
|
|
165
|
+
return 'ArrayNode';
|
|
166
|
+
if (isFormNode(node))
|
|
167
|
+
return 'FormNode';
|
|
168
|
+
return 'Unknown';
|
|
169
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Условная валидация
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import type { FieldPath } from '../../types/field-path';
|
|
8
|
+
import type { ConditionFn } from '../../types/validation-schema';
|
|
9
|
+
import type { FieldPathNode } from '../../types';
|
|
10
|
+
/**
|
|
11
|
+
* Применить валидацию только при выполнении условия
|
|
12
|
+
*
|
|
13
|
+
* @group Validation
|
|
14
|
+
* @category Core Functions
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* applyWhen(
|
|
19
|
+
* path.loanType,
|
|
20
|
+
* (type) => type === 'mortgage',
|
|
21
|
+
* (path) => {
|
|
22
|
+
* required(path.propertyValue, { message: 'Укажите стоимость' });
|
|
23
|
+
* min(path.propertyValue, 1000000);
|
|
24
|
+
* }
|
|
25
|
+
* );
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function applyWhen<TForm, TField>(fieldPath: FieldPathNode<TForm, TField>, condition: ConditionFn<TField>, validationFn: (path: FieldPath<TForm>) => void): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Условная валидация
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import { extractPath, createFieldPath } from '../field-path';
|
|
8
|
+
import { getCurrentValidationRegistry } from '../../utils/registry-helpers';
|
|
9
|
+
/**
|
|
10
|
+
* Применить валидацию только при выполнении условия
|
|
11
|
+
*
|
|
12
|
+
* @group Validation
|
|
13
|
+
* @category Core Functions
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* applyWhen(
|
|
18
|
+
* path.loanType,
|
|
19
|
+
* (type) => type === 'mortgage',
|
|
20
|
+
* (path) => {
|
|
21
|
+
* required(path.propertyValue, { message: 'Укажите стоимость' });
|
|
22
|
+
* min(path.propertyValue, 1000000);
|
|
23
|
+
* }
|
|
24
|
+
* );
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export function applyWhen(fieldPath, condition, validationFn) {
|
|
28
|
+
const path = extractPath(fieldPath);
|
|
29
|
+
// Входим в условный блок
|
|
30
|
+
getCurrentValidationRegistry().enterCondition(path, condition);
|
|
31
|
+
try {
|
|
32
|
+
// Выполняем вложенную валидацию
|
|
33
|
+
// Создаем новый FieldPath proxy для вложенной функции
|
|
34
|
+
const nestedPath = createFieldPath();
|
|
35
|
+
validationFn(nestedPath);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
// Выходим из условного блока
|
|
39
|
+
getCurrentValidationRegistry().exitCondition();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Композиция validation схем
|
|
3
|
+
*
|
|
4
|
+
* Предоставляет функции для переиспользования validation схем:
|
|
5
|
+
* - apply: применение схемы к полям (новый API)
|
|
6
|
+
*
|
|
7
|
+
* Дополняет существующий toFieldPath и applyWhen.
|
|
8
|
+
*
|
|
9
|
+
* @group Validation
|
|
10
|
+
* @category Core Functions
|
|
11
|
+
*/
|
|
12
|
+
import type { FieldPathNode, FieldPath } from '../../types';
|
|
13
|
+
import type { ValidationSchemaFn } from '../../types/validation-schema';
|
|
14
|
+
/**
|
|
15
|
+
* Применить validation схему к корневому path формы
|
|
16
|
+
*
|
|
17
|
+
* Используется для композиции схем на уровне всей формы.
|
|
18
|
+
*
|
|
19
|
+
* @group Validation
|
|
20
|
+
* @category Core Functions
|
|
21
|
+
*
|
|
22
|
+
* @param path - Корневой FieldPath формы (весь объект путей)
|
|
23
|
+
* @param validationSchema - Схема валидации
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const creditApplicationValidation: ValidationSchemaFn<CreditApplicationForm> = (path) => {
|
|
28
|
+
* apply(path, basicInfoValidation);
|
|
29
|
+
* apply(path, contactInfoValidation);
|
|
30
|
+
* };
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function apply<TForm>(path: FieldPath<TForm>, validationSchema: ValidationSchemaFn<TForm>): void;
|
|
34
|
+
/**
|
|
35
|
+
* Применить validation схему к вложенному полю или полям
|
|
36
|
+
*
|
|
37
|
+
* Поддерживает:
|
|
38
|
+
* - Одно поле или массив полей
|
|
39
|
+
* - Одну схему или массив схем
|
|
40
|
+
* - Все комбинации (поле + схема, поле + схемы, поля + схема, поля + схемы)
|
|
41
|
+
*
|
|
42
|
+
* @param fields - Одно поле или массив полей
|
|
43
|
+
* @param validationSchemas - Одна схема или массив схем
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* // Одна схема к одному полю
|
|
48
|
+
* apply(path.registrationAddress, addressValidation);
|
|
49
|
+
*
|
|
50
|
+
* // Одна схема к нескольким полям
|
|
51
|
+
* apply([path.homeAddress, path.workAddress], addressValidation);
|
|
52
|
+
*
|
|
53
|
+
* // Несколько схем к одному полю
|
|
54
|
+
* apply(path.email, [emailValidation, uniqueEmailValidation]);
|
|
55
|
+
*
|
|
56
|
+
* // Несколько схем к нескольким полям
|
|
57
|
+
* apply(
|
|
58
|
+
* [path.email, path.confirmEmail],
|
|
59
|
+
* [emailValidation, matchValidation]
|
|
60
|
+
* );
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function apply<TForm, TField>(fields: FieldPathNode<TForm, TField> | Array<FieldPathNode<TForm, TField> | undefined> | undefined, validationSchemas: ValidationSchemaFn<TField> | Array<ValidationSchemaFn<TField>>): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Композиция validation схем
|
|
3
|
+
*
|
|
4
|
+
* Предоставляет функции для переиспользования validation схем:
|
|
5
|
+
* - apply: применение схемы к полям (новый API)
|
|
6
|
+
*
|
|
7
|
+
* Дополняет существующий toFieldPath и applyWhen.
|
|
8
|
+
*
|
|
9
|
+
* @group Validation
|
|
10
|
+
* @category Core Functions
|
|
11
|
+
*/
|
|
12
|
+
import { toFieldPath } from '../field-path';
|
|
13
|
+
// Реализация
|
|
14
|
+
export function apply(pathOrFields, validationSchemas) {
|
|
15
|
+
// Случай 1: FieldPath<TForm> + одна схема (композиция на уровне формы)
|
|
16
|
+
// Проверяем, является ли это FieldPath (не имеет __key и __path)
|
|
17
|
+
if (!Array.isArray(pathOrFields) &&
|
|
18
|
+
!Array.isArray(validationSchemas) &&
|
|
19
|
+
pathOrFields &&
|
|
20
|
+
!('__key' in pathOrFields) &&
|
|
21
|
+
!('__path' in pathOrFields)) {
|
|
22
|
+
const path = pathOrFields;
|
|
23
|
+
const schema = validationSchemas;
|
|
24
|
+
schema(path);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// Случай 2: FieldPathNode или массив полей
|
|
28
|
+
const fieldArray = (Array.isArray(pathOrFields) ? pathOrFields : [pathOrFields]).filter(Boolean);
|
|
29
|
+
const schemaArray = Array.isArray(validationSchemas) ? validationSchemas : [validationSchemas];
|
|
30
|
+
// Применяем все схемы ко всем полям
|
|
31
|
+
for (const field of fieldArray) {
|
|
32
|
+
const nestedPath = toFieldPath(field);
|
|
33
|
+
for (const schema of schemaArray) {
|
|
34
|
+
// Type assertion: в случае 2 мы работаем только с ValidationSchemaFn<TField>
|
|
35
|
+
schema(nestedPath);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Асинхронная валидация поля
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import type { ContextualAsyncValidatorFn, ValidateAsyncOptions } from '../../types/validation-schema';
|
|
8
|
+
import type { FieldPathNode } from '../../types';
|
|
9
|
+
/**
|
|
10
|
+
* Зарегистрировать асинхронный валидатор для поля
|
|
11
|
+
*
|
|
12
|
+
* @group Validation
|
|
13
|
+
* @category Core Functions
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* validateAsync(
|
|
18
|
+
* path.inn,
|
|
19
|
+
* async (ctx: ValidationContext<TForm, TField>) => {
|
|
20
|
+
* const inn = ctx.value();
|
|
21
|
+
* if (!inn) return null;
|
|
22
|
+
*
|
|
23
|
+
* const response = await fetch('/api/validate-inn', {
|
|
24
|
+
* method: 'POST',
|
|
25
|
+
* body: JSON.stringify({ inn }),
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* const data = await response.json();
|
|
29
|
+
* if (!data.valid) {
|
|
30
|
+
* return {
|
|
31
|
+
* code: 'invalidInn',
|
|
32
|
+
* message: 'ИНН не найден в базе данных ФНС',
|
|
33
|
+
* };
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* return null;
|
|
37
|
+
* },
|
|
38
|
+
* { debounce: 1000 }
|
|
39
|
+
* );
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function validateAsync<TForm, TField>(fieldPath: FieldPathNode<TForm, TField>, validatorFn: ContextualAsyncValidatorFn<TForm, TField>, options?: ValidateAsyncOptions): void;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Асинхронная валидация поля
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import { extractPath } from '../field-path';
|
|
8
|
+
import { getCurrentValidationRegistry } from '../../utils/registry-helpers';
|
|
9
|
+
/**
|
|
10
|
+
* Зарегистрировать асинхронный валидатор для поля
|
|
11
|
+
*
|
|
12
|
+
* @group Validation
|
|
13
|
+
* @category Core Functions
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* validateAsync(
|
|
18
|
+
* path.inn,
|
|
19
|
+
* async (ctx: ValidationContext<TForm, TField>) => {
|
|
20
|
+
* const inn = ctx.value();
|
|
21
|
+
* if (!inn) return null;
|
|
22
|
+
*
|
|
23
|
+
* const response = await fetch('/api/validate-inn', {
|
|
24
|
+
* method: 'POST',
|
|
25
|
+
* body: JSON.stringify({ inn }),
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* const data = await response.json();
|
|
29
|
+
* if (!data.valid) {
|
|
30
|
+
* return {
|
|
31
|
+
* code: 'invalidInn',
|
|
32
|
+
* message: 'ИНН не найден в базе данных ФНС',
|
|
33
|
+
* };
|
|
34
|
+
* }
|
|
35
|
+
*
|
|
36
|
+
* return null;
|
|
37
|
+
* },
|
|
38
|
+
* { debounce: 1000 }
|
|
39
|
+
* );
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function validateAsync(fieldPath, validatorFn, options) {
|
|
43
|
+
const path = extractPath(fieldPath);
|
|
44
|
+
getCurrentValidationRegistry().registerAsync(path, validatorFn, options);
|
|
45
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-field валидация
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import { TreeValidatorFn, ValidateTreeOptions } from '../../types';
|
|
8
|
+
/**
|
|
9
|
+
* Зарегистрировать cross-field валидатор
|
|
10
|
+
*
|
|
11
|
+
* Используется для валидации, которая зависит от нескольких полей
|
|
12
|
+
*
|
|
13
|
+
* @group Validation
|
|
14
|
+
* @category Core Functions
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* validateTree(
|
|
19
|
+
* (ctx: ValidationContext<TForm, TField>) => {
|
|
20
|
+
* const form = ctx.formValue();
|
|
21
|
+
* if (form.initialPayment && form.propertyValue) {
|
|
22
|
+
* if (form.initialPayment > form.propertyValue) {
|
|
23
|
+
* return {
|
|
24
|
+
* code: 'initialPaymentTooHigh',
|
|
25
|
+
* message: 'Первоначальный взнос не может превышать стоимость',
|
|
26
|
+
* };
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* return null;
|
|
30
|
+
* },
|
|
31
|
+
* { targetField: 'initialPayment' }
|
|
32
|
+
* );
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function validateTree<TForm>(validatorFn: TreeValidatorFn<TForm>, options?: ValidateTreeOptions): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-field валидация
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import { getCurrentValidationRegistry } from '../../utils/registry-helpers';
|
|
8
|
+
/**
|
|
9
|
+
* Зарегистрировать cross-field валидатор
|
|
10
|
+
*
|
|
11
|
+
* Используется для валидации, которая зависит от нескольких полей
|
|
12
|
+
*
|
|
13
|
+
* @group Validation
|
|
14
|
+
* @category Core Functions
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* validateTree(
|
|
19
|
+
* (ctx: ValidationContext<TForm, TField>) => {
|
|
20
|
+
* const form = ctx.formValue();
|
|
21
|
+
* if (form.initialPayment && form.propertyValue) {
|
|
22
|
+
* if (form.initialPayment > form.propertyValue) {
|
|
23
|
+
* return {
|
|
24
|
+
* code: 'initialPaymentTooHigh',
|
|
25
|
+
* message: 'Первоначальный взнос не может превышать стоимость',
|
|
26
|
+
* };
|
|
27
|
+
* }
|
|
28
|
+
* }
|
|
29
|
+
* return null;
|
|
30
|
+
* },
|
|
31
|
+
* { targetField: 'initialPayment' }
|
|
32
|
+
* );
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export function validateTree(validatorFn, options) {
|
|
36
|
+
getCurrentValidationRegistry().registerTree(validatorFn, options);
|
|
37
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Кастомная синхронная валидация поля
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import type { ContextualValidatorFn, FieldPathNode, ValidateOptions } from '../../types';
|
|
8
|
+
/**
|
|
9
|
+
* Зарегистрировать кастомный синхронный валидатор для поля
|
|
10
|
+
* Поддерживает опциональные поля
|
|
11
|
+
*
|
|
12
|
+
* @group Validation
|
|
13
|
+
* @category Core Functions
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* validate(path.birthDate, (ctx: ValidationContext<TForm, TField>) => {
|
|
18
|
+
* const birthDate = new Date(ctx.value());
|
|
19
|
+
* const age = calculateAge(birthDate);
|
|
20
|
+
*
|
|
21
|
+
* if (age < 18) {
|
|
22
|
+
* return {
|
|
23
|
+
* code: 'tooYoung',
|
|
24
|
+
* message: 'Заемщику должно быть не менее 18 лет',
|
|
25
|
+
* };
|
|
26
|
+
* }
|
|
27
|
+
*
|
|
28
|
+
* return null;
|
|
29
|
+
* });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function validate<TForm, TField>(fieldPath: FieldPathNode<TForm, TField> | undefined, validatorFn: ContextualValidatorFn<TForm, TField>, options?: ValidateOptions): void;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Кастомная синхронная валидация поля
|
|
3
|
+
*
|
|
4
|
+
* @group Validation
|
|
5
|
+
* @category Core Functions
|
|
6
|
+
*/
|
|
7
|
+
import { extractPath } from '../field-path';
|
|
8
|
+
import { getCurrentValidationRegistry } from '../../utils/registry-helpers';
|
|
9
|
+
/**
|
|
10
|
+
* Зарегистрировать кастомный синхронный валидатор для поля
|
|
11
|
+
* Поддерживает опциональные поля
|
|
12
|
+
*
|
|
13
|
+
* @group Validation
|
|
14
|
+
* @category Core Functions
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* validate(path.birthDate, (ctx: ValidationContext<TForm, TField>) => {
|
|
19
|
+
* const birthDate = new Date(ctx.value());
|
|
20
|
+
* const age = calculateAge(birthDate);
|
|
21
|
+
*
|
|
22
|
+
* if (age < 18) {
|
|
23
|
+
* return {
|
|
24
|
+
* code: 'tooYoung',
|
|
25
|
+
* message: 'Заемщику должно быть не менее 18 лет',
|
|
26
|
+
* };
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* return null;
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function validate(fieldPath, validatorFn, options) {
|
|
34
|
+
if (!fieldPath)
|
|
35
|
+
return; // Защита от undefined fieldPath
|
|
36
|
+
const path = extractPath(fieldPath);
|
|
37
|
+
getCurrentValidationRegistry().registerSync(path, validatorFn, options);
|
|
38
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FieldPath proxy - типобезопасный доступ к путям полей формы
|
|
3
|
+
*/
|
|
4
|
+
import type { FieldPath, FieldPathNode } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Создать FieldPath proxy для формы
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const path = createFieldPath<MyForm>();
|
|
11
|
+
* console.log(path.email.__path); // 'email'
|
|
12
|
+
* console.log(path.personalData.firstName.__path); // 'personalData.firstName'
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function createFieldPath<T>(): FieldPath<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Извлечь путь из FieldPathNode
|
|
18
|
+
*/
|
|
19
|
+
export declare function extractPath(node: FieldPathNode<unknown, unknown> | unknown): string;
|
|
20
|
+
/**
|
|
21
|
+
* Преобразовать FieldPathNode в FieldPath для переиспользования схем
|
|
22
|
+
*
|
|
23
|
+
* Позволяет композировать validation schemas:
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const personalDataValidation = (path: FieldPath<PersonalData>) => {
|
|
28
|
+
* required(path.firstName, { message: 'Имя обязательно' });
|
|
29
|
+
* required(path.lastName, { message: 'Фамилия обязательна' });
|
|
30
|
+
* };
|
|
31
|
+
*
|
|
32
|
+
* const mainValidation = (path: FieldPath<MyForm>) => {
|
|
33
|
+
* // Переиспользуем схему
|
|
34
|
+
* personalDataValidation(toFieldPath(path.personalData));
|
|
35
|
+
* required(path.email);
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function toFieldPath<T>(node: FieldPathNode<unknown, T, never> | FieldPathNode<any, T, any>): FieldPath<T>;
|
|
40
|
+
/**
|
|
41
|
+
* Извлечь ключ поля из FieldPathNode
|
|
42
|
+
*/
|
|
43
|
+
export declare function extractKey(node: FieldPathNode<unknown, unknown> | unknown): string;
|