@reformer/core 1.1.0-beta.7 → 1.1.0-beta.8

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 (80) hide show
  1. package/dist/behaviors-BRaiR-UY.js +528 -0
  2. package/dist/behaviors.d.ts +6 -2
  3. package/dist/behaviors.js +18 -227
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +3380 -10
  6. package/dist/validators-DjXtDVoE.js +455 -0
  7. package/dist/validators.d.ts +6 -2
  8. package/dist/validators.js +29 -281
  9. package/package.json +1 -1
  10. package/dist/core/behavior/behavior-applicator.js +0 -92
  11. package/dist/core/behavior/behavior-context.js +0 -43
  12. package/dist/core/behavior/behavior-registry.js +0 -198
  13. package/dist/core/behavior/behaviors/compute-from.js +0 -84
  14. package/dist/core/behavior/behaviors/copy-from.js +0 -64
  15. package/dist/core/behavior/behaviors/enable-when.js +0 -81
  16. package/dist/core/behavior/behaviors/index.js +0 -11
  17. package/dist/core/behavior/behaviors/reset-when.js +0 -63
  18. package/dist/core/behavior/behaviors/revalidate-when.js +0 -51
  19. package/dist/core/behavior/behaviors/sync-fields.js +0 -66
  20. package/dist/core/behavior/behaviors/transform-value.js +0 -110
  21. package/dist/core/behavior/behaviors/watch-field.js +0 -56
  22. package/dist/core/behavior/compose-behavior.js +0 -166
  23. package/dist/core/behavior/create-field-path.js +0 -69
  24. package/dist/core/behavior/index.js +0 -17
  25. package/dist/core/behavior/types.js +0 -7
  26. package/dist/core/context/form-context-impl.js +0 -37
  27. package/dist/core/factories/index.js +0 -6
  28. package/dist/core/factories/node-factory.js +0 -281
  29. package/dist/core/nodes/array-node.js +0 -534
  30. package/dist/core/nodes/field-node.js +0 -510
  31. package/dist/core/nodes/form-node.js +0 -343
  32. package/dist/core/nodes/group-node/field-registry.js +0 -215
  33. package/dist/core/nodes/group-node/index.js +0 -11
  34. package/dist/core/nodes/group-node/proxy-builder.js +0 -161
  35. package/dist/core/nodes/group-node/state-manager.js +0 -265
  36. package/dist/core/nodes/group-node.js +0 -770
  37. package/dist/core/types/deep-schema.js +0 -11
  38. package/dist/core/types/field-path.js +0 -4
  39. package/dist/core/types/form-context.js +0 -25
  40. package/dist/core/types/group-node-proxy.js +0 -31
  41. package/dist/core/types/index.js +0 -4
  42. package/dist/core/types/validation-schema.js +0 -10
  43. package/dist/core/utils/create-form.js +0 -24
  44. package/dist/core/utils/debounce.js +0 -197
  45. package/dist/core/utils/error-handler.js +0 -226
  46. package/dist/core/utils/field-path-navigator.js +0 -374
  47. package/dist/core/utils/index.js +0 -14
  48. package/dist/core/utils/registry-helpers.js +0 -79
  49. package/dist/core/utils/registry-stack.js +0 -86
  50. package/dist/core/utils/resources.js +0 -69
  51. package/dist/core/utils/subscription-manager.js +0 -214
  52. package/dist/core/utils/type-guards.js +0 -169
  53. package/dist/core/validation/core/apply-when.js +0 -41
  54. package/dist/core/validation/core/apply.js +0 -38
  55. package/dist/core/validation/core/index.js +0 -8
  56. package/dist/core/validation/core/validate-async.js +0 -45
  57. package/dist/core/validation/core/validate-tree.js +0 -43
  58. package/dist/core/validation/core/validate.js +0 -38
  59. package/dist/core/validation/field-path.js +0 -147
  60. package/dist/core/validation/index.js +0 -33
  61. package/dist/core/validation/validate-form.js +0 -152
  62. package/dist/core/validation/validation-applicator.js +0 -217
  63. package/dist/core/validation/validation-context.js +0 -75
  64. package/dist/core/validation/validation-registry.js +0 -298
  65. package/dist/core/validation/validators/array-validators.js +0 -86
  66. package/dist/core/validation/validators/date.js +0 -117
  67. package/dist/core/validation/validators/email.js +0 -60
  68. package/dist/core/validation/validators/index.js +0 -14
  69. package/dist/core/validation/validators/max-length.js +0 -60
  70. package/dist/core/validation/validators/max.js +0 -60
  71. package/dist/core/validation/validators/min-length.js +0 -60
  72. package/dist/core/validation/validators/min.js +0 -60
  73. package/dist/core/validation/validators/number.js +0 -90
  74. package/dist/core/validation/validators/pattern.js +0 -62
  75. package/dist/core/validation/validators/phone.js +0 -58
  76. package/dist/core/validation/validators/required.js +0 -69
  77. package/dist/core/validation/validators/url.js +0 -55
  78. package/dist/create-field-path-nXfTtl55.js +0 -283
  79. package/dist/hooks/useFormControl.js +0 -298
  80. package/dist/validation-context-cWXmh_Ho.js +0 -156
@@ -1,161 +0,0 @@
1
- /**
2
- * ProxyBuilder - создание Proxy для типобезопасного доступа к полям GroupNode
3
- *
4
- * Извлечено из GroupNode для соблюдения SRP (Single Responsibility Principle).
5
- * Отвечает только за создание Proxy с расширенной поддержкой операций.
6
- *
7
- * @template T Тип формы (объект)
8
- *
9
- * @example
10
- * ```typescript
11
- * const fieldRegistry = new FieldRegistry<FormType>();
12
- * const proxyBuilder = new ProxyBuilder(fieldRegistry);
13
- * const proxy = proxyBuilder.build(groupNode);
14
- *
15
- * // Теперь можно обращаться к полям напрямую:
16
- * console.log(proxy.email.value);
17
- * console.log('email' in proxy); // true
18
- * ```
19
- */
20
- /**
21
- * Строитель Proxy для GroupNode
22
- *
23
- * Создает Proxy с поддержкой:
24
- * - get: Прямой доступ к полям через точечную нотацию
25
- * - set: Предупреждение о попытке прямой установки полей
26
- * - has: Проверка существования поля ('email' in form)
27
- * - ownKeys: Перечисление всех ключей (Object.keys(form))
28
- * - getOwnPropertyDescriptor: Получение дескрипторов полей
29
- *
30
- * @template T Тип формы (объект)
31
- */
32
- export class ProxyBuilder {
33
- fieldRegistry;
34
- /**
35
- * @param fieldRegistry - Реестр полей для доступа к коллекции
36
- */
37
- constructor(fieldRegistry) {
38
- this.fieldRegistry = fieldRegistry;
39
- }
40
- /**
41
- * Создать Proxy для GroupNode
42
- *
43
- * Proxy позволяет обращаться к полям формы напрямую:
44
- * - form.email вместо form.fields.get('email')
45
- * - form.address.city вместо form.fields.get('address').fields.get('city')
46
- *
47
- * @param target - GroupNode для которого создается Proxy
48
- * @returns Proxy с типобезопасным доступом к полям
49
- *
50
- * @example
51
- * ```typescript
52
- * const proxy = proxyBuilder.build(groupNode);
53
- *
54
- * // Доступ к полям
55
- * console.log(proxy.email.value); // Работает!
56
- * console.log(proxy.name.value); // Работает!
57
- *
58
- * // Доступ к методам GroupNode
59
- * await proxy.validate(); // Работает!
60
- * proxy.markAsTouched(); // Работает!
61
- *
62
- * // Проверка существования
63
- * if ('email' in proxy) { ... }
64
- *
65
- * // Перечисление ключей
66
- * Object.keys(proxy); // ['email', 'name', ...]
67
- * ```
68
- */
69
- build(target) {
70
- return new Proxy(target, {
71
- /**
72
- * Get trap: Перехват доступа к свойствам
73
- *
74
- * Приоритет:
75
- * 1. Собственные свойства и методы GroupNode (validate, setValue и т.д.)
76
- * 2. Поля формы из fieldRegistry
77
- * 3. undefined для несуществующих свойств
78
- */
79
- get: (target, prop) => {
80
- // Приоритет 1: Собственные свойства и методы GroupNode
81
- // Это важно, чтобы методы validate(), setValue() и т.д. работали корректно
82
- if (prop in target) {
83
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
- return target[prop];
85
- }
86
- // Приоритет 2: Поля формы
87
- // Используем fieldRegistry для типобезопасного доступа
88
- if (typeof prop === 'string' && this.fieldRegistry.has(prop)) {
89
- return this.fieldRegistry.get(prop);
90
- }
91
- // Fallback для несуществующих свойств
92
- return undefined;
93
- },
94
- /**
95
- * Set trap: Перехват установки свойств
96
- *
97
- * Запрещает прямую установку значений полей через form.email = value
98
- * Пользователь должен использовать form.email.setValue(value) или form.setValue({...})
99
- */
100
- set: (target, prop, value) => {
101
- // Запретить прямое изменение полей
102
- if (typeof prop === 'string' && this.fieldRegistry.has(prop)) {
103
- if (import.meta.env.DEV) {
104
- console.warn(`[GroupNode] Cannot set field "${prop}" directly. Use .setValue() or .patchValue() instead.\n` +
105
- `Example: form.setValue({ ${prop}: ${JSON.stringify(value)} })`);
106
- }
107
- return false;
108
- }
109
- // Разрешить установку других свойств
110
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
111
- target[prop] = value;
112
- return true;
113
- },
114
- /**
115
- * Has trap: Перехват оператора 'in'
116
- *
117
- * Позволяет проверять существование полей:
118
- * if ('email' in form) { ... }
119
- */
120
- has: (target, prop) => {
121
- // Проверяем наличие в полях
122
- if (typeof prop === 'string' && this.fieldRegistry.has(prop)) {
123
- return true;
124
- }
125
- // Проверяем наличие в самом объекте
126
- return prop in target;
127
- },
128
- /**
129
- * OwnKeys trap: Перехват Object.keys() / Object.getOwnPropertyNames()
130
- *
131
- * Возвращает объединенный список:
132
- * - Ключей самого GroupNode
133
- * - Ключей полей из fieldRegistry
134
- */
135
- ownKeys: (target) => {
136
- const nodeKeys = Reflect.ownKeys(target);
137
- const fieldKeys = Array.from(this.fieldRegistry.keys());
138
- // Используем Set для удаления дубликатов
139
- return [...new Set([...nodeKeys, ...fieldKeys])];
140
- },
141
- /**
142
- * GetOwnPropertyDescriptor trap: Перехват Object.getOwnPropertyDescriptor()
143
- *
144
- * Возвращает дескриптор свойства для полей и свойств GroupNode
145
- * Важно для корректной работы Object.keys() и других рефлексивных операций
146
- */
147
- getOwnPropertyDescriptor: (target, prop) => {
148
- // Дескриптор для полей формы
149
- if (typeof prop === 'string' && this.fieldRegistry.has(prop)) {
150
- return {
151
- enumerable: true, // Поле должно быть перечисляемым
152
- configurable: true, // Поле может быть удалено
153
- // Не указываем writable, т.к. это accessor property через get/set traps
154
- };
155
- }
156
- // Дескриптор для свойств самого объекта
157
- return Reflect.getOwnPropertyDescriptor(target, prop);
158
- },
159
- });
160
- }
161
- }
@@ -1,265 +0,0 @@
1
- /**
2
- * StateManager - управление состоянием GroupNode
3
- *
4
- * Инкапсулирует всю логику создания и управления сигналами состояния:
5
- * - Приватные сигналы (submitting, disabled, formErrors)
6
- * - Публичные computed signals (value, valid, invalid, touched, dirty, pending, errors, status, submitting)
7
- *
8
- * Извлечено из GroupNode для соблюдения SRP (Single Responsibility Principle).
9
- * Отвечает только за логику управления состоянием формы.
10
- *
11
- * @template T Тип формы (объект)
12
- *
13
- * @example
14
- * ```typescript
15
- * class GroupNode {
16
- * private stateManager: StateManager<T>;
17
- *
18
- * constructor(schema: FormSchema<T>) {
19
- * this.fieldRegistry = new FieldRegistry<T>();
20
- * // ... создание полей ...
21
- * this.stateManager = new StateManager(this.fieldRegistry);
22
- *
23
- * // Доступ к computed signals
24
- * this.value = this.stateManager.value;
25
- * this.valid = this.stateManager.valid;
26
- * }
27
- * }
28
- * ```
29
- */
30
- import { signal, computed } from '@preact/signals-core';
31
- /**
32
- * Менеджер состояния для GroupNode
33
- *
34
- * Создает и управляет всеми сигналами состояния формы:
35
- * - value - значение формы как объект
36
- * - valid/invalid - валидность формы
37
- * - touched/dirty - пользовательское взаимодействие
38
- * - pending - асинхронная валидация в процессе
39
- * - errors - все ошибки валидации (form-level + field-level)
40
- * - status - общий статус формы
41
- * - submitting - флаг отправки формы
42
- *
43
- * @template T Тип формы (объект)
44
- */
45
- export class StateManager {
46
- fieldRegistry;
47
- // ============================================================================
48
- // Приватные сигналы (мутабельные)
49
- // ============================================================================
50
- /**
51
- * Флаг отправки формы
52
- * Устанавливается в true во время отправки формы на сервер
53
- */
54
- _submitting;
55
- /**
56
- * Флаг disabled состояния
57
- * Если true, форма считается disabled
58
- */
59
- _disabled;
60
- /**
61
- * Form-level validation errors (не связанные с конкретным полем)
62
- * Используется для server-side errors или кросс-полевой валидации
63
- */
64
- _formErrors;
65
- // ============================================================================
66
- // Публичные computed signals (read-only)
67
- // ============================================================================
68
- /**
69
- * Значение формы как объект
70
- *
71
- * Computed signal, который автоматически пересчитывается при изменении любого поля.
72
- * Использует мемоизацию - если зависимости не изменились, вернет закешированный объект.
73
- *
74
- * @example
75
- * ```typescript
76
- * const form = new GroupNode({ email: { value: 'test@mail.com' } });
77
- * console.log(form.value.value); // { email: 'test@mail.com' }
78
- * ```
79
- */
80
- value;
81
- /**
82
- * Форма валидна?
83
- *
84
- * Computed signal. Форма валидна, если:
85
- * - Нет form-level errors
86
- * - Все поля валидны
87
- */
88
- valid;
89
- /**
90
- * Форма невалидна?
91
- *
92
- * Computed signal. Инверсия valid.
93
- */
94
- invalid;
95
- /**
96
- * Хотя бы одно поле touched?
97
- *
98
- * Computed signal. Возвращает true, если хотя бы одно поле было touched.
99
- */
100
- touched;
101
- /**
102
- * Хотя бы одно поле dirty?
103
- *
104
- * Computed signal. Возвращает true, если хотя бы одно поле изменилось.
105
- */
106
- dirty;
107
- /**
108
- * Асинхронная валидация в процессе?
109
- *
110
- * Computed signal. Возвращает true, если хотя бы одно поле находится в pending состоянии.
111
- */
112
- pending;
113
- /**
114
- * Все ошибки валидации
115
- *
116
- * Computed signal. Возвращает массив всех ошибок:
117
- * - Form-level errors
118
- * - Field-level errors (из всех вложенных полей)
119
- */
120
- errors;
121
- /**
122
- * Общий статус формы
123
- *
124
- * Computed signal. Возможные значения:
125
- * - 'disabled' - форма disabled
126
- * - 'pending' - асинхронная валидация в процессе
127
- * - 'invalid' - форма невалидна
128
- * - 'valid' - форма валидна
129
- */
130
- status;
131
- /**
132
- * Форма в процессе отправки?
133
- *
134
- * Computed signal (обертка над _submitting для read-only доступа).
135
- */
136
- submitting;
137
- // ============================================================================
138
- // Конструктор
139
- // ============================================================================
140
- /**
141
- * Создать менеджер состояния
142
- *
143
- * @param fieldRegistry - реестр полей формы
144
- */
145
- constructor(fieldRegistry) {
146
- this.fieldRegistry = fieldRegistry;
147
- // Инициализация приватных сигналов
148
- this._submitting = signal(false);
149
- this._disabled = signal(false);
150
- this._formErrors = signal([]);
151
- // Создание computed signals
152
- // Computed signal для значения формы
153
- // Автоматически кеширует результат (мемоизация)
154
- // Первый вызов: O(n) где n = количество полей
155
- // Повторные вызовы (если зависимости не изменились): O(1) (возврат кешированного объекта)
156
- this.value = computed(() => {
157
- const result = {};
158
- this.fieldRegistry.forEach((field, key) => {
159
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
160
- result[key] = field.value.value;
161
- });
162
- return result;
163
- });
164
- // Computed signal для валидности формы
165
- this.valid = computed(() => {
166
- // Проверяем отсутствие form-level errors
167
- const hasFormErrors = this._formErrors.value.length > 0;
168
- if (hasFormErrors)
169
- return false;
170
- // Проверяем все поля
171
- return Array.from(this.fieldRegistry.values()).every((field) => field.valid.value);
172
- });
173
- // Computed signal для невалидности (инверсия valid)
174
- this.invalid = computed(() => !this.valid.value);
175
- // Computed signal для pending состояния
176
- this.pending = computed(() => Array.from(this.fieldRegistry.values()).some((field) => field.pending.value));
177
- // Computed signal для touched состояния
178
- this.touched = computed(() => Array.from(this.fieldRegistry.values()).some((field) => field.touched.value));
179
- // Computed signal для dirty состояния
180
- this.dirty = computed(() => Array.from(this.fieldRegistry.values()).some((field) => field.dirty.value));
181
- // Computed signal для ошибок (form-level + field-level)
182
- this.errors = computed(() => {
183
- const allErrors = [];
184
- // Добавляем form-level errors
185
- allErrors.push(...this._formErrors.value);
186
- // Добавляем field-level errors
187
- this.fieldRegistry.forEach((field) => {
188
- allErrors.push(...field.errors.value);
189
- });
190
- return allErrors;
191
- });
192
- // Computed signal для статуса формы
193
- this.status = computed(() => {
194
- if (this._disabled.value)
195
- return 'disabled';
196
- if (this.pending.value)
197
- return 'pending';
198
- if (this.invalid.value)
199
- return 'invalid';
200
- return 'valid';
201
- });
202
- // Computed signal для submitting (read-only обертка)
203
- this.submitting = computed(() => this._submitting.value);
204
- }
205
- // ============================================================================
206
- // Публичные методы для управления состоянием
207
- // ============================================================================
208
- /**
209
- * Установить form-level ошибки
210
- *
211
- * @param errors - массив ошибок валидации
212
- *
213
- * @example
214
- * ```typescript
215
- * // Server-side ошибки
216
- * stateManager.setFormErrors([
217
- * { code: 'server_error', message: 'Пользователь с таким email уже существует' }
218
- * ]);
219
- * ```
220
- */
221
- setFormErrors(errors) {
222
- this._formErrors.value = errors;
223
- }
224
- /**
225
- * Очистить form-level ошибки
226
- */
227
- clearFormErrors() {
228
- this._formErrors.value = [];
229
- }
230
- /**
231
- * Получить form-level ошибки
232
- */
233
- getFormErrors() {
234
- return this._formErrors.value;
235
- }
236
- /**
237
- * Установить флаг submitting
238
- *
239
- * @param value - true если форма отправляется, false если нет
240
- *
241
- * @example
242
- * ```typescript
243
- * stateManager.setSubmitting(true);
244
- * await api.submitForm(form.getValue());
245
- * stateManager.setSubmitting(false);
246
- * ```
247
- */
248
- setSubmitting(value) {
249
- this._submitting.value = value;
250
- }
251
- /**
252
- * Установить флаг disabled
253
- *
254
- * @param value - true если форма disabled, false если нет
255
- */
256
- setDisabled(value) {
257
- this._disabled.value = value;
258
- }
259
- /**
260
- * Получить флаг disabled
261
- */
262
- isDisabled() {
263
- return this._disabled.value;
264
- }
265
- }