@reformer/core 9.0.0 → 9.1.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 (105) hide show
  1. package/README.md +52 -57
  2. package/dist/behaviors-node-BMOI2JJF.js +26 -0
  3. package/dist/behaviors-value-lCpqicfa.js +148 -0
  4. package/dist/behaviors.d.ts +2 -133
  5. package/dist/behaviors.js +148 -147
  6. package/dist/{core/utils → form}/aggregate-signals.d.ts +2 -2
  7. package/dist/form/behaviors-node.d.ts +55 -0
  8. package/dist/form/behaviors.d.ts +133 -0
  9. package/dist/{core/utils → form}/create-form.d.ts +5 -4
  10. package/dist/{core/utils → form}/error-handler.d.ts +1 -1
  11. package/dist/{core → form}/factories/node-factory.d.ts +1 -1
  12. package/dist/{core/utils → form}/form-proxy-builder.d.ts +2 -2
  13. package/dist/{core/utils → form}/form-submitter.d.ts +6 -1
  14. package/dist/{hooks → form/hooks}/types.d.ts +31 -1
  15. package/dist/{hooks → form/hooks}/useArrayLength.d.ts +1 -1
  16. package/dist/{hooks → form/hooks}/useFormControl.d.ts +3 -3
  17. package/dist/{hooks → form/hooks}/useFormControlValue.d.ts +2 -2
  18. package/dist/{hooks → form/hooks}/useSignalSubscription.d.ts +8 -1
  19. package/dist/form/index.d.ts +36 -0
  20. package/dist/{core → form}/nodes/array-node.d.ts +1 -1
  21. package/dist/{core → form}/nodes/field-node.d.ts +1 -1
  22. package/dist/{core → form}/nodes/form-node.d.ts +1 -1
  23. package/dist/{core → form}/nodes/group-node.d.ts +34 -4
  24. package/dist/{core → form}/nodes/model-array-node.d.ts +10 -3
  25. package/dist/{core/utils → form}/signal-node-registry.d.ts +1 -1
  26. package/dist/{core/utils → form}/status-machine.d.ts +1 -1
  27. package/dist/{core/utils → form}/type-guards.d.ts +5 -5
  28. package/dist/{core/types/index.d.ts → form/types/contracts.d.ts} +11 -90
  29. package/dist/{core → form}/types/deep-schema.d.ts +23 -1
  30. package/dist/{core → form}/types/form-proxy.d.ts +26 -1
  31. package/dist/form/types/index.d.ts +91 -0
  32. package/dist/{core → form}/types/schema-node.d.ts +1 -1
  33. package/dist/{core → form}/types/validation-schema.d.ts +19 -9
  34. package/dist/{core/model/validate-model.d.ts → form/validate-model-core.d.ts} +25 -25
  35. package/dist/form/validate-model.d.ts +27 -0
  36. package/dist/{core → form}/validation/validators/required.d.ts +2 -1
  37. package/dist/form/validators.d.ts +6 -0
  38. package/dist/form-model-C8Fi83k4.js +439 -0
  39. package/dist/index.d.ts +11 -16
  40. package/dist/index.js +666 -1011
  41. package/dist/{core/model/behaviors.d.ts → state/behaviors-value.d.ts} +0 -38
  42. package/dist/{core/utils → state}/derived-registry.d.ts +29 -0
  43. package/dist/state/form-model.d.ts +26 -0
  44. package/dist/state/index.d.ts +31 -0
  45. package/dist/state/safe-effect.d.ts +93 -0
  46. package/dist/{core/model → state}/types.d.ts +14 -11
  47. package/dist/state.d.ts +2 -0
  48. package/dist/state.js +19 -0
  49. package/dist/validators/email.d.ts +1 -1
  50. package/dist/validators/future-date.d.ts +1 -1
  51. package/dist/validators/integer.d.ts +1 -1
  52. package/dist/validators/is-date.d.ts +1 -1
  53. package/dist/validators/is-number.d.ts +1 -1
  54. package/dist/validators/max-age.d.ts +1 -1
  55. package/dist/validators/max-date.d.ts +1 -1
  56. package/dist/validators/max-length.d.ts +1 -1
  57. package/dist/validators/max.d.ts +1 -1
  58. package/dist/validators/min-age.d.ts +1 -1
  59. package/dist/validators/min-date.d.ts +1 -1
  60. package/dist/validators/min-length.d.ts +1 -1
  61. package/dist/validators/min.d.ts +1 -1
  62. package/dist/validators/multiple-of.d.ts +1 -1
  63. package/dist/validators/non-negative.d.ts +1 -1
  64. package/dist/validators/non-zero.d.ts +1 -1
  65. package/dist/validators/past-date.d.ts +1 -1
  66. package/dist/validators/pattern.d.ts +1 -1
  67. package/dist/validators/pattern.js +7 -6
  68. package/dist/validators/phone.d.ts +1 -1
  69. package/dist/validators/required.d.ts +1 -1
  70. package/dist/validators/required.js +5 -9
  71. package/dist/validators/url.d.ts +1 -1
  72. package/dist/validators.d.ts +6 -6
  73. package/llms.txt +307 -166
  74. package/package.json +5 -1
  75. package/dist/behaviors-O9a1Djj9.js +0 -147
  76. package/dist/core/model/form-model.d.ts +0 -18
  77. package/dist/core/model/index.d.ts +0 -12
  78. package/dist/core/utils/index.d.ts +0 -18
  79. package/dist/core/utils/safe-effect.d.ts +0 -73
  80. /package/dist/{core → form}/factories/index.d.ts +0 -0
  81. /package/dist/{core/utils → form}/unique-id.d.ts +0 -0
  82. /package/dist/{core → form}/validation/index.d.ts +0 -0
  83. /package/dist/{core → form}/validation/validators/date-utils.d.ts +0 -0
  84. /package/dist/{core → form}/validation/validators/email.d.ts +0 -0
  85. /package/dist/{core → form}/validation/validators/future-date.d.ts +0 -0
  86. /package/dist/{core → form}/validation/validators/index.d.ts +0 -0
  87. /package/dist/{core → form}/validation/validators/integer.d.ts +0 -0
  88. /package/dist/{core → form}/validation/validators/is-date.d.ts +0 -0
  89. /package/dist/{core → form}/validation/validators/is-number.d.ts +0 -0
  90. /package/dist/{core → form}/validation/validators/max-age.d.ts +0 -0
  91. /package/dist/{core → form}/validation/validators/max-date.d.ts +0 -0
  92. /package/dist/{core → form}/validation/validators/max-length.d.ts +0 -0
  93. /package/dist/{core → form}/validation/validators/max.d.ts +0 -0
  94. /package/dist/{core → form}/validation/validators/min-age.d.ts +0 -0
  95. /package/dist/{core → form}/validation/validators/min-date.d.ts +0 -0
  96. /package/dist/{core → form}/validation/validators/min-length.d.ts +0 -0
  97. /package/dist/{core → form}/validation/validators/min.d.ts +0 -0
  98. /package/dist/{core → form}/validation/validators/multiple-of.d.ts +0 -0
  99. /package/dist/{core → form}/validation/validators/non-negative.d.ts +0 -0
  100. /package/dist/{core → form}/validation/validators/non-zero.d.ts +0 -0
  101. /package/dist/{core → form}/validation/validators/past-date.d.ts +0 -0
  102. /package/dist/{core → form}/validation/validators/pattern.d.ts +0 -0
  103. /package/dist/{core → form}/validation/validators/phone.d.ts +0 -0
  104. /package/dist/{core → form}/validation/validators/url.d.ts +0 -0
  105. /package/dist/{core/utils → state}/subscription-manager.d.ts +0 -0
@@ -1,5 +1,5 @@
1
1
  import { FormValue, ValidationError } from './index';
2
- import { FormModel } from '../model/types';
2
+ import { FormModel } from '../../state/types';
3
3
  /**
4
4
  * Чистый синхронный валидатор поля.
5
5
  *
@@ -35,27 +35,37 @@ import { FormModel } from '../model/types';
35
35
  export type Validator<TForm, TField> = (value: TField, scope: unknown, root: FormModel<TForm>) => ValidationError | null;
36
36
  /**
37
37
  * Чистый асинхронный валидатор поля. Та же тройка аргументов `(value, scope, root)`, что у
38
- * {@link Validator}, но возвращает `Promise`. Регистрируется через
39
- * `validateAsync(path, validator, { debounce })`.
38
+ * {@link Validator}, но возвращает `Promise`.
39
+ *
40
+ * @deprecated Осиротевший остаток удалённого оператора `validateAsync` (Ф7). Рантаймом не
41
+ * потребляется — живой async-путь узла поля использует `AsyncValidatorFn` `(value, { signal })`.
42
+ * Экспортируется только ради обратной совместимости.
40
43
  */
41
44
  export type AsyncValidator<TForm, TField> = (value: TField, scope: unknown, root: FormModel<TForm>) => Promise<ValidationError | null>;
42
45
  /**
43
- * Функция условия для applyWhen.
46
+ * Функция-предикат `(value) => boolean`.
47
+ *
48
+ * @deprecated Осиротевший остаток удалённого оператора `applyWhen` (Ф7). Рантаймом не
49
+ * потребляется; экспортируется только ради обратной совместимости.
44
50
  */
45
51
  export type ConditionFn<T> = (value: T) => boolean;
46
52
  /**
47
- * Опции для функции validate.
53
+ * Опции валидатора-фабрики (`required()`/`pattern()`/…). Передаются вторым (или последним)
54
+ * аргументом в фабрику и попадают в возвращаемую {@link ValidationError}.
48
55
  */
49
56
  export interface ValidateOptions {
50
- /** Сообщение об ошибке */
57
+ /** Готовое сообщение об ошибке. Если не задано, валидаторы кладут `''`, и отображаемый текст
58
+ * резолвится из `code` (см. резолвер сообщений в `@reformer/cdk`). */
51
59
  message?: string;
52
- /** Параметры ошибки */
60
+ /** Параметры ошибки (подстановка в шаблон сообщения / i18n). */
53
61
  params?: Record<string, FormValue>;
54
62
  }
55
63
  /**
56
- * Опции для функции validateAsync.
64
+ * @deprecated Осиротевший остаток удалённого оператора `validateAsync` (Ф7): опция `debounce`
65
+ * подключалась тем оператором, которого больше нет. Рантаймом не потребляется; экспортируется
66
+ * только ради обратной совместимости.
57
67
  */
58
68
  export interface ValidateAsyncOptions extends ValidateOptions {
59
- /** Задержка перед выполнением валидации (в мс) */
69
+ /** Задержка перед выполнением валидации (в мс). */
60
70
  debounce?: number;
61
71
  }
@@ -1,6 +1,6 @@
1
- import { ValidationError } from '../types';
2
- import { FormSchemaNode } from '../types/schema-node';
3
- import { FormModel } from './types';
1
+ import { ValidationError } from './types/contracts';
2
+ import { FormSchemaNode } from './types/schema-node';
3
+ import { FormModel, PathAwareSignal } from '../state/types';
4
4
  /**
5
5
  * Валидатор слоя **данных**. `value` — значение поля; `model` — ближайший scope (под-модель элемента
6
6
  * массива или корень); `root` — корневая модель.
@@ -21,6 +21,26 @@ export interface ModelValidationResult {
21
21
  /** Ключ — путь поля (`'coBorrowers.0.relationship'`). Только поля с ошибками. */
22
22
  errors: Record<string, ValidationError[]>;
23
23
  }
24
+ export interface FieldTask {
25
+ signal: PathAwareSignal<unknown>;
26
+ validators: ModelValidator[];
27
+ scope: unknown;
28
+ }
29
+ /** Результат обхода схемы: что валидировать и что очистить. */
30
+ export interface CollectResult {
31
+ /** Активные поля с валидаторами (прогоняются). */
32
+ tasks: FieldTask[];
33
+ /** Сигналы полей в ВЫКЛЮЧЕННЫХ ветках — их ошибки нужно очистить (`setErrors([])`). */
34
+ clearSignals: PathAwareSignal<unknown>[];
35
+ }
36
+ /** Один обход схемы → задачи (активные) + сигналы на очистку (выключенные ветки). */
37
+ export declare function collect(model: unknown, schema: unknown): CollectResult;
38
+ /**
39
+ * Есть ли среди собранных ошибок блокирующие. Ошибка с `severity: 'warning'` показывается,
40
+ * но НЕ блокирует submit (см. {@link ValidationError.severity} — 'warning' allows submission),
41
+ * поэтому `valid` выводится из наличия блокирующих ошибок, а не из общего количества ошибок.
42
+ */
43
+ export declare const hasBlockingErrors: (errors: Record<string, ValidationError[]>) => boolean;
24
44
  /**
25
45
  * Синхронная headless-валидация данных. Асинхронные валидаторы пропускаются.
26
46
  *
@@ -48,25 +68,5 @@ export declare function validateModelSync<T>(model: FormModel<T>, schema: FormSc
48
68
  * ```
49
69
  */
50
70
  export declare function validateModel<T>(model: FormModel<T>, schema: FormSchemaNode): Promise<ModelValidationResult>;
51
- /**
52
- * In-form валидация: прогоняет {@link validateModel} и роутит ошибки в ноды формы
53
- * (через реестр сигнал→нода): `node.setErrors(errors[path] ?? [])` — заодно очищает прошедшие поля
54
- * И поля выключенных веток (`{ when, children }` с ложным условием). Дерево обходится ОДИН раз.
55
- *
56
- * @group Model
57
- * @param model - Модель данных ({@link FormModel}) — источник значений полей.
58
- * @param schema - Единая схема формы (та же, что передавалась в `createForm`).
59
- * @returns {@link ModelValidationResult} — `valid` + ошибки по пути поля; побочный эффект — ошибки
60
- * разведены по нодам формы.
61
- * @remarks Поля, не материализованные в форме (элементы массива — строятся per-item), не роутятся
62
- * в родительскую форму; их ошибки доступны в возвращаемом результате по пути.
63
- *
64
- * @example Валидация перед submit (ошибки показываются в UI автоматически)
65
- * ```typescript
66
- * const form = createForm({ model, schema });
67
- * form.touchAll();
68
- * const res = await validateFormModel(model, schema);
69
- * if (res.valid) await api.save(model.get());
70
- * ```
71
- */
72
- export declare function validateFormModel<T>(model: FormModel<T>, schema: FormSchemaNode): Promise<ModelValidationResult>;
71
+ /** Прогон задач (sync + async): возвращает ошибки по пути. */
72
+ export declare function runTasks(tasks: FieldTask[], model: unknown): Promise<Record<string, ValidationError[]>>;
@@ -0,0 +1,27 @@
1
+ import { FormSchemaNode } from './types/schema-node';
2
+ import { FormModel } from '../state/types';
3
+ import { ModelValidationResult } from './validate-model-core';
4
+ export { validateModel, validateModelSync } from './validate-model-core';
5
+ export type { ModelValidator, ModelValidationResult } from './validate-model-core';
6
+ /**
7
+ * In-form валидация: прогоняет {@link validateModel} и роутит ошибки в ноды формы
8
+ * (через реестр сигнал→нода): `node.setErrors(errors[path] ?? [])` — заодно очищает прошедшие поля
9
+ * И поля выключенных веток (`{ when, children }` с ложным условием). Дерево обходится ОДИН раз.
10
+ *
11
+ * @group Model
12
+ * @param model - Модель данных ({@link FormModel}) — источник значений полей.
13
+ * @param schema - Единая схема формы (та же, что передавалась в `createForm`).
14
+ * @returns {@link ModelValidationResult} — `valid` + ошибки по пути поля; побочный эффект — ошибки
15
+ * разведены по нодам формы.
16
+ * @remarks Поля, не материализованные в форме (элементы массива — строятся per-item), не роутятся
17
+ * в родительскую форму; их ошибки доступны в возвращаемом результате по пути.
18
+ *
19
+ * @example Валидация перед submit (ошибки показываются в UI автоматически)
20
+ * ```typescript
21
+ * const form = createForm({ model, schema });
22
+ * form.touchAll();
23
+ * const res = await validateFormModel(model, schema);
24
+ * if (res.valid) await api.save(model.get());
25
+ * ```
26
+ */
27
+ export declare function validateFormModel<T>(model: FormModel<T>, schema: FormSchemaNode): Promise<ModelValidationResult>;
@@ -4,7 +4,8 @@ import { Validator, ValidateOptions } from '../../types/validation-schema';
4
4
  *
5
5
  * Возвращает чистую функцию-валидатор `(value, control, root)`. Передаётся в `validate()`.
6
6
  *
7
- * Пустыми считаются: `null`, `undefined`, `''` (пустая строка).
7
+ * Пустыми считаются: `null`, `undefined`, `''` (пустая строка), `[]` (пустой массив —
8
+ * обязательный multi-select / FormArray без выбранных элементов).
8
9
  * Для boolean полей требуется значение `true`.
9
10
  *
10
11
  * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Re-export validators from the main index to ensure single module instance.
3
+ * This prevents static registry isolation issues when consuming the library.
4
+ */
5
+ export { validators as default } from '../index';
6
+ export * from './validation/index';
@@ -0,0 +1,439 @@
1
+ import { signal as v } from "@preact/signals-core";
2
+ import { i as w } from "./behaviors-value-lCpqicfa.js";
3
+ class P {
4
+ /**
5
+ * Хранилище подписок
6
+ * Ключ: уникальный идентификатор подписки
7
+ * Значение: функция отписки (dispose)
8
+ */
9
+ subscriptions = /* @__PURE__ */ new Map();
10
+ /**
11
+ * Добавляет подписку
12
+ *
13
+ * Если подписка с таким ключом уже существует, отписывается от неё
14
+ * и заменяет новой. Это предотвращает утечки памяти при повторной
15
+ * регистрации подписки с тем же ключом.
16
+ *
17
+ * @param key Уникальный ключ подписки
18
+ * @param dispose Функция отписки (обычно возвращаемая из effect())
19
+ * @returns Функция для отписки от этой конкретной подписки
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const manager = new SubscriptionManager();
24
+ *
25
+ * // Добавление подписки
26
+ * const unsubscribe = manager.add('mySubscription', () => {
27
+ * console.log('Disposing subscription');
28
+ * });
29
+ *
30
+ * // Отписка через возвращаемую функцию
31
+ * unsubscribe();
32
+ *
33
+ * // Или через manager.remove()
34
+ * manager.add('anotherSub', disposeFn);
35
+ * manager.remove('anotherSub');
36
+ * ```
37
+ */
38
+ add(t, e) {
39
+ return this.subscriptions.has(t) && (process.env.NODE_ENV !== "production" && console.warn(`[SubscriptionManager] Subscription "${t}" already exists, replacing`), this.subscriptions.get(t)?.()), this.subscriptions.set(t, e), () => this.remove(t);
40
+ }
41
+ /**
42
+ * Удаляет подписку по ключу
43
+ *
44
+ * Вызывает функцию отписки и удаляет подписку из хранилища.
45
+ * Если подписка с таким ключом не найдена, ничего не делает.
46
+ *
47
+ * @param key Ключ подписки
48
+ * @returns true, если подписка была удалена, false если не найдена
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const manager = new SubscriptionManager();
53
+ * manager.add('mySub', disposeFn);
54
+ *
55
+ * // Удаление подписки
56
+ * const removed = manager.remove('mySub'); // true
57
+ *
58
+ * // Попытка удалить несуществующую подписку
59
+ * const removed2 = manager.remove('nonExistent'); // false
60
+ * ```
61
+ */
62
+ remove(t) {
63
+ const e = this.subscriptions.get(t);
64
+ return e ? (e(), this.subscriptions.delete(t), !0) : !1;
65
+ }
66
+ /**
67
+ * Очищает все подписки
68
+ *
69
+ * Вызывает функции отписки для всех активных подписок
70
+ * и очищает хранилище. Обычно используется при dispose узла формы.
71
+ *
72
+ * @example
73
+ * ```typescript
74
+ * class FieldNode {
75
+ * private subscriptions = new SubscriptionManager();
76
+ *
77
+ * dispose() {
78
+ * // Отписываемся от всех effect
79
+ * this.subscriptions.clear();
80
+ * }
81
+ * }
82
+ * ```
83
+ */
84
+ clear() {
85
+ this.subscriptions.forEach((t) => {
86
+ t();
87
+ }), this.subscriptions.clear();
88
+ }
89
+ /**
90
+ * Возвращает количество активных подписок
91
+ *
92
+ * Полезно для отладки утечек памяти. Если количество подписок
93
+ * растет без ограничений, это может указывать на то, что
94
+ * компоненты не отписываются должным образом.
95
+ *
96
+ * @returns Количество активных подписок
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * const manager = new SubscriptionManager();
101
+ * console.log(manager.size()); // 0
102
+ *
103
+ * manager.add('sub1', disposeFn1);
104
+ * manager.add('sub2', disposeFn2);
105
+ * console.log(manager.size()); // 2
106
+ *
107
+ * manager.clear();
108
+ * console.log(manager.size()); // 0
109
+ * ```
110
+ */
111
+ size() {
112
+ return this.subscriptions.size;
113
+ }
114
+ /**
115
+ * Проверяет, есть ли подписка с данным ключом
116
+ *
117
+ * @param key Ключ подписки
118
+ * @returns true, если подписка существует
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const manager = new SubscriptionManager();
123
+ * manager.add('mySub', disposeFn);
124
+ *
125
+ * console.log(manager.has('mySub')); // true
126
+ * console.log(manager.has('nonExistent')); // false
127
+ * ```
128
+ */
129
+ has(t) {
130
+ return this.subscriptions.has(t);
131
+ }
132
+ /**
133
+ * Возвращает список всех ключей активных подписок
134
+ *
135
+ * Полезно для отладки: можно увидеть, какие подписки активны.
136
+ *
137
+ * @returns Массив ключей всех активных подписок
138
+ *
139
+ * @example
140
+ * ```typescript
141
+ * const manager = new SubscriptionManager();
142
+ * manager.add('watch-value', disposeFn1);
143
+ * manager.add('watch-errors', disposeFn2);
144
+ *
145
+ * console.log(manager.getKeys()); // ['watch-value', 'watch-errors']
146
+ * ```
147
+ */
148
+ getKeys() {
149
+ return Array.from(this.subscriptions.keys());
150
+ }
151
+ /**
152
+ * Отписывается от всех подписок (алиас для clear())
153
+ *
154
+ * Используется при dispose() узла формы для совместимости с ожидаемым API.
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * class FieldNode {
159
+ * private subscriptions = new SubscriptionManager();
160
+ *
161
+ * dispose() {
162
+ * this.subscriptions.dispose();
163
+ * }
164
+ * }
165
+ * ```
166
+ */
167
+ dispose() {
168
+ this.clear();
169
+ }
170
+ }
171
+ const u = (i) => !(i === null || typeof i != "object" || Array.isArray(i) || i instanceof Date || typeof Blob < "u" && i instanceof Blob || typeof File < "u" && i instanceof File), a = (i, t) => i === "" ? String(t) : `${i}.${t}`, p = (i) => /^\d+$/.test(i), o = (i) => {
172
+ if (Array.isArray(i)) return i.map(o);
173
+ if (u(i)) {
174
+ const t = {};
175
+ for (const e of Object.keys(i)) t[e] = o(i[e]);
176
+ return t;
177
+ }
178
+ return i;
179
+ }, f = (i, t) => {
180
+ if (i === t) return !0;
181
+ if (Array.isArray(i) && Array.isArray(t))
182
+ return i.length !== t.length ? !1 : i.every((e, s) => f(e, t[s]));
183
+ if (u(i) && u(t)) {
184
+ const e = Object.keys(i), s = Object.keys(t);
185
+ return e.length !== s.length ? !1 : e.every((r) => f(i[r], t[r]));
186
+ }
187
+ return !1;
188
+ };
189
+ class _ {
190
+ constructor(t, e) {
191
+ this.path = e;
192
+ const s = v(t);
193
+ s.__path = e, this.signal = s, this.initial = o(t);
194
+ }
195
+ kind = "leaf";
196
+ signal;
197
+ initial;
198
+ rebase(t) {
199
+ this.path = t, this.signal.__path = t;
200
+ }
201
+ /** Реактивное чтение (внутри effect/computed создаёт зависимость). */
202
+ read() {
203
+ return this.signal.value;
204
+ }
205
+ /** Нереактивный снимок. */
206
+ peek() {
207
+ return this.signal.peek();
208
+ }
209
+ set(t) {
210
+ this.signal.value = t;
211
+ }
212
+ resetToInitial() {
213
+ this.signal.value = o(this.initial);
214
+ }
215
+ captureInitial() {
216
+ this.initial = o(this.signal.peek());
217
+ }
218
+ dirty() {
219
+ return !f(this.signal.peek(), this.initial);
220
+ }
221
+ }
222
+ class b {
223
+ constructor(t, e) {
224
+ this.path = e;
225
+ for (const s of Object.keys(t))
226
+ this.children.set(s, c(t[s], a(e, s)));
227
+ }
228
+ kind = "group";
229
+ children = /* @__PURE__ */ new Map();
230
+ rebase(t) {
231
+ this.path = t;
232
+ for (const [e, s] of this.children) s.rebase(a(t, e));
233
+ }
234
+ peek() {
235
+ const t = {};
236
+ for (const [e, s] of this.children) t[e] = s.peek();
237
+ return t;
238
+ }
239
+ set(t) {
240
+ if (t == null || typeof t != "object") return;
241
+ const e = t;
242
+ for (const [s, r] of this.children)
243
+ s in e && (r.kind === "leaf" && w(r.signal) || r.set(e[s]));
244
+ }
245
+ resetToInitial() {
246
+ for (const t of this.children.values()) t.resetToInitial();
247
+ }
248
+ captureInitial() {
249
+ for (const t of this.children.values()) t.captureInitial();
250
+ }
251
+ dirty() {
252
+ for (const t of this.children.values()) if (t.dirty()) return !0;
253
+ return !1;
254
+ }
255
+ }
256
+ class k {
257
+ constructor(t, e) {
258
+ this.path = e, this.items = v(t.map((s, r) => c(s, a(e, r)))), this.initial = o(t);
259
+ }
260
+ kind = "array";
261
+ items;
262
+ initial;
263
+ rebase(t) {
264
+ this.path = t, this.items.peek().forEach((e, s) => e.rebase(a(t, s)));
265
+ }
266
+ reindex() {
267
+ this.items.peek().forEach((t, e) => t.rebase(a(this.path, e)));
268
+ }
269
+ push(t) {
270
+ const e = this.items.peek();
271
+ this.items.value = [...e, c(t, a(this.path, e.length))];
272
+ }
273
+ insertAt(t, e) {
274
+ const s = [...this.items.peek()];
275
+ s.splice(t, 0, c(e, a(this.path, t))), this.items.value = s, this.reindex();
276
+ }
277
+ removeAt(t) {
278
+ const e = [...this.items.peek()];
279
+ e.splice(t, 1), this.items.value = e, this.reindex();
280
+ }
281
+ move(t, e) {
282
+ const s = [...this.items.peek()], [r] = s.splice(t, 1);
283
+ r && s.splice(e, 0, r), this.items.value = s, this.reindex();
284
+ }
285
+ swap(t, e) {
286
+ const s = [...this.items.peek()];
287
+ t < 0 || e < 0 || t >= s.length || e >= s.length || t === e || ([s[t], s[e]] = [s[e], s[t]], this.items.value = s, this.reindex());
288
+ }
289
+ clear() {
290
+ this.items.value = [];
291
+ }
292
+ peek() {
293
+ return this.items.peek().map((t) => t.peek());
294
+ }
295
+ set(t) {
296
+ const e = Array.isArray(t) ? t : [];
297
+ this.items.value = e.map((s, r) => c(s, a(this.path, r)));
298
+ }
299
+ resetToInitial() {
300
+ this.set(o(this.initial));
301
+ }
302
+ captureInitial() {
303
+ this.initial = o(this.peek());
304
+ }
305
+ dirty() {
306
+ return !f(this.peek(), this.initial);
307
+ }
308
+ }
309
+ function c(i, t) {
310
+ return Array.isArray(i) ? new k(i, t) : u(i) ? new b(i, t) : new _(i, t);
311
+ }
312
+ function l(i) {
313
+ if (i)
314
+ return i.kind === "group" ? A(i) : i.kind === "array" ? x(i) : i.read();
315
+ }
316
+ function x(i) {
317
+ const t = {
318
+ get length() {
319
+ return i.items.value.length;
320
+ },
321
+ push: (e) => i.push(e),
322
+ insertAt: (e, s) => i.insertAt(e, s),
323
+ removeAt: (e) => i.removeAt(e),
324
+ move: (e, s) => i.move(e, s),
325
+ swap: (e, s) => i.swap(e, s),
326
+ clear: () => i.clear(),
327
+ at: (e) => l(i.items.value[e]),
328
+ map: (e) => i.items.value.map((s, r) => e(l(s), r)),
329
+ forEach: (e) => i.items.value.forEach((s, r) => e(l(s), r)),
330
+ toArray: () => i.peek(),
331
+ [Symbol.iterator]: function* () {
332
+ const e = i.items.value;
333
+ for (let s = 0; s < e.length; s++) yield l(e[s]);
334
+ }
335
+ };
336
+ return new Proxy(t, {
337
+ get: (e, s, r) => s === "__path" ? i.path : typeof s == "string" && p(s) ? l(i.items.value[Number(s)]) : Reflect.get(e, s, r),
338
+ has: (e, s) => typeof s == "string" && p(s) ? Number(s) < i.items.value.length : Reflect.has(e, s)
339
+ });
340
+ }
341
+ function d(i) {
342
+ if (i.kind === "leaf") return i.signal;
343
+ if (i.kind === "group")
344
+ return new Proxy(
345
+ {},
346
+ {
347
+ get: (e, s) => {
348
+ if (s === "__path") return i.path;
349
+ if (typeof s != "string") return;
350
+ const r = i.children.get(s);
351
+ return r ? d(r) : void 0;
352
+ },
353
+ has: (e, s) => typeof s == "string" && i.children.has(s),
354
+ ownKeys: () => [...i.children.keys()],
355
+ getOwnPropertyDescriptor: (e, s) => typeof s == "string" && i.children.has(s) ? { enumerable: !0, configurable: !0 } : void 0
356
+ }
357
+ );
358
+ const t = i;
359
+ return new Proxy(
360
+ {
361
+ get length() {
362
+ return t.items.value.length;
363
+ }
364
+ },
365
+ {
366
+ get: (e, s, r) => {
367
+ if (s === "__path") return t.path;
368
+ if (typeof s == "string" && p(s)) {
369
+ const n = t.items.value[Number(s)];
370
+ return n ? d(n) : void 0;
371
+ }
372
+ return Reflect.get(e, s, r);
373
+ }
374
+ }
375
+ );
376
+ }
377
+ function I(i, t) {
378
+ if (!t) return;
379
+ let e = i;
380
+ for (const s of t.split(".")) {
381
+ if (!e) return;
382
+ if (e.kind === "group") e = e.children.get(s);
383
+ else if (e.kind === "array") e = e.items.peek()[Number(s)];
384
+ else return;
385
+ }
386
+ return e && e.kind === "leaf" ? e.signal : void 0;
387
+ }
388
+ const g = /* @__PURE__ */ new Set([
389
+ "$",
390
+ "get",
391
+ "set",
392
+ "patch",
393
+ "isDirty",
394
+ "reset",
395
+ "captureInitial",
396
+ "signalAt"
397
+ ]), y = /* @__PURE__ */ new WeakMap();
398
+ function A(i) {
399
+ const t = y.get(i);
400
+ if (t) return t;
401
+ const e = {
402
+ $: d(i),
403
+ get: () => i.peek(),
404
+ set: (r) => i.set(r),
405
+ patch: (r) => i.set(r),
406
+ isDirty: () => i.dirty(),
407
+ reset: () => i.resetToInitial(),
408
+ captureInitial: () => i.captureInitial(),
409
+ signalAt: (r) => I(i, r)
410
+ }, s = new Proxy(
411
+ {},
412
+ {
413
+ get: (r, n) => {
414
+ if (n === "__path") return i.path;
415
+ if (typeof n != "string") return;
416
+ const h = i.children.get(n);
417
+ if (h) return l(h);
418
+ if (g.has(n)) return e[n];
419
+ },
420
+ set: (r, n, h) => {
421
+ if (typeof n != "string") return !1;
422
+ const m = i.children.get(n);
423
+ return m ? (m.set(h), !0) : !1;
424
+ },
425
+ has: (r, n) => typeof n == "string" && (i.children.has(n) || g.has(n)),
426
+ ownKeys: () => [...i.children.keys()],
427
+ getOwnPropertyDescriptor: (r, n) => typeof n == "string" && i.children.has(n) ? { enumerable: !0, configurable: !0 } : void 0
428
+ }
429
+ );
430
+ return y.set(i, s), s;
431
+ }
432
+ function S(i) {
433
+ const t = new b(i, "");
434
+ return A(t);
435
+ }
436
+ export {
437
+ P as S,
438
+ S as c
439
+ };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,11 @@
1
- export * from './core/types';
2
- export * from './core/factories';
3
- export * from './core/utils';
4
- export * from './core/model';
5
- export { FormNode } from './core/nodes/form-node';
6
- export { FieldNode } from './core/nodes/field-node';
7
- export { GroupNode } from './core/nodes/group-node';
8
- export { ArrayNode } from './core/nodes/array-node';
9
- export { ModelArrayNode } from './core/nodes/model-array-node';
10
- export type { ModelArrayControl } from './core/nodes/model-array-node';
11
- export type { SetValueOptions } from './core/nodes/form-node';
12
- export { useFormControl } from './hooks/useFormControl';
13
- export { useFormControlValue } from './hooks/useFormControlValue';
14
- export { useArrayLength } from './hooks/useArrayLength';
15
- export type { FieldControlState, ArrayControlState } from './hooks/types';
16
- export * as validators from './core/validation';
1
+ /**
2
+ * Публичный barrel `@reformer/core` — зонтик над модулями `model` (state) и `form`.
3
+ *
4
+ * Состав экспортов НЕ изменился при модуляризации (реорг в src/model + src/form): реализация
5
+ * разложена по модулям, а этот barrel по-прежнему отдаёт единую поверхность.
6
+ */
7
+ export * from './form/types/index';
8
+ export * from './form/factories/index';
9
+ export * from './state/index';
10
+ export * from './form/index';
11
+ export * as validators from './form/validation/index';