@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
@@ -0,0 +1,52 @@
1
+ import { e as p } from "./locale-CG54AU2Q.js";
2
+ function u(t) {
3
+ const n = t.messages;
4
+ return n !== null && typeof n == "object";
5
+ }
6
+ function y(t) {
7
+ if (t != null) {
8
+ if (typeof t != "object" || Array.isArray(t))
9
+ throw new TypeError("источник локали вернул не объект");
10
+ return u(t) ? t : { messages: t };
11
+ }
12
+ }
13
+ function g(t) {
14
+ const n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), r = (e) => {
15
+ const i = n.get(e);
16
+ if (i !== void 0) return Promise.resolve(i);
17
+ const c = o.get(e);
18
+ if (c !== void 0) return c;
19
+ const l = Promise.all(t.map(async (s) => y(await s(e)))).then((s) => {
20
+ let a = { code: e, messages: {} };
21
+ for (const f of s)
22
+ f !== void 0 && (a = p(a, f));
23
+ return a = { ...a, code: e }, n.set(e, a), a;
24
+ }).finally(() => {
25
+ o.delete(e);
26
+ });
27
+ return o.set(e, l), l;
28
+ };
29
+ return Object.assign(r, {
30
+ peek: (e) => n.get(e),
31
+ preload: r
32
+ });
33
+ }
34
+ function h(t, n) {
35
+ return async (o) => {
36
+ const r = t(o), e = await fetch(r, n);
37
+ if (!e.ok)
38
+ throw new Error(`локаль «${o}»: ${r} ответил ${e.status}`);
39
+ return await e.json();
40
+ };
41
+ }
42
+ function d(t) {
43
+ return (n) => {
44
+ const o = n.split("-")[0].toLowerCase(), e = (Object.prototype.hasOwnProperty.call(t, n) ? t[n] : void 0) ?? (Object.prototype.hasOwnProperty.call(t, o) ? t[o] : void 0);
45
+ return e === void 0 ? null : e();
46
+ };
47
+ }
48
+ export {
49
+ d as b,
50
+ g as c,
51
+ h as f
52
+ };
package/dist/locale/en.js CHANGED
@@ -1,4 +1,4 @@
1
- import { m as e } from "../en-CjAqn7h0.js";
1
+ import { m as e } from "../en-HP8XEych.js";
2
2
  const o = { code: "en", weekStartsOn: 0, messages: e };
3
3
  export {
4
4
  o as en
@@ -17,6 +17,8 @@
17
17
  "validation.max": "Must be at most {max}",
18
18
  "validation.minLength": "Enter at least {minLength, plural, one{# character} other{# characters}}",
19
19
  "validation.maxLength": "Enter no more than {maxLength, plural, one{# character} other{# characters}}",
20
+ "validation.minItems": "At least {minLength, plural, one{# item} other{# items}}",
21
+ "validation.maxItems": "No more than {maxLength, plural, one{# item} other{# items}}",
20
22
  "validation.isNumber": "Enter a number",
21
23
  "validation.integer": "Enter a whole number",
22
24
  "validation.multipleOf": "Must be a multiple of {multipleOf}",
@@ -37,6 +39,7 @@
37
39
  "validation.maxTotalFileSize": "The total size of the files exceeds {maxTotalFileSize}",
38
40
  "validation.fileExists": "File {fileName} has already been added",
39
41
  "validation.uploadAborted": "Upload cancelled",
40
- "validation.uploadFailed": "Failed to upload {fileName}"
42
+ "validation.uploadFailed": "Failed to upload {fileName}",
43
+ "validation.ruleFailed": "Could not check this field. Try again"
41
44
  }
42
45
  }
package/dist/locale/ru.js CHANGED
@@ -14,6 +14,8 @@ const a = {
14
14
  "validation.max": "Не больше {max}",
15
15
  "validation.minLength": "Не меньше {minLength, plural, one{# символа} few{# символов} many{# символов} other{# символа}}",
16
16
  "validation.maxLength": "Не больше {maxLength, plural, one{# символа} few{# символов} many{# символов} other{# символа}}",
17
+ "validation.minItems": "Не меньше {minLength, plural, one{# элемента} few{# элементов} many{# элементов} other{# элемента}}",
18
+ "validation.maxItems": "Не больше {maxLength, plural, one{# элемента} few{# элементов} many{# элементов} other{# элемента}}",
17
19
  "validation.isNumber": "Введите число",
18
20
  "validation.integer": "Введите целое число",
19
21
  "validation.multipleOf": "Число должно быть кратно {multipleOf}",
@@ -34,7 +36,8 @@ const a = {
34
36
  "validation.maxTotalFileSize": "Суммарный размер файлов больше {maxTotalFileSize}",
35
37
  "validation.fileExists": "Файл {fileName} уже добавлен",
36
38
  "validation.uploadAborted": "Загрузка прервана",
37
- "validation.uploadFailed": "Не удалось загрузить файл {fileName}"
39
+ "validation.uploadFailed": "Не удалось загрузить файл {fileName}",
40
+ "validation.ruleFailed": "Не удалось проверить поле. Повторите попытку"
38
41
  }, i = a, e = { code: "ru", weekStartsOn: 1, messages: i };
39
42
  export {
40
43
  e as ru
@@ -17,6 +17,8 @@
17
17
  "validation.max": "Не больше {max}",
18
18
  "validation.minLength": "Не меньше {minLength, plural, one{# символа} few{# символов} many{# символов} other{# символа}}",
19
19
  "validation.maxLength": "Не больше {maxLength, plural, one{# символа} few{# символов} many{# символов} other{# символа}}",
20
+ "validation.minItems": "Не меньше {minLength, plural, one{# элемента} few{# элементов} many{# элементов} other{# элемента}}",
21
+ "validation.maxItems": "Не больше {maxLength, plural, one{# элемента} few{# элементов} many{# элементов} other{# элемента}}",
20
22
  "validation.isNumber": "Введите число",
21
23
  "validation.integer": "Введите целое число",
22
24
  "validation.multipleOf": "Число должно быть кратно {multipleOf}",
@@ -37,6 +39,7 @@
37
39
  "validation.maxTotalFileSize": "Суммарный размер файлов больше {maxTotalFileSize}",
38
40
  "validation.fileExists": "Файл {fileName} уже добавлен",
39
41
  "validation.uploadAborted": "Загрузка прервана",
40
- "validation.uploadFailed": "Не удалось загрузить файл {fileName}"
42
+ "validation.uploadFailed": "Не удалось загрузить файл {fileName}",
43
+ "validation.ruleFailed": "Не удалось проверить поле. Повторите попытку"
41
44
  }
42
45
  }
@@ -0,0 +1,219 @@
1
+ class v extends Error {
2
+ name = "MessageSyntaxError";
3
+ }
4
+ const O = (t) => `⟦${t}⟧`, w = 100, L = new RegExp("\\p{Pattern_White_Space}", "u"), _ = /[\p{White_Space}\p{Pattern_Syntax}]/u, $ = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map();
5
+ function E(t) {
6
+ let e = x.get(t);
7
+ if (e === void 0) {
8
+ try {
9
+ Intl.getCanonicalLocales(t), e = t;
10
+ } catch {
11
+ e = "en", process.env.NODE_ENV !== "production" && console.warn(
12
+ `[@reformer/core/i18n] код языка «${t}» не BCP 47 — числа, даты и формы слов форматируются по en.`
13
+ );
14
+ }
15
+ x.set(t, e);
16
+ }
17
+ return e;
18
+ }
19
+ function M(t) {
20
+ try {
21
+ return String(t);
22
+ } catch {
23
+ return "";
24
+ }
25
+ }
26
+ function b(t) {
27
+ let e = 0, n = 0;
28
+ const r = (s) => {
29
+ throw new v(`${s} (позиция ${e}) в сообщении: ${t}`);
30
+ }, i = (s, o) => s === "{" || s === "}" || s === "<" || s === ">" || o && s === "#", l = () => {
31
+ for (; e < t.length && L.test(t[e]); ) e++;
32
+ }, m = () => {
33
+ const s = e;
34
+ for (; e < t.length && !_.test(t[e]); ) e++;
35
+ return e === s && r("ожидалось имя"), t.slice(s, e);
36
+ }, p = (s) => {
37
+ if (s !== "plural" || t[e] !== "=") return m();
38
+ const o = e++;
39
+ (t[e] === "+" || t[e] === "-") && e++;
40
+ const f = e;
41
+ for (; e < t.length && t[e] >= "0" && t[e] <= "9"; ) e++;
42
+ return (e === f || !Number.isSafeInteger(Number(t.slice(f, e)))) && r("после «=» ожидалось целое число"), t.slice(o, e);
43
+ }, c = (s) => {
44
+ if (e++, t[e] === "'")
45
+ return e++, "'";
46
+ if (!i(t[e], s)) return "'";
47
+ let o = "";
48
+ for (; e < t.length; )
49
+ if (t[e] !== "'") o += t[e++];
50
+ else if (t[e + 1] === "'")
51
+ o += "'", e += 2;
52
+ else
53
+ return e++, o;
54
+ return o;
55
+ }, a = (s, o) => {
56
+ const f = [];
57
+ let h = "";
58
+ const g = () => {
59
+ h !== "" && (f.push({ kind: "text", value: h }), h = "");
60
+ };
61
+ for (; e < t.length; ) {
62
+ const d = t[e];
63
+ if (d === "}") {
64
+ s || r("непарная «}» — литерал пишется как '}'");
65
+ break;
66
+ }
67
+ d === "'" ? h += c(o !== null) : d === "#" && o !== null ? (e++, g(), f.push({ kind: "number", name: o })) : d === "{" ? (g(), f.push(N())) : (h += d, e++);
68
+ }
69
+ return g(), f;
70
+ }, u = (s, o, f) => {
71
+ const h = /* @__PURE__ */ new Map();
72
+ for (l(); e < t.length && t[e] !== "}"; ) {
73
+ const g = p(o);
74
+ h.has(g) && r(`ветка «${g}» в «${s}, ${o}» повторяется`), l(), t[e] !== "{" && r(`ожидалась «{» после ветки «${g}»`), e++, h.set(g, a(!0, f)), t[e] !== "}" && r(`ветка «${g}» не закрыта`), e++, l();
75
+ }
76
+ return t[e] !== "}" && r(`«${s}, ${o}» не закрыт «}»`), e++, h.has("other") || r(`в «${s}, ${o}» нет обязательной ветки other`), h;
77
+ }, N = () => {
78
+ n === w && r(`вложенность аргументов глубже ${w} уровней`), n++, e++, l();
79
+ const s = m();
80
+ l();
81
+ let o;
82
+ if (t[e] === "}")
83
+ e++, o = { kind: "arg", name: s };
84
+ else {
85
+ t[e] !== "," && r(`ожидались «,» или «}» после аргумента «${s}»`), e++, l();
86
+ const f = m();
87
+ f !== "plural" && f !== "select" && r(`неизвестный тип «${f}» у «${s}» — поддерживаются plural и select`), l(), t[e] !== "," && r(`ожидалась «,» после «${f}»`), e++, o = {
88
+ kind: f,
89
+ name: s,
90
+ branches: u(s, f, f === "plural" ? s : null)
91
+ };
92
+ }
93
+ return n--, o;
94
+ };
95
+ return a(!1, null);
96
+ }
97
+ function j(t, e, n, r = {}) {
98
+ const i = r.onMissingArgument ?? O, l = (p) => {
99
+ const c = e[p];
100
+ return typeof c == "number" && Number.isFinite(c) ? c : null;
101
+ }, m = (p) => {
102
+ let c = "";
103
+ for (const a of p)
104
+ if (a.kind === "text") c += a.value;
105
+ else if (a.kind === "arg")
106
+ c += e[a.name] === void 0 ? i(a.name) : M(e[a.name]);
107
+ else if (a.kind === "number") {
108
+ const u = l(a.name);
109
+ c += u === null ? i(a.name) : A(n).format(u);
110
+ } else if (a.kind === "plural") {
111
+ const u = l(a.name);
112
+ c += u === null ? i(a.name) : m(
113
+ a.branches.get(`=${u}`) ?? a.branches.get(P(n).select(u)) ?? a.branches.get("other")
114
+ );
115
+ } else {
116
+ const u = e[a.name];
117
+ c += u === void 0 ? i(a.name) : m(a.branches.get(M(u)) ?? a.branches.get("other"));
118
+ }
119
+ return c;
120
+ };
121
+ return m(t);
122
+ }
123
+ function P(t) {
124
+ let e = $.get(t);
125
+ return e === void 0 && $.set(t, e = new Intl.PluralRules(E(t))), e;
126
+ }
127
+ function A(t) {
128
+ let e = y.get(t);
129
+ return e === void 0 && y.set(t, e = new Intl.NumberFormat(E(t))), e;
130
+ }
131
+ function F(t, e = {}) {
132
+ const n = /* @__PURE__ */ new Map();
133
+ return (r, i = {}) => {
134
+ let l = n.get(r);
135
+ return l === void 0 && n.set(r, l = b(r)), j(l, i, t, e);
136
+ };
137
+ }
138
+ const I = Object.freeze({
139
+ code: "en",
140
+ messages: Object.freeze({})
141
+ });
142
+ function C(t, e) {
143
+ const { messages: n, ...r } = e;
144
+ return {
145
+ ...t,
146
+ ...r,
147
+ messages: n === void 0 ? t.messages : { ...t.messages, ...n }
148
+ };
149
+ }
150
+ function S(t, e) {
151
+ return Object.prototype.hasOwnProperty.call(t, e);
152
+ }
153
+ function k(t, e = /* @__PURE__ */ new Set()) {
154
+ for (const n of t)
155
+ if (n.kind !== "text" && (e.add(n.name), n.kind === "plural" || n.kind === "select"))
156
+ for (const r of n.branches.values()) k(r, e);
157
+ return e;
158
+ }
159
+ function D(t, e) {
160
+ const n = [], r = /* @__PURE__ */ new Map();
161
+ for (const [i, l] of Object.entries(t)) {
162
+ if (typeof l != "string") {
163
+ n.push({ key: i, kind: "syntax", message: "сообщение не является строкой" });
164
+ continue;
165
+ }
166
+ try {
167
+ r.set(i, b(l));
168
+ } catch (m) {
169
+ n.push({
170
+ key: i,
171
+ kind: "syntax",
172
+ message: m instanceof Error ? m.message : String(m)
173
+ });
174
+ }
175
+ }
176
+ if (e === void 0) return n;
177
+ for (const i of Object.keys(t))
178
+ S(e, i) || n.push({ key: i, kind: "extra", message: "ключа нет в образце" });
179
+ for (const [i, l] of Object.entries(e)) {
180
+ if (!S(t, i)) {
181
+ n.push({ key: i, kind: "missing", message: "ключ есть в образце, но не переведён" });
182
+ continue;
183
+ }
184
+ const m = r.get(i);
185
+ if (m === void 0) continue;
186
+ let p;
187
+ try {
188
+ if (typeof l != "string") throw new TypeError("сообщение не является строкой");
189
+ p = b(l);
190
+ } catch (u) {
191
+ n.push({
192
+ key: i,
193
+ kind: "syntax",
194
+ message: `в образце: ${u instanceof Error ? u.message : String(u)}`
195
+ });
196
+ continue;
197
+ }
198
+ const c = [...k(p)].sort().join(", "), a = [...k(m)].sort().join(", ");
199
+ c !== a && n.push({
200
+ key: i,
201
+ kind: "arguments",
202
+ message: `образец ждёт {${c}}, словарь — {${a}}`
203
+ });
204
+ }
205
+ return n;
206
+ }
207
+ export {
208
+ I as D,
209
+ v as M,
210
+ F as c,
211
+ C as e,
212
+ j as f,
213
+ S as h,
214
+ E as i,
215
+ k as m,
216
+ b as p,
217
+ M as t,
218
+ D as v
219
+ };
package/dist/locale.js CHANGED
@@ -1,4 +1,4 @@
1
- import { b as e } from "./loader-Dv_Hl7JC.js";
1
+ import { b as e } from "./loader-BWkigpVe.js";
2
2
  const n = ["en", "ru"], t = e({
3
3
  en: () => import("./locale/en.js").then((o) => o.en),
4
4
  ru: () => import("./locale/ru.js").then((o) => o.ru)
@@ -4,6 +4,12 @@ export type BehaviorCleanup = () => void;
4
4
  /**
5
5
  * Вычисляемое поле: `target = fn(...sourceValues)` при изменении источников.
6
6
  *
7
+ * Примитив модели: цель вычисляемой НЕ помечает. Поэтому массовая запись (`model.set`,
8
+ * `model.patch`, `model.reset`) её перезаписывает, а `isDirty()` её учитывает — до следующей смены
9
+ * источников. Оператор поведения `computeFrom` из `@reformer/core/behaviors` цель помечает
10
+ * (`markDerived`) и защищён от циклов: массовая запись такую цель не трогает. В поведении формы
11
+ * нужен оператор; примитив — для модели без формы.
12
+ *
7
13
  * @group Model
8
14
  * @param sources Сигналы-источники (`model.$.a`, `model.$.b`).
9
15
  * @param target Сигнал-цель (`model.$.total`).
@@ -16,7 +22,7 @@ export type BehaviorCleanup = () => void;
16
22
  * computeFrom([model.$.price, model.$.qty], model.$.total, (price, qty) => price * qty);
17
23
  * ```
18
24
  */
19
- export declare function computeFrom<R>(sources: ReadonlySignal<any>[], target: Signal<R>, fn: (...values: any[]) => R, options?: {
25
+ export declare function computeFrom<R>(sources: ReadonlySignal<any>[], target: Signal<R>, fn: (...values: any[]) => NoInfer<R>, options?: {
20
26
  when?: (...values: any[]) => boolean;
21
27
  }): BehaviorCleanup;
22
28
  /**
@@ -59,6 +65,18 @@ export declare function watchField<T>(source: ReadonlySignal<T>, cb: (value: T)
59
65
  * ```
60
66
  */
61
67
  export declare function transformValue<T>(target: Signal<T>, transformer: (value: T) => T): BehaviorCleanup;
68
+ /**
69
+ * Опции {@link resetWhen}. Без `resetValue` поле сбрасывается в `null`, поэтому `resetValue`
70
+ * обязателен, если `null` не входит в тип поля: `resetWhen(model.$.promoCode, cond)` для поля
71
+ * `string` не компилируется — нужно `{ resetValue: '' }`.
72
+ *
73
+ * @group Behaviors
74
+ */
75
+ export type ResetWhenOptionsArg<T> = null extends T ? [options?: {
76
+ resetValue?: NoInfer<T>;
77
+ }] : [options: {
78
+ resetValue: NoInfer<T>;
79
+ }];
62
80
  /**
63
81
  * Сброс значения поля к `resetValue` (по умолчанию `null`), когда `condition` истинно.
64
82
  *
@@ -68,12 +86,12 @@ export declare function transformValue<T>(target: Signal<T>, transformer: (value
68
86
  * resetWhen(model.$.cardNumber, () => model.paymentType !== 'card', { resetValue: '' });
69
87
  * ```
70
88
  */
71
- export declare function resetWhen<T>(target: Signal<T>, condition: () => boolean, options?: {
72
- resetValue?: T;
73
- }): BehaviorCleanup;
89
+ export declare function resetWhen<T>(target: Signal<T>, condition: () => boolean, ...[options]: ResetWhenOptionsArg<T>): BehaviorCleanup;
74
90
  /**
75
91
  * Двусторонняя синхронизация двух полей (опционально с трансформом `a → b`).
76
- * Сходимость обеспечивается peek-guard'ом; флаг предотвращает лишние круги.
92
+ * Сходимость обеспечивается peek-guard'ом; флаг предотвращает лишние круги. При создании источник —
93
+ * `a`: `b` получает его значение (через `transform`), обратной записи при создании нет. Записи в
94
+ * оба поля в одном тике — побеждает последняя.
77
95
  *
78
96
  * @group Model
79
97
  * @example
@@ -81,7 +99,7 @@ export declare function resetWhen<T>(target: Signal<T>, condition: () => boolean
81
99
  * syncFields(model.$.field1, model.$.field2);
82
100
  * ```
83
101
  */
84
- export declare function syncFields<T>(a: Signal<T>, b: Signal<T>, options?: {
102
+ export declare function syncFields<T>(a: Signal<T>, b: Signal<NoInfer<T>>, options?: {
85
103
  transform?: (value: T) => T;
86
104
  }): BehaviorCleanup;
87
105
  /**
@@ -16,7 +16,7 @@ export declare function eachLeafSignal<T>(model: FormModel<T>, visit: (signal: P
16
16
  * Обойти ВСЕ ручки значений модели: листья (включая элементы массивов) И сами массивы.
17
17
  *
18
18
  * Отличие от {@link eachLeafSignal} — узлы-массивы: массив бывает одним значением поля
19
- * (`{ value: model.$.tags, component }`), и нода такого поля привязана к сигналу массива, а не
19
+ * (`{ model: model.$.tags, component }`), и нода такого поля привязана к сигналу массива, а не
20
20
  * к сигналам элементов. Обходчику, которому нужна именно НОДА поля (стратегия `blur` подписывается
21
21
  * на её `touched`), одних листьев мало — он не увидел бы мультивыбор. Так строятся триггеры
22
22
  * `change`/`blur` стратегий валидации (см. `createFormValidation`).
@@ -25,7 +25,7 @@ export declare function eachLeafSignal<T>(model: FormModel<T>, visit: (signal: P
25
25
  */
26
26
  export declare function eachValueSignal<T>(model: FormModel<T>, visit: (signal: PathAwareSignal<unknown>) => void): void;
27
27
  /**
28
- * Создать реактивную модель данных формы (слой M1).
28
+ * Создать реактивную модель данных формы.
29
29
  *
30
30
  * @group Model
31
31
  * @param initial Начальные значения (объект). Определяют форму данных и initial-снимок.
@@ -3,7 +3,7 @@ import { Signal } from '@preact/signals-core';
3
3
  * Пометить сигнал производным (вычисляемым).
4
4
  *
5
5
  * Вызывается операторами {@link computeFrom}/`compute` для их сигнала-цели. После этого
6
- * bulk-сеттеры (`model.set`/`model.patch`, `patchValue`/`setValue`) пропускают это поле, чтобы
6
+ * bulk-сеттеры (`model.set`/`model.patch`, `setValue` группы формы) пропускают это поле, чтобы
7
7
  * значение из payload не затирало вычисляемое. Прикладной код напрямую обычно не вызывает.
8
8
  *
9
9
  * Идемпотентна на уровне флага: повторные вызовы наращивают счётчик ссылок, чтобы каждый оператор,
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `@reformer/core/model` — низкоуровневый реактивный субстрат (M1) и barrel модуля `model`.
2
+ * `@reformer/core/model` — низкоуровневый реактивный субстрат и barrel модуля `model`.
3
3
  *
4
4
  * Это «прокси-объект с сигналами» и инструментарий для построения доменных модулей поверх него
5
5
  * (form, table, …). Модуль СТРОГО реактивный: НИЧЕГО связанного с формами/валидацией/схемами здесь
@@ -13,19 +13,30 @@
13
13
  * Состав (реэкспорты — из тех же файлов, что использует зонтик `.`, поэтому `.` и `/model` — один
14
14
  * module-инстанс: общий `derived`-WeakMap, единая идентичность `Signal`):
15
15
  * - **модель** — `createModel` + типы `FormModel`/`ModelArray`/… + `PathAwareSignal`;
16
+ * - **шаблон элемента массива** — `arrayOf(blank)`: что кладёт `push()` без значения;
16
17
  * - **обход значений** — `eachLeafSignal` (листья) и `eachValueSignal` (листья и массивы целиком);
18
+ * - **ручка → фасад** — `modelOf(model.$.<группа | массив>)`: под-модель или фасад массива;
17
19
  * - **value-операции** (реактивные правила) — `computeFrom`/`copyFrom`/`watchField`/`transformValue`/
18
20
  * `resetWhen`/`syncFields`/`revalidateWhen`;
19
21
  * - **producer-owned флаг** — `markDerived`/`isDerived`/`unmarkDerived`;
20
- * - **утилиты субстрата** — `runOutsideEffect`/`safeCallback`/`safeDebouncedCallback`.
22
+ * - **утилиты субстрата** — `runOutsideEffect`/`safeCallback`/`safeDebouncedCallback` и
23
+ * `deferredWritesSettled` (дождаться отложенных записей текущего тика);
24
+ * - **сравнение значений** — `deepEqual`, на нём стоят `isDirty` и сверка «модель изменилась».
25
+ *
26
+ * Запасной шаблон элемента массива модель принимает от того, кто строит её извне (сборка формы
27
+ * передаёт `initialValue` узла-массива); что это узел схемы, модель не знает.
21
28
  *
22
29
  * @group Model
23
30
  * @module model
24
31
  */
25
32
  export { createModel, eachLeafSignal, eachValueSignal } from './create-model';
26
- export type { FormModel, ModelArray, ModelArraySignals, ModelGroupSignals, ModelObject, ModelValue, ModelSignals, ModelApi, PathAwareSignal, } from './types';
33
+ export { arrayOf } from './model-nodes';
34
+ export type { DeepPartial, FormModel, ModelArray, ModelArraySignals, ModelGroupSignals, ModelObject, ModelValue, ModelSignals, ModelApi, PathAwareSignal, } from './types';
27
35
  export { isModelContainerSignal, isValueSignal } from './model-signals-proxy';
36
+ export { modelOf } from './model-value-proxy';
37
+ export type { ModelOf } from './model-value-proxy';
28
38
  export { computeFrom, copyFrom, watchField, transformValue, resetWhen, syncFields, revalidateWhen, } from './behaviors-value';
29
- export type { BehaviorCleanup } from './behaviors-value';
39
+ export type { BehaviorCleanup, ResetWhenOptionsArg } from './behaviors-value';
30
40
  export { markDerived, isDerived, unmarkDerived } from './derived-registry';
31
- export { runOutsideEffect, safeCallback, safeDebouncedCallback } from './safe-effect';
41
+ export { runOutsideEffect, safeCallback, safeDebouncedCallback, deferredWritesSettled, } from './safe-effect';
42
+ export { deepEqual } from './model-nodes';