@reformer/core 11.0.0-beta.1 → 11.0.0-beta.10

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 (283) hide show
  1. package/README.md +90 -68
  2. package/dist/behaviors-value-D05z3my6.js +109 -0
  3. package/dist/behaviors.d.ts +1 -1
  4. package/dist/behaviors.js +376 -211
  5. package/dist/create-model-DPSG3I0O.js +30 -0
  6. package/dist/date-utils-90-qZbse.js +43 -0
  7. package/dist/en-HP8XEych.js +44 -0
  8. package/dist/form/aggregate-signals.d.ts +21 -63
  9. package/dist/form/behaviors/collections.d.ts +84 -0
  10. package/dist/form/behaviors/context.d.ts +56 -0
  11. package/dist/form/behaviors/index.d.ts +30 -0
  12. package/dist/form/behaviors/internals.d.ts +41 -0
  13. package/dist/form/{behaviors-node.d.ts → behaviors/node.d.ts} +28 -5
  14. package/dist/form/behaviors/operators.d.ts +59 -0
  15. package/dist/form/behaviors/schema-operators.d.ts +83 -0
  16. package/dist/form/behaviors/types.d.ts +37 -0
  17. package/dist/form/create-form.d.ts +59 -70
  18. package/dist/form/flow/flow.d.ts +87 -0
  19. package/dist/form/form-bundle.d.ts +153 -0
  20. package/dist/form/form-level.d.ts +121 -0
  21. package/dist/form/form-proxy-builder.d.ts +6 -22
  22. package/dist/form/index.d.ts +23 -24
  23. package/dist/form/nodes/form-array-node.d.ts +100 -0
  24. package/dist/form/nodes/form-control-node.d.ts +73 -0
  25. package/dist/form/nodes/form-group-node.d.ts +66 -0
  26. package/dist/form/nodes/node-kind.d.ts +29 -0
  27. package/dist/form/nodes/state/availability.d.ts +6 -0
  28. package/dist/form/nodes/state/component.d.ts +6 -0
  29. package/dist/form/nodes/state/index.d.ts +12 -0
  30. package/dist/form/nodes/state/interaction.d.ts +13 -0
  31. package/dist/form/nodes/state/issues.d.ts +9 -0
  32. package/dist/form/nodes/state/pending.d.ts +6 -0
  33. package/dist/form/schema/compile.d.ts +59 -0
  34. package/dist/form/schema/compiled.d.ts +143 -0
  35. package/dist/form/schema/row-key.d.ts +11 -0
  36. package/dist/form/schema-controller.d.ts +159 -0
  37. package/dist/form/schema-subtree.d.ts +28 -0
  38. package/dist/form/signal-node-registry.d.ts +27 -22
  39. package/dist/form/submission.d.ts +93 -0
  40. package/dist/form/type-guards.d.ts +14 -73
  41. package/dist/form/types/contracts.d.ts +21 -85
  42. package/dist/form/types/field-config.d.ts +27 -0
  43. package/dist/form/types/index.d.ts +5 -57
  44. package/dist/form/types/nodes.d.ts +159 -0
  45. package/dist/form/types/schema-node.d.ts +147 -46
  46. package/dist/form/types/validation-schema.d.ts +25 -17
  47. package/dist/form/validation/context.d.ts +67 -0
  48. package/dist/form/validation/index.d.ts +24 -28
  49. package/dist/form/validation/operators.d.ts +101 -0
  50. package/dist/form/validation/run.d.ts +120 -0
  51. package/dist/form/validation/strategy.d.ts +89 -0
  52. package/dist/form/validation/types.d.ts +83 -0
  53. package/dist/form/validators/date-utils.d.ts +42 -0
  54. package/dist/form/validators/email.d.ts +23 -0
  55. package/dist/form/{validation/validators → validators}/file-type.d.ts +10 -10
  56. package/dist/form/{validation/validators → validators}/file-utils.d.ts +3 -2
  57. package/dist/form/validators/future-date.d.ts +23 -0
  58. package/dist/form/{validation/validators → validators}/index.d.ts +7 -4
  59. package/dist/form/validators/integer.d.ts +22 -0
  60. package/dist/form/validators/is-date.d.ts +24 -0
  61. package/dist/form/validators/is-number.d.ts +25 -0
  62. package/dist/form/validators/max-age.d.ts +28 -0
  63. package/dist/form/validators/max-date.d.ts +25 -0
  64. package/dist/form/{validation/validators → validators}/max-file-size.d.ts +10 -10
  65. package/dist/form/validators/max-files.d.ts +26 -0
  66. package/dist/form/validators/max-length.d.ts +33 -0
  67. package/dist/form/validators/max-total-file-size.d.ts +26 -0
  68. package/dist/form/validators/max.d.ts +26 -0
  69. package/dist/form/validators/min-age.d.ts +27 -0
  70. package/dist/form/validators/min-date.d.ts +25 -0
  71. package/dist/form/{validation/validators → validators}/min-file-size.d.ts +10 -10
  72. package/dist/form/validators/min-files.d.ts +27 -0
  73. package/dist/form/validators/min-length.d.ts +33 -0
  74. package/dist/form/validators/min.d.ts +26 -0
  75. package/dist/form/validators/multiple-of.d.ts +25 -0
  76. package/dist/form/validators/non-negative.d.ts +22 -0
  77. package/dist/form/validators/non-zero.d.ts +22 -0
  78. package/dist/form/validators/past-date.d.ts +23 -0
  79. package/dist/form/validators/pattern.d.ts +26 -0
  80. package/dist/form/{validation/validators → validators}/phone.d.ts +11 -11
  81. package/dist/form/validators/required.d.ts +29 -0
  82. package/dist/form/validators/url.d.ts +45 -0
  83. package/dist/form/validators/validation-issue.d.ts +8 -0
  84. package/dist/i18n/descriptor.d.ts +54 -0
  85. package/dist/i18n/en.json.d.ts +49 -0
  86. package/dist/i18n/loader.d.ts +71 -0
  87. package/dist/i18n/locale-store.d.ts +46 -0
  88. package/dist/i18n/locale.d.ts +90 -0
  89. package/dist/i18n/message-format.d.ts +136 -0
  90. package/dist/i18n/resolve-localized.d.ts +17 -0
  91. package/dist/i18n/ru.json.d.ts +49 -0
  92. package/dist/i18n/translator.d.ts +61 -0
  93. package/dist/i18n/validation-message.d.ts +53 -0
  94. package/dist/i18n.d.ts +26 -0
  95. package/dist/i18n.js +86 -0
  96. package/dist/index.d.ts +17 -5
  97. package/dist/index.js +942 -2601
  98. package/dist/loader-BWkigpVe.js +52 -0
  99. package/dist/locale/en.d.ts +2 -0
  100. package/dist/locale/en.js +5 -0
  101. package/dist/locale/en.json +45 -0
  102. package/dist/locale/index.d.ts +18 -0
  103. package/dist/locale/ru.d.ts +2 -0
  104. package/dist/locale/ru.js +44 -0
  105. package/dist/locale/ru.json +45 -0
  106. package/dist/locale-CG54AU2Q.js +219 -0
  107. package/dist/locale.d.ts +2 -0
  108. package/dist/locale.js +9 -0
  109. package/dist/{state → model}/behaviors-value.d.ts +24 -6
  110. package/dist/{state/form-model.d.ts → model/create-model.d.ts} +18 -4
  111. package/dist/{state → model}/derived-registry.d.ts +1 -1
  112. package/dist/model/index.d.ts +42 -0
  113. package/dist/model/model-nodes.d.ts +190 -0
  114. package/dist/model/model-signals-proxy.d.ts +63 -0
  115. package/dist/model/model-value-proxy.d.ts +84 -0
  116. package/dist/{state → model}/safe-effect.d.ts +50 -2
  117. package/dist/model/types.d.ts +239 -0
  118. package/dist/model.d.ts +2 -0
  119. package/dist/model.js +27 -0
  120. package/dist/node-kind-C-r6ZMdo.js +15 -0
  121. package/dist/platforms/react/field-binding/field-adapter.d.ts +87 -0
  122. package/dist/platforms/react/field-binding/field-handle.d.ts +53 -0
  123. package/dist/platforms/react/form-bundle-context.d.ts +27 -0
  124. package/dist/{form → platforms/react}/hooks/types.d.ts +58 -36
  125. package/dist/platforms/react/hooks/use-form-bundle.d.ts +41 -0
  126. package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
  127. package/dist/{form → platforms/react}/hooks/use-form-validation.d.ts +13 -7
  128. package/dist/{form → platforms/react}/hooks/useArrayLength.d.ts +6 -6
  129. package/dist/{form → platforms/react}/hooks/useFormControl.d.ts +7 -9
  130. package/dist/{form → platforms/react}/hooks/useFormControlValue.d.ts +18 -18
  131. package/dist/{form → platforms/react}/hooks/useSignalSubscription.d.ts +9 -1
  132. package/dist/platforms/react/i18n/context.d.ts +18 -0
  133. package/dist/platforms/react/i18n/hooks.d.ts +65 -0
  134. package/dist/platforms/react/i18n/provider.d.ts +59 -0
  135. package/dist/platforms/react/index.d.ts +30 -0
  136. package/dist/react.d.ts +22 -0
  137. package/dist/react.js +505 -0
  138. package/dist/runtime-token.d.ts +1 -2
  139. package/dist/safe-effect-BazLOv1g.js +669 -0
  140. package/dist/schema-controller-CpiO2JoK.js +143 -0
  141. package/dist/signals.d.ts +15 -9
  142. package/dist/signals.js +11 -6
  143. package/dist/strategy-DzvnsWLh.js +375 -0
  144. package/dist/type-guards-D-N_5Ddh.js +19 -0
  145. package/dist/validation-issue-B9mjI8jz.js +7 -0
  146. package/dist/validation-message-Ced9MGxs.js +194 -0
  147. package/dist/validation.d.ts +1 -1
  148. package/dist/validation.js +11 -165
  149. package/dist/validators/email.d.ts +1 -1
  150. package/dist/validators/email.js +5 -8
  151. package/dist/validators/future-date.d.ts +1 -1
  152. package/dist/validators/future-date.js +10 -13
  153. package/dist/validators/integer.d.ts +1 -1
  154. package/dist/validators/integer.js +4 -7
  155. package/dist/validators/is-date.d.ts +1 -1
  156. package/dist/validators/is-date.js +5 -8
  157. package/dist/validators/is-number.d.ts +1 -1
  158. package/dist/validators/is-number.js +4 -7
  159. package/dist/validators/max-age.d.ts +1 -1
  160. package/dist/validators/max-age.js +8 -12
  161. package/dist/validators/max-date.d.ts +1 -1
  162. package/dist/validators/max-date.js +10 -13
  163. package/dist/validators/max-length.d.ts +1 -1
  164. package/dist/validators/max-length.js +7 -10
  165. package/dist/validators/max.d.ts +1 -1
  166. package/dist/validators/max.js +4 -7
  167. package/dist/validators/min-age.d.ts +1 -1
  168. package/dist/validators/min-age.js +10 -11
  169. package/dist/validators/min-date.d.ts +1 -1
  170. package/dist/validators/min-date.js +8 -11
  171. package/dist/validators/min-length.d.ts +1 -1
  172. package/dist/validators/min-length.js +4 -7
  173. package/dist/validators/min.d.ts +1 -1
  174. package/dist/validators/min.js +4 -7
  175. package/dist/validators/multiple-of.d.ts +1 -1
  176. package/dist/validators/multiple-of.js +11 -10
  177. package/dist/validators/non-negative.d.ts +1 -1
  178. package/dist/validators/non-negative.js +2 -5
  179. package/dist/validators/non-zero.d.ts +1 -1
  180. package/dist/validators/non-zero.js +4 -7
  181. package/dist/validators/past-date.d.ts +1 -1
  182. package/dist/validators/past-date.js +10 -13
  183. package/dist/validators/pattern.d.ts +1 -1
  184. package/dist/validators/pattern.js +5 -8
  185. package/dist/validators/phone.d.ts +1 -1
  186. package/dist/validators/phone.js +10 -11
  187. package/dist/validators/required.d.ts +1 -1
  188. package/dist/validators/required.js +4 -7
  189. package/dist/validators/url.d.ts +1 -1
  190. package/dist/validators/url.js +48 -17
  191. package/dist/validators.d.ts +1 -1
  192. package/dist/validators.js +86 -108
  193. package/docs/llms/01-api-reference.md +60 -34
  194. package/docs/llms/02-quick-start.md +112 -74
  195. package/docs/llms/03-api-signatures.md +369 -148
  196. package/docs/llms/04-common-patterns.md +58 -56
  197. package/docs/llms/05-common-mistakes.md +69 -44
  198. package/docs/llms/06-troubleshooting.md +14 -9
  199. package/docs/llms/07-complete-import.md +74 -43
  200. package/docs/llms/08-form-types.md +11 -4
  201. package/docs/llms/09-formschema.md +132 -84
  202. package/docs/llms/10-arrays.md +141 -61
  203. package/docs/llms/11-async-watchfield.md +2 -2
  204. package/docs/llms/13-multi-step.md +134 -63
  205. package/docs/llms/14-extended-mistakes.md +20 -17
  206. package/docs/llms/15-project-structure.md +224 -70
  207. package/docs/llms/16-ui-components.md +86 -46
  208. package/docs/llms/17-nonexistent-api.md +217 -32
  209. package/docs/llms/18-conditional-fields.md +71 -32
  210. package/docs/llms/19-reading-values.md +45 -4
  211. package/docs/llms/20-compute-vs-watch.md +25 -10
  212. package/docs/llms/21-array-operations.md +76 -26
  213. package/docs/llms/22-cycle-detection.md +1 -1
  214. package/docs/llms/23-copy-from.md +2 -2
  215. package/docs/llms/24-sync-fields.md +6 -5
  216. package/docs/llms/25-reset-when.md +14 -7
  217. package/docs/llms/26-transform-value.md +4 -4
  218. package/docs/llms/27-revalidate-when.md +16 -15
  219. package/docs/llms/28-submit-and-reset.md +278 -128
  220. package/docs/llms/29-async-preload.md +41 -31
  221. package/docs/llms/30-type-safety-recipes.md +105 -51
  222. package/docs/llms/31-async-validator-debounce.md +96 -53
  223. package/docs/llms/33-validation-strategy.md +178 -66
  224. package/docs/llms/34-i18n.md +298 -0
  225. package/docs/llms/35-unified-contract.md +309 -0
  226. package/docs/llms/36-issue-messages.md +284 -0
  227. package/docs/llms/37-compiled-schema.md +332 -0
  228. package/docs/llms/38-form-flow.md +396 -0
  229. package/llms-index.json +1 -0
  230. package/llms.txt +10690 -3089
  231. package/package.json +48 -9
  232. package/dist/behaviors-node-DGEFMTQu.js +0 -18
  233. package/dist/behaviors-value-C7dSEhCc.js +0 -134
  234. package/dist/date-utils-dTT_x_Be.js +0 -31
  235. package/dist/derived-registry-CluZCQ7U.js +0 -16
  236. package/dist/form/behaviors.d.ts +0 -133
  237. package/dist/form/error-handler.d.ts +0 -166
  238. package/dist/form/factories/index.d.ts +0 -6
  239. package/dist/form/factories/node-factory.d.ts +0 -188
  240. package/dist/form/form-submitter.d.ts +0 -121
  241. package/dist/form/nodes/array-node.d.ts +0 -276
  242. package/dist/form/nodes/field-node.d.ts +0 -294
  243. package/dist/form/nodes/form-node.d.ts +0 -326
  244. package/dist/form/nodes/group-node.d.ts +0 -284
  245. package/dist/form/nodes/model-array-node.d.ts +0 -121
  246. package/dist/form/status-machine.d.ts +0 -115
  247. package/dist/form/types/deep-schema.d.ts +0 -107
  248. package/dist/form/types/form-proxy.d.ts +0 -141
  249. package/dist/form/unique-id.d.ts +0 -45
  250. package/dist/form/validation/validators/date-utils.d.ts +0 -30
  251. package/dist/form/validation/validators/email.d.ts +0 -23
  252. package/dist/form/validation/validators/future-date.d.ts +0 -23
  253. package/dist/form/validation/validators/integer.d.ts +0 -22
  254. package/dist/form/validation/validators/is-date.d.ts +0 -23
  255. package/dist/form/validation/validators/is-number.d.ts +0 -24
  256. package/dist/form/validation/validators/max-age.d.ts +0 -25
  257. package/dist/form/validation/validators/max-date.d.ts +0 -25
  258. package/dist/form/validation/validators/max-files.d.ts +0 -26
  259. package/dist/form/validation/validators/max-length.d.ts +0 -27
  260. package/dist/form/validation/validators/max-total-file-size.d.ts +0 -26
  261. package/dist/form/validation/validators/max.d.ts +0 -25
  262. package/dist/form/validation/validators/min-age.d.ts +0 -25
  263. package/dist/form/validation/validators/min-date.d.ts +0 -25
  264. package/dist/form/validation/validators/min-files.d.ts +0 -26
  265. package/dist/form/validation/validators/min-length.d.ts +0 -27
  266. package/dist/form/validation/validators/min.d.ts +0 -25
  267. package/dist/form/validation/validators/multiple-of.d.ts +0 -24
  268. package/dist/form/validation/validators/non-negative.d.ts +0 -22
  269. package/dist/form/validation/validators/non-zero.d.ts +0 -22
  270. package/dist/form/validation/validators/past-date.d.ts +0 -23
  271. package/dist/form/validation/validators/pattern.d.ts +0 -33
  272. package/dist/form/validation/validators/required.d.ts +0 -32
  273. package/dist/form/validation/validators/url.d.ts +0 -43
  274. package/dist/form/validation-schema.d.ts +0 -106
  275. package/dist/form/validation-strategy.d.ts +0 -55
  276. package/dist/form/validators.d.ts +0 -11
  277. package/dist/form-model-DYCzGGKF.js +0 -286
  278. package/dist/state/index.d.ts +0 -31
  279. package/dist/state/subscription-manager.d.ts +0 -180
  280. package/dist/state/types.d.ts +0 -144
  281. package/dist/state.d.ts +0 -2
  282. package/dist/state.js +0 -21
  283. package/dist/subscription-manager-705bls97.js +0 -171
@@ -1,57 +1,5 @@
1
- import { FormSchema } from './deep-schema';
2
- import { FormNode } from '../nodes/form-node';
3
- export type { FormValue, ValidatorFn, AsyncValidatorOptions, AsyncValidatorFn, ValidationError, ErrorFilterOptions, FieldStatus, } from './contracts';
4
- export type { FieldConfig } from './deep-schema';
5
- export type { Validator, ValidateOptions } from './validation-schema';
6
- export type { FormSchema } from './deep-schema';
7
- export type { FormSchemaNode, SchemaArrayControl } from './schema-node';
8
- export type { FormControlsProxy, FormProxy, FormArrayProxy } from './form-proxy';
9
- /**
10
- * Конфигурация GroupNode.
11
- *
12
- * Под M1 группа создаётся из плоской {@link FormSchema} (дерево field-конфигов). Обёртка
13
- * `{ form }` сохранена для совместимости вызова, legacy behavior/validation-схемы удалены (Ф7).
14
- *
15
- * @group Types
16
- * @category Configuration Types
17
- */
18
- export interface GroupNodeConfig<T> {
19
- /** Схема структуры формы (поля и их конфигурация) */
20
- form: FormSchema<T>;
21
- }
22
- /**
23
- * Тип для Record с unknown значениями
24
- * Используется вместо инлайнового `Record<string, unknown>`
25
- * @internal
26
- */
27
- export type UnknownRecord = Record<string, unknown>;
28
- /**
29
- * Интерфейс для узлов, похожих на ArrayNode (с методом at)
30
- * Используется для duck typing при обходе путей
31
- * @internal
32
- */
33
- export interface ArrayNodeLike {
34
- at(index: number): FormNode<unknown> | undefined;
35
- length: unknown;
36
- }
37
- /**
38
- * Конфиг с полем schema (для ArrayConfig)
39
- * @internal
40
- */
41
- export interface ConfigWithSchema {
42
- schema: unknown;
43
- initialItems?: unknown[];
44
- }
45
- /**
46
- * Конфиг с полем value (для извлечения значений)
47
- * @internal
48
- */
49
- export interface ConfigWithValue {
50
- value: unknown;
51
- }
52
- /**
53
- * Тип для проверки на функцию в conditional types
54
- * Используется вместо Function для type narrowing
55
- * @internal
56
- */
57
- export type AnyFunction = (...args: never[]) => unknown;
1
+ export type { ValidationIssue } from './contracts';
2
+ export type { FieldConfig } from './field-config';
3
+ export type { RuleOptions } from './validation-schema';
4
+ export type { ComponentRef, FormSchemaNode, SchemaFieldNode, SchemaArrayNode, SchemaPartNode, SchemaContainerNode, SchemaChild, SchemaValueHandle, SchemaArrayHandle, SchemaGroupHandle, SchemaArrayControl, } from './schema-node';
5
+ export type { FormNode, FormControl, FormGroup, FormArray, FormFields } from './nodes';
@@ -0,0 +1,159 @@
1
+ import { ReadonlySignal } from '@preact/signals-core';
2
+ import { ValidationIssue } from './contracts';
3
+ import { ComponentRef } from './schema-node';
4
+ /**
5
+ * Общий контракт ноды формы — поля, группы и массива под-форм.
6
+ *
7
+ * Значением нода не владеет: источник истины — модель (`model.$.<путь>`), нода держит состояние
8
+ * взаимодействия (`touched`, `dirty`), доступность и замечания валидации.
9
+ *
10
+ * @typeParam T - Значение ноды
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * const { form } = createForm<{ email: string }>({ initial: { email: '' } });
15
+ * form.email.setValue('user@mail.com');
16
+ * form.email.markAsTouched();
17
+ * form.valid.value; // true — замечаний нет
18
+ * ```
19
+ */
20
+ export interface FormNode<T> {
21
+ /** Текущее значение. */
22
+ readonly value: ReadonlySignal<T>;
23
+ /** Замечаний, которые блокируют отправку, нет; нода включена и не ждёт проверки. */
24
+ readonly valid: ReadonlySignal<boolean>;
25
+ /** Есть блокирующие замечания; нода включена и не ждёт проверки. */
26
+ readonly invalid: ReadonlySignal<boolean>;
27
+ /** Идёт асинхронная проверка. */
28
+ readonly pending: ReadonlySignal<boolean>;
29
+ /** Нода отключена: её замечания сняты, в проверку она не входит. */
30
+ readonly disabled: ReadonlySignal<boolean>;
31
+ /** Пользователь взаимодействовал с нодой. */
32
+ readonly touched: ReadonlySignal<boolean>;
33
+ /** Значение меняли после создания или сброса. */
34
+ readonly dirty: ReadonlySignal<boolean>;
35
+ /** Замечания ноды; у группы и массива — свои и всех детей. */
36
+ readonly issues: ReadonlySignal<readonly ValidationIssue[]>;
37
+ /**
38
+ * Собственные замечания ноды — без замечаний детей: у группы и массива это правила на их ручке
39
+ * (`minLength` массива, `cross` группы), у поля — то же, что `issues`.
40
+ */
41
+ readonly ownIssues: ReadonlySignal<readonly ValidationIssue[]>;
42
+ /** Значение без подписки. */
43
+ getValue(): T;
44
+ /** Записать значение в модель. */
45
+ setValue(value: T): void;
46
+ /**
47
+ * Вернуть значение и состояние к начальным; с аргументом — к переданному значению. В цель
48
+ * `compute` значение не пишется (кроме явного `reset(значение)` самого поля): ею владеет
49
+ * поведение — сбрасывается только состояние.
50
+ */
51
+ reset(value?: T): void;
52
+ markAsTouched(): void;
53
+ markAsUntouched(): void;
54
+ enable(): void;
55
+ disable(): void;
56
+ /** Поставить замечания извне (ответ сервера, своя проверка). */
57
+ setIssues(issues: readonly ValidationIssue[]): void;
58
+ clearIssues(): void;
59
+ }
60
+ /**
61
+ * Поле формы: нода над листом модели и состояние его компонента.
62
+ *
63
+ * @typeParam T - Значение поля
64
+ */
65
+ export interface FormControl<T> extends FormNode<T> {
66
+ /** Компонент поля из узла схемы. */
67
+ readonly component: ComponentRef | undefined;
68
+ /** Пропсы компонента: из узла схемы и правок {@link FormControl.updateComponentProps}. */
69
+ readonly componentProps: ReadonlySignal<Readonly<Record<string, unknown>>>;
70
+ /**
71
+ * Показывать ли состояние ошибки (`aria-invalid`, рамка): поле невалидно и его трогали или
72
+ * меняли. Предупреждение (`severity: 'warning'`) поле невалидным не делает — тексты замечаний
73
+ * показывают по {@link FormControl.shouldShowIssues}.
74
+ */
75
+ readonly shouldShowError: ReadonlySignal<boolean>;
76
+ /**
77
+ * Показывать ли тексты замечаний: у поля есть замечания — ошибки или предупреждения, — и его
78
+ * трогали или меняли. Условия те же, что у {@link FormControl.shouldShowError} (не выключено,
79
+ * проверка не идёт), но в счёт идёт любое замечание, а не только блокирующее.
80
+ */
81
+ readonly shouldShowIssues: ReadonlySignal<boolean>;
82
+ /** Слить правку в пропсы компонента (например, опции после загрузки справочника). */
83
+ updateComponentProps(patch: Record<string, unknown>): void;
84
+ }
85
+ /**
86
+ * Массив под-форм: строка — {@link FormGroup} над элементом массива модели.
87
+ *
88
+ * Данными массив не владеет: мутации уходят в массив модели, формы строк держатся за под-модели
89
+ * и при `move`/`swap` не пересоздаются.
90
+ *
91
+ * Индексы (`at`, `keyAt`, `insert`, `removeAt`, `move`, `swap`) — по строкам формы. Элемент `null`
92
+ * в массиве модели строкой не становится, и индекс строки может не совпасть с индексом модели.
93
+ *
94
+ * @typeParam T - Элемент массива
95
+ */
96
+ export interface FormArray<T extends object> extends FormNode<T[]> {
97
+ /** Число строк; чтение в эффекте или `computed` подписывает на изменения. */
98
+ readonly length: number;
99
+ at(index: number): FormGroup<T> | undefined;
100
+ map<R>(callback: (row: FormGroup<T>, index: number) => R): R[];
101
+ forEach(callback: (row: FormGroup<T>, index: number) => void): void;
102
+ /** Стабильный ключ строки: держится за элемент модели и не меняется при `move` и `swap`. */
103
+ keyAt(index: number): string;
104
+ /** Добавить строку; без значения — по шаблону массива модели (`arrayOf(blank)`). */
105
+ push(item?: T): void;
106
+ insert(index: number, item?: T): void;
107
+ removeAt(index: number): void;
108
+ move(from: number, to: number): void;
109
+ swap(first: number, second: number): void;
110
+ clear(): void;
111
+ }
112
+ /**
113
+ * Признак «объект-группа»: обычный объект, а не массив, дата, файл, функция или примитив.
114
+ * `extends object` ловит и `interface`, и `type` (интерфейс не приводится к `Record`).
115
+ * Значение неизвестной формы (`unknown`, `{}`) — поле: у него нет известных полей, и словарь
116
+ * `Record<string, unknown>` остаётся группой полей, а не группой групп — иначе такая группа не
117
+ * приводилась бы к `FormGroup<any>` внутри обобщённых типов (контекст React, элементы списка).
118
+ *
119
+ * @internal
120
+ */
121
+ type IsGroupObject<V> = V extends ReadonlyArray<unknown> ? false : V extends Date | File | Blob ? false : V extends (...args: never[]) => unknown ? false : V extends object ? Record<never, never> extends V ? false : true : false;
122
+ /** `T` — это `any`. @internal */
123
+ type IsAny<T> = 0 extends 1 & T ? true : false;
124
+ /**
125
+ * Ноды полей группы по именам полей данных: массив объектов — {@link FormArray}, объект —
126
+ * {@link FormGroup}, остальное (примитивы, массивы примитивов, даты, файлы) — {@link FormControl}.
127
+ * Опциональность снята: нода есть у каждого поля, опционально лишь значение.
128
+ *
129
+ * `FormFields<any>` — нестрогий словарь: так группа любой формы приводится к `FormGroup<any>`
130
+ * (контекст React, обобщённые компоненты), а не упирается в отображение полей типа `any`.
131
+ *
132
+ * @typeParam T - Значение группы
133
+ */
134
+ export type FormFields<T> = IsAny<T> extends true ? Record<string, any> : {
135
+ [K in keyof T]-?: NonNullable<T[K]> extends ReadonlyArray<infer U> ? IsGroupObject<U> extends true ? FormArray<U & object> : FormControl<T[K]> : IsGroupObject<NonNullable<T[K]>> extends true ? FormGroup<NonNullable<T[K]>> : FormControl<T[K]>;
136
+ };
137
+ /**
138
+ * Группа полей: нода над группой модели и доступ к нодам полей.
139
+ *
140
+ * `form.email` — нода поля; поле с именем члена {@link FormNode} (`value`, `issues`, `reset`, …)
141
+ * недостижимо точкой и доступно через `form.$`: `form.$.value`. Остальные имена полей данных
142
+ * (`id`, `status`, `fields`, `submit`, …) ничем не затенены.
143
+ *
144
+ * @typeParam T - Значение группы
145
+ *
146
+ * @example
147
+ * ```typescript
148
+ * interface Order { status: string; value: number; customer: { name: string } }
149
+ * const { form } = createForm<Order>({ initial: { status: 'new', value: 0, customer: { name: '' } } });
150
+ * form.status.setValue('paid'); // поле данных
151
+ * form.$.value.setValue(100); // поле, затенённое членом ноды
152
+ * form.customer.name.markAsTouched();
153
+ * ```
154
+ */
155
+ export type FormGroup<T> = FormNode<T> & Omit<FormFields<T>, keyof FormNode<T>> & {
156
+ /** Ноды всех полей по имени, включая затенённые членами {@link FormNode}. */
157
+ readonly $: FormFields<T>;
158
+ };
159
+ export {};
@@ -1,8 +1,22 @@
1
- import { ElementType } from 'react';
2
1
  import { Signal } from '../../signals';
3
2
  /**
4
- * Минимальный контракт реактивного массива модели ({@link FormSchemaNode.array}).
5
- * Совпадает по форме с рантайм-фасадом `model.<array>` (см. `ModelArray`); рендерерский
3
+ * Ссылка на компонент узла схемы: то, что слой представления умеет нарисовать. Для React это
4
+ * компонент (функция либо объект `forwardRef`/`memo`) или имя HTML-тега (`'div'`, `'h3'`).
5
+ *
6
+ * Ядро ссылку не интерпретирует и о слое представления не знает: она доезжает до рендерера как
7
+ * есть, а к типу своего UI-слоя её приводит уже он.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const byComponent: ComponentRef = Input; // React-компонент
12
+ * const byTag: ComponentRef = 'section'; // HTML-тег
13
+ * ```
14
+ *
15
+ * @group Types
16
+ */
17
+ export type ComponentRef = string | object;
18
+ /**
19
+ * Контракт реактивного массива модели — фасада `model.<массив>`. Рендерерский
6
20
  * `RenderModelArrayControl` — его расширение (добавляет `move`).
7
21
  *
8
22
  * @group Types
@@ -13,68 +27,155 @@ export interface SchemaArrayControl {
13
27
  /** Реактивная длина. */
14
28
  readonly length: number;
15
29
  at(index: number): unknown;
16
- push(item: unknown): void;
30
+ push(item?: unknown): void;
17
31
  removeAt(index: number): void;
18
32
  }
19
33
  /**
20
- * Узел единой схемы M1 — layout-дерево, обходимое `createForm({ model, schema })`
21
- * и рендерерами (schema-валидация живёт отдельно — `@reformer/core/validation`).
34
+ * Ручка значения из дерева `model.$`: лист (`model.$.email`) или массив целиком
35
+ * (`model.$.tags`). Группа ручкой значения не является — у неё нет пути.
22
36
  *
23
- * Узел совмещает несколько ролей (различаются рантаймом по форме):
24
- * - **поле** — несёт `value: Signal` (сигнал модели `model.$.x`) + `component`/`validators`;
25
- * - **массив** — `{ array: model.<path>, item(itemModel) }`;
26
- * - **контейнер/ветка** — вложенные узлы (`children`), опц. условие `when`;
27
- * - **record-of-fields** — под-узлы под произвольными именованными ключами (индексная сигнатура).
37
+ * @group Types
38
+ */
39
+ export type SchemaValueHandle = Signal<any> & {
40
+ readonly __path: string;
41
+ };
42
+ /**
43
+ * Ручка массива из дерева `model.$` (`model.$.phones`) — ручка значения с длиной.
28
44
  *
29
- * Индексная сигнатура (`[key: string]: unknown`) отражает свободный рекурсивный обход: под-узлы
30
- * допустимы под любым ключом. Известные поля типизированы (даёт автокомплит и проверку их типов).
45
+ * @group Types
46
+ */
47
+ export type SchemaArrayHandle = SchemaValueHandle & {
48
+ readonly length: number;
49
+ };
50
+ /**
51
+ * Ручка группы из дерева `model.$` (`model.$.address`).
31
52
  *
32
53
  * @group Types
33
54
  */
34
- export interface FormSchemaNode {
55
+ export interface SchemaGroupHandle {
56
+ peek(): object | null | undefined;
57
+ /** Признак «не ручка значения»: у листа и массива путь есть, у группы — нет. */
58
+ readonly __path?: never;
59
+ }
60
+ /** Ключи, общие для узла любого вида. */
61
+ interface SchemaNodeBase {
35
62
  /**
36
- * «Ручка» значения поля — маркер узла-поля. Обычно сигнал модели (`model.$.<path>`), но форма
37
- * зависит от таргета (для массива `model.$.x` — дерево сигналов; в renderer-типах сужается до
38
- * `Signal`). Движок разбирает узел как поле рантаймом по `value instanceof Signal`.
63
+ * UI-компонент либо нативный HTML-тег (`'div'`, `'p'`, `'h3'`) для презентационной вёрстки
64
+ * прямо в схеме. Опционален: ядро работает без UI и `component` не интерпретирует — он доезжает
65
+ * до рендерера как есть.
39
66
  */
40
- value?: unknown;
67
+ component?: ComponentRef;
41
68
  /**
42
- * UI-компонент либо нативный HTML-тег (`'div'`, `'p'`, `'h3'`) для презентационной вёрстки
43
- * прямо в схеме. Опционален: core-часть работает без UI (значение/валидация) и `component`
44
- * не интерпретирует — он доезжает до рендерера как есть.
69
+ * Пропсы компонента. Вложенных узлов здесь нет: обход схемы в пропсы не заглядывает, дети узла
70
+ * пишутся в `children`.
45
71
  */
46
- component?: ElementType;
47
- /** Props компонента. Также «клапан» для вложенности под-узлов (напр. steps визарда). */
48
72
  componentProps?: Record<string, unknown>;
49
- updateOn?: 'change' | 'blur' | 'submit';
50
- disabled?: boolean;
51
- /** Задержка (мс) перед запуском асинхронной валидации. */
52
- debounce?: number;
53
- /** Идентификатор узла (для wizard/tabs/renderBehavior). */
73
+ /** Идентификатор узла: по нему узел адресуют поведение (`schema.node(...)`) и шаги визарда. */
54
74
  selector?: string;
55
75
  /**
56
- * ⚠️ Рантайм этого поля НЕ ЧИТАЕТ — `renderer-react` берёт testId из `componentProps.testId`
57
- * (иначе выводит из пути сигнала). Поле оставлено только потому, что `RenderSchemaNode`
58
- * рендерера объявляет свой одноимённый; пишите `componentProps: { testId: '…' }`.
76
+ * Прежний ключ привязки поля — его нет: пишите `model: model.$.<поле>`.
77
+ *
78
+ * Запрет объявлен явно: в `children` узел стоит в объединении с реактивным текстом
79
+ * (`Signal`, у которого есть `value`), и без него прежний ключ проходил проверку лишних ключей.
59
80
  */
60
- testId?: string;
81
+ value?: never;
82
+ /** Прежний ключ привязки массива — его нет: пишите `model: model.$.<массив>` вместе с `item`. */
83
+ array?: never;
84
+ }
85
+ /**
86
+ * Поле: узел, привязанный к ручке значения — листу или массиву целиком (мультивыбор, теги, файлы).
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * { model: model.$.email, component: Input, componentProps: { label: 'Email' } }
91
+ * ```
92
+ *
93
+ * @group Types
94
+ */
95
+ export interface SchemaFieldNode extends SchemaNodeBase {
96
+ /** Привязка поля — ручка значения `model.$.<лист | массив>`. */
97
+ model: SchemaValueHandle;
61
98
  /**
62
- * Содержимое узла: под-узлы (даёт контекстную типизацию вложенным литералам — value/validators/when)
63
- * и текстовые части. Текст (литерал, число, сигнал модели) — такой же ребёнок, как узел: core его
64
- * не интерпретирует (обход пропускает примитивы и не спускается внутрь сигнала), а рендерер
65
- * выводит на своём месте в порядке следования.
99
+ * Поле создаётся отключённым — и остаётся: это постоянная блокировка (вычисляемые `total`,
100
+ * `fullName`). `enable()` группы, массива или формы её не снимает; снимает только явный
101
+ * `enable()` самого поля либо оператор `enableWhen` на нём.
66
102
  */
67
- children?: readonly (FormSchemaNode | string | number | Signal<any>)[];
68
- /** Реактивный массив модели (`model.<path>`) — маркер узла-массива (вместе с `item`). */
69
- array?: SchemaArrayControl;
70
- /** Схема элемента массива: под-модель элемента → узел поддерева. */
71
- item?: (itemModel: any) => FormSchemaNode;
103
+ disabled?: boolean;
104
+ item?: never;
105
+ part?: never;
106
+ children?: never;
107
+ }
108
+ /**
109
+ * Массив под-форм: у каждой строки своя форма, разметку строки строит `item`.
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * { model: model.$.phones, component: FieldArray, item: (row) => ({ children: [...] }) }
114
+ * ```
115
+ *
116
+ * @group Types
117
+ */
118
+ export interface SchemaArrayNode extends SchemaNodeBase {
119
+ /** Привязка — ручка массива `model.$.<массив>`. */
120
+ model: SchemaArrayHandle;
121
+ /** Схема строки: под-модель строки → узел поддерева. */
122
+ item: (model: any) => FormSchemaNode;
72
123
  /**
73
- * Значение нового элемента массива для кнопки «Добавить»: либо готовое значение,
74
- * либо фабрика `() => value`. Тип не различает варианты (union `unknown | (() => unknown)`
75
- * схлопывается в `unknown`) — рантайм различает по `typeof initialValue === 'function'`.
124
+ * Шаблон нового элемента массива для кнопки «Добавить»: либо готовое значение, либо фабрика
125
+ * `() => value`. Запасной путь — для форм, чья модель создаётся из данных без кода: шаблон,
126
+ * объявленный в модели (`arrayOf(blank)`), главнее.
127
+ *
128
+ * Тип не различает варианты (union `unknown | (() => unknown)` схлопывается в `unknown`) —
129
+ * рантайм различает по `typeof initialValue === 'function'`.
76
130
  */
77
131
  initialValue?: unknown;
78
- /** Свободная вложенность: record-of-fields и произвольные под-узлы. */
79
- [key: string]: unknown;
132
+ part?: never;
133
+ children?: never;
134
+ }
135
+ /**
136
+ * Подформа: часть схемы, подключённая к группе модели. Часть объявляется один раз и подключается
137
+ * к любой группе той же формы данных; привязки внутри части идут через `$` полученной под-модели.
138
+ *
139
+ * @example
140
+ * ```ts
141
+ * { model: model.$.registrationAddress, part: address }
142
+ * ```
143
+ *
144
+ * @group Types
145
+ */
146
+ export interface SchemaPartNode extends SchemaNodeBase {
147
+ /** Привязка — ручка группы `model.$.<группа>`. */
148
+ model: SchemaGroupHandle;
149
+ /** Часть схемы: под-модель группы → узел поддерева. */
150
+ part: (model: any) => FormSchemaNode;
151
+ item?: never;
152
+ children?: never;
153
+ }
154
+ /** Ребёнок контейнера: вложенный узел либо текстовая часть — литерал, число, сигнал модели. */
155
+ export type SchemaChild = FormSchemaNode | string | number | Signal<any>;
156
+ /**
157
+ * Контейнер: узел с детьми (секция, шаг визарда, html-тег). Текст — такой же ребёнок, как узел:
158
+ * ядро его не интерпретирует, а рендерер выводит на своём месте в порядке следования.
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * { component: Section, componentProps: { title: 'Контакты' }, children: [phoneField, emailField] }
163
+ * ```
164
+ *
165
+ * @group Types
166
+ */
167
+ export interface SchemaContainerNode extends SchemaNodeBase {
168
+ children?: readonly SchemaChild[];
169
+ model?: never;
170
+ item?: never;
171
+ part?: never;
80
172
  }
173
+ /**
174
+ * Узел схемы формы: поле, массив под-форм, подформа или контейнер — см. описание модуля.
175
+ *
176
+ * Тип закрыт: опечатка в ключе, группа без `part` и `item` не на массиве — ошибки компиляции.
177
+ *
178
+ * @group Types
179
+ */
180
+ export type FormSchemaNode = SchemaFieldNode | SchemaArrayNode | SchemaPartNode | SchemaContainerNode;
181
+ export {};
@@ -1,24 +1,32 @@
1
- import { FormValue, ValidationError } from './index';
2
- import { FormModel } from '../../state/types';
3
1
  /**
4
- * Чистый синхронный валидатор поля (legacy-сигнатура `(value, scope, root)`).
2
+ * Типы фабрик валидаторов (`@reformer/core/validators`).
5
3
  *
6
- * @deprecated Осиротевший остаток удалённого дерево-движка (`validateFormModel`). Живой контракт —
7
- * `Rule<T> = (value) => ValidationError | null` из `@reformer/core/validation`: правила
8
- * передаются в `validate(sig, [rules])` внутри `defineValidationSchema` и запускаются
9
- * `validateModel(model, schema)`. Cross-field — оператор `cross(sig, (f) => …)` над снапшотом
10
- * `model.get()` (третий аргумент `root` больше не нужен). Тип экспортируется только ради
11
- * обратной совместимости (`SchemaValidator`-union).
4
+ * Контракт валидации — `@reformer/core/validation`: `defineValidation` + операторы
5
+ * (`validate`/`validateAsync`/`validateWhen`/`cross`/`apply`/`applyEach`) и раннер
6
+ * `validateModel(model, definition)`; правила там — `Rule<T> = (value) => issue | null`.
12
7
  */
13
- export type Validator<TForm, TField> = (value: TField, scope: unknown, root: FormModel<TForm>) => ValidationError | null;
14
8
  /**
15
9
  * Опции валидатора-фабрики (`required()`/`pattern()`/…). Передаются вторым (или последним)
16
- * аргументом в фабрику и попадают в возвращаемую {@link ValidationError}.
10
+ * аргументом в фабрику и попадают в возвращаемое {@link ValidationIssue}.
11
+ *
12
+ * Текста среди опций нет: правило сообщает только код и параметры, а строку по коду даёт слой
13
+ * представления (`resolveIssueMessage` из `@reformer/core/i18n`). Нужен свой текст для
14
+ * конкретного поля — дайте правилу свой код и запись в словаре формы.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * // правило
19
+ * required({ code: 'loanAmount.required' });
20
+ * // словарь формы (`defineIssueMessages`)
21
+ * const messages = defineIssueMessages({ 'loanAmount.required': 'Укажите сумму кредита' });
22
+ * ```
17
23
  */
18
- export interface ValidateOptions {
19
- /** Готовое сообщение об ошибке. Если не задано, валидаторы кладут `''`, и отображаемый текст
20
- * резолвится из `code` (см. резолвер сообщений в `@reformer/cdk`). */
21
- message?: string;
22
- /** Параметры ошибки (подстановка в шаблон сообщения / i18n). */
23
- params?: Record<string, FormValue>;
24
+ export interface RuleOptions {
25
+ /**
26
+ * Свой код вместо встроенного. По нему текст ищется сначала в словаре формы, затем в локали
27
+ * (`validation.<code>`); принято именовать `<поле>.<правило>`.
28
+ */
29
+ code?: string;
30
+ /** Дополнительные параметры замечания: подставляются в текст поверх параметров правила. */
31
+ params?: Readonly<Record<string, unknown>>;
24
32
  }
@@ -0,0 +1,67 @@
1
+ import { FormModel, PathAwareSignal } from '../../model/types';
2
+ import { ValidationIssue } from '../types/contracts';
3
+ import { ValidationFailure } from './types';
4
+ /** Сток одного прогона: модель scope, накопленные ошибки, незавершённые async-правила, гейты. */
5
+ export interface VContext {
6
+ /**
7
+ * Модель текущей области — источник снапшота для `cross` и модель для `apply`. В корне прогона
8
+ * это вся модель; внутри `apply(ручка, схема)` / `applyEach` — под-модель группы или строки.
9
+ */
10
+ model: FormModel<unknown>;
11
+ /**
12
+ * Накопленные ошибки по сигналу (ключ — идентичность `PathAwareSignal`). Здесь и поля выключенной
13
+ * ветки `validateWhen` — с пустым списком: при разносе их прежние ошибки гасятся.
14
+ */
15
+ issues: Map<PathAwareSignal<unknown>, ValidationIssue[]>;
16
+ /**
17
+ * Поля, правила которых в этом прогоне действительно выполнялись — ветка активна. Только их разнос
18
+ * с `touch` помечает тронутыми: поле выключенной ветки пользователь не видел.
19
+ */
20
+ checked: Set<PathAwareSignal<unknown>>;
21
+ /** Незавершённые async-правила (раннер их дожидается). */
22
+ pending: Promise<void>[];
23
+ /** Поля с async-правилами: на время ожидания раннер держит их ноды в `pending`. */
24
+ asyncFields: Set<PathAwareSignal<unknown>>;
25
+ /**
26
+ * Правила, которые не вернули результат. Список — один на весь прогон: области `apply` /
27
+ * `applyEach` получают поверхностную копию контекста и пишут в ту же ссылку.
28
+ */
29
+ failures: ValidationFailure[];
30
+ /** Стек активных условий `validateWhen` (все должны быть истинны, чтобы правило сработало). */
31
+ whenStack: Array<() => boolean>;
32
+ /** Отмена устаревшего прогона: прокидывается в async-правила, гасит роутинг после await. */
33
+ signal: AbortSignal;
34
+ /**
35
+ * Определение, правила которого исполняются сейчас: корень прогона либо схема, подключённая
36
+ * `apply` / `applyEach`. Замечание помечается им: так разнос отличает замечания одного
37
+ * определения, полученные разными прогонами (шаг и вся форма), от замечаний чужого.
38
+ */
39
+ origin: object;
40
+ /** Замечания по полю и определению-источнику. Одна ссылка на весь прогон, как `failures`. */
41
+ origins: Map<PathAwareSignal<unknown>, Map<object, ValidationIssue[]>>;
42
+ /** Определения, исполненные в прогоне: за их замечания на проверенных полях прогон отвечает. */
43
+ executed: Set<object>;
44
+ }
45
+ /**
46
+ * Открыть ambient-окно на время `fn` и закрыть его в `finally`.
47
+ *
48
+ * Единственный способ установить контекст: прямое присваивание `current` из другого модуля
49
+ * невозможно. Сохранение/восстановление `prev` делает вложенный прогон безопасным.
50
+ */
51
+ export declare function runWithContext<R>(ctx: VContext, fn: () => R): R;
52
+ /** Контекст активного прогона либо понятная ошибка, если оператор вызван вне схемы. */
53
+ export declare function requireCtx(op: string): VContext;
54
+ /**
55
+ * «Тронуть» сигнал: гарантирует его наличие в замечаниях прогона (даже пустым) → он попадёт в
56
+ * очистку. Возвращает список текущего определения ({@link VContext.origin}): в него и пишут правила.
57
+ */
58
+ export declare function touch(ctx: VContext, sig: PathAwareSignal<unknown>): ValidationIssue[];
59
+ /** Исполнить определение: его замечания помечаются им же. */
60
+ export declare function withOrigin(ctx: VContext, origin: object, fn: () => void): void;
61
+ /** Активна ли текущая ветка (все `validateWhen`-условия истинны). */
62
+ export declare const gated: (ctx: VContext) => boolean;
63
+ /**
64
+ * Правила поля выполняются: ветка активна. Поле запоминается проверенным ({@link VContext.checked}).
65
+ * Без активной ветки — `false`, и поле остаётся только в `issues` для гашения.
66
+ */
67
+ export declare function checking(ctx: VContext, sig: PathAwareSignal<unknown>): boolean;
@@ -1,28 +1,24 @@
1
- export { required } from './validators/required';
2
- export { min } from './validators/min';
3
- export { max } from './validators/max';
4
- export { minLength } from './validators/min-length';
5
- export { maxLength } from './validators/max-length';
6
- export { email } from './validators/email';
7
- export { pattern } from './validators/pattern';
8
- export { url } from './validators/url';
9
- export { phone, type PhoneFormat } from './validators/phone';
10
- export { isNumber } from './validators/is-number';
11
- export { integer } from './validators/integer';
12
- export { multipleOf } from './validators/multiple-of';
13
- export { nonNegative } from './validators/non-negative';
14
- export { nonZero } from './validators/non-zero';
15
- export { isDate } from './validators/is-date';
16
- export { minDate } from './validators/min-date';
17
- export { maxDate } from './validators/max-date';
18
- export { pastDate } from './validators/past-date';
19
- export { futureDate } from './validators/future-date';
20
- export { minAge } from './validators/min-age';
21
- export { maxAge } from './validators/max-age';
22
- export { maxFileSize } from './validators/max-file-size';
23
- export { minFileSize } from './validators/min-file-size';
24
- export { fileType } from './validators/file-type';
25
- export { maxFiles } from './validators/max-files';
26
- export { minFiles } from './validators/min-files';
27
- export { maxTotalFileSize } from './validators/max-total-file-size';
28
- export { isFileLike, matchesFileAccept, toFileArray, type FileLike } from './validators/file-utils';
1
+ /**
2
+ * Декларативный контракт СХЕМЫ ВАЛИДАЦИИ — `@reformer/core/validation`.
3
+ *
4
+ * Схема валидации — обычная функция `({ model, cross }) => void`. Внутри вызываются свободные операторы
5
+ * (`validate`/`validateAsync`/`validateWhen`/`apply`/`applyEach`) и `cross` области, которые САМИ пишут ошибки в
6
+ * ambient-сток текущего прогона — автор не видит ни коллектора, ни `getNodeForSignal`, ни `.push`.
7
+ * Раннер открывает ambient-окно на время СИНХРОННОГО прогона схемы и дожидается async-правил
8
+ * ({@link runValidation} — сбор результата), затем разносит ошибки по нодам формы, гася поля, ставшие
9
+ * валидными ({@link applyValidationResult}); {@link validateModel} делает оба шага и отвечает `boolean`.
10
+ *
11
+ * Зеркалит контракт поведения (`@reformer/core/behaviors`): тот же ambient-стиль, но отдельный слой —
12
+ * валидация НЕ реактивна (прогон по требованию: submit/шаг), поведение — реактивно (живые подписки).
13
+ *
14
+ * Модуль разложен по зонам ответственности: `./types` — контракт правил и схемы, `./context` —
15
+ * ambient-сток прогона, `./operators` — операторы схемы, `./run` — раннер, `./strategy` — КОГДА
16
+ * запускать (реэкспортируется отсюда, тот же сабпат).
17
+ *
18
+ * @group Validation
19
+ * @module form/validation
20
+ */
21
+ export type { Rule, AsyncRule, ValidationDefinition, ValidationScope, ValidationStatus, ValidationFailure, ValidationResult, } from './types';
22
+ export { validate, validateAsync, validateWhen, apply, applyEach } from './operators';
23
+ export { defineValidation, runValidation, applyValidationResult, validateModel } from './run';
24
+ export * from './strategy';