@reformer/core 11.0.0-beta.7 → 11.0.0-beta.9

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 (226) hide show
  1. package/README.md +90 -68
  2. package/dist/behaviors-value-HA_Q03hc.js +108 -0
  3. package/dist/behaviors.js +382 -217
  4. package/dist/create-model-BvcbNPgL.js +30 -0
  5. package/dist/date-utils-90-qZbse.js +43 -0
  6. package/dist/{en-CjAqn7h0.js → en-HP8XEych.js} +6 -3
  7. package/dist/form/aggregate-signals.d.ts +21 -63
  8. package/dist/form/behaviors/collections.d.ts +42 -8
  9. package/dist/form/behaviors/context.d.ts +37 -4
  10. package/dist/form/behaviors/index.d.ts +6 -4
  11. package/dist/form/behaviors/internals.d.ts +9 -3
  12. package/dist/form/behaviors/node.d.ts +25 -2
  13. package/dist/form/behaviors/operators.d.ts +17 -9
  14. package/dist/form/behaviors/schema-operators.d.ts +78 -0
  15. package/dist/form/behaviors/types.d.ts +25 -5
  16. package/dist/form/create-form.d.ts +57 -70
  17. package/dist/form/flow/flow.d.ts +87 -0
  18. package/dist/form/form-bundle.d.ts +153 -0
  19. package/dist/form/form-config-base.d.ts +46 -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 +20 -20
  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 +153 -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 +19 -92
  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 +23 -27
  47. package/dist/form/validation/context.d.ts +46 -6
  48. package/dist/form/validation/index.d.ts +9 -8
  49. package/dist/form/validation/operators.d.ts +71 -17
  50. package/dist/form/validation/run.d.ts +93 -18
  51. package/dist/form/validation/strategy.d.ts +41 -13
  52. package/dist/form/validation/types.d.ts +74 -19
  53. package/dist/form/validators/date-utils.d.ts +13 -1
  54. package/dist/form/validators/email.d.ts +8 -7
  55. package/dist/form/validators/file-type.d.ts +8 -7
  56. package/dist/form/validators/file-utils.d.ts +2 -1
  57. package/dist/form/validators/future-date.d.ts +8 -7
  58. package/dist/form/validators/index.d.ts +1 -1
  59. package/dist/form/validators/integer.d.ts +8 -7
  60. package/dist/form/validators/is-date.d.ts +11 -9
  61. package/dist/form/validators/is-number.d.ts +11 -9
  62. package/dist/form/validators/max-age.d.ts +13 -9
  63. package/dist/form/validators/max-date.d.ts +8 -7
  64. package/dist/form/validators/max-file-size.d.ts +8 -7
  65. package/dist/form/validators/max-files.d.ts +8 -7
  66. package/dist/form/validators/max-length.d.ts +14 -7
  67. package/dist/form/validators/max-total-file-size.d.ts +8 -7
  68. package/dist/form/validators/max.d.ts +10 -8
  69. package/dist/form/validators/min-age.d.ts +12 -9
  70. package/dist/form/validators/min-date.d.ts +8 -7
  71. package/dist/form/validators/min-file-size.d.ts +8 -7
  72. package/dist/form/validators/min-files.d.ts +11 -9
  73. package/dist/form/validators/min-length.d.ts +14 -7
  74. package/dist/form/validators/min.d.ts +10 -8
  75. package/dist/form/validators/multiple-of.d.ts +10 -8
  76. package/dist/form/validators/non-negative.d.ts +8 -7
  77. package/dist/form/validators/non-zero.d.ts +8 -7
  78. package/dist/form/validators/past-date.d.ts +8 -7
  79. package/dist/form/validators/pattern.d.ts +9 -8
  80. package/dist/form/validators/phone.d.ts +8 -7
  81. package/dist/form/validators/required.d.ts +11 -9
  82. package/dist/form/validators/url.d.ts +20 -13
  83. package/dist/form/validators/validation-issue.d.ts +8 -0
  84. package/dist/i18n/descriptor.d.ts +1 -1
  85. package/dist/i18n/en.json.d.ts +5 -1
  86. package/dist/i18n/locale-store.d.ts +7 -0
  87. package/dist/i18n/message-format.d.ts +24 -4
  88. package/dist/i18n/ru.json.d.ts +5 -1
  89. package/dist/i18n/translator.d.ts +11 -0
  90. package/dist/i18n/validation-message.d.ts +42 -7
  91. package/dist/i18n.d.ts +7 -12
  92. package/dist/i18n.js +66 -283
  93. package/dist/index.d.ts +16 -7
  94. package/dist/index.js +958 -2798
  95. package/dist/loader-BWkigpVe.js +52 -0
  96. package/dist/locale/en.js +1 -1
  97. package/dist/locale/en.json +4 -1
  98. package/dist/locale/ru.js +4 -1
  99. package/dist/locale/ru.json +4 -1
  100. package/dist/locale-CG54AU2Q.js +219 -0
  101. package/dist/locale.js +1 -1
  102. package/dist/model/behaviors-value.d.ts +24 -6
  103. package/dist/model/create-model.d.ts +2 -2
  104. package/dist/model/derived-registry.d.ts +1 -1
  105. package/dist/model/index.d.ts +16 -5
  106. package/dist/model/model-nodes.d.ts +138 -8
  107. package/dist/model/model-signals-proxy.d.ts +11 -5
  108. package/dist/model/model-value-proxy.d.ts +84 -3
  109. package/dist/model/safe-effect.d.ts +33 -1
  110. package/dist/model/types.d.ts +70 -17
  111. package/dist/model.js +21 -17
  112. package/dist/node-kind-C-r6ZMdo.js +15 -0
  113. package/dist/platforms/react/field-binding/field-adapter.d.ts +1 -1
  114. package/dist/platforms/react/field-binding/field-handle.d.ts +5 -2
  115. package/dist/platforms/react/form-bundle-context.d.ts +27 -0
  116. package/dist/platforms/react/hooks/types.d.ts +57 -38
  117. package/dist/platforms/react/hooks/use-form-bundle.d.ts +19 -4
  118. package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
  119. package/dist/platforms/react/hooks/use-form-validation.d.ts +12 -6
  120. package/dist/platforms/react/hooks/useArrayLength.d.ts +6 -6
  121. package/dist/platforms/react/hooks/useFormControl.d.ts +7 -9
  122. package/dist/platforms/react/hooks/useFormControlValue.d.ts +18 -19
  123. package/dist/platforms/react/hooks/useSignalSubscription.d.ts +9 -1
  124. package/dist/platforms/react/i18n/context.d.ts +6 -1
  125. package/dist/platforms/react/i18n/hooks.d.ts +16 -10
  126. package/dist/platforms/react/i18n/provider.d.ts +9 -2
  127. package/dist/platforms/react/index.d.ts +7 -4
  128. package/dist/react.d.ts +22 -0
  129. package/dist/react.js +505 -0
  130. package/dist/runtime-token.d.ts +1 -2
  131. package/dist/safe-effect-BbtX3KuN.js +643 -0
  132. package/dist/schema-controller-CpiO2JoK.js +143 -0
  133. package/dist/signals.d.ts +15 -9
  134. package/dist/signals.js +11 -6
  135. package/dist/strategy-CoFSemuP.js +375 -0
  136. package/dist/type-guards-D-N_5Ddh.js +19 -0
  137. package/dist/validation-issue-B9mjI8jz.js +7 -0
  138. package/dist/validation-message-Ced9MGxs.js +194 -0
  139. package/dist/validation.js +9 -8
  140. package/dist/validators/email.js +5 -5
  141. package/dist/validators/future-date.js +8 -8
  142. package/dist/validators/integer.js +3 -3
  143. package/dist/validators/is-date.js +4 -4
  144. package/dist/validators/is-number.js +4 -4
  145. package/dist/validators/max-age.js +8 -9
  146. package/dist/validators/max-date.js +8 -8
  147. package/dist/validators/max-length.js +7 -7
  148. package/dist/validators/max.js +4 -4
  149. package/dist/validators/min-age.js +10 -8
  150. package/dist/validators/min-date.js +3 -3
  151. package/dist/validators/min-length.js +5 -5
  152. package/dist/validators/min.js +4 -4
  153. package/dist/validators/multiple-of.js +11 -7
  154. package/dist/validators/non-negative.js +3 -3
  155. package/dist/validators/non-zero.js +3 -3
  156. package/dist/validators/past-date.js +8 -8
  157. package/dist/validators/pattern.js +5 -5
  158. package/dist/validators/phone.js +11 -9
  159. package/dist/validators/required.js +2 -2
  160. package/dist/validators/url.js +48 -12
  161. package/dist/validators.js +17 -17
  162. package/docs/llms/01-api-reference.md +60 -34
  163. package/docs/llms/02-quick-start.md +111 -80
  164. package/docs/llms/03-api-signatures.md +368 -153
  165. package/docs/llms/04-common-patterns.md +58 -56
  166. package/docs/llms/05-common-mistakes.md +69 -44
  167. package/docs/llms/06-troubleshooting.md +14 -9
  168. package/docs/llms/07-complete-import.md +74 -43
  169. package/docs/llms/08-form-types.md +11 -4
  170. package/docs/llms/09-formschema.md +131 -83
  171. package/docs/llms/10-arrays.md +119 -69
  172. package/docs/llms/11-async-watchfield.md +2 -2
  173. package/docs/llms/13-multi-step.md +134 -63
  174. package/docs/llms/14-extended-mistakes.md +20 -17
  175. package/docs/llms/15-project-structure.md +221 -74
  176. package/docs/llms/16-ui-components.md +55 -42
  177. package/docs/llms/17-nonexistent-api.md +199 -32
  178. package/docs/llms/18-conditional-fields.md +66 -32
  179. package/docs/llms/19-reading-values.md +15 -3
  180. package/docs/llms/20-compute-vs-watch.md +16 -10
  181. package/docs/llms/21-array-operations.md +76 -26
  182. package/docs/llms/22-cycle-detection.md +1 -1
  183. package/docs/llms/23-copy-from.md +2 -2
  184. package/docs/llms/24-sync-fields.md +6 -5
  185. package/docs/llms/25-reset-when.md +14 -7
  186. package/docs/llms/26-transform-value.md +4 -4
  187. package/docs/llms/27-revalidate-when.md +16 -15
  188. package/docs/llms/28-submit-and-reset.md +276 -128
  189. package/docs/llms/29-async-preload.md +40 -30
  190. package/docs/llms/30-type-safety-recipes.md +105 -51
  191. package/docs/llms/31-async-validator-debounce.md +96 -53
  192. package/docs/llms/33-validation-strategy.md +178 -66
  193. package/docs/llms/34-i18n.md +69 -43
  194. package/docs/llms/35-unified-contract.md +307 -0
  195. package/docs/llms/36-issue-messages.md +284 -0
  196. package/docs/llms/37-compiled-schema.md +332 -0
  197. package/docs/llms/38-form-flow.md +397 -0
  198. package/llms-index.json +1 -1
  199. package/llms.txt +6968 -3278
  200. package/package.json +23 -4
  201. package/dist/behaviors-value-C7dSEhCc.js +0 -134
  202. package/dist/create-model-B8U-COv-.js +0 -103
  203. package/dist/date-utils-dTT_x_Be.js +0 -31
  204. package/dist/form/create-core-form.d.ts +0 -70
  205. package/dist/form/factories/index.d.ts +0 -6
  206. package/dist/form/factories/node-factory.d.ts +0 -189
  207. package/dist/form/form-submitter.d.ts +0 -121
  208. package/dist/form/nodes/array-node.d.ts +0 -276
  209. package/dist/form/nodes/field-node.d.ts +0 -297
  210. package/dist/form/nodes/form-node.d.ts +0 -326
  211. package/dist/form/nodes/group-node.d.ts +0 -284
  212. package/dist/form/nodes/model-array-node.d.ts +0 -121
  213. package/dist/form/nodes/subscription-manager.d.ts +0 -180
  214. package/dist/form/status-machine.d.ts +0 -115
  215. package/dist/form/types/deep-schema.d.ts +0 -107
  216. package/dist/form/types/form-proxy.d.ts +0 -141
  217. package/dist/form/unique-id.d.ts +0 -45
  218. package/dist/form/validation/config.d.ts +0 -73
  219. package/dist/form/validation/error-handler.d.ts +0 -166
  220. package/dist/form/validators/validation-error.d.ts +0 -8
  221. package/dist/index-BrNkQj1y.js +0 -105
  222. package/dist/loader-Dv_Hl7JC.js +0 -216
  223. package/dist/model-signals-proxy-2vqS243J.js +0 -250
  224. package/dist/node-DGEFMTQu.js +0 -18
  225. package/dist/strategy-BXS_gBfz.js +0 -170
  226. package/dist/validation-error-B-U3RsV0.js +0 -11
@@ -1,5 +1,5 @@
1
- import { FormModel, ModelArray, PathAwareSignal, ValidationError } from '../../index';
2
- import { AsyncRule, Rule, ValidationSchema } from './types';
1
+ import { FormModel, ModelArray, PathAwareSignal } from '../../model/types';
2
+ import { AsyncRule, Rule, ValidationDefinition, ValidationScope } from './types';
3
3
  /**
4
4
  * Синхронные правила поля.
5
5
  *
@@ -8,40 +8,94 @@ import { AsyncRule, Rule, ValidationSchema } from './types';
8
8
  *
9
9
  * @example
10
10
  * ```ts
11
- * validate(model.$.loanAmount, [required({ message: 'Сумма' }), min(50000)]);
11
+ * validate(model.$.loanAmount, [required({ code: 'loanAmount.required' }), min(50000)]);
12
12
  * validate(model.$.tags, [required(), maxLength(3)]); // tags: string[] — массив как значение
13
13
  * ```
14
14
  */
15
15
  export declare function validate<TField>(sig: PathAwareSignal<TField>, rules: Rule<TField>[]): void;
16
16
  /**
17
- * Асинхронные правила поля (зеркалит движковое разделение `validators` / `asyncValidators`).
18
- * Раннер дожидается их и прокидывает `AbortSignal` для отмены устаревших ответов.
17
+ * Асинхронные правила поля. Раннер дожидается их и прокидывает `AbortSignal` для отмены
18
+ * устаревших ответов.
19
+ *
20
+ * Отклонённое правило (сеть, исключение) — сбой проверки: он попадает в `failures` результата
21
+ * прогона, статус прогона становится `error`, а на поле ложится блокирующая ошибка `ruleFailed`
22
+ * (текст — из словаря локали). Отмена устаревшего прогона сбоем не считается.
19
23
  *
20
24
  * @example
21
25
  * ```ts
22
26
  * validateAsync(model.$.username, [async (v, { signal }) => {
23
27
  * const r = await fetch(`/api/free?u=${v}`, { signal });
24
- * return (await r.json()).free ? null : { code: 'taken', message: 'Занято' };
28
+ * return (await r.json()).free ? null : { code: 'taken' };
25
29
  * }]);
26
30
  * ```
27
31
  */
28
32
  export declare function validateAsync<TField>(sig: PathAwareSignal<TField>, rules: AsyncRule<TField>[]): void;
29
33
  /**
30
34
  * Условная валидация: правила внутри `cb` активны, только пока `cond()` истинно; иначе их поля
31
- * ГАСЯТСЯ (пустой bucket → `setErrors([])`). Не трогает включение/сброс поля — это дело поведения (`enableWhen`).
35
+ * ГАСЯТСЯ (пустой bucket → `setIssues([])`). Не трогает включение/сброс поля — это дело поведения (`enableWhen`).
32
36
  */
33
37
  export declare function validateWhen(cond: () => boolean, cb: () => void): void;
34
38
  /**
35
- * Cross-field правило: `fn` получает СНАПШОТ модели текущего scope (`model.get()`) и вешает ошибку на `sig`.
36
- * Для элементов массива / под-моделей захватывайте нужный снапшот в замыкание (`const item = im.get()`),
37
- * т.к. `fn` всегда получает модель ТЕКУЩЕГО scope (корень прогона), а не под-модель.
39
+ * Область схемы над моделью: сама модель и `cross`, снимок которого — эта модель.
40
+ *
41
+ * @internal
42
+ */
43
+ export declare function scopeOf<T>(model: FormModel<T>): ValidationScope<T>;
44
+ /** Привязка к группе: ручка `model.$.<группа>` (тип значения — из её `peek()`). */
45
+ interface GroupBinding<V> {
46
+ peek(): V;
47
+ }
48
+ /** Привязка к массиву под-форм: ручка `model.$.<массив>`. */
49
+ interface ArrayBinding<U> {
50
+ peek(): readonly U[] | null | undefined;
51
+ }
52
+ /**
53
+ * Применить схему к КАЖДОМУ элементу массива под-форм. Схема элемента — обычная
54
+ * `ValidationDefinition` над типом элемента: тот же набор правил подключается и к группе через
55
+ * {@link apply}.
56
+ *
57
+ * У каждого элемента своя область: `cross` внутри схемы получает снапшот элемента.
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const propertyRules = defineValidation<Property>(({ model, cross }) => {
62
+ * validate(model.$.type, [required()]);
63
+ * cross(model.$.estimatedValue, (property) =>
64
+ * property.hasEncumbrance && property.estimatedValue < 100_000 ? tooCheap : null
65
+ * );
66
+ * });
67
+ *
68
+ * applyEach(model.$.properties, propertyRules);
69
+ * ```
70
+ */
71
+ export declare function applyEach<U extends object>(array: ArrayBinding<U> | ModelArray<U>, schema: ValidationDefinition<U>): void;
72
+ /**
73
+ * Подключить схему подформы к группе модели — одной или нескольким.
74
+ *
75
+ * Схема запускается в области группы: `model` в ней — под-модель, `cross` получает снапшот
76
+ * группы. Привязка — ручка `model.$.<группа>`, как у узла-подформы схемы и у `apply` поведения.
77
+ *
78
+ * @example
79
+ * ```ts
80
+ * const addressRules = defineValidation<Address>(({ model }) => {
81
+ * validate(model.$.city, [required()]);
82
+ * });
83
+ *
84
+ * apply(model.$.registrationAddress, addressRules);
85
+ * validateWhen(
86
+ * () => !model.sameAsRegistration,
87
+ * () => apply(model.$.residenceAddress, addressRules)
88
+ * );
89
+ * ```
38
90
  */
39
- export declare function cross<TSnapshot>(sig: PathAwareSignal<unknown>, fn: (form: TSnapshot) => ValidationError | null): void;
91
+ export declare function apply<V extends object | null | undefined>(group: GroupBinding<V> | GroupBinding<V>[], schema: ValidationDefinition<NonNullable<V>>): void;
40
92
  /**
41
- * Применить под-правила к КАЖДОМУ элементу текущего массива модели.
42
- * `U extends object` — элементы должны быть под-моделями (объектами); массив примитивов — одно
43
- * значение поля, его проверяют целиком: `validate(model.$.<массив>, [...])`.
93
+ * Композиция схем над ТОЙ ЖЕ моделью области — так форма собирается из схем шагов.
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * const formRules = defineValidation<Form>(() => apply(loanRules, contactsRules));
98
+ * ```
44
99
  */
45
- export declare function each<U extends object>(arr: ModelArray<U>, itemFn: (item: FormModel<U>) => void): void;
46
- /** Композиция под-схем в текущую (над той же моделью scope). Заменяет пошаговую группировку. */
47
- export declare function apply<T>(...schemas: ValidationSchema<T>[]): void;
100
+ export declare function apply<T>(...schemas: ValidationDefinition<T>[]): void;
101
+ export {};
@@ -1,33 +1,108 @@
1
- import { FormModel } from '../../index';
2
- import { ValidationSchema } from './types';
1
+ import { FormModel } from '../../model/types';
2
+ import { ValidationResult, ValidationDefinition } from './types';
3
3
  /**
4
4
  * Тонкая identity-обёртка для типизации/discoverability (как `defineFormBehavior`). Возвращает схему как есть.
5
5
  *
6
6
  * @example
7
7
  * ```ts
8
- * export const step1 = defineValidationSchema<LoanForm>(({ model }) => {
8
+ * export const step1 = defineValidation<LoanForm>(({ model }) => {
9
9
  * validate(model.$.loanAmount, [required(), min(50000)]);
10
10
  * });
11
11
  * ```
12
12
  */
13
- export declare function defineValidationSchema<T>(schema: ValidationSchema<T>): ValidationSchema<T>;
13
+ export declare function defineValidation<T>(schema: ValidationDefinition<T>): ValidationDefinition<T>;
14
14
  /**
15
- * Провалидировать модель ЛЮБОЙ схемой (шаг или вся форма). Открывает ambient-окно на время
16
- * синхронного прогона `schema`, дожидается async-правил, разносит ошибки по нодам формы и гасит
17
- * поля, ставшие валидными. Возвращает `true`, если нет блокирующих ошибок (`severity:'warning'` не блокирует).
15
+ * Отменить идущий прогон пары (model, schema): его `AbortSignal` срабатывает, ожидание async-правил
16
+ * размыкается, результат получает статус `cancelled` и по нодам не разносится. Контроллер живой
17
+ * проверки зовёт это при снятии — иначе ответ правила лёг бы на ноды уже снятой формы.
18
18
  *
19
- * Гашение — на пару (model, schema): `validateModel(model, step2)` и `validateModel(model, form)` не мешают
20
- * друг другу. Устаревший прогон (быстрый повторный вызов той же (model, schema)) отменяется через `AbortSignal`
21
- * и возвращает `false` (**fail-closed** — отменённому результату нельзя доверять для submit).
19
+ * @internal
20
+ */
21
+ export declare function cancelRun(model: object, schema: object): void;
22
+ /**
23
+ * Какие поля пометить тронутыми при разносе: `false` — никакие, `true` — проверенные правилами,
24
+ * `'all'` — проверенные, а при отказе (`invalid`, `error`) ещё и всю форму.
25
+ *
26
+ * @internal
27
+ */
28
+ export type ValidationTouch = boolean | 'all';
29
+ /** Идёт ли сейчас касание полей от имени проверки ({@link touchByValidation}). @internal */
30
+ export declare const isTouchByValidation: () => boolean;
31
+ /**
32
+ * Собрать результат проверки модели схемой — без формы и без побочных эффектов на нодах.
33
+ *
34
+ * Открывает ambient-окно на время синхронного прогона `schema`, дожидается async-правил и
35
+ * возвращает {@link ValidationResult}. Нод формы не трогает: ошибки по ним разносит
36
+ * {@link applyValidationResult}. Подходит для проверки данных без UI (сервер, тест, предпросмотр).
37
+ *
38
+ * Статус результата:
39
+ * - `cancelled` — прогон устарел: пока он шёл, для той же пары (model, schema) запущен следующий;
40
+ * - `error` — хотя бы одно async-правило не вернуло результат (сеть, исключение) — см. `failures`;
41
+ * - `invalid` — есть блокирующие ошибки (`severity: 'warning'` не блокирует);
42
+ * - `valid` — блокирующих ошибок нет.
43
+ *
44
+ * ⚠️ `schema` должна быть СТАБИЛЬНОЙ ссылкой: отмена устаревших прогонов ключится по идентичности
45
+ * `schema`. Держите схемы в `const` / `defineValidation`.
46
+ *
47
+ * @param model - Модель данных формы.
48
+ * @param schema - Схема валидации (стабильная ссылка).
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const result = await runValidation(model, formRules);
53
+ * if (result.status === 'error') showToast('Не удалось проверить форму, повторите попытку');
54
+ * else if (result.status !== 'cancelled') applyValidationResult(result, { touch: true });
55
+ * ```
56
+ */
57
+ export declare function runValidation<T>(model: FormModel<T>, schema: ValidationDefinition<T>): Promise<ValidationResult>;
58
+ /**
59
+ * Разнести собранный результат по нодам формы: поставить ошибки проверенным полям и погасить поля,
60
+ * которые были с ошибкой в прошлом разнесённом прогоне той же пары (model, schema), а теперь не
61
+ * проверялись (удалённая строка массива, выключенная ветка).
62
+ *
63
+ * Отменённый результат (`status: 'cancelled'`) не разносится: его async-часть оборвана.
64
+ *
65
+ * `options.touch`: пометить `touched` ИМЕННО поля, которые схема проверяла (не всё поддерево):
66
+ * поля выключенной ветки `validateWhen` и, в проверке уровня формы, выключенные поля не метятся —
67
+ * пользователь их не видел, и после включения их ошибка не должна быть видна с первой проверки.
68
+ * Замечания становятся видимыми (`shouldShowIssues`: есть замечания и `touched || dirty`) без
69
+ * ручного `form.markAsTouched()`; при пошаговой валидации следующий шаг не показывается
70
+ * «тронутым».
71
+ *
72
+ * @param result - Результат {@link runValidation}.
73
+ * @param options - `{ touch }` — пометить проверенные поля `touched` для показа ошибок.
74
+ */
75
+ export declare function applyValidationResult(result: ValidationResult, options?: {
76
+ touch?: boolean;
77
+ }): void;
78
+ /**
79
+ * Прогон с разносом и полным результатом — общий движок {@link validateModel}, контроллера
80
+ * стратегии и прогонов шага. На время async-правил держит ноды их полей в `pending`.
81
+ * `skipDisabled` — проверка уровня формы: поля выключенных нод не учитываются.
82
+ *
83
+ * `touch`: `true` — пометить тронутыми проверенные поля; `'all'` — то же, а при отказе (`invalid`,
84
+ * `error`) ещё и всю форму: так попытка отправки раскрывает замечания полей, которых правила не
85
+ * касались. Отменённый результат не разносится и ничего не трогает.
86
+ *
87
+ * @internal
88
+ */
89
+ export declare function runAndApply<T>(model: FormModel<T>, schema: ValidationDefinition<T>, options?: {
90
+ touch?: ValidationTouch;
91
+ skipDisabled?: boolean;
92
+ }): Promise<ValidationResult>;
93
+ /**
94
+ * Провалидировать модель ЛЮБОЙ схемой (шаг или вся форма): собрать результат и разнести ошибки по
95
+ * нодам формы. Возвращает `true` только для статуса `valid`: ошибки, сбой правила и отмена дают
96
+ * `false` (**fail-closed**). Чтобы различить их, берите {@link runValidation} либо
97
+ * `bundle.validate()` / `bundle.validateStep(id)` сборки формы.
22
98
  *
23
- * ⚠️ `schema` должна быть СТАБИЛЬНОЙ ссылкой: отмена устаревших прогонов ключится по идентичности `schema`.
24
- * Инлайн-стрелка (`validateModel(model, ({ model }) => …)`) каждый раз создаёт НОВЫЙ прогон без дедупликации —
25
- * держите схемы в `const` / `defineValidationSchema`.
99
+ * Гашение — на пару (model, schema): `validateModel(model, step2)` и `validateModel(model, form)`
100
+ * не мешают друг другу. Устаревший прогон (быстрый повторный вызов той же (model, schema))
101
+ * отменяется через `AbortSignal`.
26
102
  *
27
- * `options.touch` (§6): по завершении помечает `touched` ИМЕННО поля, которые схема проверяла
28
- * (не всё поддерево). Ошибки становятся видимыми (`shouldShowError = invalid && (touched||dirty)`)
29
- * без ручного `form.markAsTouched()`; при пошаговой валидации следующий шаг не показывается
30
- * «тронутым» до ввода. Валидные проверенные поля тоже метятся — это безвредно (ошибка не покажется).
103
+ * ⚠️ `schema` должна быть СТАБИЛЬНОЙ ссылкой: отмена устаревших прогонов ключится по идентичности
104
+ * `schema`. Инлайн-стрелка (`validateModel(model, ({ model }) => …)`) каждый раз создаёт НОВЫЙ
105
+ * прогон без дедупликации — держите схемы в `const` / `defineValidation`.
31
106
  *
32
107
  * @param model - Модель данных формы.
33
108
  * @param schema - Схема валидации (стабильная ссылка).
@@ -40,6 +115,6 @@ export declare function defineValidationSchema<T>(schema: ValidationSchema<T>):
40
115
  * const stepOk = await validateModel(model, step2Validation, { touch: true }); // + показать ошибки шага
41
116
  * ```
42
117
  */
43
- export declare function validateModel<T>(model: FormModel<T>, schema: ValidationSchema<T>, options?: {
118
+ export declare function validateModel<T>(model: FormModel<T>, schema: ValidationDefinition<T>, options?: {
44
119
  touch?: boolean;
45
120
  }): Promise<boolean>;
@@ -1,12 +1,13 @@
1
1
  import { ReadonlySignal } from '@preact/signals-core';
2
- import { FormModel } from '../../index';
3
- import { ValidationSchema } from './types';
2
+ import { FormModel } from '../../model/types';
3
+ import { ValidationResult, ValidationDefinition } from './types';
4
4
  /**
5
5
  * Когда запускается schema-валидация:
6
- * - `submit` (по умолчанию) — только явным вызовом `validate()` (на отправке);
7
- * - `blur` — при потере фокуса поля (смена `touched` любого листа);
6
+ * - `submit` (по умолчанию) — только явным прогоном (`validate()`, отправка);
7
+ * - `blur` — при потере фокуса поля (каждый уход из любого листа, и повторный тоже);
8
8
  * - `change` — на каждый ввод (с опц. `debounce`);
9
- * - `afterFirstSubmit` — тихо до первого `validate()`, затем live (см. `liveAfterSubmit`).
9
+ * - `afterFirstSubmit` — тихо до первой попытки отправки (`run({ submit: true })`), затем live
10
+ * (см. `liveAfterSubmit`). Проверка без отправки (`validate()`) фазу не переключает.
10
11
  */
11
12
  export type ValidationStrategyKind = 'submit' | 'blur' | 'change' | 'afterFirstSubmit';
12
13
  export interface ValidationStrategyOptions {
@@ -17,12 +18,35 @@ export interface ValidationStrategyOptions {
17
18
  /** Режим live-фазы для `afterFirstSubmit`. Default `'change'`. */
18
19
  liveAfterSubmit?: 'change' | 'blur';
19
20
  }
21
+ /**
22
+ * Опции полного прогона {@link FormValidationController.run}.
23
+ */
24
+ export interface FormValidationRunOptions {
25
+ /**
26
+ * Какие поля пометить тронутыми: `true` (по умолчанию) — проверенные правилами; `'all'` — они же,
27
+ * а при отказе (`invalid`, `error`) ещё и вся форма.
28
+ */
29
+ touch?: true | 'all';
30
+ /**
31
+ * Прогон — попытка отправки: переводит `afterFirstSubmit` в живую фазу. Проверка без отправки
32
+ * (`validate()`, кнопка «Проверить») фазу не трогает.
33
+ */
34
+ submit?: boolean;
35
+ }
20
36
  export interface FormValidationController {
21
37
  /**
22
- * Полный прогон схемы с раскрытием ошибок (`touch: true`) — для submit. Также переводит
23
- * `afterFirstSubmit` в live-фазу. Возвращает `false`, если есть блокирующие ошибки.
38
+ * Полный прогон схемы с раскрытием замечаний проверенных полей (`touch: true`). Попыткой
39
+ * отправки не считается: `afterFirstSubmit` остаётся в тихой фазе. Возвращает `true` только для
40
+ * статуса `valid`: ошибки, сбой правила и отмена дают `false`.
24
41
  */
25
42
  validate(): Promise<boolean>;
43
+ /**
44
+ * Полный прогон с полным результатом: по статусу отличают ошибки (`invalid`) от сбоя правила
45
+ * (`error`) и отмены (`cancelled`). Без опций — тот же прогон, что
46
+ * {@link FormValidationController.validate}; `{ submit: true }` — попытка отправки,
47
+ * `{ touch: 'all' }` — при отказе раскрыть всю форму.
48
+ */
49
+ run(options?: FormValidationRunOptions): Promise<ValidationResult>;
26
50
  /**
27
51
  * Армировать реактивные подписки стратегии. Идемпотентно. Возвращает `dispose`. НЕ звать при SSR.
28
52
  *
@@ -31,7 +55,10 @@ export interface FormValidationController {
31
55
  * после такого цикла молча оставался бы без живой валидации.
32
56
  */
33
57
  start(): () => void;
34
- /** Снять подписки/таймеры. Идемпотентно; после него `start()` снова армирует стратегию. */
58
+ /**
59
+ * Снять подписки и таймеры, отменить идущий прогон (его `validate()` или `run()` получит
60
+ * `cancelled`). Идемпотентно; после него `start()` снова армирует стратегию.
61
+ */
35
62
  dispose(): void;
36
63
  /** Идёт ли прогон (submit или live) — снапшот. */
37
64
  readonly isValidating: boolean;
@@ -39,23 +66,24 @@ export interface FormValidationController {
39
66
  readonly validating: ReadonlySignal<boolean>;
40
67
  }
41
68
  /**
42
- * Собрать контроллер валидации формы с выбранной стратегией запуска. Переиспользует
43
- * {@link validateModel} как единственный движок прогона.
69
+ * Собрать контроллер валидации формы с выбранной стратегией запуска. Движок прогона — тот же, что у
70
+ * `validateModel`.
44
71
  *
45
72
  * Фабрика ЧИСТАЯ до `start()` (никаких подписок) — безопасна для SSR/headless. Реактивные триггеры
46
73
  * арминуются только в `start()` (в React — из `useEffect`).
47
74
  *
48
75
  * @typeParam T - Форма данных модели.
49
76
  * @param model - Модель данных.
50
- * @param schema - Схема валидации. **Стабильная ссылка** (иначе `validateModel` не отменит устаревший прогон).
77
+ * @param schema - Схема валидации. **Стабильная ссылка** (иначе устаревший прогон не отменится).
51
78
  * @param options - {@link ValidationStrategyOptions}.
52
79
  *
53
80
  * @example
54
81
  * ```ts
55
82
  * const ctrl = createFormValidation(model, schema, { strategy: 'afterFirstSubmit', debounce: 300 });
56
83
  * const dispose = ctrl.start(); // на клиенте
57
- * const ok = await ctrl.validate(); // submit → раскрыть все ошибки
84
+ * const ok = await ctrl.validate(); // проверка: замечания проверенных полей
85
+ * const sent = await ctrl.run({ touch: 'all', submit: true }); // попытка отправки: живая фаза
58
86
  * dispose();
59
87
  * ```
60
88
  */
61
- export declare function createFormValidation<T>(model: FormModel<T>, schema: ValidationSchema<T>, options?: ValidationStrategyOptions): FormValidationController;
89
+ export declare function createFormValidation<T>(model: FormModel<T>, schema: ValidationDefinition<T>, options?: ValidationStrategyOptions): FormValidationController;
@@ -1,28 +1,83 @@
1
- import { FormModel, ValidationError } from '../../index';
1
+ import { FormModel, PathAwareSignal } from '../../model/types';
2
+ import { ValidationIssue } from '../types/contracts';
2
3
  /**
3
- * Внутренний callable-вид правила: value-only фабрики игнорируют 2-й/3-й аргумент.
4
+ * Синхронное правило поля типа `TField`: получает значение, возвращает ошибку или `null`.
4
5
  *
5
- * @internal
6
- */
7
- export type CallableRule = (value: unknown, model: unknown, root: unknown) => ValidationError | null;
8
- /**
9
- * Синхронное правило поля типа `TField`. Проверяется ТОЛЬКО значение (`value`).
6
+ * Правило, написанное для более широкого типа, подходит полю с более узким: `min()` принимает
7
+ * `number | null | undefined` и годится и полю `number`, и полю `number | null`; `required()`
8
+ * принимает любое значение. Обратное — ошибка компиляции: `validate(model.$.age, [email()])`
9
+ * подсветится, потому что `email` ждёт строку, а поле числовое.
10
+ *
11
+ * Правило над несколькими полями — оператор `cross` области схемы: он получает снимок модели.
10
12
  *
11
- * Позиционные `scope`/`root` помечены `never` намеренно: так встроенные value-only фабрики
12
- * (`required()`/`min()`/… — они `(value, model, root) => …`) и inline-правила `(value) => …`
13
- * ОБА присваиваются в `Rule<TField>[]` без `any`, при этом сохраняется проверка типа поля
14
- * (`validate(model.$.age, [email()])` подсветится — `email` ждёт `string`, поле `number`).
15
- * На вызове раннер приводит правило к callable и передаёт `(value, model, model)`.
13
+ * @example
14
+ * ```ts
15
+ * const AMOUNT_RULES: Rule<number | null>[] = [required(), min(50000)];
16
+ * const notReserved: Rule<string> = (value) =>
17
+ * value === 'admin' ? { code: 'reserved' } : null;
18
+ * ```
16
19
  */
17
- export type Rule<TField> = (value: TField, scope: never, root: never) => ValidationError | null;
20
+ export type Rule<TField> = (value: TField) => ValidationIssue | null;
18
21
  /**
19
22
  * Асинхронное правило поля. Получает `AbortSignal` для отмены устаревших ответов (быстрый повторный
20
- * прогон той же схемы отменяет предыдущий). Сетевой сбой не должен блокировать — ловите и возвращайте `null`.
23
+ * прогон той же схемы отменяет предыдущий).
24
+ *
25
+ * Отклонённое правило (сеть, исключение) — это сбой проверки, а не «ошибок нет»: прогон получает
26
+ * статус `error`, поле — блокирующую ошибку `ruleFailed`. Если недоступность сервиса не должна
27
+ * мешать отправке, ловите ошибку в правиле и возвращайте `null` — это решение автора правила.
21
28
  */
22
29
  export type AsyncRule<TField> = (value: TField, ctx: {
23
30
  signal: AbortSignal;
24
- }) => Promise<ValidationError | null>;
25
- /** Схема валидации — обычная функция над (под)моделью. First-class значение (можно `apply`/тестировать/переиспользовать). */
26
- export type ValidationSchema<T> = (ctx: {
27
- model: FormModel<T>;
28
- }) => void;
31
+ }) => Promise<ValidationIssue | null>;
32
+ /**
33
+ * Область схемы валидации — то, что схема получает аргументом.
34
+ *
35
+ * В корне прогона область — вся форма; в схеме, подключённой через `apply` / `applyEach`, —
36
+ * под-модель группы или строки массива. Поэтому правила подформы пишутся один раз и не знают, где
37
+ * она стоит.
38
+ */
39
+ export interface ValidationScope<T> {
40
+ /** Модель области. Привязки правил — через её `$`: `validate(model.$.email, [...])`. */
41
+ readonly model: FormModel<T>;
42
+ /**
43
+ * Правило над несколькими полями: `check` получает снимок модели области (`model.get()`) и
44
+ * вешает ошибку на поле `handle`. Тип снимка выведен из схемы — приводить его не нужно.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * defineValidation<Loan>(({ model, cross }) => {
49
+ * cross(model.$.initialPayment, (loan) =>
50
+ * loan.initialPayment > loan.propertyValue ? tooHigh : null
51
+ * );
52
+ * });
53
+ * ```
54
+ */
55
+ cross(handle: PathAwareSignal<unknown>, check: (snapshot: T) => ValidationIssue | null): void;
56
+ }
57
+ /** Схема валидации — обычная функция над областью. First-class значение (можно `apply`/тестировать/переиспользовать). */
58
+ export type ValidationDefinition<T> = (scope: ValidationScope<T>) => void;
59
+ /**
60
+ * Чем закончился прогон схемы:
61
+ * - `valid` — блокирующих ошибок нет (`severity: 'warning'` не блокирует);
62
+ * - `invalid` — есть блокирующие ошибки;
63
+ * - `error` — хотя бы одно async-правило не вернуло результат (сеть, исключение);
64
+ * - `cancelled` — прогон устарел: для той же пары (model, schema) запущен следующий.
65
+ *
66
+ * Приоритет при нескольких причинах: `cancelled` → `error` → `invalid` → `valid`.
67
+ */
68
+ export type ValidationStatus = 'valid' | 'invalid' | 'cancelled' | 'error';
69
+ /** Правило, которое не вернуло результат. */
70
+ export interface ValidationFailure {
71
+ /** Ручка поля `model.$.…`, чьё правило отклонилось. */
72
+ readonly handle: PathAwareSignal<unknown>;
73
+ /** То, чем правило отклонилось (ошибка сети, исключение). */
74
+ readonly error: unknown;
75
+ }
76
+ /** Результат прогона схемы валидации — см. `runValidation`. */
77
+ export interface ValidationResult {
78
+ readonly status: ValidationStatus;
79
+ /** Ошибки по ручке поля `model.$.…`; путь — метаданные ручки (`handle.__path`). */
80
+ readonly issues: ReadonlyMap<PathAwareSignal<unknown>, readonly ValidationIssue[]>;
81
+ /** Правила, которые не вернули результат (сеть, исключение). */
82
+ readonly failures: readonly ValidationFailure[];
83
+ }
@@ -6,7 +6,14 @@
6
6
  * @module form/validators/date-utils
7
7
  */
8
8
  /**
9
- * Парсит значение в объект Date
9
+ * Парсит значение в объект Date. Строгий формат: `Date` либо строка `YYYY-MM-DD` (значение
10
+ * `<input type="date">`); любая другая строка — не дата. Разбор движка (`new Date(строка)`) не
11
+ * используется: он угадывает дату по обрывкам (`'hello 1'`, `'March 7'`), и результат зависит от
12
+ * движка.
13
+ *
14
+ * Строка `YYYY-MM-DD` — локальная полночь этого дня: `new Date('2024-01-01')` дал бы полночь UTC,
15
+ * и западнее UTC правила дат сравнивали бы предыдущий день. Несуществующая дата (`2023-02-29`)
16
+ * не разбирается — движок перенёс бы её на 1 марта.
10
17
  *
11
18
  * @param value - Значение для парсинга (Date, string или undefined)
12
19
  * @returns Date объект или null если парсинг не удался
@@ -20,11 +27,16 @@ export declare function getToday(): Date;
20
27
  * Нормализует дату, обнуляя время
21
28
  */
22
29
  export declare function normalizeDate(date: Date): Date;
30
+ /** Дата рождения позже сегодняшнего дня. */
31
+ export declare function isFutureBirth(birthDate: Date): boolean;
23
32
  /**
24
33
  * Вычисляет полный возраст (в годах) по календарным полям.
25
34
  *
26
35
  * Считаем по годам/месяцам/дням, а не делением миллисекунд на усреднённый год (365.25 дн): усреднение
27
36
  * даёт off-by-one на границе — в день N-летия накопленных реальных дней меньше `N * 365.25`, и `floor`
28
37
  * роняет возраст до `N - 1` (т.е. `minAge(18)` ошибочно отклонял 18-летнего в его день рождения).
38
+ *
39
+ * Родившийся 29 февраля в невисокосный год становится на год старше 28 февраля: срок, исчисляемый
40
+ * годами, истекает в последний день месяца, если соответствующего числа в нём нет (ГК РФ, ст. 192).
29
41
  */
30
42
  export declare function calculateAge(birthDate: Date): number;
@@ -1,22 +1,23 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора формата email.
4
5
  *
5
6
  * Проверяет по упрощённому regex `^[^\s@]+@[^\s@]+\.[^\s@]+$`. Пустые значения
6
7
  * (`''`/`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
7
8
  *
8
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
9
- * @returns Чистый валидатор {@link Validator} для строкового поля
9
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
10
+ * @returns Правило {@link Rule} для строкового поля
10
11
  *
11
12
  * @example Проверка формата email
12
13
  * ```typescript
13
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
14
+ * import { defineValidation, validate } from '@reformer/core/validation';
14
15
  * import { required, email } from '@reformer/core/validators';
15
16
  *
16
17
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
17
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
18
- * validate(model.$.email, [required(), email({ message: 'Введите корректный email' })]);
18
+ * const validation = defineValidation<MyForm>(({ model }) => {
19
+ * validate(model.$.email, [required(), email({ code: 'email.email' })]);
19
20
  * });
20
21
  * ```
21
22
  */
22
- export declare function email<TForm = unknown, TField extends string | null | undefined = string>(options?: ValidateOptions): Validator<TForm, TField>;
23
+ export declare function email(options?: RuleOptions): Rule<string | null | undefined>;
@@ -1,4 +1,5 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора типа файла.
4
5
  *
@@ -12,19 +13,19 @@ import { Validator, ValidateOptions } from '../types/validation-schema';
12
13
  * пропускаются (используйте {@link required} для обязательности).
13
14
  *
14
15
  * @param accept - Accept-строка допустимых типов, например `'image/*,.pdf'`
15
- * @param options - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
16
+ * @param options - Опции валидатора ({@link RuleOptions}). В `params` ошибки автоматически
16
17
  * попадают `accept` и `fileName` (первый нарушивший файл).
17
- * @returns Чистый валидатор {@link Validator} для файла или массива файлов
18
+ * @returns Правило {@link Rule} для файла или массива файлов
18
19
  *
19
20
  * @example Только изображения и PDF
20
21
  * ```typescript
21
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
22
+ * import { defineValidation, validate } from '@reformer/core/validation';
22
23
  * import { fileType } from '@reformer/core/validators';
23
24
  *
24
25
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
25
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
26
- * validate(model.$.documents, [fileType('image/*,.pdf', { message: 'Только изображения или PDF' })]);
26
+ * const validation = defineValidation<MyForm>(({ model }) => {
27
+ * validate(model.$.documents, [fileType('image/*,.pdf', { code: 'documents.fileType' })]);
27
28
  * });
28
29
  * ```
29
30
  */
30
- export declare function fileType<TForm = unknown, TField = unknown>(accept: string, options?: ValidateOptions): Validator<TForm, TField>;
31
+ export declare function fileType(accept: string, options?: RuleOptions): Rule<unknown>;
@@ -39,7 +39,8 @@ export declare function toFileArray(value: unknown): FileLike[] | null;
39
39
  /**
40
40
  * Проверяет файл против accept-паттерна в синтаксисе нативного атрибута
41
41
  * `<input type="file" accept>`: список через запятую из расширений (`.pdf`),
42
- * точных MIME (`image/png`) и wildcard-категорий (`image/*`). Регистронезависимо.
42
+ * точных MIME (`image/png`) и wildcard-категорий (`image/*`); шаблон «любой тип» (звёздочка,
43
+ * слэш, звёздочка) пропускает любой файл. Регистронезависимо.
43
44
  *
44
45
  * Нужен собственный матчер, потому что `accept` у нативного input — только подсказка
45
46
  * пикеру: на drag-and-drop и на программное значение он не действует.
@@ -1,22 +1,23 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
4
  * Фабрика валидатора, проверяющего что дата не в прошлом.
4
5
  *
5
6
  * Дата не должна быть раньше сегодняшнего дня (сравнение по нормализованным датам).
6
7
  * Пустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).
7
8
  *
8
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
9
- * @returns Чистый валидатор {@link Validator} для поля даты (`string | Date`)
9
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
10
+ * @returns Правило {@link Rule} для поля даты (`string | Date`)
10
11
  *
11
12
  * @example Дата не в прошлом
12
13
  * ```typescript
13
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
14
+ * import { defineValidation, validate } from '@reformer/core/validation';
14
15
  * import { required, futureDate } from '@reformer/core/validators';
15
16
  *
16
17
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
17
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
18
- * validate(model.$.appointmentDate, [required(), futureDate({ message: 'Дата записи должна быть в будущем' })]);
18
+ * const validation = defineValidation<MyForm>(({ model }) => {
19
+ * validate(model.$.appointmentDate, [required(), futureDate({ code: 'appointmentDate.futureDate' })]);
19
20
  * });
20
21
  * ```
21
22
  */
22
- export declare function futureDate<TForm = unknown, TField extends string | Date | null | undefined = string | Date>(options?: ValidateOptions): Validator<TForm, TField>;
23
+ export declare function futureDate(options?: RuleOptions): Rule<string | Date | null | undefined>;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Все примитивы — фабрики, возвращающие чистый `Validator<TForm, TField>`; передаются вторым
5
5
  * аргументом оператора `validate` внутри схемы валидации: `validate(model.$.age, [required(), min(18)])`.
6
- * В layout-схему формы правила НЕ кладутся — поля `validators` у узла нет (снято в 7.0).
6
+ * В layout-схему формы правила НЕ кладутся — поля `validators` у узла нет.
7
7
  *
8
8
  * Гранулярные сабпаты (`@reformer/core/validators/required` и ещё 20) собираются отдельными
9
9
  * entry для tree-shaking; этот модуль отдаёт полный набор для случаев, когда правил много.