@reformer/core 11.0.0-beta.8 → 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 (224) hide show
  1. package/README.md +91 -73
  2. package/dist/behaviors-value-HA_Q03hc.js +108 -0
  3. package/dist/behaviors.js +370 -242
  4. package/dist/{create-model-BBRHhHwK.js → create-model-BvcbNPgL.js} +6 -6
  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 +28 -7
  9. package/dist/form/behaviors/context.d.ts +19 -2
  10. package/dist/form/behaviors/index.d.ts +3 -3
  11. package/dist/form/behaviors/internals.d.ts +9 -2
  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 +6 -4
  15. package/dist/form/behaviors/types.d.ts +12 -4
  16. package/dist/form/create-form.d.ts +47 -35
  17. package/dist/form/flow/flow.d.ts +87 -0
  18. package/dist/form/form-bundle.d.ts +45 -28
  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 +16 -21
  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 +30 -14
  37. package/dist/form/signal-node-registry.d.ts +6 -7
  38. package/dist/form/submission.d.ts +93 -0
  39. package/dist/form/type-guards.d.ts +14 -73
  40. package/dist/form/types/contracts.d.ts +19 -92
  41. package/dist/form/types/field-config.d.ts +27 -0
  42. package/dist/form/types/index.d.ts +5 -57
  43. package/dist/form/types/nodes.d.ts +159 -0
  44. package/dist/form/types/schema-node.d.ts +139 -63
  45. package/dist/form/types/validation-schema.d.ts +23 -27
  46. package/dist/form/validation/context.d.ts +42 -7
  47. package/dist/form/validation/index.d.ts +9 -8
  48. package/dist/form/validation/operators.d.ts +22 -30
  49. package/dist/form/validation/run.d.ts +93 -18
  50. package/dist/form/validation/strategy.d.ts +41 -13
  51. package/dist/form/validation/types.d.ts +74 -20
  52. package/dist/form/validators/date-utils.d.ts +13 -1
  53. package/dist/form/validators/email.d.ts +8 -7
  54. package/dist/form/validators/file-type.d.ts +8 -7
  55. package/dist/form/validators/file-utils.d.ts +2 -1
  56. package/dist/form/validators/future-date.d.ts +8 -7
  57. package/dist/form/validators/index.d.ts +1 -1
  58. package/dist/form/validators/integer.d.ts +8 -7
  59. package/dist/form/validators/is-date.d.ts +11 -9
  60. package/dist/form/validators/is-number.d.ts +11 -9
  61. package/dist/form/validators/max-age.d.ts +13 -9
  62. package/dist/form/validators/max-date.d.ts +8 -7
  63. package/dist/form/validators/max-file-size.d.ts +8 -7
  64. package/dist/form/validators/max-files.d.ts +8 -7
  65. package/dist/form/validators/max-length.d.ts +14 -7
  66. package/dist/form/validators/max-total-file-size.d.ts +8 -7
  67. package/dist/form/validators/max.d.ts +10 -8
  68. package/dist/form/validators/min-age.d.ts +12 -9
  69. package/dist/form/validators/min-date.d.ts +8 -7
  70. package/dist/form/validators/min-file-size.d.ts +8 -7
  71. package/dist/form/validators/min-files.d.ts +11 -9
  72. package/dist/form/validators/min-length.d.ts +14 -7
  73. package/dist/form/validators/min.d.ts +10 -8
  74. package/dist/form/validators/multiple-of.d.ts +10 -8
  75. package/dist/form/validators/non-negative.d.ts +8 -7
  76. package/dist/form/validators/non-zero.d.ts +8 -7
  77. package/dist/form/validators/past-date.d.ts +8 -7
  78. package/dist/form/validators/pattern.d.ts +9 -8
  79. package/dist/form/validators/phone.d.ts +8 -7
  80. package/dist/form/validators/required.d.ts +11 -9
  81. package/dist/form/validators/url.d.ts +20 -13
  82. package/dist/form/validators/validation-issue.d.ts +8 -0
  83. package/dist/i18n/descriptor.d.ts +1 -1
  84. package/dist/i18n/en.json.d.ts +5 -1
  85. package/dist/i18n/locale-store.d.ts +7 -0
  86. package/dist/i18n/message-format.d.ts +24 -4
  87. package/dist/i18n/ru.json.d.ts +5 -1
  88. package/dist/i18n/translator.d.ts +11 -0
  89. package/dist/i18n/validation-message.d.ts +42 -7
  90. package/dist/i18n.d.ts +7 -12
  91. package/dist/i18n.js +66 -283
  92. package/dist/index.d.ts +16 -7
  93. package/dist/index.js +924 -2855
  94. package/dist/loader-BWkigpVe.js +52 -0
  95. package/dist/locale/en.js +1 -1
  96. package/dist/locale/en.json +4 -1
  97. package/dist/locale/ru.js +4 -1
  98. package/dist/locale/ru.json +4 -1
  99. package/dist/locale-CG54AU2Q.js +219 -0
  100. package/dist/locale.js +1 -1
  101. package/dist/model/behaviors-value.d.ts +24 -6
  102. package/dist/model/create-model.d.ts +2 -2
  103. package/dist/model/derived-registry.d.ts +1 -1
  104. package/dist/model/index.d.ts +11 -5
  105. package/dist/model/model-nodes.d.ts +79 -12
  106. package/dist/model/model-signals-proxy.d.ts +5 -6
  107. package/dist/model/model-value-proxy.d.ts +20 -15
  108. package/dist/model/safe-effect.d.ts +33 -1
  109. package/dist/model/types.d.ts +63 -13
  110. package/dist/model.js +20 -18
  111. package/dist/node-kind-C-r6ZMdo.js +15 -0
  112. package/dist/platforms/react/field-binding/field-adapter.d.ts +1 -1
  113. package/dist/platforms/react/field-binding/field-handle.d.ts +5 -2
  114. package/dist/platforms/react/form-bundle-context.d.ts +2 -2
  115. package/dist/platforms/react/hooks/types.d.ts +57 -38
  116. package/dist/platforms/react/hooks/use-form-bundle.d.ts +19 -4
  117. package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
  118. package/dist/platforms/react/hooks/use-form-validation.d.ts +12 -6
  119. package/dist/platforms/react/hooks/useArrayLength.d.ts +6 -6
  120. package/dist/platforms/react/hooks/useFormControl.d.ts +7 -9
  121. package/dist/platforms/react/hooks/useFormControlValue.d.ts +18 -19
  122. package/dist/platforms/react/hooks/useSignalSubscription.d.ts +9 -1
  123. package/dist/platforms/react/i18n/context.d.ts +6 -1
  124. package/dist/platforms/react/i18n/hooks.d.ts +16 -10
  125. package/dist/platforms/react/i18n/provider.d.ts +9 -2
  126. package/dist/platforms/react/index.d.ts +6 -4
  127. package/dist/react.d.ts +22 -0
  128. package/dist/react.js +505 -0
  129. package/dist/runtime-token.d.ts +1 -2
  130. package/dist/safe-effect-BbtX3KuN.js +643 -0
  131. package/dist/schema-controller-CpiO2JoK.js +143 -0
  132. package/dist/signals.d.ts +15 -9
  133. package/dist/signals.js +11 -6
  134. package/dist/strategy-CoFSemuP.js +375 -0
  135. package/dist/type-guards-D-N_5Ddh.js +19 -0
  136. package/dist/validation-issue-B9mjI8jz.js +7 -0
  137. package/dist/validation-message-Ced9MGxs.js +194 -0
  138. package/dist/validation.js +9 -9
  139. package/dist/validators/email.js +5 -5
  140. package/dist/validators/future-date.js +8 -8
  141. package/dist/validators/integer.js +3 -3
  142. package/dist/validators/is-date.js +4 -4
  143. package/dist/validators/is-number.js +4 -4
  144. package/dist/validators/max-age.js +8 -9
  145. package/dist/validators/max-date.js +8 -8
  146. package/dist/validators/max-length.js +7 -7
  147. package/dist/validators/max.js +4 -4
  148. package/dist/validators/min-age.js +10 -8
  149. package/dist/validators/min-date.js +3 -3
  150. package/dist/validators/min-length.js +5 -5
  151. package/dist/validators/min.js +4 -4
  152. package/dist/validators/multiple-of.js +11 -7
  153. package/dist/validators/non-negative.js +3 -3
  154. package/dist/validators/non-zero.js +3 -3
  155. package/dist/validators/past-date.js +8 -8
  156. package/dist/validators/pattern.js +5 -5
  157. package/dist/validators/phone.js +11 -9
  158. package/dist/validators/required.js +2 -2
  159. package/dist/validators/url.js +48 -12
  160. package/dist/validators.js +17 -17
  161. package/docs/llms/01-api-reference.md +60 -34
  162. package/docs/llms/02-quick-start.md +111 -80
  163. package/docs/llms/03-api-signatures.md +368 -153
  164. package/docs/llms/04-common-patterns.md +58 -56
  165. package/docs/llms/05-common-mistakes.md +69 -44
  166. package/docs/llms/06-troubleshooting.md +14 -9
  167. package/docs/llms/07-complete-import.md +74 -43
  168. package/docs/llms/08-form-types.md +11 -4
  169. package/docs/llms/09-formschema.md +129 -81
  170. package/docs/llms/10-arrays.md +106 -75
  171. package/docs/llms/11-async-watchfield.md +2 -2
  172. package/docs/llms/13-multi-step.md +134 -63
  173. package/docs/llms/14-extended-mistakes.md +20 -17
  174. package/docs/llms/15-project-structure.md +221 -74
  175. package/docs/llms/16-ui-components.md +55 -42
  176. package/docs/llms/17-nonexistent-api.md +199 -32
  177. package/docs/llms/18-conditional-fields.md +66 -32
  178. package/docs/llms/19-reading-values.md +15 -3
  179. package/docs/llms/20-compute-vs-watch.md +16 -10
  180. package/docs/llms/21-array-operations.md +51 -27
  181. package/docs/llms/22-cycle-detection.md +1 -1
  182. package/docs/llms/23-copy-from.md +2 -2
  183. package/docs/llms/24-sync-fields.md +6 -5
  184. package/docs/llms/25-reset-when.md +14 -7
  185. package/docs/llms/26-transform-value.md +4 -4
  186. package/docs/llms/27-revalidate-when.md +16 -15
  187. package/docs/llms/28-submit-and-reset.md +276 -128
  188. package/docs/llms/29-async-preload.md +39 -29
  189. package/docs/llms/30-type-safety-recipes.md +105 -51
  190. package/docs/llms/31-async-validator-debounce.md +96 -53
  191. package/docs/llms/33-validation-strategy.md +177 -65
  192. package/docs/llms/34-i18n.md +69 -43
  193. package/docs/llms/35-unified-contract.md +100 -39
  194. package/docs/llms/36-issue-messages.md +284 -0
  195. package/docs/llms/37-compiled-schema.md +332 -0
  196. package/docs/llms/38-form-flow.md +397 -0
  197. package/llms-index.json +1 -1
  198. package/llms.txt +6084 -3420
  199. package/package.json +23 -4
  200. package/dist/behaviors-value-C7dSEhCc.js +0 -134
  201. package/dist/date-utils-dTT_x_Be.js +0 -31
  202. package/dist/form/create-core-form.d.ts +0 -72
  203. package/dist/form/factories/index.d.ts +0 -6
  204. package/dist/form/factories/node-factory.d.ts +0 -189
  205. package/dist/form/form-submitter.d.ts +0 -121
  206. package/dist/form/nodes/array-node.d.ts +0 -276
  207. package/dist/form/nodes/field-node.d.ts +0 -297
  208. package/dist/form/nodes/form-node.d.ts +0 -326
  209. package/dist/form/nodes/group-node.d.ts +0 -284
  210. package/dist/form/nodes/model-array-node.d.ts +0 -126
  211. package/dist/form/nodes/subscription-manager.d.ts +0 -180
  212. package/dist/form/status-machine.d.ts +0 -115
  213. package/dist/form/types/deep-schema.d.ts +0 -107
  214. package/dist/form/types/form-proxy.d.ts +0 -141
  215. package/dist/form/unique-id.d.ts +0 -45
  216. package/dist/form/validation/config.d.ts +0 -73
  217. package/dist/form/validation/error-handler.d.ts +0 -166
  218. package/dist/form/validators/validation-error.d.ts +0 -8
  219. package/dist/index-BrNkQj1y.js +0 -105
  220. package/dist/loader-Dv_Hl7JC.js +0 -216
  221. package/dist/model-value-proxy-caTmAiUd.js +0 -419
  222. package/dist/node-BeV_lV5i.js +0 -100
  223. package/dist/strategy-DgzELWno.js +0 -204
  224. package/dist/validation-error-B-U3RsV0.js +0 -11
@@ -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,29 +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, scope, root)`: модель текущей
16
- * области (в корне прогона — вся модель) и корень прогона.
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
+ * ```
17
19
  */
18
- export type Rule<TField> = (value: TField, scope: never, root: never) => ValidationError | null;
20
+ export type Rule<TField> = (value: TField) => ValidationIssue | null;
19
21
  /**
20
22
  * Асинхронное правило поля. Получает `AbortSignal` для отмены устаревших ответов (быстрый повторный
21
- * прогон той же схемы отменяет предыдущий). Сетевой сбой не должен блокировать — ловите и возвращайте `null`.
23
+ * прогон той же схемы отменяет предыдущий).
24
+ *
25
+ * Отклонённое правило (сеть, исключение) — это сбой проверки, а не «ошибок нет»: прогон получает
26
+ * статус `error`, поле — блокирующую ошибку `ruleFailed`. Если недоступность сервиса не должна
27
+ * мешать отправке, ловите ошибку в правиле и возвращайте `null` — это решение автора правила.
22
28
  */
23
29
  export type AsyncRule<TField> = (value: TField, ctx: {
24
30
  signal: AbortSignal;
25
- }) => Promise<ValidationError | null>;
26
- /** Схема валидации — обычная функция над (под)моделью. First-class значение (можно `apply`/тестировать/переиспользовать). */
27
- export type ValidationSchema<T> = (ctx: {
28
- model: FormModel<T>;
29
- }) => 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; этот модуль отдаёт полный набор для случаев, когда правил много.
@@ -1,21 +1,22 @@
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
  * Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6
7
  *
7
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
8
- * @returns Чистый валидатор {@link Validator} для числового поля
8
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
9
+ * @returns Правило {@link Rule} для числового поля
9
10
  *
10
11
  * @example Проверка целого числа
11
12
  * ```typescript
12
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
13
+ * import { defineValidation, validate } from '@reformer/core/validation';
13
14
  * import { required, integer } from '@reformer/core/validators';
14
15
  *
15
16
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
16
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
17
- * validate(model.$.count, [required(), integer({ message: 'Должно быть целым числом' })]);
17
+ * const validation = defineValidation<MyForm>(({ model }) => {
18
+ * validate(model.$.count, [required(), integer({ code: 'count.integer' })]);
18
19
  * });
19
20
  * ```
20
21
  */
21
- export declare function integer<TForm = unknown, TField extends number | null | undefined = number>(options?: ValidateOptions): Validator<TForm, TField>;
22
+ export declare function integer(options?: RuleOptions): Rule<number | null | undefined>;
@@ -1,22 +1,24 @@
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
- * Принимает `Date` или строку, парсимую в дату. Пустые значения (`''`/`null`/`undefined`)
6
- * пропускаются (используйте {@link required} для обязательности).
6
+ * Строгий формат: `Date` либо строка `YYYY-MM-DD` с существующим днём календаря. Строки в иных
7
+ * форматах (`'31.12.2024'`, `'March 7'`, дата со временем) — `date_invalid`. Пустые значения
8
+ * (`''`/`null`/`undefined`) пропускаются (используйте {@link required} для обязательности).
7
9
  *
8
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
9
- * @returns Чистый валидатор {@link Validator} для поля даты (`string | Date`)
10
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
11
+ * @returns Правило {@link Rule} для поля даты (`string | Date`)
10
12
  *
11
13
  * @example Проверка валидности даты
12
14
  * ```typescript
13
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
15
+ * import { defineValidation, validate } from '@reformer/core/validation';
14
16
  * import { required, isDate } from '@reformer/core/validators';
15
17
  *
16
18
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
17
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
18
- * validate(model.$.eventDate, [required(), isDate({ message: 'Введите корректную дату' })]);
19
+ * const validation = defineValidation<MyForm>(({ model }) => {
20
+ * validate(model.$.eventDate, [required(), isDate({ code: 'eventDate.isDate' })]);
19
21
  * });
20
22
  * ```
21
23
  */
22
- export declare function isDate<TForm = unknown, TField extends string | Date | null | undefined = string | Date>(options?: ValidateOptions): Validator<TForm, TField>;
24
+ export declare function isDate(options?: RuleOptions): Rule<string | Date | null | undefined>;
@@ -1,23 +1,25 @@
1
- import { Validator, ValidateOptions } from '../types/validation-schema';
1
+ import { RuleOptions } from '../types/validation-schema';
2
+ import { Rule } from '../validation/types';
2
3
  /**
3
- * Фабрика валидатора, проверяющего что значение — конечное число (не NaN, не строка).
4
+ * Фабрика валидатора, проверяющего что значение — конечное число (не `NaN`, не `±Infinity`,
5
+ * не строка).
4
6
  *
5
- * Пустые значения (`null`/`undefined`) пропускаются (используйте {@link required} для
7
+ * Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required} для
6
8
  * обязательности). В отличие от других number-валидаторов, **не** пропускает не-числа
7
9
  * и `NaN` — это его задача.
8
10
  *
9
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
10
- * @returns Чистый валидатор {@link Validator} для числового поля
11
+ * @param options - Опции валидатора ({@link RuleOptions}): `code`, `params`
12
+ * @returns Правило {@link Rule} для числового поля
11
13
  *
12
14
  * @example Проверка, что значение — число
13
15
  * ```typescript
14
- * import { defineValidationSchema, validate } from '@reformer/core/validation';
16
+ * import { defineValidation, validate } from '@reformer/core/validation';
15
17
  * import { required, isNumber } from '@reformer/core/validators';
16
18
  *
17
19
  * // Правила живут в отдельной схеме над МОДЕЛЬЮ — layout-схема валидаторов не несёт.
18
- * const validation = defineValidationSchema<MyForm>(({ model }) => {
19
- * validate(model.$.amount, [required(), isNumber({ message: 'Введите число' })]);
20
+ * const validation = defineValidation<MyForm>(({ model }) => {
21
+ * validate(model.$.amount, [required(), isNumber({ code: 'amount.isNumber' })]);
20
22
  * });
21
23
  * ```
22
24
  */
23
- export declare function isNumber<TForm = unknown, TField extends number | null | undefined = number>(options?: ValidateOptions): Validator<TForm, TField>;
25
+ export declare function isNumber(options?: RuleOptions): Rule<number | null | undefined>;