@logixjs/form 0.0.1

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 (101) hide show
  1. package/dist/Error-VvknI9Wj.d.cts +37 -0
  2. package/dist/Error-VvknI9Wj.d.ts +37 -0
  3. package/dist/Error.cjs +46 -0
  4. package/dist/Error.cjs.map +1 -0
  5. package/dist/Error.d.cts +1 -0
  6. package/dist/Error.d.ts +1 -0
  7. package/dist/Error.js +14 -0
  8. package/dist/Error.js.map +1 -0
  9. package/dist/Form.cjs +2455 -0
  10. package/dist/Form.cjs.map +1 -0
  11. package/dist/Form.d.cts +64 -0
  12. package/dist/Form.d.ts +64 -0
  13. package/dist/Form.js +25 -0
  14. package/dist/Form.js.map +1 -0
  15. package/dist/FormView-CAg9LVrf.d.cts +17 -0
  16. package/dist/FormView-CAg9LVrf.d.ts +17 -0
  17. package/dist/FormView.cjs +61 -0
  18. package/dist/FormView.cjs.map +1 -0
  19. package/dist/FormView.d.cts +1 -0
  20. package/dist/FormView.d.ts +1 -0
  21. package/dist/FormView.js +8 -0
  22. package/dist/FormView.js.map +1 -0
  23. package/dist/Path-DOjMkAS6.d.cts +42 -0
  24. package/dist/Path-DOjMkAS6.d.ts +42 -0
  25. package/dist/Path.cjs +132 -0
  26. package/dist/Path.cjs.map +1 -0
  27. package/dist/Path.d.cts +1 -0
  28. package/dist/Path.d.ts +1 -0
  29. package/dist/Path.js +22 -0
  30. package/dist/Path.js.map +1 -0
  31. package/dist/Rule-BOAiSVz9.d.cts +202 -0
  32. package/dist/Rule-BOAiSVz9.d.ts +202 -0
  33. package/dist/Rule.cjs +307 -0
  34. package/dist/Rule.cjs.map +1 -0
  35. package/dist/Rule.d.cts +2 -0
  36. package/dist/Rule.d.ts +2 -0
  37. package/dist/Rule.js +34 -0
  38. package/dist/Rule.js.map +1 -0
  39. package/dist/SchemaErrorMapping-Cu5gl7-Z.d.ts +50 -0
  40. package/dist/SchemaErrorMapping-DOrgLzii.d.cts +50 -0
  41. package/dist/SchemaErrorMapping.cjs +305 -0
  42. package/dist/SchemaErrorMapping.cjs.map +1 -0
  43. package/dist/SchemaErrorMapping.d.cts +2 -0
  44. package/dist/SchemaErrorMapping.d.ts +2 -0
  45. package/dist/SchemaErrorMapping.js +17 -0
  46. package/dist/SchemaErrorMapping.js.map +1 -0
  47. package/dist/SchemaPathMapping-BCoUW-_q.d.ts +16 -0
  48. package/dist/SchemaPathMapping-BUq2zm8W.d.cts +20 -0
  49. package/dist/SchemaPathMapping-BUq2zm8W.d.ts +20 -0
  50. package/dist/SchemaPathMapping-DJnExqM3.d.cts +16 -0
  51. package/dist/SchemaPathMapping.cjs +179 -0
  52. package/dist/SchemaPathMapping.cjs.map +1 -0
  53. package/dist/SchemaPathMapping.d.cts +2 -0
  54. package/dist/SchemaPathMapping.d.ts +2 -0
  55. package/dist/SchemaPathMapping.js +12 -0
  56. package/dist/SchemaPathMapping.js.map +1 -0
  57. package/dist/Trait-Bu794ROY.d.cts +49 -0
  58. package/dist/Trait-Bu794ROY.d.ts +49 -0
  59. package/dist/Trait.cjs +48 -0
  60. package/dist/Trait.cjs.map +1 -0
  61. package/dist/Trait.d.cts +2 -0
  62. package/dist/Trait.d.ts +2 -0
  63. package/dist/Trait.js +12 -0
  64. package/dist/Trait.js.map +1 -0
  65. package/dist/chunk-5DRI5UGD.js +105 -0
  66. package/dist/chunk-5DRI5UGD.js.map +1 -0
  67. package/dist/chunk-AD2ZA7KA.js +23 -0
  68. package/dist/chunk-AD2ZA7KA.js.map +1 -0
  69. package/dist/chunk-EOXJRCM6.js +146 -0
  70. package/dist/chunk-EOXJRCM6.js.map +1 -0
  71. package/dist/chunk-JZ5FZKPJ.js +71 -0
  72. package/dist/chunk-JZ5FZKPJ.js.map +1 -0
  73. package/dist/chunk-LNJJPZAG.js +46 -0
  74. package/dist/chunk-LNJJPZAG.js.map +1 -0
  75. package/dist/chunk-NAR5SIFP.js +22 -0
  76. package/dist/chunk-NAR5SIFP.js.map +1 -0
  77. package/dist/chunk-OJVEZKU7.js +117 -0
  78. package/dist/chunk-OJVEZKU7.js.map +1 -0
  79. package/dist/chunk-PZ5AY32C.js +10 -0
  80. package/dist/chunk-PZ5AY32C.js.map +1 -0
  81. package/dist/chunk-S5JTU2CM.js +31 -0
  82. package/dist/chunk-S5JTU2CM.js.map +1 -0
  83. package/dist/chunk-YHDEJ47V.js +1885 -0
  84. package/dist/chunk-YHDEJ47V.js.map +1 -0
  85. package/dist/chunk-YVHXLY63.js +315 -0
  86. package/dist/chunk-YVHXLY63.js.map +1 -0
  87. package/dist/impl-BfSlyM58.d.ts +225 -0
  88. package/dist/impl-Ccdm5eDF.d.cts +225 -0
  89. package/dist/index.cjs +2689 -0
  90. package/dist/index.cjs.map +1 -0
  91. package/dist/index.d.cts +12 -0
  92. package/dist/index.d.ts +12 -0
  93. package/dist/index.js +56 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/react/index.cjs +332 -0
  96. package/dist/react/index.cjs.map +1 -0
  97. package/dist/react/index.d.cts +43 -0
  98. package/dist/react/index.d.ts +43 -0
  99. package/dist/react/index.js +201 -0
  100. package/dist/react/index.js.map +1 -0
  101. package/package.json +62 -0
package/dist/Form.cjs ADDED
@@ -0,0 +1,2455 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/Form.ts
31
+ var Form_exports = {};
32
+ __export(Form_exports, {
33
+ derived: () => derived,
34
+ fromValues: () => fromValues,
35
+ list: () => list2,
36
+ make: () => make2,
37
+ node: () => node,
38
+ rules: () => rules,
39
+ traits: () => traits
40
+ });
41
+ module.exports = __toCommonJS(Form_exports);
42
+
43
+ // src/internal/form/impl.ts
44
+ var Logix4 = __toESM(require("@logixjs/core"), 1);
45
+ var import_effect4 = require("effect");
46
+
47
+ // src/internal/form/traits.ts
48
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
49
+ var normalizeValidateOn = (input, fallback) => {
50
+ if (!Array.isArray(input)) return fallback;
51
+ const out = [];
52
+ for (const x of input) {
53
+ if (x === "onSubmit" || x === "onChange" || x === "onBlur") out.push(x);
54
+ }
55
+ return out.length > 0 ? Array.from(new Set(out)) : fallback;
56
+ };
57
+ var normalizeRuleValidateOn = (input) => {
58
+ if (!Array.isArray(input)) return [];
59
+ const out = [];
60
+ for (const x of input) {
61
+ if (x === "onChange" || x === "onBlur") out.push(x);
62
+ }
63
+ return Array.from(new Set(out));
64
+ };
65
+ var readSubmitCount = (state) => {
66
+ const form = state && typeof state === "object" && !Array.isArray(state) ? state.$form : void 0;
67
+ const v = form && typeof form === "object" && !Array.isArray(form) ? form.submitCount : void 0;
68
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
69
+ };
70
+ var RULE_SKIP = /* @__PURE__ */ Symbol.for("logix.state-trait.validate.skip");
71
+ var normalizeDerived = (input) => {
72
+ if (input === void 0) return void 0;
73
+ if (!isPlainObject(input)) {
74
+ throw new Error(`[Form.make] "derived" must be a plain object`);
75
+ }
76
+ const isAllowedTargetPath = (path) => {
77
+ if (!path) return false;
78
+ if (path === "$root") return false;
79
+ if (path === "errors" || path.startsWith("errors.")) return false;
80
+ if (path === "$form" || path.startsWith("$form.")) return false;
81
+ return true;
82
+ };
83
+ const isDerivedEntry = (value) => {
84
+ if (!isPlainObject(value)) return false;
85
+ if (value._tag === "StateTraitNode" || value._tag === "StateTraitList") return false;
86
+ const kind = value.kind;
87
+ return kind === "computed" || kind === "link" || kind === "source";
88
+ };
89
+ const out = {};
90
+ const keys = Object.keys(input).sort((a, b) => a.localeCompare(b));
91
+ for (const rawKey of keys) {
92
+ const key = rawKey.trim();
93
+ if (!key) {
94
+ throw new Error(`[Form.make] "derived" contains an empty key`);
95
+ }
96
+ if (!isAllowedTargetPath(key)) {
97
+ throw new Error(`[Form.make] "derived" cannot write to "${key}" (only values/ui are allowed)`);
98
+ }
99
+ const value = input[rawKey];
100
+ if (!isDerivedEntry(value)) {
101
+ throw new Error(`[Form.make] "derived.${key}" must be a Form.Trait entry (computed/link/source)`);
102
+ }
103
+ out[key] = value;
104
+ }
105
+ return Object.keys(out).length > 0 ? out : void 0;
106
+ };
107
+ var mergeTraitSpecs = (base, extra, baseLabel, extraLabel) => {
108
+ if (!base && !extra) return void 0;
109
+ if (!base) return extra;
110
+ if (!extra) return base;
111
+ const isStateTraitNode2 = (value) => isPlainObject(value) && value._tag === "StateTraitNode";
112
+ const isStateTraitList2 = (value) => isPlainObject(value) && value._tag === "StateTraitList";
113
+ const isStateTraitEntry2 = (value) => isPlainObject(value) && (value.kind === "computed" || value.kind === "source" || value.kind === "link" || value.kind === "check");
114
+ const mergeEntryOrRecord = (path, a, b) => {
115
+ if (a === void 0) return b;
116
+ if (b === void 0) return a;
117
+ if (isStateTraitEntry2(a) || isStateTraitEntry2(b)) {
118
+ throw new Error(
119
+ `[Form.make] Cannot merge "${path}": entry/record conflict between "${baseLabel}" and "${extraLabel}"`
120
+ );
121
+ }
122
+ if (!isPlainObject(a) || !isPlainObject(b)) {
123
+ throw new Error(
124
+ `[Form.make] Cannot merge "${path}": incompatible values between "${baseLabel}" and "${extraLabel}"`
125
+ );
126
+ }
127
+ const out2 = { ...a };
128
+ for (const [k, v] of Object.entries(b)) {
129
+ if (k in out2) {
130
+ throw new Error(`[Form.make] Duplicate trait key "${path}.${k}" between "${baseLabel}" and "${extraLabel}"`);
131
+ }
132
+ out2[k] = v;
133
+ }
134
+ return out2;
135
+ };
136
+ const mergeCheckRules = (path, a, b) => {
137
+ if (a === void 0) return b;
138
+ if (b === void 0) return a;
139
+ if (!isPlainObject(a) || !isPlainObject(b)) {
140
+ throw new Error(
141
+ `[Form.make] Cannot merge "${path}.check": incompatible values between "${baseLabel}" and "${extraLabel}"`
142
+ );
143
+ }
144
+ const out2 = { ...a };
145
+ for (const [k, v] of Object.entries(b)) {
146
+ if (k in out2) {
147
+ throw new Error(
148
+ `[Form.make] Duplicate check rule "${path}.check.${k}" between "${baseLabel}" and "${extraLabel}"`
149
+ );
150
+ }
151
+ out2[k] = v;
152
+ }
153
+ return out2;
154
+ };
155
+ const mergeNodes = (path, a, b) => {
156
+ const out2 = { ...a };
157
+ if (a.meta !== void 0 && b.meta !== void 0) {
158
+ throw new Error(`[Form.make] Duplicate node meta at "${path}" between "${baseLabel}" and "${extraLabel}"`);
159
+ }
160
+ if (out2.meta === void 0 && b.meta !== void 0) out2.meta = b.meta;
161
+ out2.computed = mergeEntryOrRecord(`${path}.computed`, a.computed, b.computed);
162
+ out2.source = mergeEntryOrRecord(`${path}.source`, a.source, b.source);
163
+ out2.link = mergeEntryOrRecord(`${path}.link`, a.link, b.link);
164
+ out2.check = mergeCheckRules(path, a.check, b.check);
165
+ return out2;
166
+ };
167
+ const mergeLists = (path, a, b) => {
168
+ const trackByA = a.identityHint && typeof a.identityHint === "object" ? a.identityHint.trackBy : void 0;
169
+ const trackByB = b.identityHint && typeof b.identityHint === "object" ? b.identityHint.trackBy : void 0;
170
+ if (trackByA !== void 0 && trackByB !== void 0 && trackByA !== trackByB) {
171
+ throw new Error(
172
+ `[Form.make] Conflicting list identityHint.trackBy for "${path}" between "${baseLabel}" and "${extraLabel}"`
173
+ );
174
+ }
175
+ const item = a.item && b.item ? mergeNodes(`${path}.item`, a.item, b.item) : a.item !== void 0 ? a.item : b.item;
176
+ const list3 = a.list && b.list ? mergeNodes(`${path}.list`, a.list, b.list) : a.list !== void 0 ? a.list : b.list;
177
+ return {
178
+ ...a,
179
+ ...b,
180
+ ...trackByA !== void 0 || trackByB !== void 0 ? { identityHint: { trackBy: String(trackByA ?? trackByB) } } : {},
181
+ ...item !== void 0 ? { item } : {},
182
+ ...list3 !== void 0 ? { list: list3 } : {}
183
+ };
184
+ };
185
+ const out = { ...base };
186
+ for (const [k, v] of Object.entries(extra)) {
187
+ const existing = out[k];
188
+ if (existing === void 0) {
189
+ out[k] = v;
190
+ continue;
191
+ }
192
+ if (isStateTraitList2(existing) && isStateTraitList2(v)) {
193
+ out[k] = mergeLists(k, existing, v);
194
+ continue;
195
+ }
196
+ if (isStateTraitNode2(existing) && isStateTraitNode2(v)) {
197
+ out[k] = mergeNodes(k, existing, v);
198
+ continue;
199
+ }
200
+ throw new Error(`[Form.make] Duplicate trait path "${k}" between "${baseLabel}" and "${extraLabel}"`);
201
+ }
202
+ return out;
203
+ };
204
+ var wrapTraitsForValidateOn = (spec, options) => {
205
+ const validateOn = options.validateOn;
206
+ const reValidateOn = options.reValidateOn;
207
+ const isNode = (value) => typeof value === "object" && value !== null && value._tag === "StateTraitNode";
208
+ const isList = (value) => typeof value === "object" && value !== null && value._tag === "StateTraitList";
209
+ const isCheckEntry = (value) => Boolean(value) && typeof value === "object" && value.kind === "check" && value.meta && typeof value.meta === "object";
210
+ const explicitTriggers = /* @__PURE__ */ new Set();
211
+ const wrapRule = (rule) => {
212
+ if (typeof rule === "function") {
213
+ const validate2 = rule;
214
+ return (input, ctx) => {
215
+ const mode = ctx?.mode;
216
+ if (mode === "submit" || mode === "manual") return validate2(input, ctx);
217
+ const trigger = mode === "valueChange" ? "onChange" : mode === "blur" ? "onBlur" : void 0;
218
+ if (!trigger) return validate2(input, ctx);
219
+ const submitCount = readSubmitCount(ctx?.state);
220
+ const effective = submitCount > 0 ? reValidateOn : validateOn;
221
+ return effective.includes(trigger) ? validate2(input, ctx) : RULE_SKIP;
222
+ };
223
+ }
224
+ if (!rule || typeof rule !== "object") return rule;
225
+ const anyRule = rule;
226
+ const validate = anyRule.validate;
227
+ if (typeof validate !== "function") return rule;
228
+ const hasExplicit = Array.isArray(anyRule.validateOn);
229
+ const explicit = hasExplicit ? normalizeRuleValidateOn(anyRule.validateOn) : void 0;
230
+ if (explicit) {
231
+ for (const t of explicit) explicitTriggers.add(t);
232
+ }
233
+ const wrappedValidate = (input, ctx) => {
234
+ const mode = ctx?.mode;
235
+ if (mode === "submit" || mode === "manual") return validate(input, ctx);
236
+ const trigger = mode === "valueChange" ? "onChange" : mode === "blur" ? "onBlur" : void 0;
237
+ if (!trigger) return validate(input, ctx);
238
+ if (hasExplicit) {
239
+ return explicit && explicit.includes(trigger) ? validate(input, ctx) : RULE_SKIP;
240
+ }
241
+ const submitCount = readSubmitCount(ctx?.state);
242
+ const effective = submitCount > 0 ? reValidateOn : validateOn;
243
+ return effective.includes(trigger) ? validate(input, ctx) : RULE_SKIP;
244
+ };
245
+ return {
246
+ ...anyRule,
247
+ ...hasExplicit ? { validateOn: explicit } : {},
248
+ validate: wrappedValidate
249
+ };
250
+ };
251
+ const visit = (value) => {
252
+ if (isNode(value)) {
253
+ const check = value.check;
254
+ if (!check) return value;
255
+ const wrapped = {};
256
+ for (const name of Object.keys(check)) {
257
+ wrapped[name] = wrapRule(check[name]);
258
+ }
259
+ return { ...value, check: wrapped };
260
+ }
261
+ if (isList(value)) {
262
+ return {
263
+ ...value,
264
+ item: value.item ? visit(value.item) : void 0,
265
+ list: value.list ? visit(value.list) : void 0
266
+ };
267
+ }
268
+ if (isCheckEntry(value)) {
269
+ const meta = value.meta;
270
+ const rules2 = meta?.rules;
271
+ if (!isPlainObject(rules2)) return value;
272
+ const wrapped = {};
273
+ for (const name of Object.keys(rules2)) {
274
+ wrapped[name] = wrapRule(rules2[name]);
275
+ }
276
+ return {
277
+ ...value,
278
+ meta: { ...meta, rules: wrapped }
279
+ };
280
+ }
281
+ if (isPlainObject(value)) {
282
+ const out = {};
283
+ for (const [k, v] of Object.entries(value)) {
284
+ out[k] = visit(v);
285
+ }
286
+ return out;
287
+ }
288
+ return value;
289
+ };
290
+ return {
291
+ traits: visit(spec),
292
+ rulesValidateOn: Array.from(explicitTriggers)
293
+ };
294
+ };
295
+
296
+ // src/internal/form/path.ts
297
+ var getAtPath = (state, path) => {
298
+ if (!path) return state;
299
+ const segments = path.split(".");
300
+ let current = state;
301
+ for (const segment of segments) {
302
+ if (current == null) return void 0;
303
+ const index = Number(segment);
304
+ if (Array.isArray(current) && Number.isInteger(index) && String(index) === segment) {
305
+ current = current[index];
306
+ continue;
307
+ }
308
+ current = current[segment];
309
+ }
310
+ return current;
311
+ };
312
+ var cloneContainer = (value) => {
313
+ if (Array.isArray(value)) return value.slice();
314
+ if (value && typeof value === "object") return { ...value };
315
+ return void 0;
316
+ };
317
+ var setAtPath = (state, path, value) => {
318
+ if (!path) return value;
319
+ const segments = path.split(".");
320
+ const rootClone = cloneContainer(state) ?? {};
321
+ let current = rootClone;
322
+ let currentSource = state;
323
+ for (let i = 0; i < segments.length - 1; i++) {
324
+ const segment = segments[i];
325
+ const index = Number(segment);
326
+ const isIndex = Number.isInteger(index) && String(index) === segment;
327
+ const nextSource = currentSource == null ? void 0 : isIndex && Array.isArray(currentSource) ? currentSource[index] : currentSource[segment];
328
+ const nextSegment = segments[i + 1];
329
+ const nextIndex = Number(nextSegment);
330
+ const nextIsIndex = Number.isInteger(nextIndex) && String(nextIndex) === nextSegment;
331
+ const nextClone = cloneContainer(nextSource) ?? (nextIsIndex ? [] : {});
332
+ if (isIndex && Array.isArray(current)) {
333
+ current[index] = nextClone;
334
+ } else {
335
+ current[segment] = nextClone;
336
+ }
337
+ current = nextClone;
338
+ currentSource = nextSource;
339
+ }
340
+ const last = segments[segments.length - 1];
341
+ const lastIndex = Number(last);
342
+ const lastIsIndex = Number.isInteger(lastIndex) && String(lastIndex) === last;
343
+ if (lastIsIndex && Array.isArray(current)) {
344
+ current[lastIndex] = value;
345
+ } else {
346
+ current[last] = value;
347
+ }
348
+ return rootClone;
349
+ };
350
+ var unsetAtPath = (state, path) => {
351
+ if (!path) return state;
352
+ if (getAtPath(state, path) === void 0) return state;
353
+ const segments = path.split(".");
354
+ const rootClone = cloneContainer(state);
355
+ if (rootClone === void 0) return state;
356
+ let current = rootClone;
357
+ let currentSource = state;
358
+ for (let i = 0; i < segments.length - 1; i++) {
359
+ const segment = segments[i];
360
+ const index = Number(segment);
361
+ const isIndex = Number.isInteger(index) && String(index) === segment;
362
+ const nextSource = currentSource == null ? void 0 : isIndex && Array.isArray(currentSource) ? currentSource[index] : currentSource[segment];
363
+ const nextClone = cloneContainer(nextSource);
364
+ if (nextClone === void 0) {
365
+ return state;
366
+ }
367
+ if (isIndex && Array.isArray(current)) {
368
+ current[index] = nextClone;
369
+ } else {
370
+ current[segment] = nextClone;
371
+ }
372
+ current = nextClone;
373
+ currentSource = nextSource;
374
+ }
375
+ const last = segments[segments.length - 1];
376
+ const lastIndex = Number(last);
377
+ const lastIsIndex = Number.isInteger(lastIndex) && String(lastIndex) === last;
378
+ if (lastIsIndex && Array.isArray(current)) {
379
+ current[lastIndex] = void 0;
380
+ return rootClone;
381
+ }
382
+ if (current && typeof current === "object") {
383
+ delete current[last];
384
+ }
385
+ return rootClone;
386
+ };
387
+ var updateArrayAtPath = (state, path, update) => {
388
+ const current = getAtPath(state, path);
389
+ const items = Array.isArray(current) ? current : [];
390
+ const next = update(items);
391
+ return setAtPath(state, path, next);
392
+ };
393
+
394
+ // src/Path.ts
395
+ var isNumericSegment = (seg) => /^[0-9]+$/.test(seg);
396
+ var splitPath = (path) => {
397
+ if (!path) return [];
398
+ const parts = path.split(".").filter((p) => p.length > 0);
399
+ const segs = [];
400
+ for (const part of parts) {
401
+ if (!part) continue;
402
+ if (part.endsWith("[]")) {
403
+ const base = part.slice(0, -2);
404
+ if (base) segs.push(base);
405
+ segs.push("[]");
406
+ continue;
407
+ }
408
+ const bracket = /^(.+)\[(\d+)\]$/.exec(part);
409
+ if (bracket) {
410
+ const base = bracket[1];
411
+ if (base) segs.push(base);
412
+ segs.push(bracket[2]);
413
+ continue;
414
+ }
415
+ segs.push(part);
416
+ }
417
+ return segs;
418
+ };
419
+ var toErrorsPath = (valuePath) => {
420
+ if (!valuePath) return "errors";
421
+ const segs = splitPath(valuePath);
422
+ const out = [];
423
+ for (const seg of segs) {
424
+ if (isNumericSegment(seg)) {
425
+ out.push("rows", seg);
426
+ continue;
427
+ }
428
+ if (seg === "[]") {
429
+ continue;
430
+ }
431
+ out.push(seg);
432
+ }
433
+ return `errors.${out.join(".")}`;
434
+ };
435
+ var toManualErrorsPath = (valuePath) => {
436
+ const base = toErrorsPath(valuePath);
437
+ return base === "errors" ? "errors.$manual" : base.replace(/^errors\./, "errors.$manual.");
438
+ };
439
+ var toSchemaErrorsPath = (valuePath) => {
440
+ const base = toErrorsPath(valuePath);
441
+ return base === "errors" ? "errors.$schema" : base.replace(/^errors\./, "errors.$schema.");
442
+ };
443
+
444
+ // src/internal/form/errors.ts
445
+ var isErrorValueLeafObject = (value) => {
446
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
447
+ const anyValue = value;
448
+ const msg = anyValue.message;
449
+ if (typeof msg !== "string" || msg.length === 0) return false;
450
+ for (const key of Object.keys(anyValue)) {
451
+ if (key !== "message" && key !== "code" && key !== "details") return false;
452
+ }
453
+ const code = anyValue.code;
454
+ if (code !== void 0 && (typeof code !== "string" || code.length === 0)) return false;
455
+ return true;
456
+ };
457
+ var countErrorLeaves = (value) => {
458
+ if (value === null || value === void 0) return 0;
459
+ if (typeof value === "string") return value.length > 0 ? 1 : 0;
460
+ if (Array.isArray(value)) return value.reduce((acc, v) => acc + countErrorLeaves(v), 0);
461
+ if (typeof value === "object") {
462
+ if (isErrorValueLeafObject(value)) return 1;
463
+ let acc = 0;
464
+ for (const [k, v] of Object.entries(value)) {
465
+ if (k === "$rowId") continue;
466
+ acc += countErrorLeaves(v);
467
+ }
468
+ return acc;
469
+ }
470
+ return 1;
471
+ };
472
+ var readErrorCount = (state) => {
473
+ const form = state && typeof state === "object" && !Array.isArray(state) ? state.$form : void 0;
474
+ const v = form && typeof form === "object" && !Array.isArray(form) ? form.errorCount : void 0;
475
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
476
+ };
477
+ var writeErrorCount = (state, nextCount) => setAtPath(state, "$form.errorCount", Math.max(0, nextCount));
478
+
479
+ // src/internal/form/arrays.ts
480
+ var isAuxRootPath = (path) => path === "errors" || path === "ui" || path === "$form" || path.startsWith("errors.") || path.startsWith("ui.") || path.startsWith("$form.");
481
+ var normalizeArrayToLength = (items, length) => {
482
+ const next = items.slice(0, length);
483
+ while (next.length < length) next.push(void 0);
484
+ return next;
485
+ };
486
+ var syncAuxArrays = (state, path, currentLength, update) => {
487
+ if (!path || isAuxRootPath(path)) return state;
488
+ const nextUi = updateArrayAtPath(
489
+ state,
490
+ `ui.${path}`,
491
+ (items) => update(normalizeArrayToLength(items, currentLength))
492
+ );
493
+ const nextErrors = updateArrayAtPath(
494
+ nextUi,
495
+ `errors.${path}.rows`,
496
+ (items) => update(normalizeArrayToLength(items, currentLength))
497
+ );
498
+ const manualRowsPath = `errors.$manual.${path}.rows`;
499
+ const nextManualErrors = getAtPath(state, manualRowsPath) !== void 0 ? updateArrayAtPath(
500
+ nextErrors,
501
+ manualRowsPath,
502
+ (items) => update(normalizeArrayToLength(items, currentLength))
503
+ ) : nextErrors;
504
+ const schemaRowsPath = `errors.$schema.${path}.rows`;
505
+ const nextSchemaErrors = getAtPath(state, schemaRowsPath) !== void 0 ? updateArrayAtPath(
506
+ nextManualErrors,
507
+ schemaRowsPath,
508
+ (items) => update(normalizeArrayToLength(items, currentLength))
509
+ ) : nextManualErrors;
510
+ return nextSchemaErrors;
511
+ };
512
+
513
+ // src/internal/form/reducer.ts
514
+ var mark = (sink, path) => {
515
+ if (!sink) return;
516
+ if (typeof path !== "string" || path.length === 0) return;
517
+ sink(path);
518
+ };
519
+ var markMany = (sink, paths) => {
520
+ for (const path of paths) {
521
+ mark(sink, path);
522
+ }
523
+ };
524
+ var mergeUiMeta = (prev, patch) => {
525
+ const base = prev && typeof prev === "object" && !Array.isArray(prev) ? prev : {};
526
+ return {
527
+ ...base,
528
+ ...patch
529
+ };
530
+ };
531
+ var setUiMeta = (state, path, patch) => {
532
+ if (!path) return state;
533
+ const prev = getAtPath(state, `ui.${path}`);
534
+ return setAtPath(state, `ui.${path}`, mergeUiMeta(prev, patch));
535
+ };
536
+ var initialMeta = () => ({
537
+ submitCount: 0,
538
+ isSubmitting: false,
539
+ isDirty: false,
540
+ errorCount: 0
541
+ });
542
+ var makeFormReducers = (params) => {
543
+ const reducers = {
544
+ setValue: (state, action, sink) => {
545
+ const path = action.payload.path;
546
+ const prevErrorCount = readErrorCount(state);
547
+ if (path === "errors" || path.startsWith("errors.")) {
548
+ mark(sink, path);
549
+ const prev = getAtPath(state, path);
550
+ const nextValue = action.payload.value;
551
+ const delta = countErrorLeaves(nextValue) - countErrorLeaves(prev);
552
+ const next2 = setAtPath(state, path, nextValue);
553
+ if (delta === 0) return next2;
554
+ mark(sink, "$form.errorCount");
555
+ return writeErrorCount(next2, prevErrorCount + delta);
556
+ }
557
+ mark(sink, path);
558
+ const next = setAtPath(state, path, action.payload.value);
559
+ if (isAuxRootPath(path)) return next;
560
+ markMany(sink, [`ui.${path}`, "$form.isDirty"]);
561
+ const nextMeta = setAtPath(next, "$form.isDirty", true);
562
+ let nextUi = setUiMeta(nextMeta, path, { dirty: true });
563
+ let nextCount = prevErrorCount;
564
+ const manualPath = toManualErrorsPath(path);
565
+ const prevManual = getAtPath(nextUi, manualPath);
566
+ if (prevManual !== void 0) {
567
+ mark(sink, manualPath);
568
+ nextCount -= countErrorLeaves(prevManual);
569
+ nextUi = unsetAtPath(nextUi, manualPath);
570
+ }
571
+ const schemaPath = toSchemaErrorsPath(path);
572
+ const prevSchema = getAtPath(nextUi, schemaPath);
573
+ if (prevSchema !== void 0) {
574
+ mark(sink, schemaPath);
575
+ nextCount -= countErrorLeaves(prevSchema);
576
+ nextUi = unsetAtPath(nextUi, schemaPath);
577
+ }
578
+ if (nextCount === prevErrorCount) return nextUi;
579
+ mark(sink, "$form.errorCount");
580
+ return writeErrorCount(nextUi, nextCount);
581
+ },
582
+ blur: (state, action, sink) => {
583
+ const path = action.payload.path;
584
+ if (isAuxRootPath(path)) return state;
585
+ mark(sink, `ui.${path}`);
586
+ return setUiMeta(state, path, { touched: true });
587
+ },
588
+ validate: (state) => state,
589
+ validatePaths: (state) => state,
590
+ submitAttempt: (state, _action, sink) => {
591
+ const prev = state.$form;
592
+ const submitCount = prev && typeof prev === "object" && !Array.isArray(prev) && typeof prev.submitCount === "number" ? prev.submitCount : 0;
593
+ mark(sink, "$form.submitCount");
594
+ return setAtPath(state, "$form.submitCount", submitCount + 1);
595
+ },
596
+ setSubmitting: (state, action, sink) => {
597
+ mark(sink, "$form.isSubmitting");
598
+ return setAtPath(state, "$form.isSubmitting", action.payload);
599
+ },
600
+ reset: (_state, action, sink) => {
601
+ const values = action.payload && typeof action.payload === "object" ? action.payload : params.initialValues;
602
+ markMany(sink, ["errors", "ui", "$form"]);
603
+ if (values && typeof values === "object" && !Array.isArray(values)) {
604
+ for (const key of Object.keys(values)) {
605
+ if (!key || isAuxRootPath(key)) continue;
606
+ mark(sink, key);
607
+ }
608
+ }
609
+ return {
610
+ ...values,
611
+ errors: {},
612
+ ui: {},
613
+ $form: initialMeta()
614
+ };
615
+ },
616
+ setError: (state, action, sink) => {
617
+ const path = action.payload.path;
618
+ if (!path || isAuxRootPath(path)) return state;
619
+ const error = action.payload.error;
620
+ const manualPath = toManualErrorsPath(path);
621
+ mark(sink, manualPath);
622
+ const prevErrorCount = readErrorCount(state);
623
+ const prevManual = getAtPath(state, manualPath);
624
+ if (error === null || error === void 0) {
625
+ const next2 = unsetAtPath(state, manualPath);
626
+ const delta2 = -countErrorLeaves(prevManual);
627
+ if (delta2 === 0) return next2;
628
+ mark(sink, "$form.errorCount");
629
+ return writeErrorCount(next2, prevErrorCount + delta2);
630
+ }
631
+ const next = setAtPath(state, manualPath, error);
632
+ const delta = countErrorLeaves(error) - countErrorLeaves(prevManual);
633
+ if (delta === 0) return next;
634
+ mark(sink, "$form.errorCount");
635
+ return writeErrorCount(next, prevErrorCount + delta);
636
+ },
637
+ clearErrors: (state, action, sink) => {
638
+ const paths = action.payload;
639
+ const prevErrorCount = readErrorCount(state);
640
+ if (paths === void 0) {
641
+ const prevManual = getAtPath(state, "errors.$manual");
642
+ mark(sink, "errors.$manual");
643
+ const next2 = unsetAtPath(state, "errors.$manual");
644
+ const delta = -countErrorLeaves(prevManual);
645
+ if (delta === 0) return next2;
646
+ mark(sink, "$form.errorCount");
647
+ return writeErrorCount(next2, prevErrorCount + delta);
648
+ }
649
+ let next = state;
650
+ let nextCount = prevErrorCount;
651
+ for (const path of paths) {
652
+ if (typeof path !== "string" || !path || isAuxRootPath(path)) continue;
653
+ const manualPath = toManualErrorsPath(path);
654
+ const prevManual = getAtPath(next, manualPath);
655
+ if (prevManual !== void 0) {
656
+ mark(sink, manualPath);
657
+ nextCount -= countErrorLeaves(prevManual);
658
+ next = unsetAtPath(next, manualPath);
659
+ }
660
+ }
661
+ const out = next;
662
+ if (nextCount === prevErrorCount) return out;
663
+ mark(sink, "$form.errorCount");
664
+ return writeErrorCount(out, nextCount);
665
+ },
666
+ arrayAppend: (state, action, sink) => {
667
+ const path = action.payload.path;
668
+ const value = action.payload.value;
669
+ const current = getAtPath(state, path);
670
+ const currentItems = Array.isArray(current) ? current : [];
671
+ markMany(sink, [path, `ui.${path}`, `errors.${path}.rows`, "$form.isDirty"]);
672
+ if (getAtPath(state, `errors.$manual.${path}.rows`) !== void 0) {
673
+ mark(sink, `errors.$manual.${path}.rows`);
674
+ }
675
+ if (getAtPath(state, `errors.$schema.${path}.rows`) !== void 0) {
676
+ mark(sink, `errors.$schema.${path}.rows`);
677
+ }
678
+ const nextState = updateArrayAtPath(state, path, (items) => [...items, value]);
679
+ const nextSync = syncAuxArrays(nextState, path, currentItems.length, (items) => [...items, void 0]);
680
+ const schemaRootPath = toSchemaErrorsPath(path);
681
+ const prevErrorCount = readErrorCount(nextSync);
682
+ const prevSchema = getAtPath(nextSync, schemaRootPath);
683
+ mark(sink, schemaRootPath);
684
+ const clearedSchema = unsetAtPath(nextSync, schemaRootPath);
685
+ const delta = -countErrorLeaves(prevSchema);
686
+ const nextWithCount = delta === 0 ? clearedSchema : writeErrorCount(clearedSchema, prevErrorCount + delta);
687
+ if (delta !== 0) mark(sink, "$form.errorCount");
688
+ return isAuxRootPath(path) ? nextWithCount : setAtPath(nextWithCount, "$form.isDirty", true);
689
+ },
690
+ arrayPrepend: (state, action, sink) => {
691
+ const path = action.payload.path;
692
+ const value = action.payload.value;
693
+ const current = getAtPath(state, path);
694
+ const currentItems = Array.isArray(current) ? current : [];
695
+ markMany(sink, [path, `ui.${path}`, `errors.${path}.rows`, "$form.isDirty"]);
696
+ if (getAtPath(state, `errors.$manual.${path}.rows`) !== void 0) {
697
+ mark(sink, `errors.$manual.${path}.rows`);
698
+ }
699
+ if (getAtPath(state, `errors.$schema.${path}.rows`) !== void 0) {
700
+ mark(sink, `errors.$schema.${path}.rows`);
701
+ }
702
+ const nextState = updateArrayAtPath(state, path, (items) => [value, ...items]);
703
+ const nextSync = syncAuxArrays(nextState, path, currentItems.length, (items) => [void 0, ...items]);
704
+ const schemaRootPath = toSchemaErrorsPath(path);
705
+ const prevErrorCount = readErrorCount(nextSync);
706
+ const prevSchema = getAtPath(nextSync, schemaRootPath);
707
+ mark(sink, schemaRootPath);
708
+ const clearedSchema = unsetAtPath(nextSync, schemaRootPath);
709
+ const delta = -countErrorLeaves(prevSchema);
710
+ const nextWithCount = delta === 0 ? clearedSchema : writeErrorCount(clearedSchema, prevErrorCount + delta);
711
+ if (delta !== 0) mark(sink, "$form.errorCount");
712
+ return isAuxRootPath(path) ? nextWithCount : setAtPath(nextWithCount, "$form.isDirty", true);
713
+ },
714
+ arrayRemove: (state, action, sink) => {
715
+ const path = action.payload.path;
716
+ const index = action.payload.index;
717
+ const current = getAtPath(state, path);
718
+ const currentItems = Array.isArray(current) ? current : [];
719
+ const prevErrorCount = readErrorCount(state);
720
+ const prevRuleRow = getAtPath(state, `errors.${path}.rows.${index}`);
721
+ const prevManualRow = getAtPath(state, `errors.$manual.${path}.rows.${index}`);
722
+ const schemaRootPath = toSchemaErrorsPath(path);
723
+ const prevSchemaRoot = getAtPath(state, schemaRootPath);
724
+ markMany(sink, [path, `ui.${path}`, `errors.${path}.rows`, schemaRootPath, "$form.isDirty"]);
725
+ if (getAtPath(state, `errors.$manual.${path}.rows`) !== void 0) {
726
+ mark(sink, `errors.$manual.${path}.rows`);
727
+ }
728
+ if (getAtPath(state, `errors.$schema.${path}.rows`) !== void 0) {
729
+ mark(sink, `errors.$schema.${path}.rows`);
730
+ }
731
+ const nextState = updateArrayAtPath(
732
+ state,
733
+ path,
734
+ (items) => items.filter((_, i) => i !== index)
735
+ );
736
+ const nextSync = syncAuxArrays(
737
+ nextState,
738
+ path,
739
+ currentItems.length,
740
+ (items) => items.filter((_, i) => i !== index)
741
+ );
742
+ let nextCount = prevErrorCount;
743
+ nextCount -= countErrorLeaves(prevRuleRow);
744
+ nextCount -= countErrorLeaves(prevManualRow);
745
+ nextCount -= countErrorLeaves(prevSchemaRoot);
746
+ const clearedSchema = unsetAtPath(nextSync, schemaRootPath);
747
+ const nextWithCount = nextCount === prevErrorCount ? clearedSchema : writeErrorCount(clearedSchema, nextCount);
748
+ if (nextCount !== prevErrorCount) mark(sink, "$form.errorCount");
749
+ return isAuxRootPath(path) ? nextWithCount : setAtPath(nextWithCount, "$form.isDirty", true);
750
+ },
751
+ arraySwap: (state, action, sink) => {
752
+ const path = action.payload.path;
753
+ const a = action.payload.indexA;
754
+ const b = action.payload.indexB;
755
+ const current = getAtPath(state, path);
756
+ const currentItems = Array.isArray(current) ? current : [];
757
+ const schemaRootPath = toSchemaErrorsPath(path);
758
+ markMany(sink, [path, `ui.${path}`, `errors.${path}.rows`, schemaRootPath, "$form.isDirty"]);
759
+ if (getAtPath(state, `errors.$manual.${path}.rows`) !== void 0) {
760
+ mark(sink, `errors.$manual.${path}.rows`);
761
+ }
762
+ if (getAtPath(state, `errors.$schema.${path}.rows`) !== void 0) {
763
+ mark(sink, `errors.$schema.${path}.rows`);
764
+ }
765
+ const swap = (items) => {
766
+ const next = items.slice();
767
+ if (a >= 0 && b >= 0 && a < next.length && b < next.length) {
768
+ const tmp = next[a];
769
+ next[a] = next[b];
770
+ next[b] = tmp;
771
+ }
772
+ return next;
773
+ };
774
+ const nextState = updateArrayAtPath(state, path, swap);
775
+ const nextSync = syncAuxArrays(nextState, path, currentItems.length, swap);
776
+ const prevErrorCount = readErrorCount(nextSync);
777
+ const prevSchema = getAtPath(nextSync, schemaRootPath);
778
+ const clearedSchema = unsetAtPath(nextSync, schemaRootPath);
779
+ const delta = -countErrorLeaves(prevSchema);
780
+ const nextWithCount = delta === 0 ? clearedSchema : writeErrorCount(clearedSchema, prevErrorCount + delta);
781
+ if (delta !== 0) mark(sink, "$form.errorCount");
782
+ return isAuxRootPath(path) ? nextWithCount : setAtPath(nextWithCount, "$form.isDirty", true);
783
+ },
784
+ arrayMove: (state, action, sink) => {
785
+ const path = action.payload.path;
786
+ const from = action.payload.from;
787
+ const to = action.payload.to;
788
+ const current = getAtPath(state, path);
789
+ const currentItems = Array.isArray(current) ? current : [];
790
+ const schemaRootPath = toSchemaErrorsPath(path);
791
+ markMany(sink, [path, `ui.${path}`, `errors.${path}.rows`, schemaRootPath, "$form.isDirty"]);
792
+ if (getAtPath(state, `errors.$manual.${path}.rows`) !== void 0) {
793
+ mark(sink, `errors.$manual.${path}.rows`);
794
+ }
795
+ if (getAtPath(state, `errors.$schema.${path}.rows`) !== void 0) {
796
+ mark(sink, `errors.$schema.${path}.rows`);
797
+ }
798
+ const move = (items) => {
799
+ const next = items.slice();
800
+ if (from < 0 || from >= next.length || to < 0 || to >= next.length) {
801
+ return next;
802
+ }
803
+ const [moved] = next.splice(from, 1);
804
+ next.splice(to, 0, moved);
805
+ return next;
806
+ };
807
+ const nextState = updateArrayAtPath(state, path, move);
808
+ const nextSync = syncAuxArrays(nextState, path, currentItems.length, move);
809
+ const prevErrorCount = readErrorCount(nextSync);
810
+ const prevSchema = getAtPath(nextSync, schemaRootPath);
811
+ const clearedSchema = unsetAtPath(nextSync, schemaRootPath);
812
+ const delta = -countErrorLeaves(prevSchema);
813
+ const nextWithCount = delta === 0 ? clearedSchema : writeErrorCount(clearedSchema, prevErrorCount + delta);
814
+ if (delta !== 0) mark(sink, "$form.errorCount");
815
+ return isAuxRootPath(path) ? nextWithCount : setAtPath(nextWithCount, "$form.isDirty", true);
816
+ }
817
+ };
818
+ return reducers;
819
+ };
820
+
821
+ // src/internal/form/controller.ts
822
+ var Logix = __toESM(require("@logixjs/core"), 1);
823
+ var import_effect = require("effect");
824
+
825
+ // src/internal/schema/SchemaPathMapping.ts
826
+ var isNumericSegment2 = (seg) => /^[0-9]+$/.test(seg);
827
+ var parseSegmentsFromString = (path) => {
828
+ if (!path) return [];
829
+ return path.split(".").filter(Boolean).map((seg) => isNumericSegment2(seg) ? Number(seg) : seg);
830
+ };
831
+ var asSegments = (value) => {
832
+ if (typeof value === "string") return parseSegmentsFromString(value);
833
+ if (Array.isArray(value)) {
834
+ const parts = [];
835
+ for (const x of value) {
836
+ if (typeof x === "number" && Number.isFinite(x)) {
837
+ parts.push(Math.floor(x));
838
+ continue;
839
+ }
840
+ if (typeof x === "string" && x.length > 0) {
841
+ parts.push(isNumericSegment2(x) ? Number(x) : x);
842
+ }
843
+ }
844
+ return parts.length ? parts : void 0;
845
+ }
846
+ return void 0;
847
+ };
848
+ var toConcretePath = (segments) => segments.map(String).join(".");
849
+ var toPatternPath = (segments) => {
850
+ const out = [];
851
+ const indices = [];
852
+ for (const seg of segments) {
853
+ if (typeof seg === "number") {
854
+ out.push("[]");
855
+ indices.push(seg);
856
+ } else {
857
+ out.push(seg);
858
+ }
859
+ }
860
+ const pattern2 = out.join(".").replace(/\.\[\]/g, "[]");
861
+ return { pattern: pattern2, indices };
862
+ };
863
+ var applyIndicesToPattern = (pattern2, indices) => {
864
+ if (!pattern2) return pattern2;
865
+ const raw = pattern2.split(".").filter(Boolean);
866
+ const out = [];
867
+ let cursor = 0;
868
+ for (const part of raw) {
869
+ if (part === "[]") {
870
+ const idx = indices[cursor++];
871
+ if (idx === void 0) return void 0;
872
+ out.push(String(idx));
873
+ continue;
874
+ }
875
+ if (part.endsWith("[]") && part.length > 2) {
876
+ const base = part.slice(0, -2);
877
+ out.push(base);
878
+ const idx = indices[cursor++];
879
+ if (idx === void 0) return void 0;
880
+ out.push(String(idx));
881
+ continue;
882
+ }
883
+ out.push(part);
884
+ }
885
+ return out.join(".");
886
+ };
887
+ var concatPaths = (prefix, rest) => {
888
+ if (!prefix) return rest;
889
+ if (!rest) return prefix;
890
+ return `${prefix}.${rest}`;
891
+ };
892
+ var mapByRename = (segments, rename) => {
893
+ const concrete = toConcretePath(segments);
894
+ const direct = rename[concrete];
895
+ if (direct !== void 0) {
896
+ return direct;
897
+ }
898
+ const { pattern: pattern2, indices } = toPatternPath(segments);
899
+ const patternDirect = rename[pattern2];
900
+ if (patternDirect !== void 0) {
901
+ return applyIndicesToPattern(patternDirect, indices);
902
+ }
903
+ const keys = Object.keys(rename).sort((a, b) => b.length - a.length);
904
+ for (const from of keys) {
905
+ const to = rename[from];
906
+ const isPattern = from.includes("[]");
907
+ const target = isPattern ? pattern2 : concrete;
908
+ if (target === from || target.startsWith(`${from}.`)) {
909
+ const rawRest = target.slice(from.length);
910
+ const rest = rawRest.startsWith(".") ? rawRest.slice(1) : rawRest;
911
+ const mapped = concatPaths(to, rest);
912
+ return isPattern ? applyIndicesToPattern(mapped, indices) : mapped;
913
+ }
914
+ }
915
+ const segMap = {};
916
+ for (const [from, to] of Object.entries(rename)) {
917
+ if (from.includes(".") || from.includes("[]")) continue;
918
+ if (to.includes(".") || to.includes("[]")) continue;
919
+ if (!to) continue;
920
+ segMap[from] = to;
921
+ }
922
+ if (Object.keys(segMap).length === 0) return void 0;
923
+ const mappedSegments = segments.map((seg) => typeof seg === "string" ? segMap[seg] ?? seg : seg);
924
+ return toConcretePath(mappedSegments);
925
+ };
926
+ var extractRawPaths = (schemaError) => {
927
+ const out = [];
928
+ if (schemaError && typeof schemaError === "object") {
929
+ const anyErr = schemaError;
930
+ if (Array.isArray(anyErr.errors)) {
931
+ for (const e of anyErr.errors) {
932
+ if (e && typeof e === "object" && "path" in e) {
933
+ out.push(e.path);
934
+ }
935
+ }
936
+ }
937
+ if (Array.isArray(anyErr.issues)) {
938
+ for (const e of anyErr.issues) {
939
+ if (e && typeof e === "object" && "path" in e) {
940
+ out.push(e.path);
941
+ }
942
+ }
943
+ }
944
+ if ("path" in anyErr) {
945
+ out.push(anyErr.path);
946
+ }
947
+ }
948
+ return out;
949
+ };
950
+ var mapSchemaErrorToFieldPaths = (schemaError, options) => {
951
+ const fromEscapeHatch = options?.errorMap?.(schemaError);
952
+ if (fromEscapeHatch && fromEscapeHatch.length) {
953
+ return Array.from(new Set(fromEscapeHatch.filter((p) => typeof p === "string" && p.length > 0)));
954
+ }
955
+ const rename = options?.rename;
956
+ const results = [];
957
+ for (const rawPath of extractRawPaths(schemaError)) {
958
+ const segments = asSegments(rawPath);
959
+ if (!segments || segments.length === 0) continue;
960
+ const mapped = rename ? mapByRename(segments, rename) : void 0;
961
+ const path = mapped ?? toConcretePath(segments);
962
+ if (path) results.push(path);
963
+ }
964
+ return Array.from(new Set(results));
965
+ };
966
+
967
+ // src/internal/schema/SchemaErrorMapping.ts
968
+ var toSchemaErrorWrites = (schemaError, options) => {
969
+ const fieldPaths = mapSchemaErrorToFieldPaths(schemaError, options);
970
+ if (fieldPaths.length === 0) return [];
971
+ const toLeaf = options?.toLeaf ?? ((e) => e);
972
+ const leaf = toLeaf(schemaError);
973
+ return fieldPaths.map((fieldPath) => ({
974
+ fieldPath,
975
+ errorPath: toSchemaErrorsPath(fieldPath),
976
+ error: leaf
977
+ }));
978
+ };
979
+ var toSchemaErrorTree = (schemaError, options) => {
980
+ const writes = toSchemaErrorWrites(schemaError, options);
981
+ if (writes.length === 0) return {};
982
+ let next = {};
983
+ for (const w of writes) {
984
+ const prefix = "errors.$schema.";
985
+ const relative = w.errorPath.startsWith(prefix) ? w.errorPath.slice(prefix.length) : w.errorPath;
986
+ if (!relative) continue;
987
+ next = setAtPath(next, relative, w.error);
988
+ }
989
+ return next;
990
+ };
991
+
992
+ // src/internal/form/controller.ts
993
+ var makeFormController = (params) => {
994
+ const runtime = params.runtime;
995
+ const bound = Logix.Bound.make(params.shape, runtime);
996
+ return {
997
+ runtime,
998
+ getState: runtime.getState,
999
+ dispatch: runtime.dispatch,
1000
+ submit: () => runtime.dispatch({ _tag: "submit", payload: void 0 }),
1001
+ controller: {
1002
+ validate: () => import_effect.Effect.gen(function* () {
1003
+ yield* Logix.TraitLifecycle.scopedValidate(bound, {
1004
+ mode: "manual",
1005
+ target: Logix.TraitLifecycle.Ref.root()
1006
+ });
1007
+ const state = yield* runtime.getState;
1008
+ const { errors: _errors, ui: _ui, $form: _meta, ...values } = state;
1009
+ const decoded = import_effect.Schema.decodeUnknownEither(params.valuesSchema)(values);
1010
+ const schemaTree = decoded._tag === "Right" ? {} : toSchemaErrorTree(decoded.left);
1011
+ yield* runtime.dispatch({
1012
+ _tag: "setValue",
1013
+ payload: { path: "errors.$schema", value: schemaTree }
1014
+ });
1015
+ }),
1016
+ validatePaths: (paths) => import_effect.Effect.gen(function* () {
1017
+ const list3 = typeof paths === "string" ? [paths] : paths;
1018
+ if (!list3 || list3.length === 0) return;
1019
+ const state = yield* runtime.getState;
1020
+ for (const raw of list3) {
1021
+ if (typeof raw !== "string") continue;
1022
+ const path = raw.trim();
1023
+ if (!path || isAuxRootPath(path)) continue;
1024
+ const value = getAtPath(state, path);
1025
+ const target = Array.isArray(value) ? Logix.TraitLifecycle.Ref.list(path) : Logix.TraitLifecycle.Ref.fromValuePath(path);
1026
+ yield* Logix.TraitLifecycle.scopedValidate(bound, {
1027
+ mode: "manual",
1028
+ target
1029
+ });
1030
+ }
1031
+ }),
1032
+ reset: (values) => runtime.dispatch({ _tag: "reset", payload: values }),
1033
+ setError: (path, error) => runtime.dispatch({ _tag: "setError", payload: { path, error } }),
1034
+ clearErrors: (paths) => runtime.dispatch({
1035
+ _tag: "clearErrors",
1036
+ payload: paths === void 0 ? void 0 : typeof paths === "string" ? [paths] : paths
1037
+ }),
1038
+ handleSubmit: (handlers) => import_effect.Effect.gen(function* () {
1039
+ yield* runtime.dispatch({ _tag: "submitAttempt", payload: void 0 });
1040
+ yield* runtime.dispatch({ _tag: "setSubmitting", payload: true });
1041
+ yield* Logix.TraitLifecycle.scopedValidate(bound, {
1042
+ mode: "submit",
1043
+ target: Logix.TraitLifecycle.Ref.root()
1044
+ });
1045
+ const stateAfterRules = yield* runtime.getState;
1046
+ const {
1047
+ errors: _errorsAfterRules,
1048
+ ui: _uiAfterRules,
1049
+ $form: _metaAfterRules,
1050
+ ...valuesAfterRules
1051
+ } = stateAfterRules;
1052
+ const decoded = import_effect.Schema.decodeUnknownEither(params.valuesSchema)(valuesAfterRules);
1053
+ const schemaTree = decoded._tag === "Right" ? {} : toSchemaErrorTree(decoded.left);
1054
+ yield* runtime.dispatch({
1055
+ _tag: "setValue",
1056
+ payload: { path: "errors.$schema", value: schemaTree }
1057
+ });
1058
+ const state = yield* runtime.getState;
1059
+ const errorCount = readErrorCount(state);
1060
+ if (errorCount > 0) {
1061
+ if (handlers.onInvalid) {
1062
+ yield* handlers.onInvalid(state.errors);
1063
+ }
1064
+ return;
1065
+ }
1066
+ const { errors: _errorsFinal, ui: _uiFinal, $form: _metaFinal, ...valuesFinal } = state;
1067
+ yield* handlers.onValid(valuesFinal);
1068
+ }).pipe(import_effect.Effect.ensuring(runtime.dispatch({ _tag: "setSubmitting", payload: false })))
1069
+ },
1070
+ field: (path) => ({
1071
+ get: runtime.getState.pipe(import_effect.Effect.map((s) => getAtPath(s, path))),
1072
+ set: (value) => runtime.dispatch({ _tag: "setValue", payload: { path, value } }),
1073
+ blur: () => runtime.dispatch({ _tag: "blur", payload: { path } })
1074
+ }),
1075
+ fieldArray: (path) => ({
1076
+ get: runtime.getState.pipe(
1077
+ import_effect.Effect.map((s) => {
1078
+ const value = getAtPath(s, path);
1079
+ return Array.isArray(value) ? value : [];
1080
+ })
1081
+ ),
1082
+ append: (value) => runtime.dispatch({ _tag: "arrayAppend", payload: { path, value } }),
1083
+ prepend: (value) => runtime.dispatch({ _tag: "arrayPrepend", payload: { path, value } }),
1084
+ remove: (index) => runtime.dispatch({ _tag: "arrayRemove", payload: { path, index } }),
1085
+ swap: (indexA, indexB) => runtime.dispatch({ _tag: "arraySwap", payload: { path, indexA, indexB } }),
1086
+ move: (from, to) => runtime.dispatch({ _tag: "arrayMove", payload: { path, from, to } })
1087
+ })
1088
+ };
1089
+ };
1090
+
1091
+ // src/internal/dsl/traits.ts
1092
+ var Logix2 = __toESM(require("@logixjs/core"), 1);
1093
+ var isPlainObject2 = (value) => Boolean(value) && typeof value === "object" && value !== null && !Array.isArray(value);
1094
+ var isStateTraitNode = (value) => Boolean(value) && typeof value === "object" && value._tag === "StateTraitNode";
1095
+ var isStateTraitList = (value) => Boolean(value) && typeof value === "object" && value._tag === "StateTraitList";
1096
+ var isStateTraitEntry = (value) => Boolean(value) && typeof value === "object" && typeof value.kind === "string";
1097
+ var normalizeRule = (rule) => {
1098
+ if (typeof rule === "function") {
1099
+ return { deps: [], validate: rule };
1100
+ }
1101
+ if (!isPlainObject2(rule)) return rule;
1102
+ const validate = rule.validate;
1103
+ if (typeof validate !== "function") return rule;
1104
+ const depsRaw = rule.deps;
1105
+ const deps = Array.isArray(depsRaw) ? depsRaw : [];
1106
+ return { ...rule, deps };
1107
+ };
1108
+ var normalizeNode = (value) => {
1109
+ const raw = isStateTraitNode(value) ? value : value;
1110
+ const checkRaw = raw?.check;
1111
+ const check = checkRaw && typeof checkRaw === "object" && !Array.isArray(checkRaw) ? Object.fromEntries(Object.entries(checkRaw).map(([k, v]) => [k, normalizeRule(v)])) : checkRaw;
1112
+ return isStateTraitNode(value) ? { ...raw, ...checkRaw !== void 0 ? { check } : {} } : Logix2.StateTrait.node({ ...raw, ...checkRaw !== void 0 ? { check } : {} });
1113
+ };
1114
+ var normalizeList = (value) => {
1115
+ const raw = isStateTraitList(value) ? value : value;
1116
+ const item = raw?.item ? normalizeNodeOrListOrEntry(raw.item) : void 0;
1117
+ const list3 = raw?.list ? normalizeNodeOrListOrEntry(raw.list) : void 0;
1118
+ const next = {
1119
+ ...raw,
1120
+ ...raw?.item !== void 0 ? { item } : {},
1121
+ ...raw?.list !== void 0 ? { list: list3 } : {}
1122
+ };
1123
+ return isStateTraitList(value) ? next : Logix2.StateTrait.list(next);
1124
+ };
1125
+ var normalizeNodeOrListOrEntry = (value) => {
1126
+ if (isStateTraitEntry(value)) return value;
1127
+ if (isStateTraitNode(value)) return normalizeNode(value);
1128
+ if (isStateTraitList(value)) return normalizeList(value);
1129
+ if (isPlainObject2(value)) {
1130
+ if ("item" in value || "list" in value || "identityHint" in value) {
1131
+ return normalizeList(value);
1132
+ }
1133
+ if ("check" in value || "computed" in value || "source" in value || "link" in value || "meta" in value) {
1134
+ return normalizeNode(value);
1135
+ }
1136
+ }
1137
+ return value;
1138
+ };
1139
+ var traits = (_valuesSchema) => {
1140
+ function run(spec) {
1141
+ return Object.fromEntries(Object.entries(spec).map(([k, v]) => [k, normalizeNodeOrListOrEntry(v)]));
1142
+ }
1143
+ return run;
1144
+ };
1145
+
1146
+ // src/internal/form/install.ts
1147
+ var Logix3 = __toESM(require("@logixjs/core"), 1);
1148
+ var import_effect2 = require("effect");
1149
+ var isAuxRootPath2 = (path) => path === "errors" || path === "ui" || path === "$form" || path.startsWith("errors.") || path.startsWith("ui.") || path.startsWith("$form.");
1150
+ var install = (module2, config) => module2.logic(($) => {
1151
+ const validateOn = config?.validateOn ?? ["onSubmit"];
1152
+ const reValidateOn = config?.reValidateOn ?? ["onChange"];
1153
+ const rulesValidateOn = config?.rulesValidateOn ?? [];
1154
+ const debounceMs = config?.debounceMs;
1155
+ const sourceWiring = Logix3.TraitLifecycle.makeSourceWiring($, module2);
1156
+ const validate = (trigger, path) => Logix3.TraitLifecycle.scopedValidate($, {
1157
+ mode: trigger,
1158
+ target: Logix3.TraitLifecycle.Ref.fromValuePath(path)
1159
+ });
1160
+ const validateRoot = () => Logix3.TraitLifecycle.scopedValidate($, {
1161
+ mode: "submit",
1162
+ target: Logix3.TraitLifecycle.Ref.root()
1163
+ });
1164
+ const pending = /* @__PURE__ */ new Map();
1165
+ const cancelPending = (path) => import_effect2.Effect.gen(function* () {
1166
+ const prev = pending.get(path);
1167
+ if (!prev) return;
1168
+ pending.delete(path);
1169
+ yield* import_effect2.Fiber.interruptFork(prev);
1170
+ });
1171
+ const scheduleDebouncedValidate = (path) => import_effect2.Effect.gen(function* () {
1172
+ const ms = debounceMs ?? 0;
1173
+ if (ms <= 0) {
1174
+ yield* validate("valueChange", path);
1175
+ return;
1176
+ }
1177
+ yield* cancelPending(path);
1178
+ const fiber = yield* import_effect2.Effect.forkScoped(
1179
+ import_effect2.Effect.sleep(import_effect2.Duration.millis(ms)).pipe(
1180
+ import_effect2.Effect.zipRight(validate("valueChange", path)),
1181
+ import_effect2.Effect.ensuring(import_effect2.Effect.sync(() => pending.delete(path))),
1182
+ import_effect2.Effect.catchAllCause(() => import_effect2.Effect.void)
1183
+ )
1184
+ );
1185
+ pending.set(path, fiber);
1186
+ });
1187
+ const has = (list3, item) => list3.includes(item);
1188
+ const wantsChange = has(validateOn, "onChange") || has(reValidateOn, "onChange") || rulesValidateOn.includes("onChange");
1189
+ const wantsBlur = has(validateOn, "onBlur") || has(reValidateOn, "onBlur") || rulesValidateOn.includes("onBlur");
1190
+ const shouldValidateNow = (submitCount, trigger) => {
1191
+ const effective = submitCount > 0 ? reValidateOn : validateOn;
1192
+ if (effective.includes(trigger)) return true;
1193
+ return rulesValidateOn.includes(trigger);
1194
+ };
1195
+ const readSubmitCount2 = (state) => {
1196
+ const form = state && typeof state === "object" && !Array.isArray(state) ? state.$form : void 0;
1197
+ const v = form && typeof form === "object" && !Array.isArray(form) ? form.submitCount : void 0;
1198
+ return typeof v === "number" && Number.isFinite(v) ? v : 0;
1199
+ };
1200
+ const setup = sourceWiring.setup;
1201
+ const run = import_effect2.Effect.gen(function* () {
1202
+ if (wantsBlur) {
1203
+ yield* $.onAction("blur").runFork(
1204
+ (action) => import_effect2.Effect.gen(function* () {
1205
+ const path = action.payload.path;
1206
+ if (!path || isAuxRootPath2(path)) return;
1207
+ yield* cancelPending(path);
1208
+ const state = yield* $.state.read;
1209
+ const submitCount = readSubmitCount2(state);
1210
+ if (!shouldValidateNow(submitCount, "onBlur")) return;
1211
+ yield* validate("blur", path);
1212
+ })
1213
+ );
1214
+ }
1215
+ yield* $.onAction("setValue").runFork(
1216
+ (action) => import_effect2.Effect.gen(function* () {
1217
+ const path = action.payload.path;
1218
+ if (!path || isAuxRootPath2(path)) return;
1219
+ yield* sourceWiring.refreshOnKeyChange(path);
1220
+ yield* cancelPending(path);
1221
+ if (!wantsChange) return;
1222
+ const state = yield* $.state.read;
1223
+ const submitCount = readSubmitCount2(state);
1224
+ if (!shouldValidateNow(submitCount, "onChange")) return;
1225
+ yield* scheduleDebouncedValidate(path);
1226
+ })
1227
+ );
1228
+ yield* $.onAction("submit").runFork(
1229
+ () => import_effect2.Effect.gen(function* () {
1230
+ pending.clear();
1231
+ yield* validateRoot();
1232
+ })
1233
+ );
1234
+ yield* $.onAction("arrayAppend").runFork(
1235
+ (action) => import_effect2.Effect.gen(function* () {
1236
+ yield* sourceWiring.refreshOnKeyChange(action.payload.path);
1237
+ if (!wantsChange) return;
1238
+ const state = yield* $.state.read;
1239
+ const submitCount = readSubmitCount2(state);
1240
+ if (!shouldValidateNow(submitCount, "onChange")) return;
1241
+ yield* Logix3.TraitLifecycle.scopedValidate($, {
1242
+ mode: "valueChange",
1243
+ target: Logix3.TraitLifecycle.Ref.list(action.payload.path)
1244
+ });
1245
+ })
1246
+ );
1247
+ yield* $.onAction("arrayPrepend").runFork(
1248
+ (action) => import_effect2.Effect.gen(function* () {
1249
+ yield* sourceWiring.refreshOnKeyChange(action.payload.path);
1250
+ if (!wantsChange) return;
1251
+ const state = yield* $.state.read;
1252
+ const submitCount = readSubmitCount2(state);
1253
+ if (!shouldValidateNow(submitCount, "onChange")) return;
1254
+ yield* Logix3.TraitLifecycle.scopedValidate($, {
1255
+ mode: "valueChange",
1256
+ target: Logix3.TraitLifecycle.Ref.list(action.payload.path)
1257
+ });
1258
+ })
1259
+ );
1260
+ yield* $.onAction("arrayRemove").runFork(
1261
+ (action) => import_effect2.Effect.gen(function* () {
1262
+ yield* sourceWiring.refreshOnKeyChange(action.payload.path);
1263
+ if (!wantsChange) return;
1264
+ const state = yield* $.state.read;
1265
+ const submitCount = readSubmitCount2(state);
1266
+ if (!shouldValidateNow(submitCount, "onChange")) return;
1267
+ yield* Logix3.TraitLifecycle.scopedValidate($, {
1268
+ mode: "valueChange",
1269
+ target: Logix3.TraitLifecycle.Ref.list(action.payload.path)
1270
+ });
1271
+ })
1272
+ );
1273
+ yield* $.onAction("arraySwap").runFork(
1274
+ (action) => import_effect2.Effect.gen(function* () {
1275
+ yield* sourceWiring.refreshOnKeyChange(action.payload.path);
1276
+ if (!wantsChange) return;
1277
+ const state = yield* $.state.read;
1278
+ const submitCount = readSubmitCount2(state);
1279
+ if (!shouldValidateNow(submitCount, "onChange")) return;
1280
+ yield* Logix3.TraitLifecycle.scopedValidate($, {
1281
+ mode: "valueChange",
1282
+ target: Logix3.TraitLifecycle.Ref.list(action.payload.path)
1283
+ });
1284
+ })
1285
+ );
1286
+ yield* $.onAction("arrayMove").runFork(
1287
+ (action) => import_effect2.Effect.gen(function* () {
1288
+ yield* sourceWiring.refreshOnKeyChange(action.payload.path);
1289
+ if (!wantsChange) return;
1290
+ const state = yield* $.state.read;
1291
+ const submitCount = readSubmitCount2(state);
1292
+ if (!shouldValidateNow(submitCount, "onChange")) return;
1293
+ yield* Logix3.TraitLifecycle.scopedValidate($, {
1294
+ mode: "valueChange",
1295
+ target: Logix3.TraitLifecycle.Ref.list(action.payload.path)
1296
+ });
1297
+ })
1298
+ );
1299
+ }).pipe(import_effect2.Effect.asVoid);
1300
+ return { setup, run };
1301
+ });
1302
+
1303
+ // src/internal/form/artifacts.ts
1304
+ var formRulesManifestArtifactKey = "@logixjs/form.rulesManifest@v1";
1305
+ var makeFormRulesManifestArtifactExporter = (params) => ({
1306
+ exporterId: "logix-form.rulesManifest@v1",
1307
+ artifactKey: formRulesManifestArtifactKey,
1308
+ export: () => {
1309
+ const manifest = params.getManifest();
1310
+ const warnings = params.getWarnings();
1311
+ return {
1312
+ manifest,
1313
+ warnings: Array.isArray(warnings) ? warnings : []
1314
+ };
1315
+ }
1316
+ });
1317
+
1318
+ // src/internal/validators/index.ts
1319
+ var import_effect3 = require("effect");
1320
+ var ERROR_VALUE_MAX_BYTES = 256;
1321
+ var textEncoder = new TextEncoder();
1322
+ var jsonByteSize = (value) => {
1323
+ const json = JSON.stringify(value);
1324
+ return textEncoder.encode(json).length;
1325
+ };
1326
+ var truncateToJsonByteBudget = (value, maxBytes) => {
1327
+ if (jsonByteSize(value) <= maxBytes) return value;
1328
+ let lo = 0;
1329
+ let hi = value.length;
1330
+ while (lo < hi) {
1331
+ const mid = Math.ceil((lo + hi) / 2);
1332
+ const slice = value.slice(0, mid);
1333
+ if (jsonByteSize(slice) <= maxBytes) lo = mid;
1334
+ else hi = mid - 1;
1335
+ }
1336
+ return value.slice(0, lo);
1337
+ };
1338
+ var assertErrorValueBudget = (value, label) => {
1339
+ const bytes = jsonByteSize(value);
1340
+ if (bytes <= ERROR_VALUE_MAX_BYTES) return value;
1341
+ throw new Error(`[Form.validators] ErrorValue for "${label}" must be JSON \u2264${ERROR_VALUE_MAX_BYTES}B (got ${bytes}B)`);
1342
+ };
1343
+ var errorValue = (label, value) => assertErrorValueBudget(value, label);
1344
+ var required = (decl) => {
1345
+ const trim = typeof decl === "object" && decl !== null ? Boolean(decl.trim) : true;
1346
+ const message = typeof decl === "string" ? decl : typeof decl === "object" && decl !== null && typeof decl.message === "string" ? decl.message : "required";
1347
+ const err = errorValue("required", message);
1348
+ return (value) => {
1349
+ if (value === null || value === void 0) return err;
1350
+ if (typeof value === "string") {
1351
+ const v = trim ? value.trim() : value;
1352
+ return v.length > 0 ? void 0 : err;
1353
+ }
1354
+ if (Array.isArray(value)) return value.length > 0 ? void 0 : err;
1355
+ if (typeof value === "boolean") return value ? void 0 : err;
1356
+ return void 0;
1357
+ };
1358
+ };
1359
+ var minLength = (decl) => {
1360
+ const min2 = typeof decl === "number" ? decl : decl.min;
1361
+ const message = typeof decl === "object" && decl !== null && typeof decl.message === "string" ? decl.message : "minLength";
1362
+ const err = errorValue("minLength", message);
1363
+ return (value) => {
1364
+ if (value === null || value === void 0) return void 0;
1365
+ if (typeof value === "string") return value.length >= min2 ? void 0 : err;
1366
+ if (Array.isArray(value)) return value.length >= min2 ? void 0 : err;
1367
+ return void 0;
1368
+ };
1369
+ };
1370
+ var maxLength = (decl) => {
1371
+ const max2 = typeof decl === "number" ? decl : decl.max;
1372
+ const message = typeof decl === "object" && decl !== null && typeof decl.message === "string" ? decl.message : "maxLength";
1373
+ const err = errorValue("maxLength", message);
1374
+ return (value) => {
1375
+ if (value === null || value === void 0) return void 0;
1376
+ if (typeof value === "string") return value.length <= max2 ? void 0 : err;
1377
+ if (Array.isArray(value)) return value.length <= max2 ? void 0 : err;
1378
+ return void 0;
1379
+ };
1380
+ };
1381
+ var min = (decl) => {
1382
+ const minValue = typeof decl === "number" ? decl : decl.min;
1383
+ const message = typeof decl === "object" && decl !== null && typeof decl.message === "string" ? decl.message : "min";
1384
+ const err = errorValue("min", message);
1385
+ return (value) => {
1386
+ if (value === null || value === void 0) return void 0;
1387
+ if (typeof value === "number" && Number.isFinite(value)) return value >= minValue ? void 0 : err;
1388
+ return void 0;
1389
+ };
1390
+ };
1391
+ var max = (decl) => {
1392
+ const maxValue = typeof decl === "number" ? decl : decl.max;
1393
+ const message = typeof decl === "object" && decl !== null && typeof decl.message === "string" ? decl.message : "max";
1394
+ const err = errorValue("max", message);
1395
+ return (value) => {
1396
+ if (value === null || value === void 0) return void 0;
1397
+ if (typeof value === "number" && Number.isFinite(value)) return value <= maxValue ? void 0 : err;
1398
+ return void 0;
1399
+ };
1400
+ };
1401
+ var pattern = (decl) => {
1402
+ const re = decl instanceof RegExp ? decl : decl.re;
1403
+ const message = typeof decl === "object" && decl !== null && typeof decl.message === "string" ? decl.message : "pattern";
1404
+ const err = errorValue("pattern", message);
1405
+ return (value) => {
1406
+ if (value === null || value === void 0) return void 0;
1407
+ if (typeof value !== "string") return void 0;
1408
+ return re.test(value) ? void 0 : err;
1409
+ };
1410
+ };
1411
+ var schemaErrorMessage = (schemaError) => {
1412
+ let message;
1413
+ try {
1414
+ message = import_effect3.ParseResult.TreeFormatter.formatErrorSync(schemaError);
1415
+ } catch {
1416
+ message = "schema invalid";
1417
+ }
1418
+ const truncated = truncateToJsonByteBudget(message, ERROR_VALUE_MAX_BYTES);
1419
+ return truncated.length > 0 ? truncated : "schema invalid";
1420
+ };
1421
+
1422
+ // src/Rule.ts
1423
+ var uniq = (items) => Array.from(new Set(items));
1424
+ var normalizeValidateOn2 = (input) => {
1425
+ if (!Array.isArray(input)) return void 0;
1426
+ const out = [];
1427
+ for (const x of input) {
1428
+ if (x === "onChange" || x === "onBlur") out.push(x);
1429
+ }
1430
+ return uniq(out);
1431
+ };
1432
+ var normalizeDeps = (input) => {
1433
+ if (!Array.isArray(input)) return void 0;
1434
+ const out = [];
1435
+ for (const x of input) {
1436
+ if (typeof x !== "string") continue;
1437
+ const v = x.trim();
1438
+ if (!v) continue;
1439
+ out.push(v);
1440
+ }
1441
+ return uniq(out);
1442
+ };
1443
+ var isPlainObject3 = (value) => Boolean(value) && typeof value === "object" && value !== null && !Array.isArray(value);
1444
+ var make = (input) => {
1445
+ if (typeof input === "function") {
1446
+ return {
1447
+ default: {
1448
+ deps: [],
1449
+ validate: input
1450
+ }
1451
+ };
1452
+ }
1453
+ if (!isPlainObject3(input)) {
1454
+ return {};
1455
+ }
1456
+ const baseDeps = normalizeDeps(input.deps) ?? [];
1457
+ const baseValidateOn = normalizeValidateOn2(input.validateOn);
1458
+ const byName = /* @__PURE__ */ new Map();
1459
+ const addRule = (name, raw) => {
1460
+ const ruleName = typeof name === "string" ? name.trim() : "";
1461
+ if (!ruleName) return;
1462
+ if (byName.has(ruleName)) {
1463
+ throw new Error(`[Form.Rule.make] Duplicate rule name "${ruleName}"`);
1464
+ }
1465
+ if (typeof raw === "function") {
1466
+ byName.set(ruleName, {
1467
+ deps: baseDeps,
1468
+ validate: raw,
1469
+ ...baseValidateOn !== void 0 ? { validateOn: baseValidateOn } : {}
1470
+ });
1471
+ return;
1472
+ }
1473
+ if (!raw || typeof raw !== "object") return;
1474
+ const entry = raw;
1475
+ const deps = normalizeDeps(entry.deps) ?? baseDeps;
1476
+ const validateOn = normalizeValidateOn2(entry.validateOn) ?? baseValidateOn;
1477
+ const validate = entry.validate;
1478
+ if (typeof validate !== "function") return;
1479
+ byName.set(ruleName, {
1480
+ ...entry,
1481
+ deps,
1482
+ validate,
1483
+ ...validateOn !== void 0 ? { validateOn } : {}
1484
+ });
1485
+ };
1486
+ const requiredDecl = input.required;
1487
+ if (requiredDecl !== void 0 && requiredDecl !== false) {
1488
+ const validate = required(requiredDecl);
1489
+ addRule("required", (value) => validate(value));
1490
+ }
1491
+ const minLengthDecl = input.minLength;
1492
+ if (minLengthDecl !== void 0) {
1493
+ const validate = minLength(minLengthDecl);
1494
+ addRule("minLength", (value) => validate(value));
1495
+ }
1496
+ const maxLengthDecl = input.maxLength;
1497
+ if (maxLengthDecl !== void 0) {
1498
+ const validate = maxLength(maxLengthDecl);
1499
+ addRule("maxLength", (value) => validate(value));
1500
+ }
1501
+ const minDecl = input.min;
1502
+ if (minDecl !== void 0) {
1503
+ const validate = min(minDecl);
1504
+ addRule("min", (value) => validate(value));
1505
+ }
1506
+ const maxDecl = input.max;
1507
+ if (maxDecl !== void 0) {
1508
+ const validate = max(maxDecl);
1509
+ addRule("max", (value) => validate(value));
1510
+ }
1511
+ const patternDecl = input.pattern;
1512
+ if (patternDecl !== void 0) {
1513
+ const validate = pattern(patternDecl);
1514
+ addRule("pattern", (value) => validate(value));
1515
+ }
1516
+ const validateBlock = input.validate;
1517
+ if (typeof validateBlock === "function") {
1518
+ addRule("validate", validateBlock);
1519
+ } else if (isPlainObject3(validateBlock)) {
1520
+ const names2 = Object.keys(validateBlock).sort((a, b) => a.localeCompare(b));
1521
+ for (const name of names2) {
1522
+ addRule(name, validateBlock[name]);
1523
+ }
1524
+ }
1525
+ const out = {};
1526
+ const names = Array.from(byName.keys()).sort((a, b) => a.localeCompare(b));
1527
+ for (const name of names) {
1528
+ out[name] = byName.get(name);
1529
+ }
1530
+ return out;
1531
+ };
1532
+ var field = (valuePath, rule, options) => ({
1533
+ kind: "field",
1534
+ valuePath,
1535
+ rule,
1536
+ ...options?.errorTarget !== void 0 ? { errorTarget: options.errorTarget } : {}
1537
+ });
1538
+ var root = (rule) => ({
1539
+ kind: "root",
1540
+ rule
1541
+ });
1542
+ var list = (listPath, spec) => ({
1543
+ kind: "list",
1544
+ listPath,
1545
+ identity: spec.identity,
1546
+ ...spec.item !== void 0 ? { item: spec.item } : {},
1547
+ ...spec.list !== void 0 ? { list: spec.list } : {}
1548
+ });
1549
+
1550
+ // src/internal/form/impl.ts
1551
+ var FormActions = {
1552
+ setValue: import_effect4.Schema.Struct({ path: import_effect4.Schema.String, value: import_effect4.Schema.Unknown }),
1553
+ blur: import_effect4.Schema.Struct({ path: import_effect4.Schema.String }),
1554
+ submit: import_effect4.Schema.Void,
1555
+ validate: import_effect4.Schema.Void,
1556
+ validatePaths: import_effect4.Schema.Array(import_effect4.Schema.String),
1557
+ submitAttempt: import_effect4.Schema.Void,
1558
+ setSubmitting: import_effect4.Schema.Boolean,
1559
+ reset: import_effect4.Schema.UndefinedOr(import_effect4.Schema.Unknown),
1560
+ setError: import_effect4.Schema.Struct({ path: import_effect4.Schema.String, error: import_effect4.Schema.Unknown }),
1561
+ clearErrors: import_effect4.Schema.UndefinedOr(import_effect4.Schema.Array(import_effect4.Schema.String)),
1562
+ arrayAppend: import_effect4.Schema.Struct({ path: import_effect4.Schema.String, value: import_effect4.Schema.Unknown }),
1563
+ arrayPrepend: import_effect4.Schema.Struct({ path: import_effect4.Schema.String, value: import_effect4.Schema.Unknown }),
1564
+ arrayRemove: import_effect4.Schema.Struct({ path: import_effect4.Schema.String, index: import_effect4.Schema.Number }),
1565
+ arraySwap: import_effect4.Schema.Struct({
1566
+ path: import_effect4.Schema.String,
1567
+ indexA: import_effect4.Schema.Number,
1568
+ indexB: import_effect4.Schema.Number
1569
+ }),
1570
+ arrayMove: import_effect4.Schema.Struct({
1571
+ path: import_effect4.Schema.String,
1572
+ from: import_effect4.Schema.Number,
1573
+ to: import_effect4.Schema.Number
1574
+ })
1575
+ };
1576
+ var initialMeta2 = () => ({
1577
+ submitCount: 0,
1578
+ isSubmitting: false,
1579
+ isDirty: false,
1580
+ errorCount: 0
1581
+ });
1582
+ var make2 = (id, config, extend) => {
1583
+ const ErrorsSchema = import_effect4.Schema.Unknown;
1584
+ const UiSchema = import_effect4.Schema.Unknown;
1585
+ const MetaSchema = import_effect4.Schema.Struct({
1586
+ submitCount: import_effect4.Schema.Number,
1587
+ isSubmitting: import_effect4.Schema.Boolean,
1588
+ isDirty: import_effect4.Schema.Boolean,
1589
+ errorCount: import_effect4.Schema.Number
1590
+ });
1591
+ const StateSchema = import_effect4.Schema.extend(
1592
+ config.values,
1593
+ import_effect4.Schema.Struct({
1594
+ errors: ErrorsSchema,
1595
+ ui: UiSchema,
1596
+ $form: MetaSchema
1597
+ })
1598
+ );
1599
+ const Actions = FormActions;
1600
+ const reducers = makeFormReducers({
1601
+ initialValues: config.initialValues
1602
+ });
1603
+ const validateOn = normalizeValidateOn(config.validateOn, ["onSubmit"]);
1604
+ const reValidateOn = normalizeValidateOn(config.reValidateOn, ["onChange"]);
1605
+ const assertCanonicalValuePath2 = (label, path) => {
1606
+ const p = String(path ?? "").trim();
1607
+ if (!p) throw new Error(`[Form.make] ${label} must be a non-empty path`);
1608
+ if (p === "$root") return;
1609
+ if (p.includes("[]") || p.includes("[") || p.includes("]")) {
1610
+ throw new Error(`[Form.make] ${label} "${p}" must not use bracket syntax`);
1611
+ }
1612
+ const segments = p.split(".").map((s) => s.trim()).filter(Boolean);
1613
+ if (segments.length === 0) {
1614
+ throw new Error(`[Form.make] ${label} "${p}" must be a non-empty path`);
1615
+ }
1616
+ for (const seg of segments) {
1617
+ if (/^[0-9]+$/.test(seg)) {
1618
+ throw new Error(`[Form.make] ${label} "${p}" must not contain numeric segments`);
1619
+ }
1620
+ }
1621
+ };
1622
+ const assertValidListIdentity2 = (identity, listPath) => {
1623
+ if (!identity || typeof identity !== "object") {
1624
+ throw new Error(`[Form.make] Missing list identity for "${listPath}"`);
1625
+ }
1626
+ const mode = identity.mode;
1627
+ if (mode === "trackBy") {
1628
+ const trackBy = identity.trackBy;
1629
+ if (typeof trackBy !== "string" || trackBy.trim().length === 0) {
1630
+ throw new Error(`[Form.make] identity.trackBy for "${listPath}" must be a non-empty string`);
1631
+ }
1632
+ if (trackBy.includes("[") || trackBy.includes("]")) {
1633
+ throw new Error(`[Form.make] identity.trackBy for "${listPath}" must not contain brackets (got "${trackBy}")`);
1634
+ }
1635
+ return;
1636
+ }
1637
+ if (mode === "store" || mode === "index") return;
1638
+ throw new Error(`[Form.make] Invalid identity.mode for "${listPath}" (got "${String(mode)}")`);
1639
+ };
1640
+ const compileRulesToTraitSpec = (rulesSpec2) => {
1641
+ if (!rulesSpec2 || rulesSpec2._tag !== "FormRulesSpec") {
1642
+ throw new Error(`[Form.make] "rules" must be a FormRulesSpec (from Form.rules(...)/rules.schema(...))`);
1643
+ }
1644
+ const joinPath2 = (prefix, suffix) => {
1645
+ if (!prefix) return suffix;
1646
+ if (!suffix) return prefix;
1647
+ return `${prefix}.${suffix}`;
1648
+ };
1649
+ const dirnamePath = (path) => {
1650
+ const p = String(path ?? "").trim();
1651
+ if (!p) return "";
1652
+ const idx = p.lastIndexOf(".");
1653
+ return idx >= 0 ? p.slice(0, idx) : "";
1654
+ };
1655
+ const isRelativeDep = (dep) => {
1656
+ if (typeof dep !== "string") return false;
1657
+ const d = dep.trim();
1658
+ if (!d) return false;
1659
+ if (d === "$root") return false;
1660
+ if (d.includes("[") || d.includes("]")) return false;
1661
+ if (d.includes(".")) return false;
1662
+ return true;
1663
+ };
1664
+ const prefixDeps = (deps, prefix) => {
1665
+ if (!Array.isArray(deps)) return void 0;
1666
+ const out = [];
1667
+ for (const raw of deps) {
1668
+ if (typeof raw !== "string") continue;
1669
+ const d = raw.trim();
1670
+ if (!d) continue;
1671
+ out.push(isRelativeDep(d) ? joinPath2(prefix, d) : d);
1672
+ }
1673
+ return out;
1674
+ };
1675
+ const prefixRuleInputDeps = (input, prefix) => {
1676
+ if (!input || typeof input !== "object") return input;
1677
+ if (Array.isArray(input)) return input;
1678
+ const anyInput = input;
1679
+ const deps = prefixDeps(anyInput.deps, prefix);
1680
+ const validate = anyInput.validate;
1681
+ if (typeof validate === "function") {
1682
+ return deps !== void 0 ? { ...anyInput, deps } : input;
1683
+ }
1684
+ if (validate && typeof validate === "object" && !Array.isArray(validate)) {
1685
+ const nextValidate = { ...validate };
1686
+ for (const [name, raw] of Object.entries(validate)) {
1687
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
1688
+ const entryDeps = prefixDeps(raw.deps, prefix);
1689
+ if (entryDeps !== void 0) {
1690
+ nextValidate[name] = { ...raw, deps: entryDeps };
1691
+ }
1692
+ }
1693
+ return {
1694
+ ...anyInput,
1695
+ ...deps !== void 0 ? { deps } : {},
1696
+ validate: nextValidate
1697
+ };
1698
+ }
1699
+ return deps !== void 0 ? { ...anyInput, deps } : input;
1700
+ };
1701
+ const decls = Array.isArray(rulesSpec2.decls) ? rulesSpec2.decls : [];
1702
+ const spec = {};
1703
+ const declared = /* @__PURE__ */ new Set();
1704
+ const withDefaultDeps = (ruleSet, defaultDep) => {
1705
+ const out = {};
1706
+ for (const name of Object.keys(ruleSet)) {
1707
+ const r = ruleSet[name];
1708
+ if (!r || typeof r !== "object" || Array.isArray(r)) {
1709
+ out[name] = r;
1710
+ continue;
1711
+ }
1712
+ const deps = Array.isArray(r.deps) ? r.deps : [];
1713
+ out[name] = deps.length > 0 ? r : { ...r, deps: [defaultDep] };
1714
+ }
1715
+ return out;
1716
+ };
1717
+ const reserve = (kind, path) => {
1718
+ const k = `${kind}:${path}`;
1719
+ if (declared.has(k)) {
1720
+ throw new Error(`[Form.make] Duplicate rules declaration for ${kind} "${path}"`);
1721
+ }
1722
+ declared.add(k);
1723
+ };
1724
+ for (const decl of decls) {
1725
+ if (!decl || typeof decl !== "object") continue;
1726
+ if (decl.kind === "field") {
1727
+ const valuePath = String(decl.valuePath ?? "").trim();
1728
+ assertCanonicalValuePath2("field path", valuePath);
1729
+ if (valuePath === "$root") {
1730
+ throw new Error(`[Form.make] field path "$root" is not allowed (use Form.Rule.root(...))`);
1731
+ }
1732
+ reserve("field", valuePath);
1733
+ const errorTarget = decl.errorTarget;
1734
+ if (errorTarget !== void 0 && errorTarget !== "$value" && errorTarget !== "$self") {
1735
+ throw new Error(`[Form.make] Invalid errorTarget for field "${valuePath}"`);
1736
+ }
1737
+ const depsPrefix = errorTarget === "$self" ? valuePath : dirnamePath(valuePath);
1738
+ const ruleInput = prefixRuleInputDeps(decl.rule, depsPrefix);
1739
+ const rules2 = withDefaultDeps(make(ruleInput), valuePath);
1740
+ const writebackPath = errorTarget === "$self" ? `errors.${valuePath}.$self` : void 0;
1741
+ spec[valuePath] = {
1742
+ fieldPath: valuePath,
1743
+ kind: "check",
1744
+ meta: {
1745
+ rules: rules2,
1746
+ writeback: {
1747
+ kind: "errors",
1748
+ ...writebackPath ? { path: writebackPath } : {}
1749
+ }
1750
+ }
1751
+ };
1752
+ continue;
1753
+ }
1754
+ if (decl.kind === "root") {
1755
+ reserve("root", "$root");
1756
+ const ruleInput = prefixRuleInputDeps(decl.rule, "");
1757
+ const rules2 = make(ruleInput);
1758
+ spec.$root = {
1759
+ fieldPath: "$root",
1760
+ kind: "check",
1761
+ meta: {
1762
+ rules: rules2,
1763
+ writeback: { kind: "errors" }
1764
+ }
1765
+ };
1766
+ continue;
1767
+ }
1768
+ if (decl.kind === "list") {
1769
+ const listPath = String(decl.listPath ?? "").trim();
1770
+ assertCanonicalValuePath2("list path", listPath);
1771
+ if (listPath === "$root") {
1772
+ throw new Error(`[Form.make] list path "$root" is not allowed`);
1773
+ }
1774
+ reserve("list", listPath);
1775
+ const identity = decl.identity;
1776
+ assertValidListIdentity2(identity, listPath);
1777
+ const itemInput = decl.item;
1778
+ const listInput = decl.list;
1779
+ const itemRules = itemInput ? make(itemInput) : void 0;
1780
+ const listRules = listInput ? make(listInput) : void 0;
1781
+ spec[listPath] = Logix4.StateTrait.list({
1782
+ identityHint: identity.mode === "trackBy" ? { trackBy: String(identity.trackBy) } : void 0,
1783
+ item: itemRules ? Logix4.StateTrait.node({ check: itemRules }) : void 0,
1784
+ list: listRules ? Logix4.StateTrait.node({ check: listRules }) : void 0
1785
+ });
1786
+ continue;
1787
+ }
1788
+ const kind = String(decl.kind ?? "");
1789
+ throw new Error(`[Form.make] Unknown rules declaration kind "${kind}"`);
1790
+ }
1791
+ return spec;
1792
+ };
1793
+ const toFieldPathSegments = (label, valuePath) => {
1794
+ assertCanonicalValuePath2(label, valuePath);
1795
+ if (valuePath === "$root") return ["$root"];
1796
+ return valuePath.split(".").map((s) => s.trim()).filter(Boolean);
1797
+ };
1798
+ const normalizeAutoValidateOn = (input) => {
1799
+ if (!Array.isArray(input)) return void 0;
1800
+ const out = [];
1801
+ for (const x of input) {
1802
+ if (x === "onChange" || x === "onBlur") out.push(x);
1803
+ }
1804
+ if (out.length === 0) return void 0;
1805
+ return Array.from(new Set(out)).sort((a, b) => a.localeCompare(b));
1806
+ };
1807
+ const normalizeRuleDeps = (deps) => {
1808
+ if (!Array.isArray(deps)) return [];
1809
+ const out = [];
1810
+ for (const x of deps) {
1811
+ if (typeof x !== "string") continue;
1812
+ const v = x.trim();
1813
+ if (!v) continue;
1814
+ out.push(v);
1815
+ }
1816
+ return Array.from(new Set(out)).sort((a, b) => a.localeCompare(b));
1817
+ };
1818
+ const rulesManifestWarningsBase = () => {
1819
+ const warnings = [];
1820
+ if (config.rules && config.traits) {
1821
+ warnings.push(
1822
+ `[Form.make] \u540C\u65F6\u4F20\u5165\u4E86 "rules" \u4E0E "traits"\uFF1A\u63A8\u8350\u5C06\u6821\u9A8C\u8FC1\u79FB\u5230 rules\uFF1Btraits \u4EC5\u4FDD\u7559 computed/source/link \u6216\u5FC5\u8981\u7684\u9AD8\u7EA7\u58F0\u660E\uFF08\u4FBF\u4E8E\u6027\u80FD/\u8BCA\u65AD\u5BF9\u7167\uFF09\u3002`
1823
+ );
1824
+ }
1825
+ return warnings;
1826
+ };
1827
+ const buildRulesManifest = () => {
1828
+ const listsByPath = /* @__PURE__ */ new Map();
1829
+ const rulesById = /* @__PURE__ */ new Map();
1830
+ const addList = (path, identity) => {
1831
+ const segments = toFieldPathSegments("list path", path);
1832
+ const key = segments.join(".");
1833
+ if (listsByPath.has(key)) return;
1834
+ listsByPath.set(key, { path: segments, identity });
1835
+ };
1836
+ const addRule = (rule) => {
1837
+ if (rulesById.has(rule.ruleId)) return;
1838
+ rulesById.set(rule.ruleId, rule);
1839
+ };
1840
+ const ruleMeta = (source) => ({ source });
1841
+ const emitRuleSet = (params) => {
1842
+ const names = Object.keys(params.rules).sort((a, b) => a.localeCompare(b));
1843
+ for (const name of names) {
1844
+ const r = params.rules[name];
1845
+ if (!r || typeof r !== "object") continue;
1846
+ const deps = normalizeRuleDeps(r.deps);
1847
+ const validateOn2 = normalizeAutoValidateOn(r.validateOn);
1848
+ addRule({
1849
+ ruleId: params.ruleId(name),
1850
+ scope: params.scope,
1851
+ deps,
1852
+ ...validateOn2 !== void 0 ? { validateOn: validateOn2 } : {},
1853
+ meta: ruleMeta(params.source)
1854
+ });
1855
+ }
1856
+ };
1857
+ if (config.rules && config.rules._tag === "FormRulesSpec") {
1858
+ const decls = Array.isArray(config.rules.decls) ? config.rules.decls : [];
1859
+ for (const decl of decls) {
1860
+ if (!decl || typeof decl !== "object") continue;
1861
+ if (decl.kind === "field") {
1862
+ const valuePath = String(decl.valuePath ?? "").trim();
1863
+ assertCanonicalValuePath2("field path", valuePath);
1864
+ if (valuePath === "$root") continue;
1865
+ const errorTarget = decl.errorTarget;
1866
+ const scope = {
1867
+ kind: "field",
1868
+ fieldPath: toFieldPathSegments("field path", valuePath),
1869
+ ...errorTarget !== void 0 ? { errorTarget } : {}
1870
+ };
1871
+ const depsPrefix = errorTarget === "$self" ? valuePath : (() => {
1872
+ const idx = valuePath.lastIndexOf(".");
1873
+ return idx >= 0 ? valuePath.slice(0, idx) : "";
1874
+ })();
1875
+ const prefixDeps = (deps, prefix) => {
1876
+ if (!Array.isArray(deps)) return void 0;
1877
+ const out = [];
1878
+ for (const raw of deps) {
1879
+ if (typeof raw !== "string") continue;
1880
+ const d = raw.trim();
1881
+ if (!d) continue;
1882
+ const isRelative = d !== "$root" && !d.includes("[") && !d.includes("]") && !d.includes(".") && !/^[0-9]+$/.test(d);
1883
+ out.push(isRelative && prefix ? `${prefix}.${d}` : d);
1884
+ }
1885
+ return out;
1886
+ };
1887
+ const prefixRuleInputDeps = (input, prefix) => {
1888
+ if (!input || typeof input !== "object") return input;
1889
+ if (Array.isArray(input)) return input;
1890
+ const anyInput = input;
1891
+ const deps = prefixDeps(anyInput.deps, prefix);
1892
+ const validate = anyInput.validate;
1893
+ if (typeof validate === "function") {
1894
+ return deps !== void 0 ? { ...anyInput, deps } : input;
1895
+ }
1896
+ if (validate && typeof validate === "object" && !Array.isArray(validate)) {
1897
+ const nextValidate = { ...validate };
1898
+ for (const [ruleName, raw] of Object.entries(validate)) {
1899
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) continue;
1900
+ const entryDeps = prefixDeps(raw.deps, prefix);
1901
+ if (entryDeps !== void 0) {
1902
+ nextValidate[ruleName] = { ...raw, deps: entryDeps };
1903
+ }
1904
+ }
1905
+ return {
1906
+ ...anyInput,
1907
+ ...deps !== void 0 ? { deps } : {},
1908
+ validate: nextValidate
1909
+ };
1910
+ }
1911
+ return deps !== void 0 ? { ...anyInput, deps } : input;
1912
+ };
1913
+ const ruleInput = prefixRuleInputDeps(decl.rule, depsPrefix);
1914
+ const rules3 = make(ruleInput);
1915
+ emitRuleSet({
1916
+ source: "rules",
1917
+ scope,
1918
+ ruleId: (name) => `${valuePath}#${name}`,
1919
+ rules: rules3
1920
+ });
1921
+ continue;
1922
+ }
1923
+ if (decl.kind === "root") {
1924
+ const ruleInput = decl.rule;
1925
+ const rules3 = make(ruleInput);
1926
+ emitRuleSet({
1927
+ source: "rules",
1928
+ scope: { kind: "root", fieldPath: ["$root"] },
1929
+ ruleId: (name) => `$root#${name}`,
1930
+ rules: rules3
1931
+ });
1932
+ continue;
1933
+ }
1934
+ if (decl.kind === "list") {
1935
+ const listPath = String(decl.listPath ?? "").trim();
1936
+ assertCanonicalValuePath2("list path", listPath);
1937
+ if (listPath === "$root") continue;
1938
+ const identity = decl.identity;
1939
+ assertValidListIdentity2(identity, listPath);
1940
+ addList(listPath, identity);
1941
+ const listFieldPath = toFieldPathSegments("list path", listPath);
1942
+ const itemInput = decl.item;
1943
+ const listInput = decl.list;
1944
+ if (itemInput) {
1945
+ const itemRules = make(itemInput);
1946
+ emitRuleSet({
1947
+ source: "rules",
1948
+ scope: { kind: "item", fieldPath: listFieldPath },
1949
+ ruleId: (name) => `${listPath}#item.${name}`,
1950
+ rules: itemRules
1951
+ });
1952
+ }
1953
+ if (listInput) {
1954
+ const listRules = make(listInput);
1955
+ emitRuleSet({
1956
+ source: "rules",
1957
+ scope: { kind: "list", fieldPath: listFieldPath },
1958
+ ruleId: (name) => `${listPath}#list.${name}`,
1959
+ rules: listRules
1960
+ });
1961
+ }
1962
+ continue;
1963
+ }
1964
+ }
1965
+ }
1966
+ const traitsSpec = config.traits ? traits(config.values)(config.traits) : void 0;
1967
+ if (traitsSpec && typeof traitsSpec === "object") {
1968
+ for (const [rawPath, value] of Object.entries(traitsSpec)) {
1969
+ const path = String(rawPath ?? "").trim();
1970
+ if (!path) continue;
1971
+ const addFieldRuleSet = (fieldPath, rules3, errorTarget) => {
1972
+ const scope = {
1973
+ kind: fieldPath === "$root" ? "root" : "field",
1974
+ fieldPath: fieldPath === "$root" ? ["$root"] : toFieldPathSegments("field path", fieldPath),
1975
+ ...errorTarget !== void 0 ? { errorTarget } : {}
1976
+ };
1977
+ const names = Object.keys(rules3).sort((a, b) => a.localeCompare(b));
1978
+ for (const name of names) {
1979
+ const r = rules3[name];
1980
+ if (!r || typeof r !== "object") continue;
1981
+ const deps = normalizeRuleDeps(r.deps);
1982
+ const validateOn2 = normalizeAutoValidateOn(r.validateOn);
1983
+ const ruleId = `${fieldPath}#${name}`;
1984
+ addRule({
1985
+ ruleId,
1986
+ scope,
1987
+ deps,
1988
+ ...validateOn2 !== void 0 ? { validateOn: validateOn2 } : {},
1989
+ meta: ruleMeta("traits")
1990
+ });
1991
+ }
1992
+ };
1993
+ if (value && typeof value === "object" && value._tag === "StateTraitList") {
1994
+ const listPath = path;
1995
+ assertCanonicalValuePath2("list path", listPath);
1996
+ if (listPath !== "$root") {
1997
+ const trackBy = value.identityHint && typeof value.identityHint === "object" ? value.identityHint.trackBy : void 0;
1998
+ addList(
1999
+ listPath,
2000
+ typeof trackBy === "string" && trackBy.length > 0 ? { mode: "trackBy", trackBy: String(trackBy) } : { mode: "store" }
2001
+ );
2002
+ }
2003
+ const listFieldPath = toFieldPathSegments("list path", listPath);
2004
+ const item = value.item;
2005
+ const list3 = value.list;
2006
+ const emitNodeRules = (node2, kind) => {
2007
+ if (!node2 || typeof node2 !== "object") return;
2008
+ if (node2._tag !== "StateTraitNode") return;
2009
+ const check = node2.check;
2010
+ if (!check || typeof check !== "object" || Array.isArray(check)) return;
2011
+ const names = Object.keys(check).sort((a, b) => a.localeCompare(b));
2012
+ for (const name of names) {
2013
+ const r = check[name];
2014
+ if (!r || typeof r !== "object") continue;
2015
+ const deps = normalizeRuleDeps(r.deps);
2016
+ const validateOn2 = normalizeAutoValidateOn(r.validateOn);
2017
+ addRule({
2018
+ ruleId: `${listPath}#${kind}.${name}`,
2019
+ scope: { kind, fieldPath: listFieldPath },
2020
+ deps,
2021
+ ...validateOn2 !== void 0 ? { validateOn: validateOn2 } : {},
2022
+ meta: ruleMeta("traits")
2023
+ });
2024
+ }
2025
+ };
2026
+ emitNodeRules(item, "item");
2027
+ emitNodeRules(list3, "list");
2028
+ continue;
2029
+ }
2030
+ if (value && typeof value === "object" && value._tag === "StateTraitNode") {
2031
+ const check = value.check;
2032
+ if (check && typeof check === "object" && !Array.isArray(check)) {
2033
+ addFieldRuleSet(path, check);
2034
+ }
2035
+ continue;
2036
+ }
2037
+ if (value && typeof value === "object" && value.kind === "check") {
2038
+ const meta = value.meta;
2039
+ const rules3 = meta && typeof meta === "object" ? meta.rules : void 0;
2040
+ if (rules3 && typeof rules3 === "object" && !Array.isArray(rules3)) {
2041
+ const writebackPath = meta && typeof meta === "object" && meta.writeback && typeof meta.writeback === "object" ? meta.writeback.path : void 0;
2042
+ const errorTarget = typeof writebackPath === "string" && writebackPath.endsWith(".$self") ? "$self" : void 0;
2043
+ addFieldRuleSet(path, rules3, errorTarget);
2044
+ }
2045
+ }
2046
+ }
2047
+ }
2048
+ const lists = Array.from(listsByPath.values()).sort((a, b) => a.path.join(".").localeCompare(b.path.join(".")));
2049
+ const rules2 = Array.from(rulesById.values()).sort((a, b) => a.ruleId.localeCompare(b.ruleId));
2050
+ return {
2051
+ moduleId: id,
2052
+ lists,
2053
+ rules: rules2
2054
+ };
2055
+ };
2056
+ const traitsBase = config.traits ? traits(config.values)(config.traits) : void 0;
2057
+ const derivedSpec = normalizeDerived(config.derived);
2058
+ const rulesSpec = config.rules ? compileRulesToTraitSpec(config.rules) : void 0;
2059
+ const mergedSpec1 = mergeTraitSpecs(traitsBase, derivedSpec, "traits", "derived");
2060
+ const mergedSpec = mergeTraitSpecs(mergedSpec1, rulesSpec, "traits/derived", "rules");
2061
+ const traitsWrapped = mergedSpec ? wrapTraitsForValidateOn(mergedSpec, { validateOn, reValidateOn }) : void 0;
2062
+ const traits2 = traitsWrapped?.traits;
2063
+ const rulesValidateOn = traitsWrapped?.rulesValidateOn ?? [];
2064
+ const def = {
2065
+ state: StateSchema,
2066
+ actions: Actions,
2067
+ reducers,
2068
+ traits: traits2,
2069
+ schemas: { values: config.values }
2070
+ };
2071
+ const module2 = extend ? Logix4.Module.make(id, def, extend) : Logix4.Module.make(id, def);
2072
+ const logics = [
2073
+ install(module2.tag, {
2074
+ validateOn,
2075
+ reValidateOn,
2076
+ rulesValidateOn,
2077
+ debounceMs: config.debounceMs
2078
+ })
2079
+ ];
2080
+ const initial = (values) => ({
2081
+ ...values ?? config.initialValues,
2082
+ errors: {},
2083
+ ui: {},
2084
+ $form: initialMeta2()
2085
+ });
2086
+ const controller = {
2087
+ make: (runtime) => {
2088
+ return makeFormController({
2089
+ runtime,
2090
+ shape: module2.shape,
2091
+ valuesSchema: config.values
2092
+ });
2093
+ }
2094
+ };
2095
+ module2.controller = controller;
2096
+ Logix4.Observability.registerTrialRunArtifactExporter(
2097
+ module2.tag,
2098
+ makeFormRulesManifestArtifactExporter({
2099
+ getManifest: buildRulesManifest,
2100
+ getWarnings: rulesManifestWarningsBase
2101
+ })
2102
+ );
2103
+ const EXTEND_HANDLE = /* @__PURE__ */ Symbol.for("logix.module.handle.extend");
2104
+ let manifestMemo;
2105
+ let manifestWarningsMemo;
2106
+ module2.tag[EXTEND_HANDLE] = (runtime, base) => {
2107
+ const form = controller.make(runtime);
2108
+ return {
2109
+ ...base,
2110
+ controller: form.controller,
2111
+ rulesManifest: () => {
2112
+ if (!manifestMemo) {
2113
+ manifestMemo = buildRulesManifest();
2114
+ }
2115
+ return manifestMemo;
2116
+ },
2117
+ rulesManifestWarnings: () => {
2118
+ if (!manifestWarningsMemo) {
2119
+ manifestWarningsMemo = rulesManifestWarningsBase();
2120
+ }
2121
+ return manifestWarningsMemo;
2122
+ }
2123
+ };
2124
+ };
2125
+ return module2.implement({
2126
+ initial: initial(),
2127
+ logics: [...logics]
2128
+ });
2129
+ };
2130
+
2131
+ // src/internal/dsl/derived.ts
2132
+ var derived = (_valuesSchema) => {
2133
+ function run(spec) {
2134
+ return spec;
2135
+ }
2136
+ return run;
2137
+ };
2138
+
2139
+ // src/internal/dsl/rules.ts
2140
+ var import_effect5 = require("effect");
2141
+ var normalizePrefix = (prefix) => {
2142
+ const p = String(prefix ?? "").trim();
2143
+ if (!p) return "";
2144
+ if (p.includes("[]") || p.includes("[") || p.includes("]")) {
2145
+ throw new Error(`[Form.rules] Invalid prefix "${p}" (bracket syntax is not allowed)`);
2146
+ }
2147
+ const segments = p.split(".").map((s) => s.trim()).filter(Boolean);
2148
+ if (segments.length === 0) return "";
2149
+ for (const seg of segments) {
2150
+ if (/^[0-9]+$/.test(seg)) {
2151
+ throw new Error(`[Form.rules] Invalid prefix "${p}" (numeric segments are not allowed)`);
2152
+ }
2153
+ }
2154
+ return segments.join(".");
2155
+ };
2156
+ var joinPath = (prefix, path) => {
2157
+ const p = String(prefix ?? "").trim();
2158
+ const s = String(path ?? "").trim();
2159
+ if (!p) return s;
2160
+ if (!s) return p;
2161
+ return `${p}.${s}`;
2162
+ };
2163
+ var flattenDecls = (decls) => {
2164
+ const out = [];
2165
+ for (const item of decls) {
2166
+ if (Array.isArray(item)) out.push(...item);
2167
+ else out.push(item);
2168
+ }
2169
+ return out;
2170
+ };
2171
+ var withPrefix = (prefix, decls) => {
2172
+ if (!prefix) return decls;
2173
+ return decls.map((decl) => {
2174
+ if (!decl || typeof decl !== "object") return decl;
2175
+ if (decl.kind === "field") {
2176
+ const valuePath = joinPath(prefix, String(decl.valuePath ?? ""));
2177
+ return { ...decl, valuePath };
2178
+ }
2179
+ if (decl.kind === "list") {
2180
+ const listPath = joinPath(prefix, String(decl.listPath ?? ""));
2181
+ return { ...decl, listPath };
2182
+ }
2183
+ return decl;
2184
+ });
2185
+ };
2186
+ var makeFieldNode = (rule) => ({
2187
+ _tag: "FormRulesNodeField",
2188
+ rule
2189
+ });
2190
+ var fieldFromSchema = (schema) => ({
2191
+ validate: {
2192
+ schema: (value) => {
2193
+ const decoded = import_effect5.Schema.decodeUnknownEither(schema)(value);
2194
+ return decoded._tag === "Right" ? void 0 : schemaErrorMessage(decoded.left);
2195
+ }
2196
+ }
2197
+ });
2198
+ var makeObjectNode = (params) => {
2199
+ const base = {
2200
+ _tag: "FormRulesNodeObject",
2201
+ shape: params.shape,
2202
+ ...params.refineRule !== void 0 ? { refineRule: params.refineRule } : {},
2203
+ ...params.superRefineRule !== void 0 ? { superRefineRule: params.superRefineRule } : {}
2204
+ };
2205
+ base.refine = (rule) => {
2206
+ if (params.refineRule !== void 0 || params.superRefineRule !== void 0) {
2207
+ throw new Error(`[Form.rules.schema] object.refine(...) can only be specified once`);
2208
+ }
2209
+ return makeObjectNode({ ...params, refineRule: rule });
2210
+ };
2211
+ base.superRefine = (rule) => {
2212
+ if (params.refineRule !== void 0 || params.superRefineRule !== void 0) {
2213
+ throw new Error(`[Form.rules.schema] object.superRefine(...) can only be specified once`);
2214
+ }
2215
+ return makeObjectNode({ ...params, superRefineRule: rule });
2216
+ };
2217
+ return base;
2218
+ };
2219
+ var makeArrayNode = (params) => {
2220
+ const base = {
2221
+ _tag: "FormRulesNodeArray",
2222
+ item: params.item,
2223
+ identity: params.identity,
2224
+ ...params.refineRule !== void 0 ? { refineRule: params.refineRule } : {},
2225
+ ...params.superRefineRule !== void 0 ? { superRefineRule: params.superRefineRule } : {}
2226
+ };
2227
+ base.refine = (rule) => {
2228
+ if (params.refineRule !== void 0 || params.superRefineRule !== void 0) {
2229
+ throw new Error(`[Form.rules.schema] array.refine(...) can only be specified once`);
2230
+ }
2231
+ return makeArrayNode({ ...params, refineRule: rule });
2232
+ };
2233
+ base.superRefine = (rule) => {
2234
+ if (params.refineRule !== void 0 || params.superRefineRule !== void 0) {
2235
+ throw new Error(`[Form.rules.schema] array.superRefine(...) can only be specified once`);
2236
+ }
2237
+ return makeArrayNode({ ...params, superRefineRule: rule });
2238
+ };
2239
+ return base;
2240
+ };
2241
+ var assertValidListIdentity = (identity, listPath) => {
2242
+ if (!identity || typeof identity !== "object") {
2243
+ throw new Error(`[Form.rules] Missing list identity for "${listPath}"`);
2244
+ }
2245
+ const mode = identity.mode;
2246
+ if (mode === "trackBy") {
2247
+ const trackBy = identity.trackBy;
2248
+ if (typeof trackBy !== "string" || trackBy.trim().length === 0) {
2249
+ throw new Error(`[Form.rules] identity.trackBy for "${listPath}" must be a non-empty string`);
2250
+ }
2251
+ if (trackBy.includes("[") || trackBy.includes("]")) {
2252
+ throw new Error(`[Form.rules] identity.trackBy for "${listPath}" must not contain brackets (got "${trackBy}")`);
2253
+ }
2254
+ return;
2255
+ }
2256
+ if (mode === "store" || mode === "index") return;
2257
+ throw new Error(`[Form.rules] Invalid identity.mode for "${listPath}" (got "${String(mode)}")`);
2258
+ };
2259
+ var assertCanonicalValuePath = (label, path) => {
2260
+ const p = String(path ?? "").trim();
2261
+ if (!p) throw new Error(`[Form.rules] ${label} must be a non-empty path`);
2262
+ if (p === "$root") return;
2263
+ if (p.includes("[]") || p.includes("[") || p.includes("]")) {
2264
+ throw new Error(`[Form.rules] ${label} "${p}" must not use bracket syntax`);
2265
+ }
2266
+ const segments = p.split(".").map((s) => s.trim()).filter(Boolean);
2267
+ if (segments.length === 0) throw new Error(`[Form.rules] ${label} "${p}" must be a non-empty path`);
2268
+ for (const seg of segments) {
2269
+ if (/^[0-9]+$/.test(seg)) {
2270
+ throw new Error(`[Form.rules] ${label} "${p}" must not contain numeric segments`);
2271
+ }
2272
+ }
2273
+ };
2274
+ var assertDeclListGuardrails = (decls) => {
2275
+ const declared = /* @__PURE__ */ new Map();
2276
+ const reserve = (kind, path) => {
2277
+ const existing = declared.get(path);
2278
+ if (existing) {
2279
+ throw new Error(`[Form.rules] Duplicate declaration for "${path}" (${existing} + ${kind})`);
2280
+ }
2281
+ declared.set(path, kind);
2282
+ };
2283
+ for (const decl of decls) {
2284
+ if (!decl || typeof decl !== "object") continue;
2285
+ if (decl.kind === "field") {
2286
+ const valuePath = String(decl.valuePath ?? "").trim();
2287
+ assertCanonicalValuePath("field path", valuePath);
2288
+ reserve("field", valuePath);
2289
+ continue;
2290
+ }
2291
+ if (decl.kind === "root") {
2292
+ reserve("root", "$root");
2293
+ continue;
2294
+ }
2295
+ if (decl.kind === "list") {
2296
+ const listPath = String(decl.listPath ?? "").trim();
2297
+ assertCanonicalValuePath("list path", listPath);
2298
+ const identity = decl.identity;
2299
+ assertValidListIdentity(identity, listPath);
2300
+ reserve("list", listPath);
2301
+ continue;
2302
+ }
2303
+ const kind = String(decl.kind ?? "");
2304
+ throw new Error(`[Form.rules] Unknown declaration kind "${kind}"`);
2305
+ }
2306
+ };
2307
+ var compileSchema = (node2, prefix) => {
2308
+ const visit = (n, at) => {
2309
+ if (!n || typeof n !== "object") return [];
2310
+ if (n._tag === "FormRulesNodeField") {
2311
+ const rule = n.rule;
2312
+ assertCanonicalValuePath("field path", at);
2313
+ return [field(at, rule)];
2314
+ }
2315
+ if (n._tag === "FormRulesNodeObject") {
2316
+ const shape = n.shape;
2317
+ const out = [];
2318
+ for (const key of Object.keys(shape)) {
2319
+ out.push(...visit(shape[key], joinPath(at, key)));
2320
+ }
2321
+ const refineRule = n.refineRule;
2322
+ const superRefineRule = n.superRefineRule;
2323
+ const selfRule = superRefineRule ?? refineRule;
2324
+ if (selfRule !== void 0) {
2325
+ if (at) {
2326
+ out.push(field(at, selfRule, { errorTarget: "$self" }));
2327
+ } else {
2328
+ out.push(root(selfRule));
2329
+ }
2330
+ }
2331
+ return out;
2332
+ }
2333
+ if (n._tag === "FormRulesNodeArray") {
2334
+ const identity = n.identity;
2335
+ assertCanonicalValuePath("list path", at);
2336
+ assertValidListIdentity(identity, at);
2337
+ const item = n.item;
2338
+ if (!item || typeof item !== "object" || item._tag !== "FormRulesNodeObject") {
2339
+ throw new Error(`[Form.rules.schema] array(item) currently requires item to be an object node`);
2340
+ }
2341
+ const itemObj = item;
2342
+ if (itemObj.refineRule !== void 0 || itemObj.superRefineRule !== void 0) {
2343
+ throw new Error(`[Form.rules.schema] array(item).item.refine(...) is not supported yet`);
2344
+ }
2345
+ const shape = itemObj.shape;
2346
+ const validate = {};
2347
+ for (const key of Object.keys(shape)) {
2348
+ const child = shape[key];
2349
+ if (!child || typeof child !== "object") continue;
2350
+ if (child._tag !== "FormRulesNodeField") {
2351
+ throw new Error(
2352
+ `[Form.rules.schema] array(item) only supports flat field nodes (nested object/array is not supported yet)`
2353
+ );
2354
+ }
2355
+ const ruleInput = child.rule;
2356
+ const leafRules = make(ruleInput);
2357
+ for (const name of Object.keys(leafRules).sort((a, b) => a.localeCompare(b))) {
2358
+ const leaf = leafRules[name];
2359
+ const ruleName = `${key}.${name}`;
2360
+ const deps = Array.isArray(leaf?.deps) ? leaf.deps : [];
2361
+ const depsWithKey = Array.from(/* @__PURE__ */ new Set([key, ...deps])).sort((a, b) => a.localeCompare(b));
2362
+ validate[ruleName] = {
2363
+ ...leaf,
2364
+ deps: depsWithKey,
2365
+ validate: (row, ctx) => {
2366
+ const v = row?.[key];
2367
+ const out = leaf.validate(v, ctx);
2368
+ if (out === /* @__PURE__ */ Symbol.for("logix.state-trait.validate.skip")) return out;
2369
+ return out === void 0 ? void 0 : { [key]: out };
2370
+ }
2371
+ };
2372
+ }
2373
+ }
2374
+ const itemRule = Object.keys(validate).length > 0 ? { validate } : void 0;
2375
+ const listRule = n.refineRule;
2376
+ const listSuper = n.superRefineRule;
2377
+ const listRuleInput = listSuper ?? listRule;
2378
+ return [
2379
+ list(at, {
2380
+ identity,
2381
+ ...itemRule !== void 0 ? { item: itemRule } : {},
2382
+ ...listRuleInput !== void 0 ? { list: listRuleInput } : {}
2383
+ })
2384
+ ];
2385
+ }
2386
+ return [];
2387
+ };
2388
+ const rootPrefix = normalizePrefix(prefix);
2389
+ return visit(node2, rootPrefix);
2390
+ };
2391
+ var rules = (_valuesSchema) => {
2392
+ const makeDsl = (prefix) => {
2393
+ const build = (...decls) => {
2394
+ const flat = flattenDecls(decls);
2395
+ const p = normalizePrefix(prefix);
2396
+ const normalized = withPrefix(p, flat);
2397
+ assertDeclListGuardrails(normalized);
2398
+ return {
2399
+ _tag: "FormRulesSpec",
2400
+ decls: normalized
2401
+ };
2402
+ };
2403
+ build.schema = (node2) => {
2404
+ const p = normalizePrefix(prefix);
2405
+ const normalized = compileSchema(node2, p);
2406
+ assertDeclListGuardrails(normalized);
2407
+ return {
2408
+ _tag: "FormRulesSpec",
2409
+ decls: normalized
2410
+ };
2411
+ };
2412
+ build.at = (p2) => makeDsl(joinPath(normalizePrefix(prefix), normalizePrefix(p2)));
2413
+ function field2(...args) {
2414
+ if (args.length >= 2 && typeof args[0] === "string") {
2415
+ return field(args[0], args[1], args[2]);
2416
+ }
2417
+ const input = args[0];
2418
+ if (import_effect5.Schema.isSchema(input)) return makeFieldNode(fieldFromSchema(input));
2419
+ return makeFieldNode(input);
2420
+ }
2421
+ build.field = field2;
2422
+ build.object = (shape) => makeObjectNode({ shape });
2423
+ build.array = (item, options) => makeArrayNode({ item, identity: options.identity });
2424
+ build.root = (ruleInput) => root(ruleInput);
2425
+ build.list = (listPath, spec) => list(listPath, spec);
2426
+ return build;
2427
+ };
2428
+ return makeDsl("");
2429
+ };
2430
+
2431
+ // src/internal/dsl/from.ts
2432
+ var fromValues = (valuesSchema) => ({
2433
+ derived: derived(valuesSchema),
2434
+ rules: rules(valuesSchema),
2435
+ traits: traits(valuesSchema)
2436
+ });
2437
+
2438
+ // src/internal/dsl/node.ts
2439
+ var Logix5 = __toESM(require("@logixjs/core"), 1);
2440
+ var node = (spec) => Logix5.StateTrait.node(spec);
2441
+
2442
+ // src/internal/dsl/list.ts
2443
+ var Logix6 = __toESM(require("@logixjs/core"), 1);
2444
+ var list2 = (spec) => Logix6.StateTrait.list(spec);
2445
+ // Annotate the CommonJS export names for ESM import in node:
2446
+ 0 && (module.exports = {
2447
+ derived,
2448
+ fromValues,
2449
+ list,
2450
+ make,
2451
+ node,
2452
+ rules,
2453
+ traits
2454
+ });
2455
+ //# sourceMappingURL=Form.cjs.map