@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.
Files changed (150) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +53 -0
  3. package/dist/behaviors.d.ts +2 -0
  4. package/dist/behaviors.js +230 -0
  5. package/dist/core/behavior/behavior-applicator.d.ts +71 -0
  6. package/dist/core/behavior/behavior-applicator.js +92 -0
  7. package/dist/core/behavior/behavior-context.d.ts +29 -0
  8. package/dist/core/behavior/behavior-context.js +38 -0
  9. package/dist/core/behavior/behavior-registry.d.ts +97 -0
  10. package/dist/core/behavior/behavior-registry.js +198 -0
  11. package/dist/core/behavior/behaviors/compute-from.d.ts +41 -0
  12. package/dist/core/behavior/behaviors/compute-from.js +84 -0
  13. package/dist/core/behavior/behaviors/copy-from.d.ts +31 -0
  14. package/dist/core/behavior/behaviors/copy-from.js +64 -0
  15. package/dist/core/behavior/behaviors/enable-when.d.ts +49 -0
  16. package/dist/core/behavior/behaviors/enable-when.js +81 -0
  17. package/dist/core/behavior/behaviors/index.d.ts +11 -0
  18. package/dist/core/behavior/behaviors/index.js +11 -0
  19. package/dist/core/behavior/behaviors/reset-when.d.ts +51 -0
  20. package/dist/core/behavior/behaviors/reset-when.js +63 -0
  21. package/dist/core/behavior/behaviors/revalidate-when.d.ts +30 -0
  22. package/dist/core/behavior/behaviors/revalidate-when.js +51 -0
  23. package/dist/core/behavior/behaviors/sync-fields.d.ts +28 -0
  24. package/dist/core/behavior/behaviors/sync-fields.js +66 -0
  25. package/dist/core/behavior/behaviors/transform-value.d.ts +120 -0
  26. package/dist/core/behavior/behaviors/transform-value.js +110 -0
  27. package/dist/core/behavior/behaviors/watch-field.d.ts +35 -0
  28. package/dist/core/behavior/behaviors/watch-field.js +56 -0
  29. package/dist/core/behavior/compose-behavior.d.ts +106 -0
  30. package/dist/core/behavior/compose-behavior.js +166 -0
  31. package/dist/core/behavior/create-field-path.d.ts +20 -0
  32. package/dist/core/behavior/create-field-path.js +69 -0
  33. package/dist/core/behavior/index.d.ts +12 -0
  34. package/dist/core/behavior/index.js +17 -0
  35. package/dist/core/behavior/types.d.ts +152 -0
  36. package/dist/core/behavior/types.js +7 -0
  37. package/dist/core/context/form-context-impl.d.ts +29 -0
  38. package/dist/core/context/form-context-impl.js +37 -0
  39. package/dist/core/factories/index.d.ts +6 -0
  40. package/dist/core/factories/index.js +6 -0
  41. package/dist/core/factories/node-factory.d.ts +209 -0
  42. package/dist/core/factories/node-factory.js +281 -0
  43. package/dist/core/nodes/array-node.d.ts +308 -0
  44. package/dist/core/nodes/array-node.js +534 -0
  45. package/dist/core/nodes/field-node.d.ts +269 -0
  46. package/dist/core/nodes/field-node.js +510 -0
  47. package/dist/core/nodes/form-node.d.ts +342 -0
  48. package/dist/core/nodes/form-node.js +343 -0
  49. package/dist/core/nodes/group-node/field-registry.d.ts +191 -0
  50. package/dist/core/nodes/group-node/field-registry.js +215 -0
  51. package/dist/core/nodes/group-node/index.d.ts +11 -0
  52. package/dist/core/nodes/group-node/index.js +11 -0
  53. package/dist/core/nodes/group-node/proxy-builder.d.ts +71 -0
  54. package/dist/core/nodes/group-node/proxy-builder.js +161 -0
  55. package/dist/core/nodes/group-node/state-manager.d.ts +184 -0
  56. package/dist/core/nodes/group-node/state-manager.js +265 -0
  57. package/dist/core/nodes/group-node.d.ts +494 -0
  58. package/dist/core/nodes/group-node.js +770 -0
  59. package/dist/core/types/deep-schema.d.ts +78 -0
  60. package/dist/core/types/deep-schema.js +11 -0
  61. package/dist/core/types/field-path.d.ts +42 -0
  62. package/dist/core/types/field-path.js +4 -0
  63. package/dist/core/types/form-context.d.ts +83 -0
  64. package/dist/core/types/form-context.js +25 -0
  65. package/dist/core/types/group-node-proxy.d.ts +135 -0
  66. package/dist/core/types/group-node-proxy.js +31 -0
  67. package/dist/core/types/index.d.ts +163 -0
  68. package/dist/core/types/index.js +4 -0
  69. package/dist/core/types/validation-schema.d.ts +104 -0
  70. package/dist/core/types/validation-schema.js +10 -0
  71. package/dist/core/utils/create-form.d.ts +61 -0
  72. package/dist/core/utils/create-form.js +24 -0
  73. package/dist/core/utils/debounce.d.ts +160 -0
  74. package/dist/core/utils/debounce.js +197 -0
  75. package/dist/core/utils/error-handler.d.ts +180 -0
  76. package/dist/core/utils/error-handler.js +226 -0
  77. package/dist/core/utils/field-path-navigator.d.ts +240 -0
  78. package/dist/core/utils/field-path-navigator.js +374 -0
  79. package/dist/core/utils/index.d.ts +14 -0
  80. package/dist/core/utils/index.js +14 -0
  81. package/dist/core/utils/registry-helpers.d.ts +50 -0
  82. package/dist/core/utils/registry-helpers.js +79 -0
  83. package/dist/core/utils/registry-stack.d.ts +69 -0
  84. package/dist/core/utils/registry-stack.js +86 -0
  85. package/dist/core/utils/resources.d.ts +41 -0
  86. package/dist/core/utils/resources.js +69 -0
  87. package/dist/core/utils/subscription-manager.d.ts +180 -0
  88. package/dist/core/utils/subscription-manager.js +214 -0
  89. package/dist/core/utils/type-guards.d.ts +116 -0
  90. package/dist/core/utils/type-guards.js +169 -0
  91. package/dist/core/validation/core/apply-when.d.ts +28 -0
  92. package/dist/core/validation/core/apply-when.js +41 -0
  93. package/dist/core/validation/core/apply.d.ts +63 -0
  94. package/dist/core/validation/core/apply.js +38 -0
  95. package/dist/core/validation/core/index.d.ts +8 -0
  96. package/dist/core/validation/core/index.js +8 -0
  97. package/dist/core/validation/core/validate-async.d.ts +42 -0
  98. package/dist/core/validation/core/validate-async.js +45 -0
  99. package/dist/core/validation/core/validate-tree.d.ts +35 -0
  100. package/dist/core/validation/core/validate-tree.js +37 -0
  101. package/dist/core/validation/core/validate.d.ts +32 -0
  102. package/dist/core/validation/core/validate.js +38 -0
  103. package/dist/core/validation/field-path.d.ts +43 -0
  104. package/dist/core/validation/field-path.js +147 -0
  105. package/dist/core/validation/index.d.ts +21 -0
  106. package/dist/core/validation/index.js +33 -0
  107. package/dist/core/validation/validate-form.d.ts +85 -0
  108. package/dist/core/validation/validate-form.js +152 -0
  109. package/dist/core/validation/validation-applicator.d.ts +89 -0
  110. package/dist/core/validation/validation-applicator.js +217 -0
  111. package/dist/core/validation/validation-context.d.ts +47 -0
  112. package/dist/core/validation/validation-context.js +75 -0
  113. package/dist/core/validation/validation-registry.d.ts +156 -0
  114. package/dist/core/validation/validation-registry.js +298 -0
  115. package/dist/core/validation/validators/array-validators.d.ts +63 -0
  116. package/dist/core/validation/validators/array-validators.js +86 -0
  117. package/dist/core/validation/validators/date.d.ts +38 -0
  118. package/dist/core/validation/validators/date.js +117 -0
  119. package/dist/core/validation/validators/email.d.ts +44 -0
  120. package/dist/core/validation/validators/email.js +60 -0
  121. package/dist/core/validation/validators/index.d.ts +14 -0
  122. package/dist/core/validation/validators/index.js +14 -0
  123. package/dist/core/validation/validators/max-length.d.ts +45 -0
  124. package/dist/core/validation/validators/max-length.js +60 -0
  125. package/dist/core/validation/validators/max.d.ts +45 -0
  126. package/dist/core/validation/validators/max.js +60 -0
  127. package/dist/core/validation/validators/min-length.d.ts +45 -0
  128. package/dist/core/validation/validators/min-length.js +60 -0
  129. package/dist/core/validation/validators/min.d.ts +45 -0
  130. package/dist/core/validation/validators/min.js +60 -0
  131. package/dist/core/validation/validators/number.d.ts +38 -0
  132. package/dist/core/validation/validators/number.js +90 -0
  133. package/dist/core/validation/validators/pattern.d.ts +47 -0
  134. package/dist/core/validation/validators/pattern.js +62 -0
  135. package/dist/core/validation/validators/phone.d.ts +34 -0
  136. package/dist/core/validation/validators/phone.js +58 -0
  137. package/dist/core/validation/validators/required.d.ts +48 -0
  138. package/dist/core/validation/validators/required.js +69 -0
  139. package/dist/core/validation/validators/url.d.ts +29 -0
  140. package/dist/core/validation/validators/url.js +55 -0
  141. package/dist/create-field-path-CdPF3lIK.js +704 -0
  142. package/dist/hooks/useFormControl.d.ts +48 -0
  143. package/dist/hooks/useFormControl.js +298 -0
  144. package/dist/index.d.ts +10 -0
  145. package/dist/index.js +8 -0
  146. package/dist/node-factory-D7DOnSSN.js +3200 -0
  147. package/dist/validators.d.ts +2 -0
  148. package/dist/validators.js +298 -0
  149. package/llms.txt +847 -0
  150. package/package.json +86 -0
@@ -0,0 +1,41 @@
1
+ export interface ResourceItem<T> {
2
+ id: string | number;
3
+ label: string;
4
+ description: string;
5
+ value: T;
6
+ [key: string]: unknown;
7
+ }
8
+ export interface ResourceResult<T> {
9
+ items: ResourceItem<T>[];
10
+ totalCount: number;
11
+ }
12
+ export interface ResourceConfig<T> {
13
+ type: 'static' | 'preload' | 'partial';
14
+ load: (params?: ResourceLoadParams) => Promise<ResourceResult<T>>;
15
+ }
16
+ export interface ResourceLoadParams {
17
+ search?: string;
18
+ page?: number;
19
+ pageSize?: number;
20
+ [key: string]: unknown;
21
+ }
22
+ /**
23
+ * Статический ресурс - данные загружаются один раз
24
+ * @param items - массив элементов
25
+ */
26
+ export declare function staticResource<T>(items: ResourceItem<T>[]): ResourceConfig<T>;
27
+ /**
28
+ * Предзагрузка - данные загружаются один раз при первом обращении через функцию
29
+ * @param loader - функция загрузки, принимает параметры и возвращает массив
30
+ */
31
+ export declare function preloadResource<T>(loader: (params?: ResourceLoadParams) => Promise<ResourceItem<T>[]>): ResourceConfig<T>;
32
+ /**
33
+ * Парциональная загрузка - данные загружаются порциями с учетом поиска/пагинации
34
+ * @param loader - функция загрузки, принимает параметры и возвращает массив
35
+ */
36
+ export declare function partialResource<T>(loader: (params?: ResourceLoadParams) => Promise<ResourceItem<T>[]>): ResourceConfig<T>;
37
+ export declare const Resources: {
38
+ static: typeof staticResource;
39
+ preload: typeof preloadResource;
40
+ partial: typeof partialResource;
41
+ };
@@ -0,0 +1,69 @@
1
+ // ============================================================================
2
+ // Типы ресурсов
3
+ // ============================================================================
4
+ // ============================================================================
5
+ // 1. Статическая стратегия
6
+ // ============================================================================
7
+ /**
8
+ * Статический ресурс - данные загружаются один раз
9
+ * @param items - массив элементов
10
+ */
11
+ export function staticResource(items) {
12
+ return {
13
+ type: 'static',
14
+ load: async () => ({
15
+ items,
16
+ totalCount: items.length,
17
+ }),
18
+ };
19
+ }
20
+ // ============================================================================
21
+ // 2. Предзагрузка
22
+ // ============================================================================
23
+ /**
24
+ * Предзагрузка - данные загружаются один раз при первом обращении через функцию
25
+ * @param loader - функция загрузки, принимает параметры и возвращает массив
26
+ */
27
+ export function preloadResource(loader) {
28
+ let cache = null;
29
+ return {
30
+ type: 'preload',
31
+ load: async (params) => {
32
+ if (!cache) {
33
+ const items = await loader(params);
34
+ cache = {
35
+ items,
36
+ totalCount: items.length,
37
+ };
38
+ }
39
+ return cache;
40
+ },
41
+ };
42
+ }
43
+ // ============================================================================
44
+ // 3. Парциональная загрузка
45
+ // ============================================================================
46
+ /**
47
+ * Парциональная загрузка - данные загружаются порциями с учетом поиска/пагинации
48
+ * @param loader - функция загрузки, принимает параметры и возвращает массив
49
+ */
50
+ export function partialResource(loader) {
51
+ return {
52
+ type: 'partial',
53
+ load: async (params) => {
54
+ const items = await loader(params);
55
+ return {
56
+ items,
57
+ totalCount: items.length, // Можно расширить для поддержки серверной пагинации
58
+ };
59
+ },
60
+ };
61
+ }
62
+ // ============================================================================
63
+ // Экспорт всех стратегий
64
+ // ============================================================================
65
+ export const Resources = {
66
+ static: staticResource,
67
+ preload: preloadResource,
68
+ partial: partialResource,
69
+ };
@@ -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,214 @@
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 class SubscriptionManager {
31
+ /**
32
+ * Хранилище подписок
33
+ * Ключ: уникальный идентификатор подписки
34
+ * Значение: функция отписки (dispose)
35
+ */
36
+ subscriptions = new Map();
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, dispose) {
66
+ // Если подписка с таким ключом уже есть, отписываемся от неё
67
+ if (this.subscriptions.has(key)) {
68
+ if (process.env.NODE_ENV !== 'production') {
69
+ console.warn(`[SubscriptionManager] Subscription "${key}" already exists, replacing`);
70
+ }
71
+ this.subscriptions.get(key)?.();
72
+ }
73
+ // Сохраняем новую подписку
74
+ this.subscriptions.set(key, dispose);
75
+ // Возвращаем функцию отписки
76
+ return () => this.remove(key);
77
+ }
78
+ /**
79
+ * Удаляет подписку по ключу
80
+ *
81
+ * Вызывает функцию отписки и удаляет подписку из хранилища.
82
+ * Если подписка с таким ключом не найдена, ничего не делает.
83
+ *
84
+ * @param key Ключ подписки
85
+ * @returns true, если подписка была удалена, false если не найдена
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * const manager = new SubscriptionManager();
90
+ * manager.add('mySub', disposeFn);
91
+ *
92
+ * // Удаление подписки
93
+ * const removed = manager.remove('mySub'); // true
94
+ *
95
+ * // Попытка удалить несуществующую подписку
96
+ * const removed2 = manager.remove('nonExistent'); // false
97
+ * ```
98
+ */
99
+ remove(key) {
100
+ const dispose = this.subscriptions.get(key);
101
+ if (dispose) {
102
+ dispose();
103
+ this.subscriptions.delete(key);
104
+ return true;
105
+ }
106
+ return false;
107
+ }
108
+ /**
109
+ * Очищает все подписки
110
+ *
111
+ * Вызывает функции отписки для всех активных подписок
112
+ * и очищает хранилище. Обычно используется при dispose узла формы.
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * class FieldNode {
117
+ * private subscriptions = new SubscriptionManager();
118
+ *
119
+ * dispose() {
120
+ * // Отписываемся от всех effect
121
+ * this.subscriptions.clear();
122
+ * }
123
+ * }
124
+ * ```
125
+ */
126
+ clear() {
127
+ // Используем forEach для совместимости
128
+ this.subscriptions.forEach((dispose) => {
129
+ dispose();
130
+ });
131
+ this.subscriptions.clear();
132
+ }
133
+ /**
134
+ * Возвращает количество активных подписок
135
+ *
136
+ * Полезно для отладки утечек памяти. Если количество подписок
137
+ * растет без ограничений, это может указывать на то, что
138
+ * компоненты не отписываются должным образом.
139
+ *
140
+ * @returns Количество активных подписок
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * const manager = new SubscriptionManager();
145
+ * console.log(manager.size()); // 0
146
+ *
147
+ * manager.add('sub1', disposeFn1);
148
+ * manager.add('sub2', disposeFn2);
149
+ * console.log(manager.size()); // 2
150
+ *
151
+ * manager.clear();
152
+ * console.log(manager.size()); // 0
153
+ * ```
154
+ */
155
+ size() {
156
+ return this.subscriptions.size;
157
+ }
158
+ /**
159
+ * Проверяет, есть ли подписка с данным ключом
160
+ *
161
+ * @param key Ключ подписки
162
+ * @returns true, если подписка существует
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * const manager = new SubscriptionManager();
167
+ * manager.add('mySub', disposeFn);
168
+ *
169
+ * console.log(manager.has('mySub')); // true
170
+ * console.log(manager.has('nonExistent')); // false
171
+ * ```
172
+ */
173
+ has(key) {
174
+ return this.subscriptions.has(key);
175
+ }
176
+ /**
177
+ * Возвращает список всех ключей активных подписок
178
+ *
179
+ * Полезно для отладки: можно увидеть, какие подписки активны.
180
+ *
181
+ * @returns Массив ключей всех активных подписок
182
+ *
183
+ * @example
184
+ * ```typescript
185
+ * const manager = new SubscriptionManager();
186
+ * manager.add('watch-value', disposeFn1);
187
+ * manager.add('watch-errors', disposeFn2);
188
+ *
189
+ * console.log(manager.getKeys()); // ['watch-value', 'watch-errors']
190
+ * ```
191
+ */
192
+ getKeys() {
193
+ return Array.from(this.subscriptions.keys());
194
+ }
195
+ /**
196
+ * Отписывается от всех подписок (алиас для clear())
197
+ *
198
+ * Используется при dispose() узла формы для совместимости с ожидаемым API.
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * class FieldNode {
203
+ * private subscriptions = new SubscriptionManager();
204
+ *
205
+ * dispose() {
206
+ * this.subscriptions.dispose();
207
+ * }
208
+ * }
209
+ * ```
210
+ */
211
+ dispose() {
212
+ this.clear();
213
+ }
214
+ }
@@ -0,0 +1,116 @@
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
+ import type { FormNode } from '../nodes/form-node';
20
+ import type { FieldNode } from '../nodes/field-node';
21
+ import type { GroupNode } from '../nodes/group-node';
22
+ import type { ArrayNode } from '../nodes/array-node';
23
+ import type { FormFields, FormValue } from '../types';
24
+ /**
25
+ * Проверить, является ли значение любым FormNode
26
+ *
27
+ * Проверяет базовые свойства, общие для всех типов узлов
28
+ *
29
+ * @group Utilities
30
+ * @category Type Guards
31
+ *
32
+ * @param value - Значение для проверки
33
+ * @returns true если value является FormNode
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * if (isFormNode(value)) {
38
+ * value.setValue(newValue);
39
+ * value.validate();
40
+ * }
41
+ * ```
42
+ */
43
+ export declare function isFormNode(value: unknown): value is FormNode<FormValue>;
44
+ /**
45
+ * Проверить, является ли значение FieldNode (примитивное поле)
46
+ *
47
+ * FieldNode представляет примитивное поле формы (string, number, boolean и т.д.)
48
+ * и имеет валидаторы, но не имеет вложенных полей или элементов массива
49
+ *
50
+ * @group Utilities
51
+ * @category Type Guards
52
+ *
53
+ * @param value - Значение для проверки
54
+ * @returns true если value является FieldNode
55
+ *
56
+ * @example
57
+ * ```typescript
58
+ * if (isFieldNode(node)) {
59
+ * node.validators; // OK
60
+ * node.asyncValidators; // OK
61
+ * node.markAsTouched(); // OK
62
+ * }
63
+ * ```
64
+ */
65
+ export declare function isFieldNode(value: unknown): value is FieldNode<FormValue>;
66
+ /**
67
+ * Проверить, является ли значение GroupNode (объект с вложенными полями)
68
+ *
69
+ * GroupNode представляет объект с вложенными полями формы
70
+ * и имеет методы для применения validation/behavior схем
71
+ *
72
+ * @param value - Значение для проверки
73
+ * @returns true если value является GroupNode
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * if (isGroupNode(node)) {
78
+ * node.applyValidationSchema(schema); // OK
79
+ * node.getFieldByPath('user.email'); // OK
80
+ * }
81
+ * ```
82
+ */
83
+ export declare function isGroupNode(value: unknown): value is GroupNode<FormFields>;
84
+ /**
85
+ * Проверить, является ли значение ArrayNode (массив форм)
86
+ *
87
+ * ArrayNode представляет массив вложенных форм (обычно GroupNode)
88
+ * и имеет array-like методы (push, removeAt, at)
89
+ *
90
+ * @param value - Значение для проверки
91
+ * @returns true если value является ArrayNode
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * if (isArrayNode(node)) {
96
+ * node.push(); // OK - добавить элемент
97
+ * node.removeAt(0); // OK - удалить элемент
98
+ * const item = node.at(0); // OK - получить элемент
99
+ * }
100
+ * ```
101
+ */
102
+ export declare function isArrayNode(value: unknown): value is ArrayNode<FormFields>;
103
+ /**
104
+ * Получить тип узла как строку (для отладки)
105
+ *
106
+ * Полезно для логирования и отладки
107
+ *
108
+ * @param node - Узел для проверки
109
+ * @returns Строковое название типа узла
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * console.log('Node type:', getNodeType(node)); // "FieldNode" | "GroupNode" | "ArrayNode" | "FormNode" | "Unknown"
114
+ * ```
115
+ */
116
+ export declare function getNodeType(node: unknown): string;