@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.
Files changed (147) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +143 -0
  3. package/dist/behaviors/compute-from.d.ts +2 -0
  4. package/dist/behaviors/compute-from.js +31 -0
  5. package/dist/behaviors/copy-from.d.ts +2 -0
  6. package/dist/behaviors/copy-from.js +29 -0
  7. package/dist/behaviors/enable-when.d.ts +2 -0
  8. package/dist/behaviors/enable-when.js +25 -0
  9. package/dist/behaviors/reset-when.d.ts +2 -0
  10. package/dist/behaviors/reset-when.js +24 -0
  11. package/dist/behaviors/revalidate-when.d.ts +2 -0
  12. package/dist/behaviors/revalidate-when.js +18 -0
  13. package/dist/behaviors/sync-fields.d.ts +2 -0
  14. package/dist/behaviors/sync-fields.js +41 -0
  15. package/dist/behaviors/transform-value.d.ts +2 -0
  16. package/dist/behaviors/transform-value.js +45 -0
  17. package/dist/behaviors/watch-field.d.ts +2 -0
  18. package/dist/behaviors/watch-field.js +21 -0
  19. package/dist/behaviors.d.ts +6 -0
  20. package/dist/behaviors.js +29 -0
  21. package/dist/core/behavior/behavior-context.d.ts +47 -0
  22. package/dist/core/behavior/behavior-registry.d.ts +85 -0
  23. package/dist/core/behavior/behaviors/compute-from.d.ts +70 -0
  24. package/dist/core/behavior/behaviors/copy-from.d.ts +56 -0
  25. package/dist/core/behavior/behaviors/enable-when.d.ts +118 -0
  26. package/dist/core/behavior/behaviors/index.d.ts +11 -0
  27. package/dist/core/behavior/behaviors/reset-when.d.ts +64 -0
  28. package/dist/core/behavior/behaviors/revalidate-when.d.ts +53 -0
  29. package/dist/core/behavior/behaviors/sync-fields.d.ts +48 -0
  30. package/dist/core/behavior/behaviors/transform-value.d.ts +192 -0
  31. package/dist/core/behavior/behaviors/watch-field.d.ts +80 -0
  32. package/dist/core/behavior/compose-behavior.d.ts +96 -0
  33. package/dist/core/behavior/index.d.ts +11 -0
  34. package/dist/core/behavior/types.d.ts +146 -0
  35. package/dist/core/factories/index.d.ts +6 -0
  36. package/dist/core/factories/node-factory.d.ts +186 -0
  37. package/dist/core/nodes/array-node.d.ts +328 -0
  38. package/dist/core/nodes/field-node.d.ts +294 -0
  39. package/dist/core/nodes/form-node.d.ts +340 -0
  40. package/dist/core/nodes/group-node.d.ts +319 -0
  41. package/dist/core/types/deep-schema.d.ts +68 -0
  42. package/dist/core/types/field-path.d.ts +42 -0
  43. package/dist/core/types/form-context.d.ts +89 -0
  44. package/dist/core/types/form-proxy.d.ts +105 -0
  45. package/dist/core/types/index.d.ts +209 -0
  46. package/dist/core/types/validation-schema.d.ts +95 -0
  47. package/dist/core/utils/abstract-registry.d.ts +74 -0
  48. package/dist/core/utils/aggregate-signals.d.ts +71 -0
  49. package/dist/core/utils/create-form.d.ts +44 -0
  50. package/dist/core/utils/error-handler.d.ts +163 -0
  51. package/dist/core/utils/field-path-navigator.d.ts +240 -0
  52. package/dist/core/utils/field-path.d.ts +60 -0
  53. package/dist/core/utils/form-observer.d.ts +176 -0
  54. package/dist/core/utils/form-proxy-builder.d.ts +25 -0
  55. package/dist/core/utils/form-submitter.d.ts +121 -0
  56. package/dist/core/utils/index.d.ts +22 -0
  57. package/dist/core/utils/registry-helpers.d.ts +43 -0
  58. package/dist/core/utils/registry-stack.d.ts +69 -0
  59. package/dist/core/utils/safe-effect.d.ts +73 -0
  60. package/dist/core/utils/status-machine.d.ts +153 -0
  61. package/dist/core/utils/subscription-manager.d.ts +180 -0
  62. package/dist/core/utils/type-guards.d.ts +98 -0
  63. package/dist/core/utils/unique-id.d.ts +53 -0
  64. package/dist/core/validation/core/apply-when.d.ts +22 -0
  65. package/dist/core/validation/core/apply.d.ts +52 -0
  66. package/dist/core/validation/core/index.d.ts +8 -0
  67. package/dist/core/validation/core/validate-async.d.ts +36 -0
  68. package/dist/core/validation/core/validate-tree.d.ts +35 -0
  69. package/dist/core/validation/core/validate.d.ts +26 -0
  70. package/dist/core/validation/index.d.ts +27 -0
  71. package/dist/core/validation/validate-form.d.ts +48 -0
  72. package/dist/core/validation/validation-applicator.d.ts +70 -0
  73. package/dist/core/validation/validation-context.d.ts +86 -0
  74. package/dist/core/validation/validation-registry.d.ts +142 -0
  75. package/dist/core/validation/validators/array-validators.d.ts +53 -0
  76. package/dist/core/validation/validators/date-utils.d.ts +26 -0
  77. package/dist/core/validation/validators/email.d.ts +37 -0
  78. package/dist/core/validation/validators/future-date.d.ts +35 -0
  79. package/dist/core/validation/validators/index.d.ts +20 -0
  80. package/dist/core/validation/validators/is-date.d.ts +36 -0
  81. package/dist/core/validation/validators/max-age.d.ts +36 -0
  82. package/dist/core/validation/validators/max-date.d.ts +36 -0
  83. package/dist/core/validation/validators/max-length.d.ts +38 -0
  84. package/dist/core/validation/validators/max.d.ts +38 -0
  85. package/dist/core/validation/validators/min-age.d.ts +36 -0
  86. package/dist/core/validation/validators/min-date.d.ts +36 -0
  87. package/dist/core/validation/validators/min-length.d.ts +38 -0
  88. package/dist/core/validation/validators/min.d.ts +38 -0
  89. package/dist/core/validation/validators/number.d.ts +31 -0
  90. package/dist/core/validation/validators/past-date.d.ts +35 -0
  91. package/dist/core/validation/validators/pattern.d.ts +40 -0
  92. package/dist/core/validation/validators/phone.d.ts +27 -0
  93. package/dist/core/validation/validators/required.d.ts +41 -0
  94. package/dist/core/validation/validators/url.d.ts +22 -0
  95. package/dist/date-utils-xUWFslTj.js +29 -0
  96. package/dist/field-path-DuKdGcIE.js +66 -0
  97. package/dist/hooks/types.d.ts +328 -0
  98. package/dist/hooks/useArrayLength.d.ts +31 -0
  99. package/dist/hooks/useFormControl.d.ts +24 -0
  100. package/dist/hooks/useFormControlValue.d.ts +167 -0
  101. package/dist/hooks/useHiddenCondition.d.ts +25 -0
  102. package/dist/hooks/useSignalSubscription.d.ts +17 -0
  103. package/dist/index-D25LsbRm.js +73 -0
  104. package/dist/index.d.ts +17 -0
  105. package/dist/index.js +3271 -0
  106. package/dist/registry-helpers-Bv_BJ1s-.js +615 -0
  107. package/dist/safe-effect-Dh8uw81c.js +20 -0
  108. package/dist/validate-C3XiA_zf.js +10 -0
  109. package/dist/validators/email.d.ts +2 -0
  110. package/dist/validators/email.js +13 -0
  111. package/dist/validators/future-date.d.ts +2 -0
  112. package/dist/validators/future-date.js +20 -0
  113. package/dist/validators/is-date.d.ts +2 -0
  114. package/dist/validators/is-date.js +12 -0
  115. package/dist/validators/max-age.d.ts +2 -0
  116. package/dist/validators/max-age.js +20 -0
  117. package/dist/validators/max-date.d.ts +2 -0
  118. package/dist/validators/max-date.js +20 -0
  119. package/dist/validators/max-length.d.ts +2 -0
  120. package/dist/validators/max-length.js +11 -0
  121. package/dist/validators/max.d.ts +2 -0
  122. package/dist/validators/max.js +11 -0
  123. package/dist/validators/min-age.d.ts +2 -0
  124. package/dist/validators/min-age.js +20 -0
  125. package/dist/validators/min-date.d.ts +2 -0
  126. package/dist/validators/min-date.js +20 -0
  127. package/dist/validators/min-length.d.ts +2 -0
  128. package/dist/validators/min-length.js +11 -0
  129. package/dist/validators/min.d.ts +2 -0
  130. package/dist/validators/min.js +11 -0
  131. package/dist/validators/number.d.ts +2 -0
  132. package/dist/validators/number.js +35 -0
  133. package/dist/validators/past-date.d.ts +2 -0
  134. package/dist/validators/past-date.js +20 -0
  135. package/dist/validators/pattern.d.ts +2 -0
  136. package/dist/validators/pattern.js +11 -0
  137. package/dist/validators/phone.d.ts +2 -0
  138. package/dist/validators/phone.js +35 -0
  139. package/dist/validators/required.d.ts +2 -0
  140. package/dist/validators/required.js +15 -0
  141. package/dist/validators/url.d.ts +2 -0
  142. package/dist/validators/url.js +19 -0
  143. package/dist/validators-BGsNOgT1.js +207 -0
  144. package/dist/validators.d.ts +6 -0
  145. package/dist/validators.js +56 -0
  146. package/llms.txt +9351 -0
  147. package/package.json +166 -0
@@ -0,0 +1,68 @@
1
+ import { ComponentType } from 'react';
2
+ import { ValidatorFn, AsyncValidatorFn, FormFields, AnyFunction } from './index';
3
+ /**
4
+ * Конфигурация поля
5
+ * @group Types
6
+ * @category Configuration Types
7
+ */
8
+ export interface FieldConfig<T> {
9
+ value: T | null;
10
+ component: ComponentType<any>;
11
+ componentProps?: any;
12
+ validators?: ValidatorFn<T>[];
13
+ asyncValidators?: AsyncValidatorFn<T>[];
14
+ disabled?: boolean;
15
+ updateOn?: 'change' | 'blur' | 'submit';
16
+ /** Задержка (в мс) перед запуском асинхронной валидации */
17
+ debounce?: number;
18
+ }
19
+ /**
20
+ * Конфигурация массива
21
+ * @group Types
22
+ * @category Configuration Types
23
+ */
24
+ export interface ArrayConfig<T extends FormFields> {
25
+ itemSchema: FormSchema<T>;
26
+ initial?: Partial<T>[];
27
+ }
28
+ /**
29
+ * Автоматически определяет тип схемы на основе TypeScript типа:
30
+ * - `T[] -> [FormSchema<T>]` (массив с одним элементом)
31
+ * - `object -> FormSchema<T>` (группа)
32
+ * - `primitive -> FieldConfig<T>` (поле)
33
+ *
34
+ * Использует NonNullable для корректной обработки опциональных полей
35
+ *
36
+ * @group Types
37
+ * @category Configuration Types
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * interface Form {
42
+ * name: string; // → FieldConfig<string>
43
+ * address: { // → FormSchema<Address>
44
+ * city: string;
45
+ * street: string;
46
+ * };
47
+ * items?: Array<{ // → [FormSchema<Item>] (опциональный)
48
+ * title: string;
49
+ * price: number;
50
+ * }>;
51
+ * }
52
+ *
53
+ * const schema: FormSchema<Form> = {
54
+ * name: { value: '', component: Input },
55
+ * address: {
56
+ * city: { value: '', component: Input },
57
+ * street: { value: '', component: Input },
58
+ * },
59
+ * items: [{
60
+ * title: { value: '', component: Input },
61
+ * price: { value: 0, component: Input },
62
+ * }],
63
+ * };
64
+ * ```
65
+ */
66
+ export type FormSchema<T> = {
67
+ [K in keyof T]: NonNullable<T[K]> extends string | number | boolean ? FieldConfig<T[K]> : NonNullable<T[K]> extends Array<infer U> ? U extends string | number | boolean ? FieldConfig<T[K]> : U extends Date | File | Blob | AnyFunction ? FieldConfig<T[K]> : [FormSchema<U>] : NonNullable<T[K]> extends Date | File | Blob | AnyFunction ? FieldConfig<T[K]> : FormSchema<NonNullable<T[K]>>;
68
+ };
@@ -0,0 +1,42 @@
1
+ import { AnyFunction } from './index';
2
+ /**
3
+ * FieldPath предоставляет типобезопасный доступ к путям полей формы
4
+ *
5
+ * Рекурсивно обрабатывает вложенные объекты для поддержки вложенных форм.
6
+ *
7
+ * Использование:
8
+ * ```typescript
9
+ * const validation = (path: FieldPath<MyForm>) => {
10
+ * required(path.email, { message: 'Email обязателен' });
11
+ *
12
+ * // Вложенные объекты
13
+ * required(path.registrationAddress.city);
14
+ * minLength(path.registrationAddress.street, 3);
15
+ *
16
+ * applyWhen(
17
+ * path.loanType,
18
+ * (type) => type === 'mortgage',
19
+ * (path) => {
20
+ * required(path.propertyValue, { message: 'Укажите стоимость' });
21
+ * }
22
+ * );
23
+ * };
24
+ * ```
25
+ */
26
+ export type FieldPath<T> = {
27
+ [K in keyof T]: NonNullable<T[K]> extends Array<unknown> ? FieldPathNode<T, T[K], K> : NonNullable<T[K]> extends Date | File | Blob | AnyFunction ? FieldPathNode<T, T[K], K> : NonNullable<T[K]> extends object ? FieldPathNode<T, T[K], K> & FieldPath<NonNullable<T[K]>> : FieldPathNode<T, T[K], K>;
28
+ };
29
+ /**
30
+ * Узел в пути поля
31
+ * Содержит метаинформацию о поле для валидации
32
+ */
33
+ export interface FieldPathNode<TForm, TField, TKey = unknown> {
34
+ /** Ключ поля */
35
+ readonly __key: TKey;
36
+ /** Путь к полю (для вложенных объектов) */
37
+ readonly __path: string;
38
+ /** Тип формы */
39
+ readonly __formType?: TForm;
40
+ /** Тип поля */
41
+ readonly __fieldType?: TField;
42
+ }
@@ -0,0 +1,89 @@
1
+ import { FormProxy } from './form-proxy';
2
+ import { FieldPathNode } from './field-path';
3
+ import { FormNode } from '../nodes/form-node';
4
+ import { FormValue } from './index';
5
+ /**
6
+ * Единый контекст для работы с формой
7
+ *
8
+ * Предоставляет:
9
+ * - `form` - типизированный Proxy-доступ к полям формы
10
+ * - `setFieldValue` - безопасная установка значения (emitEvent: false)
11
+ */
12
+ export interface FormContext<TForm> {
13
+ /**
14
+ * Форма с типизированным Proxy-доступом к полям
15
+ *
16
+ * Позволяет обращаться к полям напрямую через точечную нотацию:
17
+ * - `ctx.form.email` → FieldNode
18
+ * - `ctx.form.address.city` → FieldNode (вложенный)
19
+ * - `ctx.form.items` → ArrayNode
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // Получить значение
24
+ * ctx.form.email.value.value
25
+ *
26
+ * // Установить значение (⚠️ может вызвать цикл в behavior!)
27
+ * ctx.form.email.setValue('new@mail.com')
28
+ *
29
+ * // Безопасно установить значение
30
+ * ctx.form.email.setValue('new@mail.com', { emitEvent: false })
31
+ *
32
+ * // Обновить пропсы компонента
33
+ * ctx.form.city.updateComponentProps({ options: cities })
34
+ *
35
+ * // Валидация поля
36
+ * await ctx.form.email.validate()
37
+ *
38
+ * // Работа с массивами
39
+ * ctx.form.items.push({ title: 'New' })
40
+ * ctx.form.items.clear()
41
+ * ```
42
+ */
43
+ readonly form: FormProxy<TForm>;
44
+ /**
45
+ * Безопасно установить значение поля по строковому пути или FieldPath
46
+ *
47
+ * Автоматически использует `emitEvent: false` для предотвращения
48
+ * бесконечных циклов в behavior схемах.
49
+ *
50
+ * @param path - Путь к полю (строка или FieldPath)
51
+ * @param value - Новое значение
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * // Сброс города при смене страны (строковый путь)
56
+ * watchField(path.country, (country, ctx) => {
57
+ * ctx.setFieldValue('city', null);
58
+ * });
59
+ *
60
+ * // Использование FieldPath напрямую (более типобезопасно)
61
+ * watchField(path.country, (country, ctx) => {
62
+ * ctx.setFieldValue(path.city, null);
63
+ * });
64
+ * ```
65
+ */
66
+ setFieldValue(path: string | FieldPathNode<TForm, unknown>, value: unknown): void;
67
+ /**
68
+ * Получить поле формы по строковому пути
69
+ *
70
+ * Используется для динамического доступа к вложенным полям,
71
+ * особенно в модульных behavior схемах, применяемых через apply().
72
+ *
73
+ * @param path - Строковый путь к полю (например "address.city")
74
+ * @returns FormNode или undefined если поле не найдено
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * // В модульной behavior схеме, применяемой к вложенному полю:
79
+ * // apply([path.registrationAddress, path.residenceAddress], addressBehavior)
80
+ *
81
+ * watchField(path.region, (region, ctx) => {
82
+ * // path.city.__path = "registrationAddress.city" или "residenceAddress.city"
83
+ * const cityField = ctx.getFieldByPath(path.city.__path);
84
+ * cityField?.updateComponentProps({ options: cities });
85
+ * });
86
+ * ```
87
+ */
88
+ getFieldByPath(path: string): FormNode<FormValue> | undefined;
89
+ }
@@ -0,0 +1,105 @@
1
+ import { FormFields } from './index';
2
+ type FieldNode<_T> = any;
3
+ type GroupNode<_T> = any;
4
+ type ArrayNode<_T> = any;
5
+ /**
6
+ * Мапит тип модели данных T на правильные типы узлов формы
7
+ *
8
+ * Рекурсивно определяет типы узлов на основе структуры данных:
9
+ * - `T[K] extends Array<infer U>` где U - объект → `FormArrayProxy<U>`
10
+ * - `T[K] extends Array<infer U>` где U - примитив → `FieldNode<T[K]>` (массив как обычное поле)
11
+ * - `T[K] extends object` → `FormProxy<T[K]>` (вложенная форма с типизацией)
12
+ * - `T[K]` примитив → `FieldNode<T[K]>` (простое поле)
13
+ *
14
+ * Использует NonNullable для правильной обработки опциональных полей
15
+ *
16
+ * @group Types
17
+ * @category Proxy Types
18
+ *
19
+ * @template T - Тип модели данных формы
20
+ */
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]>;
23
+ };
24
+ /**
25
+ * Комбинированный тип для GroupNode с Proxy доступом к полям
26
+ *
27
+ * Объединяет методы и свойства GroupNode с типизированными полями формы.
28
+ * Это позволяет использовать как API GroupNode, так и прямой доступ к полям.
29
+ *
30
+ * @group Types
31
+ * @category Proxy Types
32
+ *
33
+ * @template T - Тип модели данных формы
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * interface UserForm {
38
+ * email: string;
39
+ * profile: {
40
+ * name: string;
41
+ * age: number;
42
+ * };
43
+ * }
44
+ *
45
+ * const form = createForm<UserForm>(schema);
46
+ *
47
+ * // Доступ к методам GroupNode
48
+ * await form.validate();
49
+ * const values = form.getValue();
50
+ * console.log(form.valid.value);
51
+ *
52
+ * // Прямой доступ к полям (через Proxy)
53
+ * form.email.setValue('test@mail.com');
54
+ * form.profile.name.setValue('John');
55
+ * ```
56
+ */
57
+ export type FormProxy<T> = GroupNode<T> & FormControlsProxy<T>;
58
+ /**
59
+ * Комбинированный тип для ArrayNode с Proxy доступом к элементам
60
+ *
61
+ * Объединяет методы и свойства ArrayNode с типизированным доступом к элементам массива.
62
+ *
63
+ * @group Types
64
+ * @category Proxy Types
65
+ *
66
+ * @template T - Тип модели данных элемента массива
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * interface TodoItem {
71
+ * title: string;
72
+ * completed: boolean;
73
+ * }
74
+ *
75
+ * const todos: FormArrayProxy<TodoItem> = new ArrayNode(schema);
76
+ *
77
+ * // Доступ к методам ArrayNode
78
+ * todos.push({ title: 'New todo', completed: false });
79
+ * todos.removeAt(0);
80
+ *
81
+ * // Доступ к элементам (через Proxy)
82
+ * todos.at(0)?.title.setValue('Updated title');
83
+ *
84
+ * // Итерация
85
+ * todos.forEach((item, i) => {
86
+ * console.log(item.title.value.value);
87
+ * });
88
+ * ```
89
+ */
90
+ export type FormArrayProxy<T extends FormFields> = ArrayNode<T> & {
91
+ /**
92
+ * Безопасный доступ к элементу массива по индексу
93
+ * Возвращает GroupNode с типизированными полями или undefined
94
+ */
95
+ at(index: number): FormProxy<T> | undefined;
96
+ /**
97
+ * Итерация по элементам массива с типизированными элементами
98
+ */
99
+ forEach(callback: (item: FormProxy<T>, index: number) => void): void;
100
+ /**
101
+ * Маппинг элементов массива с типизированными элементами
102
+ */
103
+ map<R>(callback: (item: FormProxy<T>, index: number) => R): R[];
104
+ };
105
+ export {};
@@ -0,0 +1,209 @@
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';
5
+ /**
6
+ * Represents any valid form value type
7
+ * Use this instead of 'any' for form values to maintain type safety
8
+ *
9
+ * @group Types
10
+ * @category Core Types
11
+ */
12
+ export type FormValue = string | number | boolean | null | undefined | Date | File | FormValue[] | {
13
+ [key: string]: FormValue;
14
+ };
15
+ /**
16
+ * Type-safe alternative to 'any' for unknown form values
17
+ * Requires explicit type checking before use
18
+ * @internal
19
+ */
20
+ export type UnknownFormValue = unknown;
21
+ /**
22
+ * Синхронная функция валидации
23
+ * @group Types
24
+ * @category Validation Types
25
+ */
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
+ }
39
+ /**
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
+ *
63
+ * @group Types
64
+ * @category Validation Types
65
+ */
66
+ export type AsyncValidatorFn<T = FormValue> = (value: T, options?: AsyncValidatorOptions) => Promise<ValidationError | null>;
67
+ /**
68
+ * Ошибка валидации
69
+ * @group Types
70
+ * @category Validation Types
71
+ */
72
+ export interface ValidationError {
73
+ code: string;
74
+ message: string;
75
+ params?: FormFields;
76
+ /** Severity level: 'error' (default) blocks submission, 'warning' shows message but allows submission */
77
+ severity?: 'error' | 'warning';
78
+ }
79
+ /**
80
+ * Опции для фильтрации ошибок в методе getErrors()
81
+ * @group Types
82
+ * @category Validation Types
83
+ */
84
+ export interface ErrorFilterOptions {
85
+ /** Фильтр по коду ошибки */
86
+ code?: string | string[];
87
+ /** Фильтр по сообщению (поддерживает частичное совпадение) */
88
+ message?: string;
89
+ /** Фильтр по параметрам ошибки */
90
+ params?: FormFields;
91
+ /** Кастомный предикат для фильтрации */
92
+ predicate?: (error: ValidationError) => boolean;
93
+ }
94
+ /**
95
+ * Статус поля формы
96
+ * @group Types
97
+ * @category Core Types
98
+ */
99
+ export type FieldStatus = 'valid' | 'invalid' | 'pending' | 'disabled';
100
+ export type { FieldConfig } from './deep-schema';
101
+ export type { FieldPath, FieldPathNode } from '../types/field-path';
102
+ export type { ContextualValidatorFn, ContextualAsyncValidatorFn, TreeValidatorFn, ConditionFn, ValidateOptions, ValidateAsyncOptions, ValidateTreeOptions, ValidationSchemaFn, ValidatorRegistration, } from './validation-schema';
103
+ export type { FormSchema, ArrayConfig } from './deep-schema';
104
+ export type { FormContext } from './form-context';
105
+ export type { FormControlsProxy, FormProxy, FormArrayProxy } from './form-proxy';
106
+ /**
107
+ * Конфигурация GroupNode с поддержкой схем
108
+ * Используется для создания форм с автоматическим применением behavior и validation схем
109
+ *
110
+ * @group Types
111
+ * @category Configuration Types
112
+ */
113
+ export interface GroupNodeConfig<T> {
114
+ /** Схема структуры формы (поля и их конфигурация) */
115
+ form: FormSchema<T>;
116
+ /** Схема реактивного поведения (copyFrom, enableWhen, computeFrom и т.д.) */
117
+ behavior?: BehaviorSchemaFn<T>;
118
+ /** Схема валидации (required, email, minLength и т.д.) */
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;
132
+ }
133
+ /**
134
+ * Тип для Record с unknown значениями
135
+ * Используется вместо инлайнового `Record<string, unknown>`
136
+ * @internal
137
+ */
138
+ export type UnknownRecord = Record<string, any>;
139
+ /**
140
+ * Интерфейс для узлов с методом applyValidationSchema
141
+ * @internal
142
+ */
143
+ export interface WithValidationSchema {
144
+ applyValidationSchema(schemaFn: unknown): void;
145
+ }
146
+ /**
147
+ * Интерфейс для узлов с методом applyBehaviorSchema
148
+ * @internal
149
+ */
150
+ export interface WithBehaviorSchema {
151
+ applyBehaviorSchema(schemaFn: unknown): void;
152
+ }
153
+ /**
154
+ * Интерфейс для узлов, похожих на ArrayNode (с методом at)
155
+ * Используется для duck typing при обходе путей
156
+ * @internal
157
+ */
158
+ export interface ArrayNodeLike {
159
+ at(index: number): FormNode<unknown> | undefined;
160
+ length: unknown;
161
+ }
162
+ /**
163
+ * Конфиг с полем schema (для ArrayConfig)
164
+ * @internal
165
+ */
166
+ export interface ConfigWithSchema {
167
+ schema: unknown;
168
+ initialItems?: unknown[];
169
+ }
170
+ /**
171
+ * Конфиг с полем value (для извлечения значений)
172
+ * @internal
173
+ */
174
+ export interface ConfigWithValue {
175
+ value: unknown;
176
+ }
177
+ /**
178
+ * Тип для конфига с полями (FormSchema generic constraint)
179
+ * Используется вместо `Record<string, any>` для схем форм
180
+ * @deprecated
181
+ * @internal
182
+ */
183
+ export type FormFields = Record<string, FormValue>;
184
+ /**
185
+ * Тип для путей к полям (field paths)
186
+ * Используется в навигации по полям вместо any
187
+ * @internal
188
+ */
189
+ export type FieldPathSegment = {
190
+ key: string;
191
+ index?: number;
192
+ };
193
+ /**
194
+ * Тип для коллбэков и обработчиков событий
195
+ * Используется вместо (...args: any[]) => any
196
+ * @internal
197
+ */
198
+ export type UnknownCallback = (...args: unknown[]) => unknown;
199
+ /**
200
+ * Тип для проверки на функцию в conditional types
201
+ * Используется вместо Function для type narrowing
202
+ * @internal
203
+ */
204
+ export type AnyFunction = (...args: never[]) => unknown;
205
+ /**
206
+ * Тип для результатов загрузки ресурсов
207
+ * @internal
208
+ */
209
+ export type ResourceLoadResult = unknown;
@@ -0,0 +1,95 @@
1
+ import { FormFields, ValidationError } from './index';
2
+ import { FieldPath } from './field-path';
3
+ import { FormContext } from './form-context';
4
+ /**
5
+ * Функция валидации поля с контекстом
6
+ *
7
+ * Новый паттерн: (value, ctx: FormContext) => ValidationError | null
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * validate(path.email, (value, ctx) => {
12
+ * if (!value) return { code: 'required', message: 'Email required' };
13
+ * const confirm = ctx.form.confirmEmail.value.value;
14
+ * if (value !== confirm) return { code: 'mismatch', message: 'Must match' };
15
+ * return null;
16
+ * });
17
+ * ```
18
+ */
19
+ export type ContextualValidatorFn<TForm, TField> = (value: TField, ctx: FormContext<TForm>) => ValidationError | null;
20
+ /**
21
+ * Асинхронная функция валидации поля с контекстом
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * validateAsync(path.email, async (value, ctx) => {
26
+ * const exists = await checkEmailExists(value);
27
+ * if (exists) return { code: 'exists', message: 'Email already taken' };
28
+ * return null;
29
+ * });
30
+ * ```
31
+ */
32
+ export type ContextualAsyncValidatorFn<TForm, TField> = (value: TField, ctx: FormContext<TForm>) => Promise<ValidationError | null>;
33
+ /**
34
+ * Функция cross-field валидации
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * validateTree((ctx) => {
39
+ * const password = ctx.form.password.value.value;
40
+ * const confirm = ctx.form.confirmPassword.value.value;
41
+ * if (password !== confirm) {
42
+ * return { code: 'mismatch', message: 'Passwords must match' };
43
+ * }
44
+ * return null;
45
+ * });
46
+ * ```
47
+ */
48
+ export type TreeValidatorFn<TForm> = (ctx: FormContext<TForm>) => ValidationError | null;
49
+ /**
50
+ * Функция условия для applyWhen
51
+ */
52
+ export type ConditionFn<T> = (value: T) => boolean;
53
+ /**
54
+ * Опции для функции validate
55
+ */
56
+ export interface ValidateOptions {
57
+ /** Сообщение об ошибке */
58
+ message?: string;
59
+ /** Параметры ошибки */
60
+ params?: FormFields;
61
+ }
62
+ /**
63
+ * Опции для функции validateAsync
64
+ */
65
+ export interface ValidateAsyncOptions extends ValidateOptions {
66
+ /** Задержка перед выполнением валидации (в мс) */
67
+ debounce?: number;
68
+ }
69
+ /**
70
+ * Опции для функции validateTree
71
+ */
72
+ export interface ValidateTreeOptions {
73
+ /** Поле, к которому привязать ошибку */
74
+ targetField?: string;
75
+ }
76
+ /**
77
+ * Функция validation schema
78
+ *
79
+ * Принимает FieldPath и определяет все правила валидации для формы
80
+ */
81
+ export type ValidationSchemaFn<T> = (path: FieldPath<T>) => void;
82
+ /**
83
+ * Регистрация валидатора в системе
84
+ * @internal
85
+ */
86
+ export interface ValidatorRegistration {
87
+ fieldPath: string;
88
+ type: 'sync' | 'async' | 'tree';
89
+ validator: ContextualValidatorFn<unknown, unknown> | ContextualAsyncValidatorFn<unknown, unknown> | TreeValidatorFn<unknown>;
90
+ options?: ValidateOptions | ValidateAsyncOptions | ValidateTreeOptions;
91
+ condition?: {
92
+ fieldPath: string;
93
+ conditionFn: ConditionFn<unknown>;
94
+ };
95
+ }
@@ -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
+ }