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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/README.md +90 -68
  2. package/dist/behaviors-value-D05z3my6.js +109 -0
  3. package/dist/behaviors.d.ts +1 -1
  4. package/dist/behaviors.js +376 -211
  5. package/dist/create-model-DPSG3I0O.js +30 -0
  6. package/dist/date-utils-90-qZbse.js +43 -0
  7. package/dist/en-HP8XEych.js +44 -0
  8. package/dist/form/aggregate-signals.d.ts +21 -63
  9. package/dist/form/behaviors/collections.d.ts +84 -0
  10. package/dist/form/behaviors/context.d.ts +56 -0
  11. package/dist/form/behaviors/index.d.ts +30 -0
  12. package/dist/form/behaviors/internals.d.ts +41 -0
  13. package/dist/form/{behaviors-node.d.ts → behaviors/node.d.ts} +28 -5
  14. package/dist/form/behaviors/operators.d.ts +59 -0
  15. package/dist/form/behaviors/schema-operators.d.ts +83 -0
  16. package/dist/form/behaviors/types.d.ts +37 -0
  17. package/dist/form/create-form.d.ts +59 -70
  18. package/dist/form/flow/flow.d.ts +87 -0
  19. package/dist/form/form-bundle.d.ts +153 -0
  20. package/dist/form/form-level.d.ts +121 -0
  21. package/dist/form/form-proxy-builder.d.ts +6 -22
  22. package/dist/form/index.d.ts +23 -24
  23. package/dist/form/nodes/form-array-node.d.ts +100 -0
  24. package/dist/form/nodes/form-control-node.d.ts +73 -0
  25. package/dist/form/nodes/form-group-node.d.ts +66 -0
  26. package/dist/form/nodes/node-kind.d.ts +29 -0
  27. package/dist/form/nodes/state/availability.d.ts +6 -0
  28. package/dist/form/nodes/state/component.d.ts +6 -0
  29. package/dist/form/nodes/state/index.d.ts +12 -0
  30. package/dist/form/nodes/state/interaction.d.ts +13 -0
  31. package/dist/form/nodes/state/issues.d.ts +9 -0
  32. package/dist/form/nodes/state/pending.d.ts +6 -0
  33. package/dist/form/schema/compile.d.ts +59 -0
  34. package/dist/form/schema/compiled.d.ts +143 -0
  35. package/dist/form/schema/row-key.d.ts +11 -0
  36. package/dist/form/schema-controller.d.ts +159 -0
  37. package/dist/form/schema-subtree.d.ts +28 -0
  38. package/dist/form/signal-node-registry.d.ts +27 -22
  39. package/dist/form/submission.d.ts +93 -0
  40. package/dist/form/type-guards.d.ts +14 -73
  41. package/dist/form/types/contracts.d.ts +21 -85
  42. package/dist/form/types/field-config.d.ts +27 -0
  43. package/dist/form/types/index.d.ts +5 -57
  44. package/dist/form/types/nodes.d.ts +159 -0
  45. package/dist/form/types/schema-node.d.ts +147 -46
  46. package/dist/form/types/validation-schema.d.ts +25 -17
  47. package/dist/form/validation/context.d.ts +67 -0
  48. package/dist/form/validation/index.d.ts +24 -28
  49. package/dist/form/validation/operators.d.ts +101 -0
  50. package/dist/form/validation/run.d.ts +120 -0
  51. package/dist/form/validation/strategy.d.ts +89 -0
  52. package/dist/form/validation/types.d.ts +83 -0
  53. package/dist/form/validators/date-utils.d.ts +42 -0
  54. package/dist/form/validators/email.d.ts +23 -0
  55. package/dist/form/{validation/validators → validators}/file-type.d.ts +10 -10
  56. package/dist/form/{validation/validators → validators}/file-utils.d.ts +3 -2
  57. package/dist/form/validators/future-date.d.ts +23 -0
  58. package/dist/form/{validation/validators → validators}/index.d.ts +7 -4
  59. package/dist/form/validators/integer.d.ts +22 -0
  60. package/dist/form/validators/is-date.d.ts +24 -0
  61. package/dist/form/validators/is-number.d.ts +25 -0
  62. package/dist/form/validators/max-age.d.ts +28 -0
  63. package/dist/form/validators/max-date.d.ts +25 -0
  64. package/dist/form/{validation/validators → validators}/max-file-size.d.ts +10 -10
  65. package/dist/form/validators/max-files.d.ts +26 -0
  66. package/dist/form/validators/max-length.d.ts +33 -0
  67. package/dist/form/validators/max-total-file-size.d.ts +26 -0
  68. package/dist/form/validators/max.d.ts +26 -0
  69. package/dist/form/validators/min-age.d.ts +27 -0
  70. package/dist/form/validators/min-date.d.ts +25 -0
  71. package/dist/form/{validation/validators → validators}/min-file-size.d.ts +10 -10
  72. package/dist/form/validators/min-files.d.ts +27 -0
  73. package/dist/form/validators/min-length.d.ts +33 -0
  74. package/dist/form/validators/min.d.ts +26 -0
  75. package/dist/form/validators/multiple-of.d.ts +25 -0
  76. package/dist/form/validators/non-negative.d.ts +22 -0
  77. package/dist/form/validators/non-zero.d.ts +22 -0
  78. package/dist/form/validators/past-date.d.ts +23 -0
  79. package/dist/form/validators/pattern.d.ts +26 -0
  80. package/dist/form/{validation/validators → validators}/phone.d.ts +11 -11
  81. package/dist/form/validators/required.d.ts +29 -0
  82. package/dist/form/validators/url.d.ts +45 -0
  83. package/dist/form/validators/validation-issue.d.ts +8 -0
  84. package/dist/i18n/descriptor.d.ts +54 -0
  85. package/dist/i18n/en.json.d.ts +49 -0
  86. package/dist/i18n/loader.d.ts +71 -0
  87. package/dist/i18n/locale-store.d.ts +46 -0
  88. package/dist/i18n/locale.d.ts +90 -0
  89. package/dist/i18n/message-format.d.ts +136 -0
  90. package/dist/i18n/resolve-localized.d.ts +17 -0
  91. package/dist/i18n/ru.json.d.ts +49 -0
  92. package/dist/i18n/translator.d.ts +61 -0
  93. package/dist/i18n/validation-message.d.ts +53 -0
  94. package/dist/i18n.d.ts +26 -0
  95. package/dist/i18n.js +86 -0
  96. package/dist/index.d.ts +17 -5
  97. package/dist/index.js +942 -2601
  98. package/dist/loader-BWkigpVe.js +52 -0
  99. package/dist/locale/en.d.ts +2 -0
  100. package/dist/locale/en.js +5 -0
  101. package/dist/locale/en.json +45 -0
  102. package/dist/locale/index.d.ts +18 -0
  103. package/dist/locale/ru.d.ts +2 -0
  104. package/dist/locale/ru.js +44 -0
  105. package/dist/locale/ru.json +45 -0
  106. package/dist/locale-CG54AU2Q.js +219 -0
  107. package/dist/locale.d.ts +2 -0
  108. package/dist/locale.js +9 -0
  109. package/dist/{state → model}/behaviors-value.d.ts +24 -6
  110. package/dist/{state/form-model.d.ts → model/create-model.d.ts} +18 -4
  111. package/dist/{state → model}/derived-registry.d.ts +1 -1
  112. package/dist/model/index.d.ts +42 -0
  113. package/dist/model/model-nodes.d.ts +190 -0
  114. package/dist/model/model-signals-proxy.d.ts +63 -0
  115. package/dist/model/model-value-proxy.d.ts +84 -0
  116. package/dist/{state → model}/safe-effect.d.ts +50 -2
  117. package/dist/model/types.d.ts +239 -0
  118. package/dist/model.d.ts +2 -0
  119. package/dist/model.js +27 -0
  120. package/dist/node-kind-C-r6ZMdo.js +15 -0
  121. package/dist/platforms/react/field-binding/field-adapter.d.ts +87 -0
  122. package/dist/platforms/react/field-binding/field-handle.d.ts +53 -0
  123. package/dist/platforms/react/form-bundle-context.d.ts +27 -0
  124. package/dist/{form → platforms/react}/hooks/types.d.ts +58 -36
  125. package/dist/platforms/react/hooks/use-form-bundle.d.ts +41 -0
  126. package/dist/platforms/react/hooks/use-form-flow.d.ts +40 -0
  127. package/dist/{form → platforms/react}/hooks/use-form-validation.d.ts +13 -7
  128. package/dist/{form → platforms/react}/hooks/useArrayLength.d.ts +6 -6
  129. package/dist/{form → platforms/react}/hooks/useFormControl.d.ts +7 -9
  130. package/dist/{form → platforms/react}/hooks/useFormControlValue.d.ts +18 -18
  131. package/dist/{form → platforms/react}/hooks/useSignalSubscription.d.ts +9 -1
  132. package/dist/platforms/react/i18n/context.d.ts +18 -0
  133. package/dist/platforms/react/i18n/hooks.d.ts +65 -0
  134. package/dist/platforms/react/i18n/provider.d.ts +59 -0
  135. package/dist/platforms/react/index.d.ts +30 -0
  136. package/dist/react.d.ts +22 -0
  137. package/dist/react.js +505 -0
  138. package/dist/runtime-token.d.ts +1 -2
  139. package/dist/safe-effect-BazLOv1g.js +669 -0
  140. package/dist/schema-controller-CpiO2JoK.js +143 -0
  141. package/dist/signals.d.ts +15 -9
  142. package/dist/signals.js +11 -6
  143. package/dist/strategy-DzvnsWLh.js +375 -0
  144. package/dist/type-guards-D-N_5Ddh.js +19 -0
  145. package/dist/validation-issue-B9mjI8jz.js +7 -0
  146. package/dist/validation-message-Ced9MGxs.js +194 -0
  147. package/dist/validation.d.ts +1 -1
  148. package/dist/validation.js +11 -165
  149. package/dist/validators/email.d.ts +1 -1
  150. package/dist/validators/email.js +5 -8
  151. package/dist/validators/future-date.d.ts +1 -1
  152. package/dist/validators/future-date.js +10 -13
  153. package/dist/validators/integer.d.ts +1 -1
  154. package/dist/validators/integer.js +4 -7
  155. package/dist/validators/is-date.d.ts +1 -1
  156. package/dist/validators/is-date.js +5 -8
  157. package/dist/validators/is-number.d.ts +1 -1
  158. package/dist/validators/is-number.js +4 -7
  159. package/dist/validators/max-age.d.ts +1 -1
  160. package/dist/validators/max-age.js +8 -12
  161. package/dist/validators/max-date.d.ts +1 -1
  162. package/dist/validators/max-date.js +10 -13
  163. package/dist/validators/max-length.d.ts +1 -1
  164. package/dist/validators/max-length.js +7 -10
  165. package/dist/validators/max.d.ts +1 -1
  166. package/dist/validators/max.js +4 -7
  167. package/dist/validators/min-age.d.ts +1 -1
  168. package/dist/validators/min-age.js +10 -11
  169. package/dist/validators/min-date.d.ts +1 -1
  170. package/dist/validators/min-date.js +8 -11
  171. package/dist/validators/min-length.d.ts +1 -1
  172. package/dist/validators/min-length.js +4 -7
  173. package/dist/validators/min.d.ts +1 -1
  174. package/dist/validators/min.js +4 -7
  175. package/dist/validators/multiple-of.d.ts +1 -1
  176. package/dist/validators/multiple-of.js +11 -10
  177. package/dist/validators/non-negative.d.ts +1 -1
  178. package/dist/validators/non-negative.js +2 -5
  179. package/dist/validators/non-zero.d.ts +1 -1
  180. package/dist/validators/non-zero.js +4 -7
  181. package/dist/validators/past-date.d.ts +1 -1
  182. package/dist/validators/past-date.js +10 -13
  183. package/dist/validators/pattern.d.ts +1 -1
  184. package/dist/validators/pattern.js +5 -8
  185. package/dist/validators/phone.d.ts +1 -1
  186. package/dist/validators/phone.js +10 -11
  187. package/dist/validators/required.d.ts +1 -1
  188. package/dist/validators/required.js +4 -7
  189. package/dist/validators/url.d.ts +1 -1
  190. package/dist/validators/url.js +48 -17
  191. package/dist/validators.d.ts +1 -1
  192. package/dist/validators.js +86 -108
  193. package/docs/llms/01-api-reference.md +60 -34
  194. package/docs/llms/02-quick-start.md +112 -74
  195. package/docs/llms/03-api-signatures.md +369 -148
  196. package/docs/llms/04-common-patterns.md +58 -56
  197. package/docs/llms/05-common-mistakes.md +69 -44
  198. package/docs/llms/06-troubleshooting.md +14 -9
  199. package/docs/llms/07-complete-import.md +74 -43
  200. package/docs/llms/08-form-types.md +11 -4
  201. package/docs/llms/09-formschema.md +132 -84
  202. package/docs/llms/10-arrays.md +141 -61
  203. package/docs/llms/11-async-watchfield.md +2 -2
  204. package/docs/llms/13-multi-step.md +134 -63
  205. package/docs/llms/14-extended-mistakes.md +20 -17
  206. package/docs/llms/15-project-structure.md +224 -70
  207. package/docs/llms/16-ui-components.md +86 -46
  208. package/docs/llms/17-nonexistent-api.md +217 -32
  209. package/docs/llms/18-conditional-fields.md +71 -32
  210. package/docs/llms/19-reading-values.md +45 -4
  211. package/docs/llms/20-compute-vs-watch.md +25 -10
  212. package/docs/llms/21-array-operations.md +76 -26
  213. package/docs/llms/22-cycle-detection.md +1 -1
  214. package/docs/llms/23-copy-from.md +2 -2
  215. package/docs/llms/24-sync-fields.md +6 -5
  216. package/docs/llms/25-reset-when.md +14 -7
  217. package/docs/llms/26-transform-value.md +4 -4
  218. package/docs/llms/27-revalidate-when.md +16 -15
  219. package/docs/llms/28-submit-and-reset.md +278 -128
  220. package/docs/llms/29-async-preload.md +41 -31
  221. package/docs/llms/30-type-safety-recipes.md +105 -51
  222. package/docs/llms/31-async-validator-debounce.md +96 -53
  223. package/docs/llms/33-validation-strategy.md +178 -66
  224. package/docs/llms/34-i18n.md +298 -0
  225. package/docs/llms/35-unified-contract.md +309 -0
  226. package/docs/llms/36-issue-messages.md +284 -0
  227. package/docs/llms/37-compiled-schema.md +332 -0
  228. package/docs/llms/38-form-flow.md +396 -0
  229. package/llms-index.json +1 -0
  230. package/llms.txt +10690 -3089
  231. package/package.json +48 -9
  232. package/dist/behaviors-node-DGEFMTQu.js +0 -18
  233. package/dist/behaviors-value-C7dSEhCc.js +0 -134
  234. package/dist/date-utils-dTT_x_Be.js +0 -31
  235. package/dist/derived-registry-CluZCQ7U.js +0 -16
  236. package/dist/form/behaviors.d.ts +0 -133
  237. package/dist/form/error-handler.d.ts +0 -166
  238. package/dist/form/factories/index.d.ts +0 -6
  239. package/dist/form/factories/node-factory.d.ts +0 -188
  240. package/dist/form/form-submitter.d.ts +0 -121
  241. package/dist/form/nodes/array-node.d.ts +0 -276
  242. package/dist/form/nodes/field-node.d.ts +0 -294
  243. package/dist/form/nodes/form-node.d.ts +0 -326
  244. package/dist/form/nodes/group-node.d.ts +0 -284
  245. package/dist/form/nodes/model-array-node.d.ts +0 -121
  246. package/dist/form/status-machine.d.ts +0 -115
  247. package/dist/form/types/deep-schema.d.ts +0 -107
  248. package/dist/form/types/form-proxy.d.ts +0 -141
  249. package/dist/form/unique-id.d.ts +0 -45
  250. package/dist/form/validation/validators/date-utils.d.ts +0 -30
  251. package/dist/form/validation/validators/email.d.ts +0 -23
  252. package/dist/form/validation/validators/future-date.d.ts +0 -23
  253. package/dist/form/validation/validators/integer.d.ts +0 -22
  254. package/dist/form/validation/validators/is-date.d.ts +0 -23
  255. package/dist/form/validation/validators/is-number.d.ts +0 -24
  256. package/dist/form/validation/validators/max-age.d.ts +0 -25
  257. package/dist/form/validation/validators/max-date.d.ts +0 -25
  258. package/dist/form/validation/validators/max-files.d.ts +0 -26
  259. package/dist/form/validation/validators/max-length.d.ts +0 -27
  260. package/dist/form/validation/validators/max-total-file-size.d.ts +0 -26
  261. package/dist/form/validation/validators/max.d.ts +0 -25
  262. package/dist/form/validation/validators/min-age.d.ts +0 -25
  263. package/dist/form/validation/validators/min-date.d.ts +0 -25
  264. package/dist/form/validation/validators/min-files.d.ts +0 -26
  265. package/dist/form/validation/validators/min-length.d.ts +0 -27
  266. package/dist/form/validation/validators/min.d.ts +0 -25
  267. package/dist/form/validation/validators/multiple-of.d.ts +0 -24
  268. package/dist/form/validation/validators/non-negative.d.ts +0 -22
  269. package/dist/form/validation/validators/non-zero.d.ts +0 -22
  270. package/dist/form/validation/validators/past-date.d.ts +0 -23
  271. package/dist/form/validation/validators/pattern.d.ts +0 -33
  272. package/dist/form/validation/validators/required.d.ts +0 -32
  273. package/dist/form/validation/validators/url.d.ts +0 -43
  274. package/dist/form/validation-schema.d.ts +0 -106
  275. package/dist/form/validation-strategy.d.ts +0 -55
  276. package/dist/form/validators.d.ts +0 -11
  277. package/dist/form-model-DYCzGGKF.js +0 -286
  278. package/dist/state/index.d.ts +0 -31
  279. package/dist/state/subscription-manager.d.ts +0 -180
  280. package/dist/state/types.d.ts +0 -144
  281. package/dist/state.d.ts +0 -2
  282. package/dist/state.js +0 -21
  283. package/dist/subscription-manager-705bls97.js +0 -171
@@ -1,24 +0,0 @@
1
- import { Validator, ValidateOptions } from '../../types/validation-schema';
2
- /**
3
- * Фабрика валидатора, проверяющего что число кратно заданному.
4
- *
5
- * Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6
- *
7
- * @param divisor - Делитель: значение должно быть кратно ему
8
- * @param options - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
9
- * попадает `multipleOf` (делитель).
10
- * @returns Чистый валидатор {@link Validator} для числового поля
11
- *
12
- * @example Проверка кратности
13
- * ```typescript
14
- * import { multipleOf } from '@reformer/core/validators';
15
- *
16
- * // Внутри FieldConfig схемы формы:
17
- * rating: {
18
- * value: model.$.rating,
19
- * component: Input,
20
- * validators: [multipleOf(0.5, { message: 'Только шаг 0.5' })],
21
- * },
22
- * ```
23
- */
24
- export declare function multipleOf<TForm = unknown, TField extends number | null | undefined = number>(divisor: number, options?: ValidateOptions): Validator<TForm, TField>;
@@ -1,22 +0,0 @@
1
- import { Validator, ValidateOptions } from '../../types/validation-schema';
2
- /**
3
- * Фабрика валидатора, проверяющего что число неотрицательное (`≥ 0`).
4
- *
5
- * Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6
- *
7
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
8
- * @returns Чистый валидатор {@link Validator} для числового поля
9
- *
10
- * @example Проверка неотрицательности
11
- * ```typescript
12
- * import { nonNegative } from '@reformer/core/validators';
13
- *
14
- * // Внутри FieldConfig схемы формы:
15
- * balance: {
16
- * value: model.$.balance,
17
- * component: Input,
18
- * validators: [nonNegative({ message: 'Баланс не может быть отрицательным' })],
19
- * },
20
- * ```
21
- */
22
- export declare function nonNegative<TForm = unknown, TField extends number | null | undefined = number>(options?: ValidateOptions): Validator<TForm, TField>;
@@ -1,22 +0,0 @@
1
- import { Validator, ValidateOptions } from '../../types/validation-schema';
2
- /**
3
- * Фабрика валидатора, проверяющего что число не равно нулю.
4
- *
5
- * Пустые значения и не-числа пропускаются (используйте {@link required} и {@link isNumber}).
6
- *
7
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
8
- * @returns Чистый валидатор {@link Validator} для числового поля
9
- *
10
- * @example Проверка «не ноль»
11
- * ```typescript
12
- * import { nonZero } from '@reformer/core/validators';
13
- *
14
- * // Внутри FieldConfig схемы формы:
15
- * divisor: {
16
- * value: model.$.divisor,
17
- * component: Input,
18
- * validators: [nonZero({ message: 'Не может быть нулём' })],
19
- * },
20
- * ```
21
- */
22
- export declare function nonZero<TForm = unknown, TField extends number | null | undefined = number>(options?: ValidateOptions): Validator<TForm, TField>;
@@ -1,23 +0,0 @@
1
- import { Validator, ValidateOptions } from '../../types/validation-schema';
2
- /**
3
- * Фабрика валидатора, проверяющего что дата не в будущем.
4
- *
5
- * Дата не должна быть позже сегодняшнего дня (сравнение по нормализованным датам).
6
- * Пустые и невалидные даты пропускаются (используйте {@link required} и {@link isDate}).
7
- *
8
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
9
- * @returns Чистый валидатор {@link Validator} для поля даты (`string | Date`)
10
- *
11
- * @example Дата не в будущем
12
- * ```typescript
13
- * import { required, pastDate } from '@reformer/core/validators';
14
- *
15
- * // Внутри FieldConfig схемы формы:
16
- * birthDate: {
17
- * value: model.$.birthDate,
18
- * component: DatePicker,
19
- * validators: [required(), pastDate({ message: 'Дата рождения не может быть в будущем' })],
20
- * },
21
- * ```
22
- */
23
- export declare function pastDate<TForm = unknown, TField extends string | Date | null | undefined = string | Date>(options?: ValidateOptions): Validator<TForm, TField>;
@@ -1,33 +0,0 @@
1
- import { Validator, ValidateOptions } from '../../types/validation-schema';
2
- /**
3
- * Фабрика валидатора регулярного выражения.
4
- *
5
- * Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required}
6
- * для обязательности).
7
- *
8
- * @param regex - Регулярное выражение для проверки значения
9
- * @param options - Опции валидатора ({@link ValidateOptions}). В `params` ошибки автоматически
10
- * попадает `pattern` (строка-источник regex).
11
- * @returns Чистый валидатор {@link Validator} для строкового поля
12
- *
13
- * @example Проверка по регулярному выражению
14
- * ```typescript
15
- * import { required, pattern } from '@reformer/core/validators';
16
- *
17
- * // Внутри FieldConfig схемы формы:
18
- * name: {
19
- * value: model.$.name,
20
- * component: Input,
21
- * validators: [pattern(/^[a-zA-Zа-яА-Я]+$/, { message: 'Только буквы' })],
22
- * },
23
- * phone: {
24
- * value: model.$.phone,
25
- * component: InputMask,
26
- * validators: [
27
- * required(),
28
- * pattern(/^\+7 \(\d{3}\) \d{3}-\d{2}-\d{2}$/, { message: 'Формат +7 (999) 123-45-67' }),
29
- * ],
30
- * },
31
- * ```
32
- */
33
- export declare function pattern<TForm = unknown, TField extends string | null | undefined = string>(regex: RegExp, options?: ValidateOptions): Validator<TForm, TField>;
@@ -1,32 +0,0 @@
1
- import { Validator, ValidateOptions } from '../../types/validation-schema';
2
- /**
3
- * Фабрика валидатора обязательного поля.
4
- *
5
- * Возвращает чистую функцию-валидатор `(value, control, root)`. Передаётся в `validate()`.
6
- *
7
- * Пустыми считаются: `null`, `undefined`, `''` (пустая строка), `[]` (пустой массив —
8
- * обязательный multi-select / FormArray без выбранных элементов).
9
- * Для boolean полей требуется значение `true`.
10
- *
11
- * @param options - Опции валидатора ({@link ValidateOptions}): `message`, `params`
12
- * @returns Чистый валидатор {@link Validator} для поля схемы
13
- *
14
- * @example Обязательные поля в схеме формы
15
- * ```typescript
16
- * import { required } from '@reformer/core/validators';
17
- *
18
- * // Внутри FieldConfig схемы формы:
19
- * email: { value: model.$.email, component: Input, validators: [required()] },
20
- * phone: {
21
- * value: model.$.phone,
22
- * component: Input,
23
- * validators: [required({ message: 'Укажите номер телефона' })],
24
- * },
25
- * agreeToTerms: {
26
- * value: model.$.agreeToTerms,
27
- * component: Checkbox,
28
- * validators: [required({ message: 'Необходимо принять условия' })],
29
- * },
30
- * ```
31
- */
32
- export declare function required<TForm = unknown, TField = unknown>(options?: ValidateOptions): Validator<TForm, TField>;
@@ -1,43 +0,0 @@
1
- import { Validator, ValidateOptions } from '../../types/validation-schema';
2
- /**
3
- * Опции валидатора {@link url}. Расширяют {@link ValidateOptions} (`message`, `params`)
4
- * настройками проверки протокола.
5
- */
6
- export interface UrlValidatorOptions extends ValidateOptions {
7
- /** Требовать наличие протокола (`http://` или `https://`). По умолчанию `false`. */
8
- requireProtocol?: boolean;
9
- /**
10
- * Список разрешённых протоколов (без `://`), например `['https']`. Если задан,
11
- * значение с иным протоколом даёт ошибку с кодом `url_protocol`.
12
- */
13
- allowedProtocols?: string[];
14
- }
15
- /**
16
- * Фабрика валидатора URL.
17
- *
18
- * Пустые значения (`''`/`null`/`undefined`) пропускаются (используйте {@link required}
19
- * для обязательности). При `requireProtocol` протокол обязателен; `allowedProtocols`
20
- * дополнительно ограничивает набор допустимых протоколов.
21
- *
22
- * @param options - Опции валидатора {@link UrlValidatorOptions}
23
- * @returns Чистый валидатор {@link Validator} для строкового поля
24
- *
25
- * @example Проверка URL
26
- * ```typescript
27
- * import { required, url } from '@reformer/core/validators';
28
- *
29
- * // Внутри FieldConfig схемы формы:
30
- * website: {
31
- * value: model.$.website,
32
- * component: Input,
33
- * validators: [required(), url({ message: 'Введите корректный URL' })],
34
- * },
35
- * // Требовать протокол и ограничить схему только https:
36
- * homepage: {
37
- * value: model.$.homepage,
38
- * component: Input,
39
- * validators: [url({ requireProtocol: true, allowedProtocols: ['https'] })],
40
- * },
41
- * ```
42
- */
43
- export declare function url<TForm = unknown, TField extends string | null | undefined = string>(options?: UrlValidatorOptions): Validator<TForm, TField>;
@@ -1,106 +0,0 @@
1
- import { FormModel, ModelArray, PathAwareSignal, ValidationError } from '../index';
2
- /**
3
- * Синхронное правило поля типа `TField`. Проверяется ТОЛЬКО значение (`value`).
4
- *
5
- * Позиционные `scope`/`root` помечены `never` намеренно: так встроенные value-only фабрики
6
- * (`required()`/`min()`/… — они `(value, model, root) => …`) и inline-правила `(value) => …`
7
- * ОБА присваиваются в `Rule<TField>[]` без `any`, при этом сохраняется проверка типа поля
8
- * (`validate(model.$.age, [email()])` подсветится — `email` ждёт `string`, поле `number`).
9
- * На вызове раннер приводит правило к callable и передаёт `(value, model, model)`.
10
- */
11
- export type Rule<TField> = (value: TField, scope: never, root: never) => ValidationError | null;
12
- /**
13
- * Асинхронное правило поля. Получает `AbortSignal` для отмены устаревших ответов (быстрый повторный
14
- * прогон той же схемы отменяет предыдущий). Сетевой сбой не должен блокировать — ловите и возвращайте `null`.
15
- */
16
- export type AsyncRule<TField> = (value: TField, ctx: {
17
- signal: AbortSignal;
18
- }) => Promise<ValidationError | null>;
19
- /** Схема валидации — обычная функция над (под)моделью. First-class значение (можно `apply`/тестировать/переиспользовать). */
20
- export type ValidationSchema<T> = (ctx: {
21
- model: FormModel<T>;
22
- }) => void;
23
- /**
24
- * Синхронные правила поля.
25
- *
26
- * @example
27
- * ```ts
28
- * validate(model.$.loanAmount, [required({ message: 'Сумма' }), min(50000)]);
29
- * ```
30
- */
31
- export declare function validate<TField>(sig: PathAwareSignal<TField>, rules: Rule<TField>[]): void;
32
- /**
33
- * Асинхронные правила поля (зеркалит движковое разделение `validators` / `asyncValidators`).
34
- * Раннер дожидается их и прокидывает `AbortSignal` для отмены устаревших ответов.
35
- *
36
- * @example
37
- * ```ts
38
- * validateAsync(model.$.username, [async (v, { signal }) => {
39
- * const r = await fetch(`/api/free?u=${v}`, { signal });
40
- * return (await r.json()).free ? null : { code: 'taken', message: 'Занято' };
41
- * }]);
42
- * ```
43
- */
44
- export declare function validateAsync<TField>(sig: PathAwareSignal<TField>, rules: AsyncRule<TField>[]): void;
45
- /**
46
- * Условная валидация: правила внутри `cb` активны, только пока `cond()` истинно; иначе их поля
47
- * ГАСЯТСЯ (пустой bucket → `setErrors([])`). Не трогает включение/сброс поля — это дело поведения (`enableWhen`).
48
- */
49
- export declare function validateWhen(cond: () => boolean, cb: () => void): void;
50
- /**
51
- * Cross-field правило: `fn` получает СНАПШОТ модели текущего scope (`model.get()`) и вешает ошибку на `sig`.
52
- * Для элементов массива / под-моделей захватывайте нужный снапшот в замыкание (`const item = im.get()`),
53
- * т.к. `fn` всегда получает модель ТЕКУЩЕГО scope (корень прогона), а не под-модель.
54
- */
55
- export declare function cross<TSnapshot>(sig: PathAwareSignal<unknown>, fn: (form: TSnapshot) => ValidationError | null): void;
56
- /**
57
- * Применить под-правила к КАЖДОМУ элементу текущего массива модели.
58
- * `U extends object` — элементы должны быть под-моделями (объектами); для массива примитивов валидируйте лист напрямую.
59
- */
60
- export declare function each<U extends object>(arr: ModelArray<U>, itemFn: (item: FormModel<U>) => void): void;
61
- /** Композиция под-схем в текущую (над той же моделью scope). Заменяет пошаговую группировку. */
62
- export declare function apply<T>(...schemas: ValidationSchema<T>[]): void;
63
- /**
64
- * Тонкая identity-обёртка для типизации/discoverability (как `defineFormBehavior`). Возвращает схему как есть.
65
- *
66
- * @example
67
- * ```ts
68
- * export const step1 = defineValidationSchema<LoanForm>(({ model }) => {
69
- * validate(model.$.loanAmount, [required(), min(50000)]);
70
- * });
71
- * ```
72
- */
73
- export declare function defineValidationSchema<T>(schema: ValidationSchema<T>): ValidationSchema<T>;
74
- /**
75
- * Провалидировать модель ЛЮБОЙ схемой (шаг или вся форма). Открывает ambient-окно на время
76
- * синхронного прогона `schema`, дожидается async-правил, разносит ошибки по нодам формы и гасит
77
- * поля, ставшие валидными. Возвращает `true`, если нет блокирующих ошибок (`severity:'warning'` не блокирует).
78
- *
79
- * Гашение — на пару (model, schema): `validateModel(model, step2)` и `validateModel(model, form)` не мешают
80
- * друг другу. Устаревший прогон (быстрый повторный вызов той же (model, schema)) отменяется через `AbortSignal`
81
- * и возвращает `false` (**fail-closed** — отменённому результату нельзя доверять для submit).
82
- *
83
- * ⚠️ `schema` должна быть СТАБИЛЬНОЙ ссылкой: отмена устаревших прогонов ключится по идентичности `schema`.
84
- * Инлайн-стрелка (`validateModel(model, ({ model }) => …)`) каждый раз создаёт НОВЫЙ прогон без дедупликации —
85
- * держите схемы в `const` / `defineValidationSchema`.
86
- *
87
- * `options.touch` (§6): по завершении помечает `touched` ИМЕННО поля, которые схема проверяла
88
- * (не всё поддерево). Ошибки становятся видимыми (`shouldShowError = invalid && (touched||dirty)`)
89
- * без ручного `form.markAsTouched()`; при пошаговой валидации следующий шаг не показывается
90
- * «тронутым» до ввода. Валидные проверенные поля тоже метятся — это безвредно (ошибка не покажется).
91
- *
92
- * @param model - Модель данных формы.
93
- * @param schema - Схема валидации (стабильная ссылка).
94
- * @param options - `{ touch }` — пометить провалидированные поля `touched` для показа ошибок.
95
- *
96
- * @example
97
- * ```ts
98
- * const ok = await validateModel(model, step2Validation); // один шаг
99
- * const all = await validateModel(model, formValidation); // вся форма
100
- * const stepOk = await validateModel(model, step2Validation, { touch: true }); // + показать ошибки шага
101
- * ```
102
- */
103
- export declare function validateModel<T>(model: FormModel<T>, schema: ValidationSchema<T>, options?: {
104
- touch?: boolean;
105
- }): Promise<boolean>;
106
- export * from './validation-strategy';
@@ -1,55 +0,0 @@
1
- import { ReadonlySignal } from '@preact/signals-core';
2
- import { FormModel } from '../index';
3
- import { ValidationSchema } from './validation-schema';
4
- /**
5
- * Когда запускается schema-валидация:
6
- * - `submit` (по умолчанию) — только явным вызовом `validate()` (на отправке);
7
- * - `blur` — при потере фокуса поля (смена `touched` любого листа);
8
- * - `change` — на каждый ввод (с опц. `debounce`);
9
- * - `afterFirstSubmit` — тихо до первого `validate()`, затем live (см. `liveAfterSubmit`).
10
- */
11
- export type ValidationStrategyKind = 'submit' | 'blur' | 'change' | 'afterFirstSubmit';
12
- export interface ValidationStrategyOptions {
13
- /** Стратегия запуска. Default `'submit'`. */
14
- strategy?: ValidationStrategyKind;
15
- /** Debounce (мс) для live-фаз (`change` и live-часть `afterFirstSubmit`). Default `0`. */
16
- debounce?: number;
17
- /** Режим live-фазы для `afterFirstSubmit`. Default `'change'`. */
18
- liveAfterSubmit?: 'change' | 'blur';
19
- }
20
- export interface FormValidationController {
21
- /**
22
- * Полный прогон схемы с раскрытием ошибок (`touch: true`) — для submit. Также переводит
23
- * `afterFirstSubmit` в live-фазу. Возвращает `false`, если есть блокирующие ошибки.
24
- */
25
- validate(): Promise<boolean>;
26
- /** Армировать реактивные подписки стратегии. Идемпотентно. Возвращает `dispose`. НЕ звать при SSR. */
27
- start(): () => void;
28
- /** Снять подписки/таймеры. Идемпотентно. */
29
- dispose(): void;
30
- /** Идёт ли прогон (submit или live) — снапшот. */
31
- readonly isValidating: boolean;
32
- /** Реактивный сигнал состояния прогона (для тонкой подписки в UI). */
33
- readonly validating: ReadonlySignal<boolean>;
34
- }
35
- /**
36
- * Собрать контроллер валидации формы с выбранной стратегией запуска. Переиспользует
37
- * {@link validateModel} как единственный движок прогона.
38
- *
39
- * Фабрика ЧИСТАЯ до `start()` (никаких подписок) — безопасна для SSR/headless. Реактивные триггеры
40
- * арминуются только в `start()` (в React — из `useEffect`).
41
- *
42
- * @typeParam T - Форма данных модели.
43
- * @param model - Модель данных.
44
- * @param schema - Схема валидации. **Стабильная ссылка** (иначе `validateModel` не отменит устаревший прогон).
45
- * @param options - {@link ValidationStrategyOptions}.
46
- *
47
- * @example
48
- * ```ts
49
- * const ctrl = createFormValidation(model, schema, { strategy: 'afterFirstSubmit', debounce: 300 });
50
- * const dispose = ctrl.start(); // на клиенте
51
- * const ok = await ctrl.validate(); // submit → раскрыть все ошибки
52
- * dispose();
53
- * ```
54
- */
55
- export declare function createFormValidation<T>(model: FormModel<T>, schema: ValidationSchema<T>, options?: ValidationStrategyOptions): FormValidationController;
@@ -1,11 +0,0 @@
1
- /**
2
- * Точка входа сабпата `@reformer/core/validators` — все фабрики правил одним импортом.
3
- *
4
- * Гранулярные сабпаты (`@reformer/core/validators/required` и ещё 21) собираются отдельными
5
- * entry для tree-shaking; этот модуль отдаёт полный набор для случаев, когда правил много.
6
- *
7
- * Ранее здесь был ещё и default-экспорт (`validators` из корневого `index`), заведённый как
8
- * часть бандл-фикса «shared static registry». Реестров, ради которых он существовал, в коде
9
- * больше нет, чанк-шаринг он не обеспечивал, потребителей не имел — удалён в 7.0.
10
- */
11
- export * from './validation/index';
@@ -1,286 +0,0 @@
1
- import { signal as k } from "@preact/signals-core";
2
- import { i as b } from "./derived-registry-CluZCQ7U.js";
3
- const h = (e) => !(e === null || typeof e != "object" || Array.isArray(e) || e instanceof Date || typeof Blob < "u" && e instanceof Blob || typeof File < "u" && e instanceof File), a = (e, i) => e === "" ? String(i) : `${e}.${i}`, p = (e) => /^\d+$/.test(e), o = (e) => {
4
- if (Array.isArray(e)) return e.map(o);
5
- if (h(e)) {
6
- const i = {};
7
- for (const t of Object.keys(e)) i[t] = o(e[t]);
8
- return i;
9
- }
10
- return e;
11
- }, u = (e, i) => {
12
- if (e === i) return !0;
13
- if (Array.isArray(e) && Array.isArray(i))
14
- return e.length !== i.length ? !1 : e.every((t, r) => u(t, i[r]));
15
- if (h(e) && h(i)) {
16
- const t = Object.keys(e), r = Object.keys(i);
17
- return t.length !== r.length ? !1 : t.every((n) => u(e[n], i[n]));
18
- }
19
- return !1;
20
- };
21
- class x {
22
- constructor(i, t) {
23
- this.path = t;
24
- const r = k(i);
25
- r.__path = t, this.signal = r, this.initial = o(i);
26
- }
27
- kind = "leaf";
28
- signal;
29
- initial;
30
- rebase(i) {
31
- this.path = i, this.signal.__path = i;
32
- }
33
- /** Реактивное чтение (внутри effect/computed создаёт зависимость). */
34
- read() {
35
- return this.signal.value;
36
- }
37
- /** Нереактивный снимок. */
38
- peek() {
39
- return this.signal.peek();
40
- }
41
- set(i) {
42
- this.signal.value = i;
43
- }
44
- resetToInitial() {
45
- this.signal.value = o(this.initial);
46
- }
47
- captureInitial() {
48
- this.initial = o(this.signal.peek());
49
- }
50
- dirty() {
51
- return !u(this.signal.peek(), this.initial);
52
- }
53
- }
54
- class A {
55
- constructor(i, t) {
56
- this.path = t;
57
- for (const r of Object.keys(i))
58
- this.children.set(r, c(i[r], a(t, r)));
59
- }
60
- kind = "group";
61
- children = /* @__PURE__ */ new Map();
62
- rebase(i) {
63
- this.path = i;
64
- for (const [t, r] of this.children) r.rebase(a(i, t));
65
- }
66
- peek() {
67
- const i = {};
68
- for (const [t, r] of this.children) i[t] = r.peek();
69
- return i;
70
- }
71
- set(i) {
72
- if (i == null || typeof i != "object") return;
73
- const t = i;
74
- for (const [r, n] of this.children)
75
- r in t && (n.kind === "leaf" && b(n.signal) || n.set(t[r]));
76
- }
77
- resetToInitial() {
78
- for (const i of this.children.values()) i.resetToInitial();
79
- }
80
- captureInitial() {
81
- for (const i of this.children.values()) i.captureInitial();
82
- }
83
- dirty() {
84
- for (const i of this.children.values()) if (i.dirty()) return !0;
85
- return !1;
86
- }
87
- }
88
- class I {
89
- constructor(i, t) {
90
- this.path = t, this.items = k(i.map((r, n) => c(r, a(t, n)))), this.initial = o(i);
91
- }
92
- kind = "array";
93
- items;
94
- initial;
95
- rebase(i) {
96
- this.path = i, this.items.peek().forEach((t, r) => t.rebase(a(i, r)));
97
- }
98
- reindex() {
99
- this.items.peek().forEach((i, t) => i.rebase(a(this.path, t)));
100
- }
101
- push(i) {
102
- const t = this.items.peek();
103
- this.items.value = [...t, c(i, a(this.path, t.length))];
104
- }
105
- insertAt(i, t) {
106
- const r = [...this.items.peek()];
107
- r.splice(i, 0, c(t, a(this.path, i))), this.items.value = r, this.reindex();
108
- }
109
- removeAt(i) {
110
- const t = [...this.items.peek()];
111
- t.splice(i, 1), this.items.value = t, this.reindex();
112
- }
113
- move(i, t) {
114
- const r = [...this.items.peek()], [n] = r.splice(i, 1);
115
- n && r.splice(t, 0, n), this.items.value = r, this.reindex();
116
- }
117
- swap(i, t) {
118
- const r = [...this.items.peek()];
119
- i < 0 || t < 0 || i >= r.length || t >= r.length || i === t || ([r[i], r[t]] = [r[t], r[i]], this.items.value = r, this.reindex());
120
- }
121
- clear() {
122
- this.items.value = [];
123
- }
124
- peek() {
125
- return this.items.peek().map((i) => i.peek());
126
- }
127
- set(i) {
128
- const t = Array.isArray(i) ? i : [];
129
- this.items.value = t.map((r, n) => c(r, a(this.path, n)));
130
- }
131
- resetToInitial() {
132
- this.set(o(this.initial));
133
- }
134
- captureInitial() {
135
- this.initial = o(this.peek());
136
- }
137
- dirty() {
138
- return !u(this.peek(), this.initial);
139
- }
140
- }
141
- function c(e, i) {
142
- return Array.isArray(e) ? new I(e, i) : h(e) ? new A(e, i) : new x(e, i);
143
- }
144
- function l(e) {
145
- if (e)
146
- return e.kind === "group" ? _(e) : e.kind === "array" ? P(e) : e.read();
147
- }
148
- function P(e) {
149
- const i = {
150
- get length() {
151
- return e.items.value.length;
152
- },
153
- push: (t) => e.push(t),
154
- insertAt: (t, r) => e.insertAt(t, r),
155
- removeAt: (t) => e.removeAt(t),
156
- move: (t, r) => e.move(t, r),
157
- swap: (t, r) => e.swap(t, r),
158
- clear: () => e.clear(),
159
- at: (t) => l(e.items.value[t]),
160
- map: (t) => e.items.value.map((r, n) => t(l(r), n)),
161
- forEach: (t) => e.items.value.forEach((r, n) => t(l(r), n)),
162
- toArray: () => e.peek(),
163
- [Symbol.iterator]: function* () {
164
- const t = e.items.value;
165
- for (let r = 0; r < t.length; r++) yield l(t[r]);
166
- }
167
- };
168
- return new Proxy(i, {
169
- get: (t, r, n) => r === "__path" ? e.path : typeof r == "string" && p(r) ? l(e.items.value[Number(r)]) : Reflect.get(t, r, n),
170
- has: (t, r) => typeof r == "string" && p(r) ? Number(r) < e.items.value.length : Reflect.has(t, r)
171
- });
172
- }
173
- function d(e) {
174
- if (e.kind === "leaf") return e.signal;
175
- if (e.kind === "group")
176
- return new Proxy(
177
- {},
178
- {
179
- get: (t, r) => {
180
- if (r === "__path") return e.path;
181
- if (typeof r != "string") return;
182
- const n = e.children.get(r);
183
- return n ? d(n) : void 0;
184
- },
185
- has: (t, r) => typeof r == "string" && e.children.has(r),
186
- ownKeys: () => [...e.children.keys()],
187
- getOwnPropertyDescriptor: (t, r) => typeof r == "string" && e.children.has(r) ? { enumerable: !0, configurable: !0 } : void 0
188
- }
189
- );
190
- const i = e;
191
- return new Proxy(
192
- {
193
- get length() {
194
- return i.items.value.length;
195
- }
196
- },
197
- {
198
- get: (t, r, n) => {
199
- if (r === "__path") return i.path;
200
- if (typeof r == "string" && p(r)) {
201
- const s = i.items.value[Number(r)];
202
- return s ? d(s) : void 0;
203
- }
204
- return Reflect.get(t, r, n);
205
- }
206
- }
207
- );
208
- }
209
- function j(e, i) {
210
- if (!i) return;
211
- let t = e;
212
- for (const r of i.split(".")) {
213
- if (!t) return;
214
- if (t.kind === "group") t = t.children.get(r);
215
- else if (t.kind === "array") t = t.items.peek()[Number(r)];
216
- else return;
217
- }
218
- return t && t.kind === "leaf" ? t.signal : void 0;
219
- }
220
- const y = /* @__PURE__ */ new Set([
221
- "$",
222
- "get",
223
- "set",
224
- "patch",
225
- "isDirty",
226
- "reset",
227
- "captureInitial",
228
- "signalAt"
229
- ]), v = /* @__PURE__ */ new WeakMap(), w = /* @__PURE__ */ new WeakMap();
230
- function _(e) {
231
- const i = v.get(e);
232
- if (i) return i;
233
- const t = {
234
- $: d(e),
235
- get: () => e.peek(),
236
- set: (n) => e.set(n),
237
- patch: (n) => e.set(n),
238
- isDirty: () => e.dirty(),
239
- reset: () => e.resetToInitial(),
240
- captureInitial: () => e.captureInitial(),
241
- signalAt: (n) => j(e, n)
242
- }, r = new Proxy(
243
- {},
244
- {
245
- get: (n, s) => {
246
- if (s === "__path") return e.path;
247
- if (typeof s != "string") return;
248
- const f = e.children.get(s);
249
- if (f) return l(f);
250
- if (y.has(s)) return t[s];
251
- },
252
- set: (n, s, f) => {
253
- if (typeof s != "string") return !1;
254
- const g = e.children.get(s);
255
- return g ? (g.set(f), !0) : !1;
256
- },
257
- has: (n, s) => typeof s == "string" && (e.children.has(s) || y.has(s)),
258
- ownKeys: () => [...e.children.keys()],
259
- getOwnPropertyDescriptor: (n, s) => typeof s == "string" && e.children.has(s) ? { enumerable: !0, configurable: !0 } : void 0
260
- }
261
- );
262
- return v.set(e, r), w.set(r, e), r;
263
- }
264
- function m(e, i) {
265
- if (e.kind === "leaf") {
266
- i(e.signal);
267
- return;
268
- }
269
- if (e.kind === "group") {
270
- for (const t of e.children.values()) m(t, i);
271
- return;
272
- }
273
- for (const t of e.items.value) m(t, i);
274
- }
275
- function D(e, i) {
276
- const t = w.get(e);
277
- t && m(t, i);
278
- }
279
- function O(e) {
280
- const i = new A(e, "");
281
- return _(i);
282
- }
283
- export {
284
- O as c,
285
- D as e
286
- };