@reformer/core 1.1.0 → 2.0.0-beta.2

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 (99) hide show
  1. package/dist/behaviors-DzYL8kY_.js +499 -0
  2. package/dist/behaviors.d.ts +6 -2
  3. package/dist/behaviors.js +19 -227
  4. package/dist/core/behavior/behavior-context.d.ts +6 -2
  5. package/dist/core/behavior/create-field-path.d.ts +3 -16
  6. package/dist/core/nodes/group-node.d.ts +14 -193
  7. package/dist/core/types/form-context.d.ts +10 -4
  8. package/dist/core/utils/field-path.d.ts +48 -0
  9. package/dist/core/utils/index.d.ts +1 -0
  10. package/dist/core/validation/core/validate-tree.d.ts +10 -4
  11. package/dist/core/validation/field-path.d.ts +3 -39
  12. package/dist/core/validation/validation-context.d.ts +23 -0
  13. package/dist/hooks/types.d.ts +328 -0
  14. package/dist/hooks/useFormControl.d.ts +13 -37
  15. package/dist/hooks/useFormControlValue.d.ts +167 -0
  16. package/dist/hooks/useSignalSubscription.d.ts +17 -0
  17. package/dist/index.d.ts +6 -1
  18. package/dist/index.js +2886 -8
  19. package/dist/{create-field-path-CdPF3lIK.js → registry-helpers-BRxAr6nG.js} +133 -347
  20. package/dist/validators-gXoHPdqM.js +418 -0
  21. package/dist/validators.d.ts +6 -2
  22. package/dist/validators.js +29 -296
  23. package/llms.txt +1283 -22
  24. package/package.json +8 -4
  25. package/dist/core/behavior/behavior-applicator.d.ts +0 -71
  26. package/dist/core/behavior/behavior-applicator.js +0 -92
  27. package/dist/core/behavior/behavior-context.js +0 -38
  28. package/dist/core/behavior/behavior-registry.js +0 -198
  29. package/dist/core/behavior/behaviors/compute-from.js +0 -84
  30. package/dist/core/behavior/behaviors/copy-from.js +0 -64
  31. package/dist/core/behavior/behaviors/enable-when.js +0 -81
  32. package/dist/core/behavior/behaviors/index.js +0 -11
  33. package/dist/core/behavior/behaviors/reset-when.js +0 -63
  34. package/dist/core/behavior/behaviors/revalidate-when.js +0 -51
  35. package/dist/core/behavior/behaviors/sync-fields.js +0 -66
  36. package/dist/core/behavior/behaviors/transform-value.js +0 -110
  37. package/dist/core/behavior/behaviors/watch-field.js +0 -56
  38. package/dist/core/behavior/compose-behavior.js +0 -166
  39. package/dist/core/behavior/create-field-path.js +0 -69
  40. package/dist/core/behavior/index.js +0 -17
  41. package/dist/core/behavior/types.js +0 -7
  42. package/dist/core/context/form-context-impl.js +0 -37
  43. package/dist/core/factories/index.js +0 -6
  44. package/dist/core/factories/node-factory.js +0 -281
  45. package/dist/core/nodes/array-node.js +0 -534
  46. package/dist/core/nodes/field-node.js +0 -510
  47. package/dist/core/nodes/form-node.js +0 -343
  48. package/dist/core/nodes/group-node/field-registry.d.ts +0 -191
  49. package/dist/core/nodes/group-node/field-registry.js +0 -215
  50. package/dist/core/nodes/group-node/index.d.ts +0 -11
  51. package/dist/core/nodes/group-node/index.js +0 -11
  52. package/dist/core/nodes/group-node/proxy-builder.d.ts +0 -71
  53. package/dist/core/nodes/group-node/proxy-builder.js +0 -161
  54. package/dist/core/nodes/group-node/state-manager.d.ts +0 -184
  55. package/dist/core/nodes/group-node/state-manager.js +0 -265
  56. package/dist/core/nodes/group-node.js +0 -770
  57. package/dist/core/types/deep-schema.js +0 -11
  58. package/dist/core/types/field-path.js +0 -4
  59. package/dist/core/types/form-context.js +0 -25
  60. package/dist/core/types/group-node-proxy.js +0 -31
  61. package/dist/core/types/index.js +0 -4
  62. package/dist/core/types/validation-schema.js +0 -10
  63. package/dist/core/utils/create-form.js +0 -24
  64. package/dist/core/utils/debounce.js +0 -197
  65. package/dist/core/utils/error-handler.js +0 -226
  66. package/dist/core/utils/field-path-navigator.js +0 -374
  67. package/dist/core/utils/index.js +0 -14
  68. package/dist/core/utils/registry-helpers.js +0 -79
  69. package/dist/core/utils/registry-stack.js +0 -86
  70. package/dist/core/utils/resources.js +0 -69
  71. package/dist/core/utils/subscription-manager.js +0 -214
  72. package/dist/core/utils/type-guards.js +0 -169
  73. package/dist/core/validation/core/apply-when.js +0 -41
  74. package/dist/core/validation/core/apply.js +0 -38
  75. package/dist/core/validation/core/index.js +0 -8
  76. package/dist/core/validation/core/validate-async.js +0 -45
  77. package/dist/core/validation/core/validate-tree.js +0 -37
  78. package/dist/core/validation/core/validate.js +0 -38
  79. package/dist/core/validation/field-path.js +0 -147
  80. package/dist/core/validation/index.js +0 -33
  81. package/dist/core/validation/validate-form.js +0 -152
  82. package/dist/core/validation/validation-applicator.js +0 -217
  83. package/dist/core/validation/validation-context.js +0 -75
  84. package/dist/core/validation/validation-registry.js +0 -298
  85. package/dist/core/validation/validators/array-validators.js +0 -86
  86. package/dist/core/validation/validators/date.js +0 -117
  87. package/dist/core/validation/validators/email.js +0 -60
  88. package/dist/core/validation/validators/index.js +0 -14
  89. package/dist/core/validation/validators/max-length.js +0 -60
  90. package/dist/core/validation/validators/max.js +0 -60
  91. package/dist/core/validation/validators/min-length.js +0 -60
  92. package/dist/core/validation/validators/min.js +0 -60
  93. package/dist/core/validation/validators/number.js +0 -90
  94. package/dist/core/validation/validators/pattern.js +0 -62
  95. package/dist/core/validation/validators/phone.js +0 -58
  96. package/dist/core/validation/validators/required.js +0 -69
  97. package/dist/core/validation/validators/url.js +0 -55
  98. package/dist/hooks/useFormControl.js +0 -298
  99. package/dist/node-factory-D7DOnSSN.js +0 -3200
@@ -1,374 +0,0 @@
1
- /**
2
- * Навигация по путям к полям формы
3
- *
4
- * Централизует логику парсинга и навигации по путям к полям формы.
5
- * Используется в ValidationContext, BehaviorContext, GroupNode для единообразной
6
- * обработки путей вида "address.city" или "items[0].name".
7
- *
8
- * Устраняет дублирование логики парсинга путей в 4 местах кодовой базы.
9
- *
10
- * @internal
11
- *
12
- * @example
13
- * ```typescript
14
- * const navigator = new FieldPathNavigator();
15
- *
16
- * // Парсинг пути
17
- * const segments = navigator.parsePath('items[0].title');
18
- * // [{ key: 'items', index: 0 }, { key: 'title' }]
19
- *
20
- * // Получение значения из объекта
21
- * const obj = { items: [{ title: 'Item 1' }] };
22
- * const value = navigator.getValueByPath(obj, 'items[0].title');
23
- * // 'Item 1'
24
- *
25
- * // Получение узла формы
26
- * const titleNode = navigator.getNodeByPath(form, 'items[0].title');
27
- * titleNode?.setValue('New Title');
28
- * ```
29
- */
30
- export class FieldPathNavigator {
31
- /**
32
- * Парсит путь в массив сегментов
33
- *
34
- * Поддерживаемые форматы:
35
- * - Простые пути: "name", "email"
36
- * - Вложенные пути: "address.city", "user.profile.avatar"
37
- * - Массивы: "items[0]", "items[0].name", "tags[1][0]"
38
- * - Комбинации: "orders[0].items[1].price"
39
- *
40
- * @param path Путь к полю (строка с точками и квадратными скобками)
41
- * @returns Массив сегментов пути
42
- *
43
- * @example
44
- * ```typescript
45
- * navigator.parsePath('email');
46
- * // [{ key: 'email' }]
47
- *
48
- * navigator.parsePath('address.city');
49
- * // [{ key: 'address' }, { key: 'city' }]
50
- *
51
- * navigator.parsePath('items[0].name');
52
- * // [{ key: 'items', index: 0 }, { key: 'name' }]
53
- * ```
54
- */
55
- parsePath(path) {
56
- const segments = [];
57
- let currentPart = '';
58
- let inBrackets = false;
59
- for (let i = 0; i < path.length; i++) {
60
- const char = path[i];
61
- if (char === '[') {
62
- inBrackets = true;
63
- currentPart += char;
64
- }
65
- else if (char === ']') {
66
- inBrackets = false;
67
- currentPart += char;
68
- }
69
- else if (char === '.' && !inBrackets) {
70
- // Разделитель найден, обрабатываем накопленную часть
71
- if (currentPart) {
72
- this.addSegment(segments, currentPart);
73
- currentPart = '';
74
- }
75
- }
76
- else {
77
- currentPart += char;
78
- }
79
- }
80
- // Добавляем последнюю часть
81
- if (currentPart) {
82
- this.addSegment(segments, currentPart);
83
- }
84
- return segments;
85
- }
86
- /**
87
- * Добавляет сегмент в массив, обрабатывая массивы
88
- * @private
89
- */
90
- addSegment(segments, part) {
91
- // Проверка на массив: items[0]
92
- const arrayMatch = part.match(/^(.+)\[(\d+)\]$/);
93
- if (arrayMatch) {
94
- segments.push({
95
- key: arrayMatch[1],
96
- index: parseInt(arrayMatch[2], 10),
97
- });
98
- }
99
- else {
100
- segments.push({ key: part });
101
- }
102
- }
103
- /**
104
- * Получает значение по пути из объекта
105
- *
106
- * Проходит по всем сегментам пути и возвращает конечное значение.
107
- * Если путь не найден, возвращает undefined.
108
- *
109
- * @param obj Объект для навигации
110
- * @param path Путь к значению
111
- * @returns Значение или undefined, если путь не найден
112
- *
113
- * @example
114
- * ```typescript
115
- * const obj = {
116
- * email: 'test@mail.com',
117
- * address: { city: 'Moscow' },
118
- * items: [{ title: 'Item 1' }]
119
- * };
120
- *
121
- * navigator.getValueByPath(obj, 'email');
122
- * // 'test@mail.com'
123
- *
124
- * navigator.getValueByPath(obj, 'address.city');
125
- * // 'Moscow'
126
- *
127
- * navigator.getValueByPath(obj, 'items[0].title');
128
- * // 'Item 1'
129
- *
130
- * navigator.getValueByPath(obj, 'invalid.path');
131
- * // undefined
132
- * ```
133
- */
134
- getValueByPath(obj, path) {
135
- const segments = this.parsePath(path);
136
- let current = obj;
137
- for (const segment of segments) {
138
- if (current == null)
139
- return undefined;
140
- current = current[segment.key];
141
- if (segment.index !== undefined) {
142
- if (!Array.isArray(current))
143
- return undefined;
144
- current = current[segment.index];
145
- }
146
- }
147
- return current;
148
- }
149
- /**
150
- * Устанавливает значение по пути в объекте (мутирует объект)
151
- *
152
- * Создает промежуточные объекты, если они не существуют.
153
- * Выбрасывает ошибку, если ожидается массив, но его нет.
154
- *
155
- * @param obj Объект для модификации
156
- * @param path Путь к значению
157
- * @param value Новое значение
158
- *
159
- * @throws {Error} Если ожидается массив по пути, но его нет
160
- *
161
- * @example
162
- * ```typescript
163
- * const obj = { address: { city: '' } };
164
- * navigator.setValueByPath(obj, 'address.city', 'Moscow');
165
- * // obj.address.city === 'Moscow'
166
- *
167
- * const obj2: UnknownRecord = {};
168
- * navigator.setValueByPath(obj2, 'address.city', 'Moscow');
169
- * // Создаст { address: { city: 'Moscow' } }
170
- *
171
- * const obj3 = { items: [{ title: 'Old' }] };
172
- * navigator.setValueByPath(obj3, 'items[0].title', 'New');
173
- * // obj3.items[0].title === 'New'
174
- * ```
175
- */
176
- setValueByPath(obj, path, value) {
177
- const segments = this.parsePath(path);
178
- if (segments.length === 0) {
179
- throw new Error('Cannot set value: empty path');
180
- }
181
- let current = obj;
182
- // Проходим до предпоследнего сегмента
183
- for (let i = 0; i < segments.length - 1; i++) {
184
- const segment = segments[i];
185
- let next = current[segment.key];
186
- if (segment.index !== undefined) {
187
- // Доступ к массиву: items[0]
188
- if (!Array.isArray(next)) {
189
- throw new Error(`Expected array at path segment: ${segment.key}, but got ${typeof next}`);
190
- }
191
- current = next[segment.index];
192
- }
193
- else {
194
- // Доступ к объекту: address
195
- if (next == null) {
196
- // Создаем объект, если его нет
197
- current[segment.key] = {};
198
- next = current[segment.key];
199
- }
200
- current = next;
201
- }
202
- }
203
- // Устанавливаем значение в последнем сегменте
204
- const lastSegment = segments[segments.length - 1];
205
- if (lastSegment.index !== undefined) {
206
- const arr = current[lastSegment.key];
207
- if (!Array.isArray(arr)) {
208
- throw new Error(`Expected array at path segment: ${lastSegment.key}, but got ${typeof arr}`);
209
- }
210
- arr[lastSegment.index] = value;
211
- }
212
- else {
213
- current[lastSegment.key] = value;
214
- }
215
- }
216
- /**
217
- * Получить значение из FormNode по пути
218
- *
219
- * Автоматически извлекает значение из FormNode (через .value.value).
220
- * Используется в ValidationContext и BehaviorContext для единообразного
221
- * доступа к значениям полей формы.
222
- *
223
- * @param form Корневой узел формы (обычно GroupNode)
224
- * @param path Путь к полю
225
- * @returns Значение поля или undefined, если путь не найден
226
- *
227
- * @example
228
- * ```typescript
229
- * const form = new GroupNode({
230
- * email: { value: 'test@mail.com', component: Input },
231
- * address: {
232
- * city: { value: 'Moscow', component: Input }
233
- * },
234
- * items: [{ title: { value: 'Item 1', component: Input } }]
235
- * });
236
- *
237
- * navigator.getFormNodeValue(form, 'email');
238
- * // 'test@mail.com'
239
- *
240
- * navigator.getFormNodeValue(form, 'address.city');
241
- * // 'Moscow'
242
- *
243
- * navigator.getFormNodeValue(form, 'items[0].title');
244
- * // 'Item 1'
245
- *
246
- * navigator.getFormNodeValue(form, 'invalid.path');
247
- * // undefined
248
- * ```
249
- */
250
- getFormNodeValue(form, path) {
251
- const node = this.getNodeByPath(form, path);
252
- if (node == null) {
253
- return undefined;
254
- }
255
- // FormNode возвращает .value.value
256
- if (this.isFormNode(node)) {
257
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
258
- return node.value.value;
259
- }
260
- // Для обычных объектов возвращаем как есть
261
- return node;
262
- }
263
- /**
264
- * Type guard для проверки, является ли объект FormNode
265
- *
266
- * Проверяет наличие характерных свойств FormNode:
267
- * - value (Signal)
268
- * - value.value (значение Signal)
269
- *
270
- * @param obj Объект для проверки
271
- * @returns true, если объект является FormNode
272
- * @private
273
- */
274
- isFormNode(obj) {
275
- return (obj != null &&
276
- typeof obj === 'object' &&
277
- 'value' in obj &&
278
- typeof obj.value === 'object' &&
279
- obj.value != null &&
280
- 'value' in obj.value);
281
- }
282
- /**
283
- * Получает узел формы по пути
284
- *
285
- * Навигирует по структуре FormNode (GroupNode/FieldNode/ArrayNode)
286
- * и возвращает узел по указанному пути.
287
- *
288
- * Поддерживает:
289
- * - Доступ к полям GroupNode через fields Map
290
- * - Доступ к элементам ArrayNode через индекс
291
- * - Proxy-доступ к полям (для обратной совместимости)
292
- *
293
- * @param form Корневой узел формы (обычно GroupNode)
294
- * @param path Путь к узлу
295
- * @returns Узел формы или null, если путь не найден
296
- *
297
- * @example
298
- * ```typescript
299
- * const form = new GroupNode({
300
- * email: { value: '', component: Input },
301
- * address: {
302
- * city: { value: '', component: Input }
303
- * },
304
- * items: [{ title: { value: '', component: Input } }]
305
- * });
306
- *
307
- * const emailNode = navigator.getNodeByPath(form, 'email');
308
- * // FieldNode
309
- *
310
- * const cityNode = navigator.getNodeByPath(form, 'address.city');
311
- * // FieldNode
312
- *
313
- * const itemNode = navigator.getNodeByPath(form, 'items[0]');
314
- * // GroupNode
315
- *
316
- * const titleNode = navigator.getNodeByPath(form, 'items[0].title');
317
- * // FieldNode
318
- *
319
- * const invalidNode = navigator.getNodeByPath(form, 'invalid.path');
320
- * // null
321
- * ```
322
- */
323
- getNodeByPath(form, path) {
324
- const segments = this.parsePath(path);
325
- let current = form;
326
- for (const segment of segments) {
327
- if (current == null)
328
- return null;
329
- const currentRecord = current;
330
- // Для GroupNode: доступ через fields Map
331
- if (currentRecord.fields && currentRecord.fields instanceof Map) {
332
- current = currentRecord.fields.get(segment.key);
333
- // Если это не ArrayNode или нет индекса, продолжаем
334
- if (segment.index === undefined) {
335
- if (current == null)
336
- return null;
337
- continue;
338
- }
339
- }
340
- // Для ArrayNode: доступ через items и индекс
341
- else if (segment.index !== undefined && currentRecord.items) {
342
- const items = currentRecord.items.value || currentRecord.items;
343
- if (!Array.isArray(items))
344
- return null;
345
- current = items[segment.index];
346
- if (current == null)
347
- return null;
348
- continue;
349
- }
350
- // Proxy-доступ (для обратной совместимости)
351
- else if (segment.index === undefined) {
352
- current = currentRecord[segment.key];
353
- if (current == null)
354
- return null;
355
- continue;
356
- }
357
- // Если нашли ArrayNode и есть индекс, получаем элемент массива
358
- if (current && segment.index !== undefined && current.items) {
359
- const items = current.items.value ||
360
- current.items;
361
- if (!Array.isArray(items))
362
- return null;
363
- current = items[segment.index];
364
- }
365
- // Если запрашивается индекс, но узел не является ArrayNode, возвращаем null
366
- else if (current && segment.index !== undefined && !current.items) {
367
- return null;
368
- }
369
- if (current == null)
370
- return null;
371
- }
372
- return current;
373
- }
374
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * Утилиты для работы с формами
3
- *
4
- * Централизованные вспомогательные классы и функции.
5
- */
6
- export { FieldPathNavigator } from './field-path-navigator';
7
- export { SubscriptionManager } from './subscription-manager';
8
- export { getCurrentValidationRegistry, getCurrentBehaviorRegistry } from './registry-helpers';
9
- export { RegistryStack } from './registry-stack';
10
- export { isFormNode, isFieldNode, isGroupNode, isArrayNode, getNodeType } from './type-guards';
11
- export { Debouncer } from './debounce';
12
- export { FormErrorHandler, ErrorStrategy } from './error-handler';
13
- export { createForm } from './create-form';
14
- export * from './resources';
@@ -1,79 +0,0 @@
1
- /**
2
- * Вспомогательные функции для работы с реестрами
3
- *
4
- * Централизует логику получения текущего активного реестра валидации/поведения
5
- * из context stack, избегая дублирования кода в schema-validators.ts,
6
- * array-validators.ts и schema-behaviors.ts
7
- */
8
- import { ValidationRegistry } from '../validation/validation-registry';
9
- import { BehaviorRegistry } from '../behavior/behavior-registry';
10
- /**
11
- * Получить текущий активный ValidationRegistry из context stack
12
- *
13
- * Используется внутри validation schema функций (validate, validateAsync, required и т.д.)
14
- * для регистрации валидаторов в активном контексте GroupNode
15
- *
16
- * @returns Текущий ValidationRegistry или заглушка в production
17
- * @throws Error если нет активного контекста (только в DEV режиме)
18
- *
19
- * @internal
20
- *
21
- * @example
22
- * ```typescript
23
- * function required(fieldPath, options) {
24
- * const registry = getCurrentValidationRegistry();
25
- * registry.registerSync(path, validator, options);
26
- * }
27
- * ```
28
- */
29
- export function getCurrentValidationRegistry() {
30
- const registry = ValidationRegistry.getCurrent();
31
- if (!registry) {
32
- if (import.meta.env.DEV) {
33
- throw new Error('No active ValidationRegistry context. Make sure to call applyValidationSchema() within a GroupNode context.');
34
- }
35
- // В production возвращаем заглушку чтобы не ломать приложение
36
- return {
37
- registerSync: () => { },
38
- registerAsync: () => { },
39
- registerTree: () => { },
40
- enterCondition: () => { },
41
- exitCondition: () => { },
42
- registerArrayItemValidation: () => { },
43
- };
44
- }
45
- return registry;
46
- }
47
- /**
48
- * Получить текущий активный BehaviorRegistry из context stack
49
- *
50
- * Используется внутри behavior schema функций (copyFrom, enableWhen, computeFrom и т.д.)
51
- * для регистрации поведений в активном контексте GroupNode
52
- *
53
- * @returns Текущий BehaviorRegistry или заглушка в production
54
- * @throws Error если нет активного контекста (только в DEV режиме)
55
- *
56
- * @internal
57
- *
58
- * @example
59
- * ```typescript
60
- * function copyFrom(target, source, options) {
61
- * const registry = getCurrentBehaviorRegistry();
62
- * const handler = createCopyBehavior(target, source, options);
63
- * registry.register(handler, { debounce: options?.debounce });
64
- * }
65
- * ```
66
- */
67
- export function getCurrentBehaviorRegistry() {
68
- const registry = BehaviorRegistry.getCurrent();
69
- if (!registry) {
70
- if (import.meta.env.DEV) {
71
- throw new Error('No active BehaviorRegistry context. Make sure to call applyBehaviorSchema() within a GroupNode context.');
72
- }
73
- // В production возвращаем заглушку чтобы не ломать приложение
74
- return {
75
- register: () => { },
76
- };
77
- }
78
- return registry;
79
- }
@@ -1,86 +0,0 @@
1
- /**
2
- * Generic Registry Stack - утилита для управления стеком регистрации
3
- *
4
- * Используется ValidationRegistry и BehaviorRegistry для tracking активного контекста.
5
- * Устраняет дублирование кода между параллельными системами.
6
- *
7
- * @template T - Тип элементов в стеке (ValidationRegistry или BehaviorRegistry)
8
- *
9
- * @internal
10
- *
11
- * @example
12
- * ```typescript
13
- * class ValidationRegistry {
14
- * private static registryStack = new RegistryStack<ValidationRegistry>();
15
- *
16
- * static getCurrent() {
17
- * return ValidationRegistry.registryStack.getCurrent();
18
- * }
19
- *
20
- * beginRegistration() {
21
- * ValidationRegistry.registryStack.push(this);
22
- * }
23
- *
24
- * endRegistration() {
25
- * ValidationRegistry.registryStack.verify(this, 'ValidationRegistry');
26
- * }
27
- * }
28
- * ```
29
- */
30
- export class RegistryStack {
31
- stack = [];
32
- /**
33
- * Добавить элемент в стек
34
- * @param item - Элемент для добавления
35
- */
36
- push(item) {
37
- this.stack.push(item);
38
- }
39
- /**
40
- * Извлечь элемент из стека
41
- * @returns Извлеченный элемент или undefined если стек пуст
42
- */
43
- pop() {
44
- return this.stack.pop();
45
- }
46
- /**
47
- * Получить текущий элемент (вершину стека) без извлечения
48
- * @returns Текущий элемент или null если стек пуст
49
- */
50
- getCurrent() {
51
- return this.stack.length > 0 ? this.stack[this.stack.length - 1] : null;
52
- }
53
- /**
54
- * Извлечь элемент из стека с проверкой
55
- * Выводит предупреждение в DEV режиме если извлеченный элемент не совпадает с ожидаемым
56
- *
57
- * @param expected - Ожидаемый элемент
58
- * @param name - Имя реестра для отладки (например, 'ValidationRegistry')
59
- */
60
- verify(expected, name) {
61
- const popped = this.pop();
62
- if (popped !== expected && import.meta.env.DEV) {
63
- console.warn(`${name}: Stack mismatch. Expected ${expected}, got ${popped}`);
64
- }
65
- }
66
- /**
67
- * Получить длину стека
68
- * @returns Количество элементов в стеке
69
- */
70
- get length() {
71
- return this.stack.length;
72
- }
73
- /**
74
- * Проверить, пуст ли стек
75
- * @returns true если стек пуст
76
- */
77
- isEmpty() {
78
- return this.stack.length === 0;
79
- }
80
- /**
81
- * Очистить стек
82
- */
83
- clear() {
84
- this.stack = [];
85
- }
86
- }
@@ -1,69 +0,0 @@
1
- // ============================================================================
2
- // Типы ресурсов
3
- // ============================================================================
4
- // ============================================================================
5
- // 1. Статическая стратегия
6
- // ============================================================================
7
- /**
8
- * Статический ресурс - данные загружаются один раз
9
- * @param items - массив элементов
10
- */
11
- export function staticResource(items) {
12
- return {
13
- type: 'static',
14
- load: async () => ({
15
- items,
16
- totalCount: items.length,
17
- }),
18
- };
19
- }
20
- // ============================================================================
21
- // 2. Предзагрузка
22
- // ============================================================================
23
- /**
24
- * Предзагрузка - данные загружаются один раз при первом обращении через функцию
25
- * @param loader - функция загрузки, принимает параметры и возвращает массив
26
- */
27
- export function preloadResource(loader) {
28
- let cache = null;
29
- return {
30
- type: 'preload',
31
- load: async (params) => {
32
- if (!cache) {
33
- const items = await loader(params);
34
- cache = {
35
- items,
36
- totalCount: items.length,
37
- };
38
- }
39
- return cache;
40
- },
41
- };
42
- }
43
- // ============================================================================
44
- // 3. Парциональная загрузка
45
- // ============================================================================
46
- /**
47
- * Парциональная загрузка - данные загружаются порциями с учетом поиска/пагинации
48
- * @param loader - функция загрузки, принимает параметры и возвращает массив
49
- */
50
- export function partialResource(loader) {
51
- return {
52
- type: 'partial',
53
- load: async (params) => {
54
- const items = await loader(params);
55
- return {
56
- items,
57
- totalCount: items.length, // Можно расширить для поддержки серверной пагинации
58
- };
59
- },
60
- };
61
- }
62
- // ============================================================================
63
- // Экспорт всех стратегий
64
- // ============================================================================
65
- export const Resources = {
66
- static: staticResource,
67
- preload: preloadResource,
68
- partial: partialResource,
69
- };