@reformer/core 2.0.1 → 4.0.0

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 (147) hide show
  1. package/dist/behaviors/compute-from.d.ts +2 -0
  2. package/dist/behaviors/compute-from.js +31 -0
  3. package/dist/behaviors/copy-from.d.ts +2 -0
  4. package/dist/behaviors/copy-from.js +29 -0
  5. package/dist/behaviors/enable-when.d.ts +2 -0
  6. package/dist/behaviors/enable-when.js +25 -0
  7. package/dist/behaviors/reset-when.d.ts +2 -0
  8. package/dist/behaviors/reset-when.js +24 -0
  9. package/dist/behaviors/revalidate-when.d.ts +2 -0
  10. package/dist/behaviors/revalidate-when.js +18 -0
  11. package/dist/behaviors/sync-fields.d.ts +2 -0
  12. package/dist/behaviors/sync-fields.js +41 -0
  13. package/dist/behaviors/transform-value.d.ts +2 -0
  14. package/dist/behaviors/transform-value.js +45 -0
  15. package/dist/behaviors/watch-field.d.ts +2 -0
  16. package/dist/behaviors/watch-field.js +21 -0
  17. package/dist/behaviors.js +26 -19
  18. package/dist/core/behavior/behavior-context.d.ts +27 -13
  19. package/dist/core/behavior/behavior-registry.d.ts +15 -27
  20. package/dist/core/behavior/behaviors/compute-from.d.ts +50 -21
  21. package/dist/core/behavior/behaviors/copy-from.d.ts +39 -14
  22. package/dist/core/behavior/behaviors/enable-when.d.ts +88 -19
  23. package/dist/core/behavior/behaviors/reset-when.d.ts +31 -18
  24. package/dist/core/behavior/behaviors/revalidate-when.d.ts +40 -17
  25. package/dist/core/behavior/behaviors/sync-fields.d.ts +34 -14
  26. package/dist/core/behavior/behaviors/transform-value.d.ts +116 -44
  27. package/dist/core/behavior/behaviors/watch-field.d.ts +66 -21
  28. package/dist/core/behavior/compose-behavior.d.ts +2 -12
  29. package/dist/core/behavior/index.d.ts +0 -1
  30. package/dist/core/behavior/types.d.ts +2 -8
  31. package/dist/core/factories/node-factory.d.ts +6 -29
  32. package/dist/core/nodes/array-node.d.ts +42 -22
  33. package/dist/core/nodes/field-node.d.ts +51 -26
  34. package/dist/core/nodes/form-node.d.ts +18 -20
  35. package/dist/core/nodes/group-node.d.ts +26 -22
  36. package/dist/core/types/deep-schema.d.ts +2 -12
  37. package/dist/core/types/field-path.d.ts +1 -1
  38. package/dist/core/types/form-context.d.ts +27 -27
  39. package/dist/core/types/{group-node-proxy.d.ts → form-proxy.d.ts} +12 -42
  40. package/dist/core/types/index.d.ts +52 -6
  41. package/dist/core/types/validation-schema.d.ts +3 -12
  42. package/dist/core/utils/abstract-registry.d.ts +74 -0
  43. package/dist/core/utils/aggregate-signals.d.ts +71 -0
  44. package/dist/core/utils/create-form.d.ts +3 -20
  45. package/dist/core/utils/error-handler.d.ts +1 -18
  46. package/dist/core/utils/field-path-navigator.d.ts +1 -1
  47. package/dist/core/utils/field-path.d.ts +23 -11
  48. package/dist/core/utils/form-observer.d.ts +176 -0
  49. package/dist/core/utils/form-proxy-builder.d.ts +25 -0
  50. package/dist/core/utils/form-submitter.d.ts +121 -0
  51. package/dist/core/utils/index.d.ts +9 -2
  52. package/dist/core/utils/registry-helpers.d.ts +0 -7
  53. package/dist/core/utils/safe-effect.d.ts +73 -0
  54. package/dist/core/utils/status-machine.d.ts +153 -0
  55. package/dist/core/utils/type-guards.d.ts +5 -23
  56. package/dist/core/utils/unique-id.d.ts +53 -0
  57. package/dist/core/validation/core/apply-when.d.ts +3 -9
  58. package/dist/core/validation/core/apply.d.ts +2 -13
  59. package/dist/core/validation/core/validate-async.d.ts +2 -8
  60. package/dist/core/validation/core/validate-tree.d.ts +0 -6
  61. package/dist/core/validation/core/validate.d.ts +1 -7
  62. package/dist/core/validation/index.d.ts +8 -2
  63. package/dist/core/validation/validate-form.d.ts +1 -38
  64. package/dist/core/validation/validation-applicator.d.ts +2 -21
  65. package/dist/core/validation/validation-context.d.ts +59 -43
  66. package/dist/core/validation/validation-registry.d.ts +11 -25
  67. package/dist/core/validation/validators/array-validators.d.ts +2 -12
  68. package/dist/core/validation/validators/date-utils.d.ts +26 -0
  69. package/dist/core/validation/validators/email.d.ts +2 -9
  70. package/dist/core/validation/validators/future-date.d.ts +35 -0
  71. package/dist/core/validation/validators/index.d.ts +7 -1
  72. package/dist/core/validation/validators/is-date.d.ts +36 -0
  73. package/dist/core/validation/validators/max-age.d.ts +36 -0
  74. package/dist/core/validation/validators/max-date.d.ts +36 -0
  75. package/dist/core/validation/validators/max-length.d.ts +3 -10
  76. package/dist/core/validation/validators/max.d.ts +3 -10
  77. package/dist/core/validation/validators/min-age.d.ts +36 -0
  78. package/dist/core/validation/validators/min-date.d.ts +36 -0
  79. package/dist/core/validation/validators/min-length.d.ts +3 -10
  80. package/dist/core/validation/validators/min.d.ts +3 -10
  81. package/dist/core/validation/validators/number.d.ts +2 -9
  82. package/dist/core/validation/validators/past-date.d.ts +35 -0
  83. package/dist/core/validation/validators/pattern.d.ts +2 -9
  84. package/dist/core/validation/validators/phone.d.ts +2 -9
  85. package/dist/core/validation/validators/required.d.ts +2 -9
  86. package/dist/core/validation/validators/url.d.ts +2 -9
  87. package/dist/date-utils-xUWFslTj.js +29 -0
  88. package/dist/field-path-DuKdGcIE.js +66 -0
  89. package/dist/hooks/types.d.ts +1 -1
  90. package/dist/hooks/useArrayLength.d.ts +31 -0
  91. package/dist/hooks/useFormControl.d.ts +4 -4
  92. package/dist/hooks/useFormControlValue.d.ts +2 -2
  93. package/dist/hooks/useHiddenCondition.d.ts +25 -0
  94. package/dist/hooks/useSignalSubscription.d.ts +1 -1
  95. package/dist/index-D25LsbRm.js +73 -0
  96. package/dist/index.d.ts +2 -0
  97. package/dist/index.js +1171 -786
  98. package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
  99. package/dist/safe-effect-Dh8uw81c.js +20 -0
  100. package/dist/validate-C3XiA_zf.js +10 -0
  101. package/dist/validators/email.d.ts +2 -0
  102. package/dist/validators/email.js +13 -0
  103. package/dist/validators/future-date.d.ts +2 -0
  104. package/dist/validators/future-date.js +20 -0
  105. package/dist/validators/is-date.d.ts +2 -0
  106. package/dist/validators/is-date.js +12 -0
  107. package/dist/validators/max-age.d.ts +2 -0
  108. package/dist/validators/max-age.js +20 -0
  109. package/dist/validators/max-date.d.ts +2 -0
  110. package/dist/validators/max-date.js +20 -0
  111. package/dist/validators/max-length.d.ts +2 -0
  112. package/dist/validators/max-length.js +11 -0
  113. package/dist/validators/max.d.ts +2 -0
  114. package/dist/validators/max.js +11 -0
  115. package/dist/validators/min-age.d.ts +2 -0
  116. package/dist/validators/min-age.js +20 -0
  117. package/dist/validators/min-date.d.ts +2 -0
  118. package/dist/validators/min-date.js +20 -0
  119. package/dist/validators/min-length.d.ts +2 -0
  120. package/dist/validators/min-length.js +11 -0
  121. package/dist/validators/min.d.ts +2 -0
  122. package/dist/validators/min.js +11 -0
  123. package/dist/validators/number.d.ts +2 -0
  124. package/dist/validators/number.js +35 -0
  125. package/dist/validators/past-date.d.ts +2 -0
  126. package/dist/validators/past-date.js +20 -0
  127. package/dist/validators/pattern.d.ts +2 -0
  128. package/dist/validators/pattern.js +11 -0
  129. package/dist/validators/phone.d.ts +2 -0
  130. package/dist/validators/phone.js +35 -0
  131. package/dist/validators/required.d.ts +2 -0
  132. package/dist/validators/required.js +15 -0
  133. package/dist/validators/url.d.ts +2 -0
  134. package/dist/validators/url.js +19 -0
  135. package/dist/validators-BGsNOgT1.js +207 -0
  136. package/dist/validators.js +54 -29
  137. package/llms.txt +7885 -318
  138. package/package.json +83 -8
  139. package/dist/behaviors-DzYL8kY_.js +0 -499
  140. package/dist/core/behavior/create-field-path.d.ts +0 -7
  141. package/dist/core/context/form-context-impl.d.ts +0 -29
  142. package/dist/core/utils/debounce.d.ts +0 -160
  143. package/dist/core/utils/resources.d.ts +0 -41
  144. package/dist/core/validation/field-path.d.ts +0 -7
  145. package/dist/core/validation/validators/date.d.ts +0 -38
  146. package/dist/registry-helpers-BRxAr6nG.js +0 -490
  147. package/dist/validators-gXoHPdqM.js +0 -418
@@ -1,34 +1,4 @@
1
- /**
2
- * Типы для Proxy-доступа к полям GroupNode
3
- *
4
- * Решает проблему типизации, когда GroupNode<T> использует Proxy для прямого доступа к полям.
5
- * TypeScript не может автоматически определить правильные типы для вложенных форм и массивов.
6
- *
7
- * @group Types
8
- *
9
- * @example
10
- * ```typescript
11
- * interface MyForm {
12
- * name: string;
13
- * address: {
14
- * city: string;
15
- * };
16
- * items: Array<{ title: string }>;
17
- * }
18
- *
19
- * const form: GroupNodeWithControls<MyForm> = new GroupNode(schema);
20
- *
21
- * // TypeScript знает, что это FieldNode<string>
22
- * form.name.setValue('John');
23
- *
24
- * // TypeScript знает, что это GroupNode<{city: string}>
25
- * form.address.city.setValue('Moscow');
26
- *
27
- * // TypeScript знает, что это ArrayNode<{title: string}>
28
- * form.items.push({ title: 'New Item' });
29
- * ```
30
- */
31
- import type { FormFields } from './index';
1
+ import { FormFields } from './index';
32
2
  type FieldNode<_T> = any;
33
3
  type GroupNode<_T> = any;
34
4
  type ArrayNode<_T> = any;
@@ -36,9 +6,9 @@ type ArrayNode<_T> = any;
36
6
  * Мапит тип модели данных T на правильные типы узлов формы
37
7
  *
38
8
  * Рекурсивно определяет типы узлов на основе структуры данных:
39
- * - `T[K] extends Array<infer U>` где U - объект → `ArrayNodeWithControls<U>`
9
+ * - `T[K] extends Array<infer U>` где U - объект → `FormArrayProxy<U>`
40
10
  * - `T[K] extends Array<infer U>` где U - примитив → `FieldNode<T[K]>` (массив как обычное поле)
41
- * - `T[K] extends object` → `GroupNodeWithControls<T[K]>` (вложенная форма с типизацией)
11
+ * - `T[K] extends object` → `FormProxy<T[K]>` (вложенная форма с типизацией)
42
12
  * - `T[K]` примитив → `FieldNode<T[K]>` (простое поле)
43
13
  *
44
14
  * Использует NonNullable для правильной обработки опциональных полей
@@ -48,8 +18,8 @@ type ArrayNode<_T> = any;
48
18
  *
49
19
  * @template T - Тип модели данных формы
50
20
  */
51
- export type FormNodeControls<T> = {
52
- [K in keyof T]: NonNullable<T[K]> extends Array<infer U> ? U extends FormFields ? ArrayNodeWithControls<U> : FieldNode<T[K]> : NonNullable<T[K]> extends FormFields ? NonNullable<T[K]> extends Date | File | Blob ? FieldNode<T[K]> : GroupNodeWithControls<NonNullable<T[K]>> : FieldNode<T[K]>;
21
+ export type FormControlsProxy<T> = {
22
+ [K in keyof T]: NonNullable<T[K]> extends Array<infer U> ? U extends FormFields ? FormArrayProxy<U> : FieldNode<T[K]> : NonNullable<T[K]> extends FormFields ? NonNullable<T[K]> extends Date | File | Blob ? FieldNode<T[K]> : FormProxy<NonNullable<T[K]>> : FieldNode<T[K]>;
53
23
  };
54
24
  /**
55
25
  * Комбинированный тип для GroupNode с Proxy доступом к полям
@@ -72,7 +42,7 @@ export type FormNodeControls<T> = {
72
42
  * };
73
43
  * }
74
44
  *
75
- * const form: GroupNodeWithControls<UserForm> = new GroupNode(schema);
45
+ * const form = createForm<UserForm>(schema);
76
46
  *
77
47
  * // Доступ к методам GroupNode
78
48
  * await form.validate();
@@ -84,7 +54,7 @@ export type FormNodeControls<T> = {
84
54
  * form.profile.name.setValue('John');
85
55
  * ```
86
56
  */
87
- export type GroupNodeWithControls<T> = GroupNode<T> & FormNodeControls<T>;
57
+ export type FormProxy<T> = GroupNode<T> & FormControlsProxy<T>;
88
58
  /**
89
59
  * Комбинированный тип для ArrayNode с Proxy доступом к элементам
90
60
  *
@@ -102,7 +72,7 @@ export type GroupNodeWithControls<T> = GroupNode<T> & FormNodeControls<T>;
102
72
  * completed: boolean;
103
73
  * }
104
74
  *
105
- * const todos: ArrayNodeWithControls<TodoItem> = new ArrayNode(schema);
75
+ * const todos: FormArrayProxy<TodoItem> = new ArrayNode(schema);
106
76
  *
107
77
  * // Доступ к методам ArrayNode
108
78
  * todos.push({ title: 'New todo', completed: false });
@@ -117,19 +87,19 @@ export type GroupNodeWithControls<T> = GroupNode<T> & FormNodeControls<T>;
117
87
  * });
118
88
  * ```
119
89
  */
120
- export type ArrayNodeWithControls<T extends FormFields> = ArrayNode<T> & {
90
+ export type FormArrayProxy<T extends FormFields> = ArrayNode<T> & {
121
91
  /**
122
92
  * Безопасный доступ к элементу массива по индексу
123
93
  * Возвращает GroupNode с типизированными полями или undefined
124
94
  */
125
- at(index: number): GroupNodeWithControls<T> | undefined;
95
+ at(index: number): FormProxy<T> | undefined;
126
96
  /**
127
97
  * Итерация по элементам массива с типизированными элементами
128
98
  */
129
- forEach(callback: (item: GroupNodeWithControls<T>, index: number) => void): void;
99
+ forEach(callback: (item: FormProxy<T>, index: number) => void): void;
130
100
  /**
131
101
  * Маппинг элементов массива с типизированными элементами
132
102
  */
133
- map<R>(callback: (item: GroupNodeWithControls<T>, index: number) => R): R[];
103
+ map<R>(callback: (item: FormProxy<T>, index: number) => R): R[];
134
104
  };
135
105
  export {};
@@ -1,3 +1,7 @@
1
+ import { BehaviorSchemaFn } from '../behavior/types';
2
+ import { FormSchema } from './deep-schema';
3
+ import { ValidationSchemaFn } from './validation-schema';
4
+ import { FormNode } from '../nodes/form-node';
1
5
  /**
2
6
  * Represents any valid form value type
3
7
  * Use this instead of 'any' for form values to maintain type safety
@@ -20,12 +24,46 @@ export type UnknownFormValue = unknown;
20
24
  * @category Validation Types
21
25
  */
22
26
  export type ValidatorFn<T = FormValue> = (value: T) => ValidationError | null;
27
+ /**
28
+ * Опции для асинхронного валидатора
29
+ * @group Types
30
+ * @category Validation Types
31
+ */
32
+ export interface AsyncValidatorOptions {
33
+ /**
34
+ * AbortSignal для отмены валидации
35
+ * Позволяет отменить асинхронную операцию при новой валидации
36
+ */
37
+ signal?: AbortSignal;
38
+ }
23
39
  /**
24
40
  * Асинхронная функция валидации
41
+ *
42
+ * @param value - Значение для валидации
43
+ * @param options - Опции валидации (опционально)
44
+ * @returns Promise с ошибкой валидации или null если значение валидно
45
+ *
46
+ * @example
47
+ * ```typescript
48
+ * // Простой валидатор (без поддержки отмены)
49
+ * const emailExists: AsyncValidatorFn<string> = async (value) => {
50
+ * const exists = await checkEmail(value);
51
+ * return exists ? { code: 'exists', message: 'Email already exists' } : null;
52
+ * };
53
+ *
54
+ * // Валидатор с поддержкой отмены
55
+ * const emailExistsAbortable: AsyncValidatorFn<string> = async (value, options) => {
56
+ * const exists = await fetch(`/api/check-email?email=${value}`, {
57
+ * signal: options?.signal // Передаём signal в fetch для отмены запроса
58
+ * });
59
+ * return exists ? { code: 'exists', message: 'Email already exists' } : null;
60
+ * };
61
+ * ```
62
+ *
25
63
  * @group Types
26
64
  * @category Validation Types
27
65
  */
28
- export type AsyncValidatorFn<T = FormValue> = (value: T) => Promise<ValidationError | null>;
66
+ export type AsyncValidatorFn<T = FormValue> = (value: T, options?: AsyncValidatorOptions) => Promise<ValidationError | null>;
29
67
  /**
30
68
  * Ошибка валидации
31
69
  * @group Types
@@ -64,10 +102,7 @@ export type { FieldPath, FieldPathNode } from '../types/field-path';
64
102
  export type { ContextualValidatorFn, ContextualAsyncValidatorFn, TreeValidatorFn, ConditionFn, ValidateOptions, ValidateAsyncOptions, ValidateTreeOptions, ValidationSchemaFn, ValidatorRegistration, } from './validation-schema';
65
103
  export type { FormSchema, ArrayConfig } from './deep-schema';
66
104
  export type { FormContext } from './form-context';
67
- export type { FormNodeControls, GroupNodeWithControls, ArrayNodeWithControls, } from './group-node-proxy';
68
- import type { BehaviorSchemaFn } from '../behavior/types';
69
- import type { FormSchema } from './deep-schema';
70
- import type { ValidationSchemaFn } from './validation-schema';
105
+ export type { FormControlsProxy, FormProxy, FormArrayProxy } from './form-proxy';
71
106
  /**
72
107
  * Конфигурация GroupNode с поддержкой схем
73
108
  * Используется для создания форм с автоматическим применением behavior и validation схем
@@ -82,6 +117,18 @@ export interface GroupNodeConfig<T> {
82
117
  behavior?: BehaviorSchemaFn<T>;
83
118
  /** Схема валидации (required, email, minLength и т.д.) */
84
119
  validation?: ValidationSchemaFn<T>;
120
+ /**
121
+ * Опциональный ValidationRegistry для dependency injection
122
+ * Используется для тестирования с mock-реестрами
123
+ * @internal
124
+ */
125
+ _validationRegistry?: unknown;
126
+ /**
127
+ * Опциональный BehaviorRegistry для dependency injection
128
+ * Используется для тестирования с mock-реестрами
129
+ * @internal
130
+ */
131
+ _behaviorRegistry?: unknown;
85
132
  }
86
133
  /**
87
134
  * Тип для Record с unknown значениями
@@ -112,7 +159,6 @@ export interface ArrayNodeLike {
112
159
  at(index: number): FormNode<unknown> | undefined;
113
160
  length: unknown;
114
161
  }
115
- import type { FormNode } from '../nodes/form-node';
116
162
  /**
117
163
  * Конфиг с полем schema (для ArrayConfig)
118
164
  * @internal
@@ -1,15 +1,6 @@
1
- /**
2
- * Типы для validation schema паттерна
3
- *
4
- * Основано на Angular Signal Forms подходе:
5
- * - Валидация определяется отдельно от схемы полей
6
- * - Поддержка условной валидации (applyWhen)
7
- * - Cross-field валидация (validateTree)
8
- * - Асинхронная валидация с контекстом
9
- */
10
- import type { FormFields, ValidationError } from './index';
11
- import type { FieldPath } from './field-path';
12
- import type { FormContext } from './form-context';
1
+ import { FormFields, ValidationError } from './index';
2
+ import { FieldPath } from './field-path';
3
+ import { FormContext } from './form-context';
13
4
  /**
14
5
  * Функция валидации поля с контекстом
15
6
  *
@@ -0,0 +1,74 @@
1
+ import { RegistryStack } from './registry-stack';
2
+ /**
3
+ * Базовый класс для реестров (BehaviorRegistry, ValidationRegistry).
4
+ *
5
+ * Реализует паттерн Template Method для управления регистрацией:
6
+ * `beginRegistration()` → `onBeginRegistration()`, `endRegistration()` → `onEndRegistration()`.
7
+ *
8
+ * @typeParam TRegistration - Тип регистрируемых элементов.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { AbstractRegistry } from '@reformer/core';
13
+ *
14
+ * class MyRegistry extends AbstractRegistry<{ name: string }> {
15
+ * protected onEndRegistration(items: { name: string }[]) {
16
+ * console.log('Registered', items.length);
17
+ * }
18
+ * }
19
+ * ```
20
+ */
21
+ export declare abstract class AbstractRegistry<TRegistration> {
22
+ /** Флаг активной регистрации */
23
+ protected isRegistering: boolean;
24
+ /** Массив зарегистрированных элементов */
25
+ protected registrations: TRegistration[];
26
+ /**
27
+ * Получить стек для конкретного класса реестра
28
+ * Создает новый стек если не существует
29
+ *
30
+ * @param ctor - Конструктор класса реестра
31
+ * @returns RegistryStack для данного класса
32
+ */
33
+ protected static getStack<T extends AbstractRegistry<any>>(ctor: new (...args: any[]) => T): RegistryStack<T>;
34
+ /**
35
+ * Получить текущий активный реестр из стека
36
+ * Должен быть переопределен в наследниках как static метод
37
+ *
38
+ * @param ctor - Конструктор класса реестра
39
+ * @returns Текущий активный реестр или null
40
+ */
41
+ protected static getCurrentFromStack<T extends AbstractRegistry<any>>(ctor: new (...args: any[]) => T): T | null;
42
+ /**
43
+ * Начать регистрацию
44
+ *
45
+ * Помещает this в global stack для изоляции форм
46
+ * Вызывает hook onBeginRegistration()
47
+ */
48
+ beginRegistration(): void;
49
+ /**
50
+ * Проверить, активна ли регистрация
51
+ */
52
+ isActive(): boolean;
53
+ /**
54
+ * Получить зарегистрированные элементы
55
+ */
56
+ getRegistrations(): TRegistration[];
57
+ /**
58
+ * Hook: вызывается в начале регистрации
59
+ * Может быть переопределен в наследниках для инициализации
60
+ */
61
+ protected onBeginRegistration(): void;
62
+ /**
63
+ * Завершить регистрацию и извлечь из стека
64
+ *
65
+ * @param registryName - Имя реестра для отладки
66
+ */
67
+ protected completeRegistration(registryName: string): void;
68
+ /**
69
+ * Отменить регистрацию без применения
70
+ *
71
+ * @param registryName - Имя реестра для отладки
72
+ */
73
+ cancelRegistration(registryName: string): void;
74
+ }
@@ -0,0 +1,71 @@
1
+ import { ReadonlySignal, Signal } from '@preact/signals-core';
2
+ import { FieldStatus, ValidationError } from '../types';
3
+ import { FormNode } from '../nodes/form-node';
4
+ /**
5
+ * Функция получения дочерних узлов
6
+ * Возвращает массив FormNode для агрегации состояния
7
+ */
8
+ type GetChildrenFn<T> = () => FormNode<T>[];
9
+ /**
10
+ * Результат создания агрегированных сигналов
11
+ */
12
+ export interface AggregateSignals {
13
+ /** Все дочерние узлы валидны и нет собственных ошибок */
14
+ valid: ReadonlySignal<boolean>;
15
+ /** Есть ошибки (инверсия valid) */
16
+ invalid: ReadonlySignal<boolean>;
17
+ /** Хотя бы один дочерний узел в состоянии pending */
18
+ pending: ReadonlySignal<boolean>;
19
+ /** Хотя бы один дочерний узел touched */
20
+ touched: ReadonlySignal<boolean>;
21
+ /** Хотя бы один дочерний узел dirty */
22
+ dirty: ReadonlySignal<boolean>;
23
+ /** Собственные ошибки + ошибки всех дочерних узлов */
24
+ errors: ReadonlySignal<ValidationError[]>;
25
+ /** Статус: disabled > pending > invalid > valid */
26
+ status: ReadonlySignal<FieldStatus>;
27
+ }
28
+ /**
29
+ * Опции для создания агрегированных сигналов
30
+ */
31
+ export interface AggregateSignalsOptions<T> {
32
+ /** Функция получения дочерних узлов */
33
+ getChildren: GetChildrenFn<T>;
34
+ /** Signal с собственными ошибками контейнера (form-level или array-level) */
35
+ ownErrors: Signal<ValidationError[]>;
36
+ /** Опциональный signal disabled состояния (для GroupNode) */
37
+ disabled?: Signal<boolean>;
38
+ }
39
+ /**
40
+ * Создать агрегированные computed signals для контейнерного узла
41
+ *
42
+ * Используется в GroupNode и ArrayNode для унификации логики
43
+ * вычисления состояния на основе дочерних узлов.
44
+ *
45
+ * @param options - Опции конфигурации
46
+ * @returns Объект с computed signals
47
+ *
48
+ * @example GroupNode
49
+ * ```typescript
50
+ * const signals = createAggregateSignals({
51
+ * getChildren: () => Array.from(this._fields.values()),
52
+ * ownErrors: this._formErrors,
53
+ * disabled: this._disabled,
54
+ * });
55
+ * this.valid = signals.valid;
56
+ * this.invalid = signals.invalid;
57
+ * // ...
58
+ * ```
59
+ *
60
+ * @example ArrayNode
61
+ * ```typescript
62
+ * const signals = createAggregateSignals({
63
+ * getChildren: () => this.items.value,
64
+ * ownErrors: this._arrayErrors,
65
+ * });
66
+ * this.valid = signals.valid;
67
+ * // ...
68
+ * ```
69
+ */
70
+ export declare function createAggregateSignals<T>(options: AggregateSignalsOptions<T>): AggregateSignals;
71
+ export {};
@@ -1,21 +1,4 @@
1
- /**
2
- * Фабричная функция для создания формы с правильной типизацией
3
- *
4
- * Решает проблему с типизацией конструктора GroupNode, который возвращает
5
- * Proxy (GroupNodeWithControls), но TypeScript не может это вывести автоматически.
6
- *
7
- * @group Utilities
8
- *
9
- * @example
10
- * ```typescript
11
- * // Вместо:
12
- * const form: GroupNodeWithControls<MyForm> = new GroupNode<MyForm>(config);
13
- *
14
- * // Используйте:
15
- * const form = createForm<MyForm>(config);
16
- * ```
17
- */
18
- import type { GroupNodeWithControls, GroupNodeConfig, FormSchema } from '../types';
1
+ import { FormProxy, GroupNodeConfig, FormSchema } from '../types';
19
2
  /**
20
3
  * Создать форму с полной конфигурацией (form, behavior, validation)
21
4
  *
@@ -43,7 +26,7 @@ import type { GroupNodeWithControls, GroupNodeConfig, FormSchema } from '../type
43
26
  * form.email.setValue('test@mail.com');
44
27
  * ```
45
28
  */
46
- export declare function createForm<T>(config: GroupNodeConfig<T>): GroupNodeWithControls<T>;
29
+ export declare function createForm<T>(config: GroupNodeConfig<T>): FormProxy<T>;
47
30
  /**
48
31
  * Создать форму только со схемой полей (обратная совместимость)
49
32
  *
@@ -58,4 +41,4 @@ export declare function createForm<T>(config: GroupNodeConfig<T>): GroupNodeWith
58
41
  * });
59
42
  * ```
60
43
  */
61
- export declare function createForm<T>(schema: FormSchema<T>): GroupNodeWithControls<T>;
44
+ export declare function createForm<T>(schema: FormSchema<T>): FormProxy<T>;
@@ -1,21 +1,4 @@
1
- /**
2
- * FormErrorHandler - централизованная обработка ошибок в формах
3
- *
4
- * Устраняет несогласованность обработки ошибок между:
5
- * - field-node.ts (логирует и конвертирует в ValidationError)
6
- * - behavior-applicator.ts (логирует и пробрасывает)
7
- * - validation-applicator.ts (логирует и проглатывает)
8
- *
9
- * @example
10
- * ```typescript
11
- * try {
12
- * await validator(value);
13
- * } catch (error) {
14
- * return FormErrorHandler.handle(error, 'AsyncValidator', ErrorStrategy.CONVERT);
15
- * }
16
- * ```
17
- */
18
- import type { ValidationError } from '../types';
1
+ import { ValidationError } from '../types';
19
2
  /**
20
3
  * Стратегия обработки ошибок
21
4
  *
@@ -1,4 +1,4 @@
1
- import type { UnknownRecord } from '../types';
1
+ import { UnknownRecord } from '../types';
2
2
  /**
3
3
  * Сегмент пути к полю формы
4
4
  *
@@ -1,12 +1,4 @@
1
- /**
2
- * FieldPath proxy - типобезопасный доступ к путям полей формы
3
- *
4
- * Единый модуль для validation и behavior схем.
5
- * Предоставляет типизированную навигацию по структуре формы.
6
- *
7
- * @module utils/field-path
8
- */
9
- import type { FieldPath, FieldPathNode } from '../types';
1
+ import { FieldPath, FieldPathNode } from '../types';
10
2
  /**
11
3
  * Создать FieldPath proxy для формы
12
4
  *
@@ -19,7 +11,17 @@ import type { FieldPath, FieldPathNode } from '../types';
19
11
  */
20
12
  export declare function createFieldPath<T>(): FieldPath<T>;
21
13
  /**
22
- * Извлечь путь из FieldPathNode
14
+ * Извлечь строковый путь из {@link FieldPathNode}.
15
+ *
16
+ * @param node - Узел `FieldPathNode` либо строка-путь.
17
+ * @returns Путь вида `"a.b.c"`.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { extractPath } from '@reformer/core';
22
+ *
23
+ * const path = (renderPath) => extractPath(renderPath.user.email); // → 'user.email'
24
+ * ```
23
25
  */
24
26
  export declare function extractPath(node: FieldPathNode<unknown, unknown> | unknown): string;
25
27
  /**
@@ -43,6 +45,16 @@ export declare function extractPath(node: FieldPathNode<unknown, unknown> | unkn
43
45
  */
44
46
  export declare function toFieldPath<T>(node: FieldPathNode<unknown, T, never> | FieldPathNode<any, T, any>): FieldPath<T>;
45
47
  /**
46
- * Извлечь ключ поля из FieldPathNode
48
+ * Извлечь имя последнего сегмента ({@link FieldPathSegment}) пути.
49
+ *
50
+ * @param node - Узел `FieldPathNode` либо строка-путь.
51
+ * @returns Имя поля без префикса родителя (последний сегмент).
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * import { extractKey } from '@reformer/core';
56
+ *
57
+ * extractKey(path.user.email); // → 'email'
58
+ * ```
47
59
  */
48
60
  export declare function extractKey(node: FieldPathNode<unknown, unknown> | unknown): string;
@@ -0,0 +1,176 @@
1
+ import { FormFields, FormValue, FieldStatus, ValidationError } from '../types';
2
+ /**
3
+ * Тип события изменения в форме
4
+ */
5
+ export type FormChangeType = 'value' | 'status' | 'errors' | 'touched' | 'dirty';
6
+ /**
7
+ * Событие изменения в форме
8
+ */
9
+ export interface FormChangeEvent {
10
+ /** Тип изменения */
11
+ type: FormChangeType;
12
+ /** Путь к полю */
13
+ path: string;
14
+ /** Timestamp события */
15
+ timestamp: number;
16
+ /** Старое значение */
17
+ oldValue?: unknown;
18
+ /** Новое значение */
19
+ newValue: unknown;
20
+ }
21
+ /**
22
+ * Интерфейс узла формы для observer
23
+ */
24
+ export interface ObservableFormNode {
25
+ value: {
26
+ value: FormValue;
27
+ };
28
+ status: {
29
+ value: FieldStatus;
30
+ };
31
+ errors: {
32
+ value: ValidationError[];
33
+ };
34
+ touched: {
35
+ value: boolean;
36
+ };
37
+ dirty: {
38
+ value: boolean;
39
+ };
40
+ }
41
+ /**
42
+ * Интерфейс формы для observer
43
+ */
44
+ export interface ObservableForm<T extends FormFields> {
45
+ value: {
46
+ value: T;
47
+ };
48
+ status: {
49
+ value: FieldStatus;
50
+ };
51
+ errors: {
52
+ value: ValidationError[];
53
+ };
54
+ touched: {
55
+ value: boolean;
56
+ };
57
+ dirty: {
58
+ value: boolean;
59
+ };
60
+ getFieldByPath(path: string): ObservableFormNode | undefined;
61
+ }
62
+ /**
63
+ * Callback для обработки событий изменения
64
+ */
65
+ export type FormChangeCallback = (event: FormChangeEvent) => void;
66
+ /**
67
+ * Опции для FormObserver
68
+ */
69
+ export interface FormObserverOptions {
70
+ /** Включить логирование в консоль (по умолчанию true в DEV) */
71
+ enableLogging?: boolean;
72
+ /** Фильтр типов событий */
73
+ eventTypes?: FormChangeType[];
74
+ /** Фильтр путей полей (regex или массив) */
75
+ pathFilter?: RegExp | string[];
76
+ }
77
+ /**
78
+ * FormObserver - мониторинг изменений в форме
79
+ *
80
+ * Полезен для:
81
+ * - Отладки сложных форм
82
+ * - Логирования изменений для аудита
83
+ * - Синхронизации с внешними системами
84
+ *
85
+ * @example
86
+ * ```typescript
87
+ * const observer = new FormObserver(form, {
88
+ * enableLogging: true,
89
+ * eventTypes: ['value', 'errors']
90
+ * });
91
+ *
92
+ * // Подписка на события
93
+ * const unsubscribe = observer.subscribe((event) => {
94
+ * console.log(`${event.type} at ${event.path}:`, event.newValue);
95
+ * });
96
+ *
97
+ * // Включить трассировку
98
+ * const disposeTracing = observer.enableTracing();
99
+ *
100
+ * // Cleanup
101
+ * unsubscribe();
102
+ * disposeTracing();
103
+ * ```
104
+ */
105
+ export declare class FormObserver<T extends FormFields> {
106
+ private readonly form;
107
+ private listeners;
108
+ private disposers;
109
+ private options;
110
+ /**
111
+ * @param form - Форма для наблюдения
112
+ * @param options - Опции observer
113
+ */
114
+ constructor(form: ObservableForm<T>, options?: FormObserverOptions);
115
+ /**
116
+ * Подписаться на события изменения
117
+ *
118
+ * @param callback - Функция обработки события
119
+ * @returns Функция отписки
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const unsubscribe = observer.subscribe((event) => {
124
+ * // Отправить событие в analytics
125
+ * analytics.track('form_change', event);
126
+ * });
127
+ * ```
128
+ */
129
+ subscribe(callback: FormChangeCallback): () => void;
130
+ /**
131
+ * Включить трассировку формы
132
+ *
133
+ * Подписывается на изменения основных сигналов формы
134
+ * и вызывает listeners при каждом изменении
135
+ *
136
+ * @returns Функция для отключения трассировки
137
+ *
138
+ * @example
139
+ * ```typescript
140
+ * const dispose = observer.enableTracing();
141
+ *
142
+ * // Позже, для отключения
143
+ * dispose();
144
+ * ```
145
+ */
146
+ enableTracing(): () => void;
147
+ /**
148
+ * Наблюдать за конкретным полем
149
+ *
150
+ * @param path - Путь к полю
151
+ * @returns Функция для отключения наблюдения
152
+ *
153
+ * @example
154
+ * ```typescript
155
+ * // Наблюдать за полем email
156
+ * const dispose = observer.watchField('email');
157
+ * ```
158
+ */
159
+ watchField(path: string): () => void;
160
+ /**
161
+ * Отправить событие всем listeners
162
+ */
163
+ private emit;
164
+ /**
165
+ * Проверить, нужно ли отслеживать тип события
166
+ */
167
+ private shouldTrack;
168
+ /**
169
+ * Проверить, соответствует ли путь фильтру
170
+ */
171
+ private matchesPathFilter;
172
+ /**
173
+ * Очистить все подписки и disposers
174
+ */
175
+ dispose(): void;
176
+ }