@reformer/core 1.0.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/LICENSE +21 -0
- package/README.md +143 -0
- package/dist/behaviors/compute-from.d.ts +2 -0
- package/dist/behaviors/compute-from.js +31 -0
- package/dist/behaviors/copy-from.d.ts +2 -0
- package/dist/behaviors/copy-from.js +29 -0
- package/dist/behaviors/enable-when.d.ts +2 -0
- package/dist/behaviors/enable-when.js +25 -0
- package/dist/behaviors/reset-when.d.ts +2 -0
- package/dist/behaviors/reset-when.js +24 -0
- package/dist/behaviors/revalidate-when.d.ts +2 -0
- package/dist/behaviors/revalidate-when.js +18 -0
- package/dist/behaviors/sync-fields.d.ts +2 -0
- package/dist/behaviors/sync-fields.js +41 -0
- package/dist/behaviors/transform-value.d.ts +2 -0
- package/dist/behaviors/transform-value.js +45 -0
- package/dist/behaviors/watch-field.d.ts +2 -0
- package/dist/behaviors/watch-field.js +21 -0
- package/dist/behaviors.d.ts +6 -0
- package/dist/behaviors.js +29 -0
- package/dist/core/behavior/behavior-context.d.ts +47 -0
- package/dist/core/behavior/behavior-registry.d.ts +85 -0
- package/dist/core/behavior/behaviors/compute-from.d.ts +70 -0
- package/dist/core/behavior/behaviors/copy-from.d.ts +56 -0
- package/dist/core/behavior/behaviors/enable-when.d.ts +118 -0
- package/dist/core/behavior/behaviors/index.d.ts +11 -0
- package/dist/core/behavior/behaviors/reset-when.d.ts +64 -0
- package/dist/core/behavior/behaviors/revalidate-when.d.ts +53 -0
- package/dist/core/behavior/behaviors/sync-fields.d.ts +48 -0
- package/dist/core/behavior/behaviors/transform-value.d.ts +192 -0
- package/dist/core/behavior/behaviors/watch-field.d.ts +80 -0
- package/dist/core/behavior/compose-behavior.d.ts +96 -0
- package/dist/core/behavior/index.d.ts +11 -0
- package/dist/core/behavior/types.d.ts +146 -0
- package/dist/core/factories/index.d.ts +6 -0
- package/dist/core/factories/node-factory.d.ts +186 -0
- package/dist/core/nodes/array-node.d.ts +328 -0
- package/dist/core/nodes/field-node.d.ts +294 -0
- package/dist/core/nodes/form-node.d.ts +340 -0
- package/dist/core/nodes/group-node.d.ts +319 -0
- package/dist/core/types/deep-schema.d.ts +68 -0
- package/dist/core/types/field-path.d.ts +42 -0
- package/dist/core/types/form-context.d.ts +89 -0
- package/dist/core/types/form-proxy.d.ts +105 -0
- package/dist/core/types/index.d.ts +209 -0
- package/dist/core/types/validation-schema.d.ts +95 -0
- package/dist/core/utils/abstract-registry.d.ts +74 -0
- package/dist/core/utils/aggregate-signals.d.ts +71 -0
- package/dist/core/utils/create-form.d.ts +44 -0
- package/dist/core/utils/error-handler.d.ts +163 -0
- package/dist/core/utils/field-path-navigator.d.ts +240 -0
- package/dist/core/utils/field-path.d.ts +60 -0
- package/dist/core/utils/form-observer.d.ts +176 -0
- package/dist/core/utils/form-proxy-builder.d.ts +25 -0
- package/dist/core/utils/form-submitter.d.ts +121 -0
- package/dist/core/utils/index.d.ts +22 -0
- package/dist/core/utils/registry-helpers.d.ts +43 -0
- package/dist/core/utils/registry-stack.d.ts +69 -0
- package/dist/core/utils/safe-effect.d.ts +73 -0
- package/dist/core/utils/status-machine.d.ts +153 -0
- package/dist/core/utils/subscription-manager.d.ts +180 -0
- package/dist/core/utils/type-guards.d.ts +98 -0
- package/dist/core/utils/unique-id.d.ts +53 -0
- package/dist/core/validation/core/apply-when.d.ts +22 -0
- package/dist/core/validation/core/apply.d.ts +52 -0
- package/dist/core/validation/core/index.d.ts +8 -0
- package/dist/core/validation/core/validate-async.d.ts +36 -0
- package/dist/core/validation/core/validate-tree.d.ts +35 -0
- package/dist/core/validation/core/validate.d.ts +26 -0
- package/dist/core/validation/index.d.ts +27 -0
- package/dist/core/validation/validate-form.d.ts +48 -0
- package/dist/core/validation/validation-applicator.d.ts +70 -0
- package/dist/core/validation/validation-context.d.ts +86 -0
- package/dist/core/validation/validation-registry.d.ts +142 -0
- package/dist/core/validation/validators/array-validators.d.ts +53 -0
- package/dist/core/validation/validators/date-utils.d.ts +26 -0
- package/dist/core/validation/validators/email.d.ts +37 -0
- package/dist/core/validation/validators/future-date.d.ts +35 -0
- package/dist/core/validation/validators/index.d.ts +20 -0
- package/dist/core/validation/validators/is-date.d.ts +36 -0
- package/dist/core/validation/validators/max-age.d.ts +36 -0
- package/dist/core/validation/validators/max-date.d.ts +36 -0
- package/dist/core/validation/validators/max-length.d.ts +38 -0
- package/dist/core/validation/validators/max.d.ts +38 -0
- package/dist/core/validation/validators/min-age.d.ts +36 -0
- package/dist/core/validation/validators/min-date.d.ts +36 -0
- package/dist/core/validation/validators/min-length.d.ts +38 -0
- package/dist/core/validation/validators/min.d.ts +38 -0
- package/dist/core/validation/validators/number.d.ts +31 -0
- package/dist/core/validation/validators/past-date.d.ts +35 -0
- package/dist/core/validation/validators/pattern.d.ts +40 -0
- package/dist/core/validation/validators/phone.d.ts +27 -0
- package/dist/core/validation/validators/required.d.ts +41 -0
- package/dist/core/validation/validators/url.d.ts +22 -0
- package/dist/date-utils-xUWFslTj.js +29 -0
- package/dist/field-path-DuKdGcIE.js +66 -0
- package/dist/hooks/types.d.ts +328 -0
- package/dist/hooks/useArrayLength.d.ts +31 -0
- package/dist/hooks/useFormControl.d.ts +24 -0
- package/dist/hooks/useFormControlValue.d.ts +167 -0
- package/dist/hooks/useHiddenCondition.d.ts +25 -0
- package/dist/hooks/useSignalSubscription.d.ts +17 -0
- package/dist/index-D25LsbRm.js +73 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +3271 -0
- package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
- package/dist/safe-effect-Dh8uw81c.js +20 -0
- package/dist/validate-C3XiA_zf.js +10 -0
- package/dist/validators/email.d.ts +2 -0
- package/dist/validators/email.js +13 -0
- package/dist/validators/future-date.d.ts +2 -0
- package/dist/validators/future-date.js +20 -0
- package/dist/validators/is-date.d.ts +2 -0
- package/dist/validators/is-date.js +12 -0
- package/dist/validators/max-age.d.ts +2 -0
- package/dist/validators/max-age.js +20 -0
- package/dist/validators/max-date.d.ts +2 -0
- package/dist/validators/max-date.js +20 -0
- package/dist/validators/max-length.d.ts +2 -0
- package/dist/validators/max-length.js +11 -0
- package/dist/validators/max.d.ts +2 -0
- package/dist/validators/max.js +11 -0
- package/dist/validators/min-age.d.ts +2 -0
- package/dist/validators/min-age.js +20 -0
- package/dist/validators/min-date.d.ts +2 -0
- package/dist/validators/min-date.js +20 -0
- package/dist/validators/min-length.d.ts +2 -0
- package/dist/validators/min-length.js +11 -0
- package/dist/validators/min.d.ts +2 -0
- package/dist/validators/min.js +11 -0
- package/dist/validators/number.d.ts +2 -0
- package/dist/validators/number.js +35 -0
- package/dist/validators/past-date.d.ts +2 -0
- package/dist/validators/past-date.js +20 -0
- package/dist/validators/pattern.d.ts +2 -0
- package/dist/validators/pattern.js +11 -0
- package/dist/validators/phone.d.ts +2 -0
- package/dist/validators/phone.js +35 -0
- package/dist/validators/required.d.ts +2 -0
- package/dist/validators/required.js +15 -0
- package/dist/validators/url.d.ts +2 -0
- package/dist/validators/url.js +19 -0
- package/dist/validators-BGsNOgT1.js +207 -0
- package/dist/validators.d.ts +6 -0
- package/dist/validators.js +56 -0
- package/llms.txt +9351 -0
- package/package.json +166 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Менеджер подписок для FormNode
|
|
3
|
+
*
|
|
4
|
+
* Централизует управление effect-подписками в узлах формы,
|
|
5
|
+
* предотвращает утечки памяти и упрощает отладку.
|
|
6
|
+
*
|
|
7
|
+
* Каждая подписка имеет уникальный ключ, что позволяет:
|
|
8
|
+
* - Отписываться от конкретной подписки по ключу
|
|
9
|
+
* - Автоматически заменять существующие подписки
|
|
10
|
+
* - Отслеживать количество активных подписок (для отладки)
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* class FieldNode {
|
|
17
|
+
* private subscriptions = new SubscriptionManager();
|
|
18
|
+
*
|
|
19
|
+
* watch(callback: Function) {
|
|
20
|
+
* const dispose = effect(() => callback(this.value.value));
|
|
21
|
+
* return this.subscriptions.add('watch', dispose);
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* dispose() {
|
|
25
|
+
* this.subscriptions.clear();
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class SubscriptionManager {
|
|
31
|
+
/**
|
|
32
|
+
* Хранилище подписок
|
|
33
|
+
* Ключ: уникальный идентификатор подписки
|
|
34
|
+
* Значение: функция отписки (dispose)
|
|
35
|
+
*/
|
|
36
|
+
private subscriptions;
|
|
37
|
+
/**
|
|
38
|
+
* Добавляет подписку
|
|
39
|
+
*
|
|
40
|
+
* Если подписка с таким ключом уже существует, отписывается от неё
|
|
41
|
+
* и заменяет новой. Это предотвращает утечки памяти при повторной
|
|
42
|
+
* регистрации подписки с тем же ключом.
|
|
43
|
+
*
|
|
44
|
+
* @param key Уникальный ключ подписки
|
|
45
|
+
* @param dispose Функция отписки (обычно возвращаемая из effect())
|
|
46
|
+
* @returns Функция для отписки от этой конкретной подписки
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const manager = new SubscriptionManager();
|
|
51
|
+
*
|
|
52
|
+
* // Добавление подписки
|
|
53
|
+
* const unsubscribe = manager.add('mySubscription', () => {
|
|
54
|
+
* console.log('Disposing subscription');
|
|
55
|
+
* });
|
|
56
|
+
*
|
|
57
|
+
* // Отписка через возвращаемую функцию
|
|
58
|
+
* unsubscribe();
|
|
59
|
+
*
|
|
60
|
+
* // Или через manager.remove()
|
|
61
|
+
* manager.add('anotherSub', disposeFn);
|
|
62
|
+
* manager.remove('anotherSub');
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
add(key: string, dispose: () => void): () => void;
|
|
66
|
+
/**
|
|
67
|
+
* Удаляет подписку по ключу
|
|
68
|
+
*
|
|
69
|
+
* Вызывает функцию отписки и удаляет подписку из хранилища.
|
|
70
|
+
* Если подписка с таким ключом не найдена, ничего не делает.
|
|
71
|
+
*
|
|
72
|
+
* @param key Ключ подписки
|
|
73
|
+
* @returns true, если подписка была удалена, false если не найдена
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const manager = new SubscriptionManager();
|
|
78
|
+
* manager.add('mySub', disposeFn);
|
|
79
|
+
*
|
|
80
|
+
* // Удаление подписки
|
|
81
|
+
* const removed = manager.remove('mySub'); // true
|
|
82
|
+
*
|
|
83
|
+
* // Попытка удалить несуществующую подписку
|
|
84
|
+
* const removed2 = manager.remove('nonExistent'); // false
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
remove(key: string): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Очищает все подписки
|
|
90
|
+
*
|
|
91
|
+
* Вызывает функции отписки для всех активных подписок
|
|
92
|
+
* и очищает хранилище. Обычно используется при dispose узла формы.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* class FieldNode {
|
|
97
|
+
* private subscriptions = new SubscriptionManager();
|
|
98
|
+
*
|
|
99
|
+
* dispose() {
|
|
100
|
+
* // Отписываемся от всех effect
|
|
101
|
+
* this.subscriptions.clear();
|
|
102
|
+
* }
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
clear(): void;
|
|
107
|
+
/**
|
|
108
|
+
* Возвращает количество активных подписок
|
|
109
|
+
*
|
|
110
|
+
* Полезно для отладки утечек памяти. Если количество подписок
|
|
111
|
+
* растет без ограничений, это может указывать на то, что
|
|
112
|
+
* компоненты не отписываются должным образом.
|
|
113
|
+
*
|
|
114
|
+
* @returns Количество активных подписок
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const manager = new SubscriptionManager();
|
|
119
|
+
* console.log(manager.size()); // 0
|
|
120
|
+
*
|
|
121
|
+
* manager.add('sub1', disposeFn1);
|
|
122
|
+
* manager.add('sub2', disposeFn2);
|
|
123
|
+
* console.log(manager.size()); // 2
|
|
124
|
+
*
|
|
125
|
+
* manager.clear();
|
|
126
|
+
* console.log(manager.size()); // 0
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
size(): number;
|
|
130
|
+
/**
|
|
131
|
+
* Проверяет, есть ли подписка с данным ключом
|
|
132
|
+
*
|
|
133
|
+
* @param key Ключ подписки
|
|
134
|
+
* @returns true, если подписка существует
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const manager = new SubscriptionManager();
|
|
139
|
+
* manager.add('mySub', disposeFn);
|
|
140
|
+
*
|
|
141
|
+
* console.log(manager.has('mySub')); // true
|
|
142
|
+
* console.log(manager.has('nonExistent')); // false
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
has(key: string): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Возвращает список всех ключей активных подписок
|
|
148
|
+
*
|
|
149
|
+
* Полезно для отладки: можно увидеть, какие подписки активны.
|
|
150
|
+
*
|
|
151
|
+
* @returns Массив ключей всех активных подписок
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```typescript
|
|
155
|
+
* const manager = new SubscriptionManager();
|
|
156
|
+
* manager.add('watch-value', disposeFn1);
|
|
157
|
+
* manager.add('watch-errors', disposeFn2);
|
|
158
|
+
*
|
|
159
|
+
* console.log(manager.getKeys()); // ['watch-value', 'watch-errors']
|
|
160
|
+
* ```
|
|
161
|
+
*/
|
|
162
|
+
getKeys(): string[];
|
|
163
|
+
/**
|
|
164
|
+
* Отписывается от всех подписок (алиас для clear())
|
|
165
|
+
*
|
|
166
|
+
* Используется при dispose() узла формы для совместимости с ожидаемым API.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```typescript
|
|
170
|
+
* class FieldNode {
|
|
171
|
+
* private subscriptions = new SubscriptionManager();
|
|
172
|
+
*
|
|
173
|
+
* dispose() {
|
|
174
|
+
* this.subscriptions.dispose();
|
|
175
|
+
* }
|
|
176
|
+
* }
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
dispose(): void;
|
|
180
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { FormNode } from '../nodes/form-node';
|
|
2
|
+
import { FieldNode } from '../nodes/field-node';
|
|
3
|
+
import { GroupNode } from '../nodes/group-node';
|
|
4
|
+
import { ArrayNode } from '../nodes/array-node';
|
|
5
|
+
import { FormFields, FormValue } from '../types';
|
|
6
|
+
/**
|
|
7
|
+
* Проверить, является ли значение любым FormNode
|
|
8
|
+
*
|
|
9
|
+
* Проверяет базовые свойства, общие для всех типов узлов
|
|
10
|
+
*
|
|
11
|
+
* @group Utilities
|
|
12
|
+
* @category Type Guards
|
|
13
|
+
*
|
|
14
|
+
* @param value - Значение для проверки
|
|
15
|
+
* @returns true если value является FormNode
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* if (isFormNode(value)) {
|
|
20
|
+
* value.setValue(newValue);
|
|
21
|
+
* value.validate();
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function isFormNode(value: unknown): value is FormNode<FormValue>;
|
|
26
|
+
/**
|
|
27
|
+
* Проверить, является ли значение FieldNode (примитивное поле)
|
|
28
|
+
*
|
|
29
|
+
* FieldNode представляет примитивное поле формы (string, number, boolean и т.д.)
|
|
30
|
+
* и имеет валидаторы, но не имеет вложенных полей или элементов массива
|
|
31
|
+
*
|
|
32
|
+
* @group Utilities
|
|
33
|
+
* @category Type Guards
|
|
34
|
+
*
|
|
35
|
+
* @param value - Значение для проверки
|
|
36
|
+
* @returns true если value является FieldNode
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* if (isFieldNode(node)) {
|
|
41
|
+
* node.validators; // OK
|
|
42
|
+
* node.asyncValidators; // OK
|
|
43
|
+
* node.markAsTouched(); // OK
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function isFieldNode(value: unknown): value is FieldNode<FormValue>;
|
|
48
|
+
/**
|
|
49
|
+
* Проверить, является ли значение GroupNode (объект с вложенными полями)
|
|
50
|
+
*
|
|
51
|
+
* GroupNode представляет объект с вложенными полями формы
|
|
52
|
+
* и имеет методы для применения validation/behavior схем
|
|
53
|
+
*
|
|
54
|
+
* @param value - Значение для проверки
|
|
55
|
+
* @returns true если value является GroupNode
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* if (isGroupNode(node)) {
|
|
60
|
+
* node.applyValidationSchema(schema); // OK
|
|
61
|
+
* node.getFieldByPath('user.email'); // OK
|
|
62
|
+
* }
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function isGroupNode(value: unknown): value is GroupNode<FormFields>;
|
|
66
|
+
/**
|
|
67
|
+
* Проверить, является ли значение ArrayNode (массив форм)
|
|
68
|
+
*
|
|
69
|
+
* ArrayNode представляет массив вложенных форм (обычно GroupNode)
|
|
70
|
+
* и имеет array-like методы (push, removeAt, at)
|
|
71
|
+
*
|
|
72
|
+
* @param value - Значение для проверки
|
|
73
|
+
* @returns true если value является ArrayNode
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* if (isArrayNode(node)) {
|
|
78
|
+
* node.push(); // OK - добавить элемент
|
|
79
|
+
* node.removeAt(0); // OK - удалить элемент
|
|
80
|
+
* const item = node.at(0); // OK - получить элемент
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function isArrayNode(value: unknown): value is ArrayNode<FormFields>;
|
|
85
|
+
/**
|
|
86
|
+
* Получить тип узла как строку (для отладки)
|
|
87
|
+
*
|
|
88
|
+
* Полезно для логирования и отладки
|
|
89
|
+
*
|
|
90
|
+
* @param node - Узел для проверки
|
|
91
|
+
* @returns Строковое название типа узла
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```typescript
|
|
95
|
+
* console.log('Node type:', getNodeType(node)); // "FieldNode" | "GroupNode" | "ArrayNode" | "FormNode" | "Unknown"
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
export declare function getNodeType(node: unknown): string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Генератор уникальных идентификаторов
|
|
3
|
+
*
|
|
4
|
+
* Использует атомный счётчик для генерации гарантированно уникальных ключей.
|
|
5
|
+
* Решает проблему возможного дублирования ключей при использовании
|
|
6
|
+
* Date.now() + Math.random() в быстрых последовательных вызовах.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const key1 = uniqueId(SubscriptionKey.Watch); // "watch-1"
|
|
11
|
+
* const key2 = uniqueId(SubscriptionKey.Watch); // "watch-2"
|
|
12
|
+
* const key3 = uniqueId(SubscriptionKey.ComputeFrom); // "computeFrom-3"
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Типобезопасные ключи для подписок
|
|
17
|
+
* Используются с uniqueId() для генерации уникальных идентификаторов
|
|
18
|
+
*/
|
|
19
|
+
export declare const SubscriptionKey: {
|
|
20
|
+
/** FieldNode.watch() */
|
|
21
|
+
readonly Watch: "watch";
|
|
22
|
+
/** FieldNode.computeFrom() */
|
|
23
|
+
readonly ComputeFrom: "computeFrom";
|
|
24
|
+
/** GroupNode.linkFields() */
|
|
25
|
+
readonly LinkFields: "linkFields";
|
|
26
|
+
/** GroupNode.watchField() */
|
|
27
|
+
readonly WatchField: "watchField";
|
|
28
|
+
/** ArrayNode.watchItems() */
|
|
29
|
+
readonly WatchItems: "watchItems";
|
|
30
|
+
/** ArrayNode.watchLength() */
|
|
31
|
+
readonly WatchLength: "watchLength";
|
|
32
|
+
};
|
|
33
|
+
export type SubscriptionKeyType = (typeof SubscriptionKey)[keyof typeof SubscriptionKey];
|
|
34
|
+
/**
|
|
35
|
+
* Генерирует уникальный идентификатор с указанным префиксом.
|
|
36
|
+
*
|
|
37
|
+
* @param prefix - Префикс для идентификатора (используйте {@link SubscriptionKey}).
|
|
38
|
+
* @returns Уникальный идентификатор в формате `${prefix}-${counter}`.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* import { uniqueId, SubscriptionKey } from '@reformer/core';
|
|
43
|
+
*
|
|
44
|
+
* uniqueId(SubscriptionKey.WatchField); // → 'watchField-1'
|
|
45
|
+
* uniqueId(SubscriptionKey.WatchField); // → 'watchField-2'
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function uniqueId(prefix: SubscriptionKeyType): string;
|
|
49
|
+
/**
|
|
50
|
+
* Сбросить счётчик (только для тестов)
|
|
51
|
+
* @internal
|
|
52
|
+
*/
|
|
53
|
+
export declare function resetUniqueIdCounter(): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FieldPath } from '../../types/field-path';
|
|
2
|
+
import { ConditionFn } from '../../types/validation-schema';
|
|
3
|
+
import { FieldPathNode } from '../../types';
|
|
4
|
+
/**
|
|
5
|
+
* Применить валидацию только при выполнении условия
|
|
6
|
+
*
|
|
7
|
+
* @group Validation
|
|
8
|
+
* @category Core Functions
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* applyWhen(
|
|
13
|
+
* path.loanType,
|
|
14
|
+
* (type) => type === 'mortgage',
|
|
15
|
+
* (path) => {
|
|
16
|
+
* required(path.propertyValue, { message: 'Укажите стоимость' });
|
|
17
|
+
* min(path.propertyValue, 1000000);
|
|
18
|
+
* }
|
|
19
|
+
* );
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function applyWhen<TForm, TField>(fieldPath: FieldPathNode<TForm, TField>, condition: ConditionFn<TField>, validationFn: (path: FieldPath<TForm>) => void): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FieldPathNode, FieldPath } from '../../types';
|
|
2
|
+
import { ValidationSchemaFn } from '../../types/validation-schema';
|
|
3
|
+
/**
|
|
4
|
+
* Применить validation схему к корневому path формы
|
|
5
|
+
*
|
|
6
|
+
* Используется для композиции схем на уровне всей формы.
|
|
7
|
+
*
|
|
8
|
+
* @group Validation
|
|
9
|
+
* @category Core Functions
|
|
10
|
+
*
|
|
11
|
+
* @param path - Корневой FieldPath формы (весь объект путей)
|
|
12
|
+
* @param validationSchema - Схема валидации
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const creditApplicationValidation: ValidationSchemaFn<CreditApplicationForm> = (path) => {
|
|
17
|
+
* apply(path, basicInfoValidation);
|
|
18
|
+
* apply(path, contactInfoValidation);
|
|
19
|
+
* };
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function apply<TForm>(path: FieldPath<TForm>, validationSchema: ValidationSchemaFn<TForm>): void;
|
|
23
|
+
/**
|
|
24
|
+
* Применить validation схему к вложенному полю или полям
|
|
25
|
+
*
|
|
26
|
+
* Поддерживает:
|
|
27
|
+
* - Одно поле или массив полей
|
|
28
|
+
* - Одну схему или массив схем
|
|
29
|
+
* - Все комбинации (поле + схема, поле + схемы, поля + схема, поля + схемы)
|
|
30
|
+
*
|
|
31
|
+
* @param fields - Одно поле или массив полей
|
|
32
|
+
* @param validationSchemas - Одна схема или массив схем
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* // Одна схема к одному полю
|
|
37
|
+
* apply(path.registrationAddress, addressValidation);
|
|
38
|
+
*
|
|
39
|
+
* // Одна схема к нескольким полям
|
|
40
|
+
* apply([path.homeAddress, path.workAddress], addressValidation);
|
|
41
|
+
*
|
|
42
|
+
* // Несколько схем к одному полю
|
|
43
|
+
* apply(path.email, [emailValidation, uniqueEmailValidation]);
|
|
44
|
+
*
|
|
45
|
+
* // Несколько схем к нескольким полям
|
|
46
|
+
* apply(
|
|
47
|
+
* [path.email, path.confirmEmail],
|
|
48
|
+
* [emailValidation, matchValidation]
|
|
49
|
+
* );
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
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,36 @@
|
|
|
1
|
+
import { ContextualAsyncValidatorFn, ValidateAsyncOptions } from '../../types/validation-schema';
|
|
2
|
+
import { FieldPathNode } from '../../types';
|
|
3
|
+
/**
|
|
4
|
+
* Зарегистрировать асинхронный валидатор для поля
|
|
5
|
+
*
|
|
6
|
+
* @group Validation
|
|
7
|
+
* @category Core Functions
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* validateAsync(
|
|
12
|
+
* path.inn,
|
|
13
|
+
* async (ctx: ValidationContext<TForm, TField>) => {
|
|
14
|
+
* const inn = ctx.value();
|
|
15
|
+
* if (!inn) return null;
|
|
16
|
+
*
|
|
17
|
+
* const response = await fetch('/api/validate-inn', {
|
|
18
|
+
* method: 'POST',
|
|
19
|
+
* body: JSON.stringify({ inn }),
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* const data = await response.json();
|
|
23
|
+
* if (!data.valid) {
|
|
24
|
+
* return {
|
|
25
|
+
* code: 'invalidInn',
|
|
26
|
+
* message: 'ИНН не найден в базе данных ФНС',
|
|
27
|
+
* };
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* return null;
|
|
31
|
+
* },
|
|
32
|
+
* { debounce: 1000 }
|
|
33
|
+
* );
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function validateAsync<TForm, TField>(fieldPath: FieldPathNode<TForm, TField>, validatorFn: ContextualAsyncValidatorFn<TForm, TField>, options?: ValidateAsyncOptions): void;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { TreeValidatorFn, ValidateTreeOptions } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Зарегистрировать cross-field валидатор
|
|
4
|
+
*
|
|
5
|
+
* Используется для валидации, которая зависит от нескольких полей
|
|
6
|
+
*
|
|
7
|
+
* @group Validation
|
|
8
|
+
* @category Core Functions
|
|
9
|
+
*
|
|
10
|
+
* @remarks
|
|
11
|
+
* Параметр `ctx` в callback требует явной типизации для корректного вывода типов:
|
|
12
|
+
* ```typescript
|
|
13
|
+
* validateTree((ctx: { form: MyFormType }) => { ... });
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Явная типизация ctx для избежания implicit any
|
|
19
|
+
* validateTree(
|
|
20
|
+
* (ctx: { form: MyForm }) => {
|
|
21
|
+
* if (ctx.form.initialPayment && ctx.form.propertyValue) {
|
|
22
|
+
* if (ctx.form.initialPayment > ctx.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,26 @@
|
|
|
1
|
+
import { ContextualValidatorFn, FieldPathNode, ValidateOptions } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Зарегистрировать кастомный синхронный валидатор для поля
|
|
4
|
+
* Поддерживает опциональные поля
|
|
5
|
+
*
|
|
6
|
+
* @group Validation
|
|
7
|
+
* @category Core Functions
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* validate(path.birthDate, (ctx: ValidationContext<TForm, TField>) => {
|
|
12
|
+
* const birthDate = new Date(ctx.value());
|
|
13
|
+
* const age = calculateAge(birthDate);
|
|
14
|
+
*
|
|
15
|
+
* if (age < 18) {
|
|
16
|
+
* return {
|
|
17
|
+
* code: 'tooYoung',
|
|
18
|
+
* message: 'Заемщику должно быть не менее 18 лет',
|
|
19
|
+
* };
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* return null;
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function validate<TForm, TField>(fieldPath: FieldPathNode<TForm, TField> | undefined, validatorFn: ContextualValidatorFn<TForm, TField>, options?: ValidateOptions): void;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export { validate } from './core/validate';
|
|
2
|
+
export { validateAsync } from './core/validate-async';
|
|
3
|
+
export { validateTree } from './core/validate-tree';
|
|
4
|
+
export { apply } from './core/apply';
|
|
5
|
+
export { applyWhen } from './core/apply-when';
|
|
6
|
+
export { required } from './validators/required';
|
|
7
|
+
export { min } from './validators/min';
|
|
8
|
+
export { max } from './validators/max';
|
|
9
|
+
export { minLength } from './validators/min-length';
|
|
10
|
+
export { maxLength } from './validators/max-length';
|
|
11
|
+
export { email } from './validators/email';
|
|
12
|
+
export { pattern } from './validators/pattern';
|
|
13
|
+
export { url } from './validators/url';
|
|
14
|
+
export { phone, type PhoneFormat } from './validators/phone';
|
|
15
|
+
export { number } from './validators/number';
|
|
16
|
+
export { isDate } from './validators/is-date';
|
|
17
|
+
export { minDate } from './validators/min-date';
|
|
18
|
+
export { maxDate } from './validators/max-date';
|
|
19
|
+
export { pastDate } from './validators/past-date';
|
|
20
|
+
export { futureDate } from './validators/future-date';
|
|
21
|
+
export { minAge } from './validators/min-age';
|
|
22
|
+
export { maxAge } from './validators/max-age';
|
|
23
|
+
export { notEmpty, validateItems } from './validators/array-validators';
|
|
24
|
+
export { createFieldPath, extractPath, extractKey, toFieldPath } from '../utils/field-path';
|
|
25
|
+
export { validateForm } from './validate-form';
|
|
26
|
+
export { ValidationRegistry } from './validation-registry';
|
|
27
|
+
export { ValidationContextImpl, TreeValidationContextImpl } from './validation-context';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { GroupNode } from '../nodes/group-node';
|
|
2
|
+
import { ValidationSchemaFn, FormFields } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Валидировать форму в соответствии с указанной схемой
|
|
5
|
+
*
|
|
6
|
+
* Функция создает временный контекст валидации, применяет валидаторы
|
|
7
|
+
* из схемы и очищает контекст без сохранения в реестр.
|
|
8
|
+
*
|
|
9
|
+
* @param form - GroupNode для валидации
|
|
10
|
+
* @param schema - Схема валидации (ValidationSchemaFn)
|
|
11
|
+
* @returns Promise<boolean> - `true` если форма валидна, `false` если есть ошибки
|
|
12
|
+
*
|
|
13
|
+
* @example Multi-step форма: валидация текущего шага
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const goToNextStep = async () => {
|
|
16
|
+
* const isValid = await validateForm(form, step1LoanValidation);
|
|
17
|
+
*
|
|
18
|
+
* if (!isValid) {
|
|
19
|
+
* form.markAsTouched(); // Показать ошибки
|
|
20
|
+
* return false;
|
|
21
|
+
* }
|
|
22
|
+
*
|
|
23
|
+
* setCurrentStep(2);
|
|
24
|
+
* return true;
|
|
25
|
+
* };
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example Полная валидация перед submit
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const handleSubmit = async () => {
|
|
31
|
+
* const isValid = await validateForm(form, fullValidationSchema);
|
|
32
|
+
*
|
|
33
|
+
* if (isValid) {
|
|
34
|
+
* await form.submit(onSubmit);
|
|
35
|
+
* }
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example Условная валидация
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const schema = isBusinessAccount
|
|
42
|
+
* ? businessValidation
|
|
43
|
+
* : personalValidation;
|
|
44
|
+
*
|
|
45
|
+
* const isValid = await validateForm(form, schema);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function validateForm<T extends FormFields>(form: GroupNode<T>, schema: ValidationSchemaFn<T>): Promise<boolean>;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { GroupNode } from '../nodes/group-node';
|
|
2
|
+
import { ValidatorRegistration } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Класс для применения валидаторов к форме
|
|
5
|
+
*
|
|
6
|
+
* Выполняет:
|
|
7
|
+
* - Группировку валидаторов по полям
|
|
8
|
+
* - Фильтрацию по условиям (condition)
|
|
9
|
+
* - Применение sync/async валидаторов к FieldNode
|
|
10
|
+
* - Применение tree валидаторов (кросс-полевая валидация)
|
|
11
|
+
*
|
|
12
|
+
* @template T Тип формы (объект)
|
|
13
|
+
*/
|
|
14
|
+
export declare class ValidationApplicator<T> {
|
|
15
|
+
private readonly form;
|
|
16
|
+
constructor(form: GroupNode<T>);
|
|
17
|
+
/**
|
|
18
|
+
* Применить валидаторы к полям формы
|
|
19
|
+
*
|
|
20
|
+
* Этапы применения:
|
|
21
|
+
* 1. Разделение валидаторов на field и tree
|
|
22
|
+
* 2. Применение field валидаторов (sync/async)
|
|
23
|
+
* 3. Применение tree валидаторов (кросс-полевая валидация)
|
|
24
|
+
*
|
|
25
|
+
* @param validators Зарегистрированные валидаторы
|
|
26
|
+
*/
|
|
27
|
+
apply(validators: ValidatorRegistration[]): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Группировка валидаторов по типам
|
|
30
|
+
*
|
|
31
|
+
* Разделяет валидаторы на:
|
|
32
|
+
* - Field validators (sync/async) - группируются по fieldPath
|
|
33
|
+
* - Tree validators - применяются ко всей форме
|
|
34
|
+
*
|
|
35
|
+
* @param validators Все зарегистрированные валидаторы
|
|
36
|
+
* @returns Сгруппированные валидаторы
|
|
37
|
+
*/
|
|
38
|
+
private groupValidators;
|
|
39
|
+
/**
|
|
40
|
+
* Применение field валидаторов к полям
|
|
41
|
+
*
|
|
42
|
+
* Для каждого поля:
|
|
43
|
+
* 1. Найти FieldNode по пути
|
|
44
|
+
* 2. Проверить условия (condition)
|
|
45
|
+
* 3. Выполнить sync/async валидаторы
|
|
46
|
+
* 4. Установить ошибки на поле
|
|
47
|
+
*
|
|
48
|
+
* @param validatorsByField Валидаторы, сгруппированные по полям
|
|
49
|
+
*/
|
|
50
|
+
private applyFieldValidators;
|
|
51
|
+
/**
|
|
52
|
+
* Применение tree валидаторов (кросс-полевая валидация)
|
|
53
|
+
*
|
|
54
|
+
* Tree валидаторы имеют доступ ко всей форме через TreeValidationContext.
|
|
55
|
+
* Ошибки устанавливаются на targetField (если указано).
|
|
56
|
+
*
|
|
57
|
+
* @param treeValidators Список tree валидаторов
|
|
58
|
+
*/
|
|
59
|
+
private applyTreeValidators;
|
|
60
|
+
/**
|
|
61
|
+
* Проверка условия (condition) для валидатора
|
|
62
|
+
*
|
|
63
|
+
* Условие определяет, должен ли валидатор выполняться.
|
|
64
|
+
* Использует getFieldByPath для поддержки вложенных путей.
|
|
65
|
+
*
|
|
66
|
+
* @param condition Условие валидатора
|
|
67
|
+
* @returns true, если условие выполнено
|
|
68
|
+
*/
|
|
69
|
+
private checkCondition;
|
|
70
|
+
}
|