@vielzeug/forge 1.3.1 → 1.4.0

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 (87) hide show
  1. package/dist/_utils.cjs +1 -1
  2. package/dist/_utils.cjs.map +1 -1
  3. package/dist/_utils.d.ts.map +1 -1
  4. package/dist/_utils.js +1 -0
  5. package/dist/_utils.js.map +1 -1
  6. package/dist/core/array.cjs +1 -1
  7. package/dist/core/array.cjs.map +1 -1
  8. package/dist/core/array.d.ts.map +1 -1
  9. package/dist/core/array.js +63 -32
  10. package/dist/core/array.js.map +1 -1
  11. package/dist/core/asyncQueue.cjs.map +1 -1
  12. package/dist/core/asyncQueue.d.ts +2 -2
  13. package/dist/core/asyncQueue.js.map +1 -1
  14. package/dist/core/context.cjs +1 -1
  15. package/dist/core/context.cjs.map +1 -1
  16. package/dist/core/context.d.ts +2 -5
  17. package/dist/core/context.d.ts.map +1 -1
  18. package/dist/core/context.js +72 -109
  19. package/dist/core/context.js.map +1 -1
  20. package/dist/core/fields.cjs +2 -0
  21. package/dist/core/fields.cjs.map +1 -0
  22. package/dist/core/fields.d.ts +52 -0
  23. package/dist/core/fields.d.ts.map +1 -0
  24. package/dist/core/fields.js +310 -0
  25. package/dist/core/fields.js.map +1 -0
  26. package/dist/core/lifecycle.cjs +1 -1
  27. package/dist/core/lifecycle.cjs.map +1 -1
  28. package/dist/core/lifecycle.d.ts +3 -1
  29. package/dist/core/lifecycle.d.ts.map +1 -1
  30. package/dist/core/lifecycle.js +10 -14
  31. package/dist/core/lifecycle.js.map +1 -1
  32. package/dist/core/notifier.cjs +2 -0
  33. package/dist/core/notifier.cjs.map +1 -0
  34. package/dist/core/notifier.d.ts +33 -0
  35. package/dist/core/notifier.d.ts.map +1 -0
  36. package/dist/core/notifier.js +78 -0
  37. package/dist/core/notifier.js.map +1 -0
  38. package/dist/core/observe.cjs +1 -1
  39. package/dist/core/observe.cjs.map +1 -1
  40. package/dist/core/observe.d.ts +8 -6
  41. package/dist/core/observe.d.ts.map +1 -1
  42. package/dist/core/observe.js +34 -45
  43. package/dist/core/observe.js.map +1 -1
  44. package/dist/core/scope.cjs +1 -1
  45. package/dist/core/scope.cjs.map +1 -1
  46. package/dist/core/scope.d.ts +6 -3
  47. package/dist/core/scope.d.ts.map +1 -1
  48. package/dist/core/scope.js +105 -156
  49. package/dist/core/scope.js.map +1 -1
  50. package/dist/errors.cjs +1 -1
  51. package/dist/errors.cjs.map +1 -1
  52. package/dist/errors.d.ts +3 -1
  53. package/dist/errors.d.ts.map +1 -1
  54. package/dist/errors.js +2 -2
  55. package/dist/errors.js.map +1 -1
  56. package/dist/forge.cjs +1 -1
  57. package/dist/forge.cjs.map +1 -1
  58. package/dist/forge.iife.js +1 -1
  59. package/dist/forge.iife.js.map +1 -1
  60. package/dist/forge.js +1 -1
  61. package/dist/forge.js.map +1 -1
  62. package/dist/form.cjs +1 -1
  63. package/dist/form.cjs.map +1 -1
  64. package/dist/form.d.ts.map +1 -1
  65. package/dist/form.js +45 -56
  66. package/dist/form.js.map +1 -1
  67. package/dist/index.cjs +1 -1
  68. package/dist/index.js +4 -4
  69. package/dist/types.cjs +1 -1
  70. package/dist/types.cjs.map +1 -1
  71. package/dist/types.d.ts +53 -36
  72. package/dist/types.d.ts.map +1 -1
  73. package/dist/types.js +2 -2
  74. package/dist/types.js.map +1 -1
  75. package/package.json +2 -2
  76. package/dist/core/validation.cjs +0 -2
  77. package/dist/core/validation.cjs.map +0 -1
  78. package/dist/core/validation.d.ts +0 -23
  79. package/dist/core/validation.d.ts.map +0 -1
  80. package/dist/core/validation.js +0 -173
  81. package/dist/core/validation.js.map +0 -1
  82. package/dist/core/values.cjs +0 -2
  83. package/dist/core/values.cjs.map +0 -1
  84. package/dist/core/values.d.ts +0 -31
  85. package/dist/core/values.d.ts.map +0 -1
  86. package/dist/core/values.js +0 -149
  87. package/dist/core/values.js.map +0 -1
@@ -2,24 +2,24 @@ import { ForgeSubmitError as e, ForgeValidationError as t } from "../errors.js";
2
2
  import { flattenValues as n, unflattenValues as r } from "../_utils.js";
3
3
  //#region src/core/scope.ts
4
4
  function i(a, o) {
5
- let s = `${o}.`;
6
- function c(e) {
5
+ let { ctx: s, fieldOps: c, root: l } = a, u = `${o}.`;
6
+ function d(e) {
7
7
  return `${o}.${e}`;
8
8
  }
9
- function l(e) {
10
- return e === o || e.startsWith(s);
9
+ function f(e) {
10
+ return e === o || e.startsWith(u);
11
11
  }
12
- function u(e) {
13
- return e.startsWith(s) ? e.slice(s.length) : e;
12
+ function p(e) {
13
+ return e.startsWith(u) ? e.slice(u.length) : e;
14
14
  }
15
- function d() {
16
- let e = a.getStateSnapshot(), t = Object.fromEntries(Object.entries(e.errors).filter(([e]) => l(e)).map(([e, t]) => [u(e), t])), n = e.touchedFields.filter(l).map(u), r = e.validatingFields.filter(l).map(u), i = Object.keys(t).length === 0, o = [...a.dirty].some(l), s = [...a.touched].some(l), c = r.length > 0;
15
+ function m() {
16
+ let e = s.getStateSnapshot(), t = Object.fromEntries(Object.entries(e.errors).filter(([e]) => f(e)).map(([e, t]) => [p(e), t])), n = e.touchedFields.filter(f).map(p), r = e.validatingFields.filter(f).map(p), i = Object.keys(t).length === 0, a = [...s.dirty].some(f), o = [...s.touched].some(f), c = r.length > 0;
17
17
  return Object.freeze({
18
18
  errors: Object.freeze(t),
19
- isDirty: o,
19
+ isDirty: a,
20
20
  isLoading: e.isLoading,
21
21
  isSubmitting: e.isSubmitting,
22
- isTouched: s,
22
+ isTouched: o,
23
23
  isValid: i,
24
24
  isValidating: c,
25
25
  submitCount: e.submitCount,
@@ -27,118 +27,93 @@ function i(a, o) {
27
27
  validatingFields: Object.freeze(r)
28
28
  });
29
29
  }
30
- function f() {
30
+ function h() {
31
31
  let e = {};
32
- for (let [t, n] of a.store) t.startsWith(s) && (e[t.slice(s.length)] = n);
32
+ for (let [t, n] of s.store) t.startsWith(u) && (e[t.slice(u.length)] = n);
33
33
  return r(e);
34
34
  }
35
- function p() {
35
+ function g() {
36
36
  let e = /* @__PURE__ */ new Set();
37
- for (let t of a.store.keys()) l(t) && e.add(u(t));
38
- for (let t of a.validators.keys()) l(t) && e.add(u(t));
37
+ for (let t of s.store.keys()) f(t) && e.add(p(t));
38
+ for (let t of s.validators.keys()) f(t) && e.add(p(t));
39
39
  return Object.freeze([...e]);
40
40
  }
41
- function m() {
42
- a.ensureNotDisposed();
43
- for (let e of a.store.keys()) l(e) && a.touched.add(e);
44
- for (let e of a.validators.keys()) l(e) && a.touched.add(e);
45
- a.requestNotify();
41
+ function _() {
42
+ s.ensureNotDisposed("touchAll"), c.touchAllKeys(f), s.requestNotify();
46
43
  }
47
- function h() {
48
- a.ensureNotDisposed();
49
- for (let e of [...a.touched]) l(e) && a.touched.delete(e);
50
- a.requestNotify();
44
+ function v() {
45
+ s.ensureNotDisposed("untouchAll"), c.untouchAllKeys(f), s.requestNotify();
51
46
  }
52
- function g() {
53
- a.ensureNotDisposed();
54
- for (let e of [...a.store.keys()]) l(e) && (a.fieldCtrls.get(e)?.abort(), a.fieldCtrls.delete(e), a.store.set(e, a.baseline.get(e)), a.dirty.delete(e), a.touched.delete(e), a.fieldErrors.delete(e) && a.invalidateErrors());
55
- a.requestNotify();
47
+ function y() {
48
+ s.ensureNotDisposed("reset"), c.resetKeys(f), s.requestNotify();
56
49
  }
57
- function _(e) {
58
- a.ensureNotDisposed();
59
- for (let e of [...a.fieldCtrls.keys()]) l(e) && (a.fieldCtrls.get(e)?.abort(), a.fieldCtrls.delete(e));
60
- let t = n(e);
61
- for (let e of [...a.store.keys()]) l(e) && (a.store.delete(e), a.baseline.delete(e), a.dirty.delete(e), a.touched.delete(e), a.fieldErrors.delete(e));
62
- a.invalidateErrors();
63
- for (let [e, n] of Object.entries(t)) {
64
- let t = c(e);
65
- a.store.set(t, n), a.baseline.set(t, n);
66
- }
67
- a.requestNotify();
50
+ function b(e) {
51
+ s.ensureNotDisposed("replace"), c.replaceKeys(f, n(e), d), s.requestNotify();
68
52
  }
69
- function v(e) {
70
- a.ensureNotDisposed();
71
- let t = n(e), r = [];
72
- for (let [e, n] of Object.entries(t)) {
73
- let t = c(e);
74
- a.baseline.set(t, n), a.store.set(t, n), a.dirty.delete(t), r.push(t);
75
- }
76
- a.requestNotify(r);
53
+ function x(e) {
54
+ s.ensureNotDisposed("patch"), s.requestNotify(c.patchKeys(e, d));
77
55
  }
78
- function y(e) {
79
- a.ensureNotDisposed();
80
- for (let e of [...a.fieldErrors.keys()]) l(e) && a.fieldErrors.delete(e);
81
- if (e) for (let [t, n] of Object.entries(e)) typeof n == "string" && a.fieldErrors.set(c(t), n);
82
- a.invalidateErrors(), a.requestNotify();
56
+ function S(e) {
57
+ s.ensureNotDisposed("resetErrors"), c.resetErrorsKeys(f, e ?? {}, d), s.requestNotify();
83
58
  }
84
- async function b(e, t) {
85
- if (a.ensureNotDisposed(), e !== void 0 && !Array.isArray(e) && !(e instanceof AbortSignal)) {
86
- let n = c(e);
87
- await a.runValidationCore([n], "partial", t);
88
- let r = a.fieldErrors.get(n);
59
+ async function C(e, t) {
60
+ if (s.ensureNotDisposed("validate"), e !== void 0 && !Array.isArray(e) && !(e instanceof AbortSignal)) {
61
+ let n = d(e);
62
+ await c.runValidationCore([n], "partial", t);
63
+ let r = s.fieldErrors.get(n);
89
64
  return {
90
65
  errors: r === void 0 ? {} : { [e]: r },
91
66
  valid: r === void 0
92
67
  };
93
68
  }
94
69
  if (Array.isArray(e)) {
95
- let n = e.map((e) => c(e));
96
- await a.runValidationCore(n, "partial", t);
70
+ let n = e.map((e) => d(e));
71
+ await c.runValidationCore(n, "partial", t);
97
72
  let r = {};
98
73
  for (let e of n) {
99
- let t = a.fieldErrors.get(e);
100
- t !== void 0 && (r[u(e)] = t);
74
+ let t = s.fieldErrors.get(e);
75
+ t !== void 0 && (r[p(e)] = t);
101
76
  }
102
77
  return {
103
78
  errors: r,
104
79
  valid: Object.keys(r).length === 0
105
80
  };
106
81
  }
107
- let n = e, r = [...a.validators.keys()].filter(l);
108
- await a.runValidationCore(r, "partial", n);
82
+ let n = e, r = [...s.validators.keys()].filter(f);
83
+ await c.runValidationCore(r, "partial", n);
109
84
  let i = {};
110
- for (let [e, t] of a.fieldErrors) l(e) && (i[u(e)] = t);
85
+ for (let [e, t] of s.fieldErrors) f(e) && (i[p(e)] = t);
111
86
  return {
112
87
  errors: i,
113
88
  valid: Object.keys(i).length === 0
114
89
  };
115
90
  }
116
- async function x(t) {
117
- if (a.ensureNotDisposed(), a.isSubmitting()) throw new e("submit() called while a submission is already in progress");
118
- a.root.batch(() => {
119
- a.incrementSubmitCount(), a.setSubmitting(!0), m();
91
+ async function w(t) {
92
+ if (s.ensureNotDisposed("submit"), s.isSubmittingState) throw new e("submit() called while a submission is already in progress");
93
+ s.batch(() => {
94
+ s.submitCount++, s.isSubmittingState = !0, _();
120
95
  });
121
96
  try {
122
- let e = [...a.validators.keys()].filter(l);
123
- await a.runValidationCore(e, "partial"), a.ensureNotDisposed();
97
+ let e = [...s.validators.keys()].filter(f);
98
+ await c.runValidationCore(e, "partial"), s.ensureNotDisposed("submit");
124
99
  let n = {};
125
- for (let [e, t] of a.fieldErrors) l(e) && (n[u(e)] = t);
100
+ for (let [e, t] of s.fieldErrors) f(e) && (n[p(e)] = t);
126
101
  return Object.keys(n).length > 0 ? {
127
102
  errors: n,
128
103
  ok: !1,
129
104
  type: "validation"
130
105
  } : {
131
106
  ok: !0,
132
- value: await t(f())
107
+ value: await t(h())
133
108
  };
134
109
  } finally {
135
- a.setSubmitting(!1), a.isDisposed() || a.requestNotify();
110
+ s.isSubmittingState = !1, s.disposed || s.requestNotify();
136
111
  }
137
112
  }
138
- function S(e, t) {
113
+ function T(e, t) {
139
114
  let n = null;
140
- return a.root.subscribe(() => {
141
- let t = d();
115
+ return l.subscribe(() => {
116
+ let t = m();
142
117
  if (n) {
143
118
  let e = n, r = Object.keys(t.errors), i = Object.keys(e.errors), a = r.length === i.length && r.every((n) => t.errors[n] === e.errors[n]), o = t.touchedFields.length === e.touchedFields.length && t.touchedFields.every((t, n) => t === e.touchedFields[n]), s = t.validatingFields.length === e.validatingFields.length && t.validatingFields.every((t, n) => t === e.validatingFields[n]);
144
119
  if (t.isDirty === e.isDirty && t.isLoading === e.isLoading && t.isSubmitting === e.isSubmitting && t.isTouched === e.isTouched && t.isValid === e.isValid && t.isValidating === e.isValidating && t.submitCount === e.submitCount && a && o && s) return;
@@ -146,138 +121,112 @@ function i(a, o) {
146
121
  n = t, e(t);
147
122
  }, t);
148
123
  }
149
- function C() {
124
+ function E() {
150
125
  return {
151
126
  array(e) {
152
- return a.root.array(c(e));
127
+ return l.array(d(e));
153
128
  },
154
129
  clearError(e) {
155
- a.root.clearError(c(e));
130
+ l.clearError(d(e));
156
131
  },
157
132
  connect(e, t) {
158
- return a.root.connect(c(e), t);
133
+ return l.connect(d(e), t);
159
134
  },
160
135
  field(e) {
161
- return a.root.field(c(e));
136
+ return l.field(d(e));
162
137
  },
163
138
  get(e) {
164
- return a.root.get(c(e));
139
+ return l.get(d(e));
165
140
  },
166
141
  register(e, t) {
167
- return a.root.fields.register(c(e), t);
142
+ return l.fields.register(d(e), t);
168
143
  },
169
144
  remove(e) {
170
- a.root.fields.remove(c(e));
145
+ l.fields.remove(d(e));
171
146
  },
172
147
  resetField(e) {
173
- a.root.resetField(c(e));
148
+ l.resetField(d(e));
174
149
  },
175
150
  set(e, t, n) {
176
- a.root.set(c(e), t, n);
151
+ l.set(d(e), t, n);
177
152
  },
178
153
  setError(e, t) {
179
- a.root.setError(c(e), t);
154
+ l.setError(d(e), t);
180
155
  },
181
156
  setValidator(e, t) {
182
- a.root.fields.setValidator(c(e), t);
157
+ l.fields.setValidator(d(e), t);
183
158
  },
184
159
  subscribeField(e, t, n) {
185
- return a.root.subscribeField(c(e), t, n);
160
+ return l.subscribeField(d(e), t, n);
186
161
  },
187
162
  touch(e) {
188
- a.root.touch(c(e));
163
+ l.touch(d(e));
189
164
  },
190
165
  untouch(e) {
191
- a.root.untouch(c(e));
166
+ l.untouch(d(e));
192
167
  }
193
168
  };
194
169
  }
195
- let w = C();
170
+ let D = E();
196
171
  return {
197
- array: (e) => w.array(e),
198
- batch: (e) => a.root.batch(e),
199
- clearError: (e) => w.clearError(e),
200
- connect: (e, t) => w.connect(e, t),
172
+ array: (e) => D.array(e),
173
+ batch: (e) => l.batch(e),
174
+ clearError: (e) => D.clearError(e),
175
+ connect: (e, t) => D.connect(e, t),
201
176
  get disposalSignal() {
202
- return a.root.disposalSignal;
177
+ return l.disposalSignal;
203
178
  },
204
179
  dispose: () => {},
205
180
  get disposed() {
206
- return a.isDisposed();
181
+ return s.disposed;
207
182
  },
208
- field: (e) => w.field(e),
183
+ field: (e) => D.field(e),
209
184
  fields: {
210
- list: p,
211
- register: (e, t) => w.register(e, t),
212
- remove: (e) => w.remove(e),
213
- setValidator: (e, t) => w.setValidator(e, t)
185
+ list: g,
186
+ register: (e, t) => D.register(e, t),
187
+ remove: (e) => D.remove(e),
188
+ setValidator: (e, t) => D.setValidator(e, t)
189
+ },
190
+ get: (e) => D.get(e),
191
+ history: {
192
+ restore: (e) => l.history.restore(e),
193
+ snapshot: () => l.history.snapshot()
214
194
  },
215
- get: (e) => w.get(e),
216
195
  get isLoading() {
217
- return a.root.isLoading;
196
+ return l.isLoading;
218
197
  },
219
198
  get isSubmitting() {
220
- return a.root.isSubmitting;
199
+ return l.isSubmitting;
221
200
  },
222
- patch: v,
223
- replace: _,
224
- reset: g,
225
- resetErrors: y,
226
- resetField: (e) => w.resetField(e),
227
- restore: (e) => a.root.restore(e),
228
- scope: (e) => i(a, c(e)),
229
- set: (e, t, n) => w.set(e, t, n),
230
- setError: (e, t) => w.setError(e, t),
231
- snapshot: () => a.root.snapshot(),
201
+ patch: x,
202
+ replace: b,
203
+ reset: y,
204
+ resetErrors: S,
205
+ resetField: (e) => D.resetField(e),
206
+ scope: (e) => i(a, d(e)),
207
+ set: (e, t, n) => D.set(e, t, n),
208
+ setError: (e, t) => D.setError(e, t),
232
209
  get state() {
233
- return d();
210
+ return m();
234
211
  },
235
- submit: x,
212
+ submit: w,
236
213
  submitOrThrow: async (e) => {
237
- let n = await x(e);
214
+ let n = await w(e);
238
215
  if (!n.ok) throw new t(n.errors);
239
216
  return n.value;
240
217
  },
241
- subscribe: (e, t) => a.root.subscribe(e, t),
242
- subscribeField: (e, t, n) => w.subscribeField(e, t, n),
243
- subscribeScoped: S,
244
- [Symbol.asyncIterator]: () => a.root[Symbol.asyncIterator](),
218
+ subscribe: T,
219
+ subscribeField: (e, t, n) => D.subscribeField(e, t, n),
220
+ [Symbol.asyncIterator]: () => l[Symbol.asyncIterator](),
245
221
  [Symbol.dispose]() {
246
222
  this.dispose();
247
223
  },
248
- touch: (e) => w.touch(e),
249
- touchAll: m,
250
- untouch: (e) => w.untouch(e),
251
- untouchAll: h,
252
- validate: b,
253
- validateStream(e) {
254
- let t = a.root.validateStream(e);
255
- return {
256
- async next() {
257
- for (;;) {
258
- let e = await t.next();
259
- if (e.done) return e;
260
- if (l(e.value.field)) return {
261
- done: !1,
262
- value: {
263
- error: e.value.error,
264
- field: u(e.value.field)
265
- }
266
- };
267
- }
268
- },
269
- return() {
270
- return t.return ? t.return() : Promise.resolve({
271
- done: !0,
272
- value: void 0
273
- });
274
- },
275
- [Symbol.asyncIterator]() {
276
- return this;
277
- }
278
- };
279
- },
280
- values: f
224
+ touch: (e) => D.touch(e),
225
+ touchAll: _,
226
+ untouch: (e) => D.untouch(e),
227
+ untouchAll: v,
228
+ validate: C,
229
+ values: h
281
230
  };
282
231
  }
283
232
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"scope.js","names":[],"sources":["../../src/core/scope.ts"],"sourcesContent":["import type {\n ArrayField,\n ConnectOptions,\n ConnectionResult,\n ErrorKeyOf,\n FieldState,\n FieldValidator,\n FlatKeyOf,\n Form,\n FormSnapshot,\n FormState,\n MaybePromise,\n RegisterFieldOptions,\n ScopedValues,\n SetOptions,\n SubmitResult,\n SubscribeOptions,\n TypeAtPath,\n Unsubscribe,\n ValidateResult,\n} from '../types';\n\nimport { flattenValues, unflattenValues } from '../_utils';\nimport { ForgeSubmitError, ForgeValidationError } from '../errors';\n\n/**\n * R3: Slim ScopeContext — delegates simple operations through `root: Form<TValues>`.\n * Only the Maps/Sets needed for bulk scoped operations are passed directly.\n * @internal\n */\nexport interface ScopeContext<TValues extends Record<string, unknown> = Record<string, unknown>> {\n /** The fully-featured root form — used for all simple one-field delegations. */\n root: Form<TValues>;\n\n /* ---- Shared mutable state (passed by reference, needed by bulk scoped ops) ---- */\n store: Map<string, unknown>;\n baseline: Map<string, unknown>;\n validators: Map<string, FieldValidator<unknown>>;\n fieldErrors: Map<string, string>;\n touched: Set<string>;\n dirty: Set<string>;\n fieldCtrls: Map<string, AbortController>;\n\n /* ---- Scalar state accessors ---- */\n isSubmitting(): boolean;\n setSubmitting(value: boolean): void;\n incrementSubmitCount(): void;\n isDisposed(): boolean;\n\n /* ---- Core helpers ---- */\n ensureNotDisposed(): void;\n invalidateErrors(): void;\n requestNotify(target?: string | Iterable<string>): void;\n getStateSnapshot(): FormState;\n\n /* ---- Validation core (needed for scoped validate/submit) ---- */\n runValidationCore(\n fields: string[],\n scope: 'full' | 'partial',\n signal?: AbortSignal,\n ): Promise<ValidateResult & { aborted: boolean }>;\n}\n\n/**\n * Creates a scoped sub-form whose field paths are relative to `pfx`.\n * All simple single-field operations delegate to `ctx.root`.\n * Only prefix-aware bulk operations (submit, validate, replace, reset, etc.) contain custom code.\n */\nexport function createScopedForm<TValues extends Record<string, unknown>, P extends string>(\n ctx: ScopeContext<TValues>,\n pfx: P,\n): Form<ScopedValues<TValues, P>> {\n const pfxDot = `${pfx}.`;\n\n function pre(name: string): string {\n return `${pfx}.${name}`;\n }\n\n function isScopedKey(key: string): boolean {\n return key === pfx || key.startsWith(pfxDot);\n }\n\n function unscope(key: string): string {\n return key.startsWith(pfxDot) ? key.slice(pfxDot.length) : key;\n }\n\n /* ---- Non-trivial scoped implementations ---- */\n\n /**\n * Compute a scoped projection of FormState from current raw Maps.\n * Errors, touchedFields, validatingFields, isValid, isDirty, isTouched reflect only\n * fields within the prefix. isSubmitting, isLoading, isValidating, submitCount are full-form.\n */\n function getScopedState(): FormState {\n const rootState = ctx.getStateSnapshot();\n const errors = Object.fromEntries(\n Object.entries(rootState.errors)\n .filter(([k]) => isScopedKey(k))\n .map(([k, v]) => [unscope(k), v]),\n );\n const touchedFields = rootState.touchedFields.filter(isScopedKey).map(unscope);\n const validatingFields = rootState.validatingFields.filter(isScopedKey).map(unscope);\n const isValid = Object.keys(errors).length === 0;\n const isDirty = [...ctx.dirty].some(isScopedKey);\n const isTouched = [...ctx.touched].some(isScopedKey);\n const isValidating = validatingFields.length > 0;\n\n return Object.freeze({\n errors: Object.freeze(errors) as FormState['errors'],\n isDirty,\n isLoading: rootState.isLoading,\n isSubmitting: rootState.isSubmitting,\n isTouched,\n isValid,\n isValidating,\n submitCount: rootState.submitCount,\n touchedFields: Object.freeze(touchedFields) as readonly string[],\n validatingFields: Object.freeze(validatingFields) as readonly string[],\n });\n }\n\n function scopedValues(): ScopedValues<TValues, P> {\n const sub: Record<string, unknown> = {};\n\n for (const [key, value] of ctx.store) {\n if (key.startsWith(pfxDot)) sub[key.slice(pfxDot.length)] = value;\n }\n\n return unflattenValues(sub) as ScopedValues<TValues, P>;\n }\n\n /**\n * Enumerate field paths within this scope's prefix, stripped to relative paths —\n * matching `scope.state`'s relative-path convention, not `state.touchedFields`'s\n * absolute-path convention. Same \"known field\" definition `scopedTouchAll()` uses.\n */\n function scopedListFields(): readonly string[] {\n const known = new Set<string>();\n\n for (const key of ctx.store.keys()) {\n if (isScopedKey(key)) known.add(unscope(key));\n }\n\n for (const key of ctx.validators.keys()) {\n if (isScopedKey(key)) known.add(unscope(key));\n }\n\n return Object.freeze([...known]);\n }\n\n function scopedTouchAll(): void {\n ctx.ensureNotDisposed();\n\n for (const name of ctx.store.keys()) {\n if (isScopedKey(name)) ctx.touched.add(name);\n }\n\n for (const name of ctx.validators.keys()) {\n if (isScopedKey(name)) ctx.touched.add(name);\n }\n\n ctx.requestNotify();\n }\n\n function scopedUntouchAll(): void {\n ctx.ensureNotDisposed();\n\n for (const name of [...ctx.touched]) {\n if (isScopedKey(name)) ctx.touched.delete(name);\n }\n\n ctx.requestNotify();\n }\n\n function scopedReset(): void {\n ctx.ensureNotDisposed();\n\n for (const key of [...ctx.store.keys()]) {\n if (!isScopedKey(key)) continue;\n\n ctx.fieldCtrls.get(key)?.abort();\n ctx.fieldCtrls.delete(key);\n ctx.store.set(key, ctx.baseline.get(key));\n ctx.dirty.delete(key);\n ctx.touched.delete(key);\n\n if (ctx.fieldErrors.delete(key)) ctx.invalidateErrors();\n }\n\n ctx.requestNotify();\n }\n\n function scopedReplace(newValues: ScopedValues<TValues, P>): void {\n ctx.ensureNotDisposed();\n\n for (const key of [...ctx.fieldCtrls.keys()]) {\n if (isScopedKey(key)) {\n ctx.fieldCtrls.get(key)?.abort();\n ctx.fieldCtrls.delete(key);\n }\n }\n\n const flat = flattenValues(newValues as Record<string, unknown>);\n\n for (const key of [...ctx.store.keys()]) {\n if (!isScopedKey(key)) continue;\n\n ctx.store.delete(key);\n ctx.baseline.delete(key);\n ctx.dirty.delete(key);\n ctx.touched.delete(key);\n ctx.fieldErrors.delete(key);\n }\n\n ctx.invalidateErrors();\n\n for (const [key, value] of Object.entries(flat)) {\n const full = pre(key);\n\n ctx.store.set(full, value);\n ctx.baseline.set(full, value);\n }\n\n ctx.requestNotify();\n }\n\n function scopedPatch(partial: Record<string, unknown>): void {\n ctx.ensureNotDisposed();\n\n const flat = flattenValues(partial);\n const changedKeys: string[] = [];\n\n for (const [key, value] of Object.entries(flat)) {\n const full = pre(key);\n\n ctx.baseline.set(full, value);\n ctx.store.set(full, value);\n ctx.dirty.delete(full);\n changedKeys.push(full);\n }\n\n ctx.requestNotify(changedKeys);\n }\n\n function scopedResetErrors(\n nextErrors?: Partial<Record<ErrorKeyOf<ScopedValues<TValues, P>>, string | undefined>>,\n ): void {\n ctx.ensureNotDisposed();\n\n for (const key of [...ctx.fieldErrors.keys()]) {\n if (isScopedKey(key)) ctx.fieldErrors.delete(key);\n }\n\n if (nextErrors) {\n for (const [key, message] of Object.entries(nextErrors)) {\n if (typeof message === 'string') ctx.fieldErrors.set(pre(key), message);\n }\n }\n\n ctx.invalidateErrors();\n ctx.requestNotify();\n }\n\n async function scopedValidate(\n nameOrFieldsOrSignal?: FlatKeyOf<ScopedValues<TValues, P>> | FlatKeyOf<ScopedValues<TValues, P>>[] | AbortSignal,\n signal?: AbortSignal,\n ): Promise<ValidateResult> {\n ctx.ensureNotDisposed();\n\n if (\n nameOrFieldsOrSignal !== undefined &&\n !Array.isArray(nameOrFieldsOrSignal) &&\n !(nameOrFieldsOrSignal instanceof AbortSignal)\n ) {\n // validate(name) — single field\n const prefixedName = pre(nameOrFieldsOrSignal as string) as FlatKeyOf<TValues>;\n\n await ctx.runValidationCore([prefixedName as string], 'partial', signal);\n\n const error = ctx.fieldErrors.get(prefixedName as string);\n\n return {\n errors: error !== undefined ? { [nameOrFieldsOrSignal as string]: error } : {},\n valid: error === undefined,\n };\n }\n\n if (Array.isArray(nameOrFieldsOrSignal)) {\n // validate(fields[]) — specific subset\n const prefixedFields = nameOrFieldsOrSignal.map((f) => pre(f as string)) as string[];\n\n await ctx.runValidationCore(prefixedFields, 'partial', signal);\n\n const errors: Record<string, string> = {};\n\n for (const pf of prefixedFields) {\n const msg = ctx.fieldErrors.get(pf);\n\n if (msg !== undefined) errors[unscope(pf)] = msg;\n }\n\n return { errors, valid: Object.keys(errors).length === 0 };\n }\n\n // validate(signal?) — all scoped fields\n const sig = nameOrFieldsOrSignal as AbortSignal | undefined;\n const fields = [...ctx.validators.keys()].filter(isScopedKey);\n\n await ctx.runValidationCore(fields, 'partial', sig);\n\n const errors: Record<string, string> = {};\n\n for (const [key, message] of ctx.fieldErrors) {\n if (isScopedKey(key)) errors[unscope(key)] = message;\n }\n\n return { errors, valid: Object.keys(errors).length === 0 };\n }\n\n async function scopedSubmit<TResult>(\n handler: (values: ScopedValues<TValues, P>) => MaybePromise<TResult>,\n ): Promise<SubmitResult<TResult>> {\n ctx.ensureNotDisposed();\n\n if (ctx.isSubmitting()) throw new ForgeSubmitError('submit() called while a submission is already in progress');\n\n ctx.root.batch(() => {\n ctx.incrementSubmitCount();\n ctx.setSubmitting(true);\n scopedTouchAll();\n });\n\n try {\n const fields = [...ctx.validators.keys()].filter(isScopedKey);\n\n await ctx.runValidationCore(fields, 'partial');\n\n ctx.ensureNotDisposed();\n\n const errors: Record<string, string> = {};\n\n for (const [key, message] of ctx.fieldErrors) {\n if (isScopedKey(key)) errors[unscope(key)] = message;\n }\n\n if (Object.keys(errors).length > 0) {\n return { errors, ok: false, type: 'validation' as const };\n }\n\n return { ok: true as const, value: await handler(scopedValues()) };\n } finally {\n ctx.setSubmitting(false);\n\n if (!ctx.isDisposed()) ctx.requestNotify();\n }\n }\n\n /**\n * Subscribe filtered to scoped fields only.\n * Errors, touchedFields, and validatingFields are remapped to relative paths.\n * `isValid`, `isDirty`, and `isTouched` reflect only fields within this scope's prefix.\n * `isSubmitting`, `isLoading`, `isValidating`, and `submitCount` reflect the full form.\n *\n * The listener fires only when the scoped projection changes — mutations outside this\n * prefix do not fire the listener.\n */\n function subscribeScoped(listener: (state: FormState) => void, options?: SubscribeOptions): Unsubscribe {\n // Track the previous scoped projection for equality comparison.\n let prevState: FormState | null = null;\n\n return ctx.root.subscribe(() => {\n const next = getScopedState();\n\n // Skip if no scoped-relevant state has changed.\n if (prevState) {\n const p = prevState;\n const errKeys = Object.keys(next.errors);\n const prevErrKeys = Object.keys(p.errors);\n const errorsMatch =\n errKeys.length === prevErrKeys.length && errKeys.every((k) => next.errors[k] === p.errors[k]);\n\n const touchedMatch =\n next.touchedFields.length === p.touchedFields.length &&\n next.touchedFields.every((v, i) => v === p.touchedFields[i]);\n\n const validatingMatch =\n next.validatingFields.length === p.validatingFields.length &&\n next.validatingFields.every((v, i) => v === p.validatingFields[i]);\n\n const flagsMatch =\n next.isDirty === p.isDirty &&\n next.isLoading === p.isLoading &&\n next.isSubmitting === p.isSubmitting &&\n next.isTouched === p.isTouched &&\n next.isValid === p.isValid &&\n next.isValidating === p.isValidating &&\n next.submitCount === p.submitCount;\n\n if (flagsMatch && errorsMatch && touchedMatch && validatingMatch) return;\n }\n\n prevState = next;\n listener(next);\n }, options);\n }\n\n function createScopedAdapter() {\n return {\n array(name: string): ArrayField {\n return ctx.root.array(pre(name) as FlatKeyOf<TValues>) as ArrayField;\n },\n clearError(name: string): void {\n ctx.root.clearError(pre(name) as ErrorKeyOf<TValues>);\n },\n connect(name: string, config?: ConnectOptions): ConnectionResult<unknown> {\n return ctx.root.connect(pre(name) as FlatKeyOf<TValues>, config) as ConnectionResult<unknown>;\n },\n field(name: string): FieldState<unknown> {\n return ctx.root.field(pre(name) as FlatKeyOf<TValues>) as FieldState<unknown>;\n },\n get(name: string): unknown {\n return ctx.root.get(pre(name) as FlatKeyOf<TValues>);\n },\n register(name: string, options?: RegisterFieldOptions<unknown>): Unsubscribe {\n return ctx.root.fields.register(\n pre(name) as FlatKeyOf<TValues>,\n options as RegisterFieldOptions<TypeAtPath<TValues, FlatKeyOf<TValues>>>,\n );\n },\n remove(name: string): void {\n ctx.root.fields.remove(pre(name) as FlatKeyOf<TValues>);\n },\n resetField(name: string): void {\n ctx.root.resetField(pre(name) as FlatKeyOf<TValues>);\n },\n set(name: string, value: unknown, options?: SetOptions): void {\n ctx.root.set(pre(name) as FlatKeyOf<TValues>, value as TypeAtPath<TValues, FlatKeyOf<TValues>>, options);\n },\n setError(name: string, message: string): void {\n ctx.root.setError(pre(name) as ErrorKeyOf<TValues>, message);\n },\n setValidator(name: string, validator?: FieldValidator): void {\n ctx.root.fields.setValidator(pre(name) as FlatKeyOf<TValues>, validator);\n },\n subscribeField(\n name: string,\n listener: (state: FieldState<unknown>) => void,\n options?: SubscribeOptions,\n ): Unsubscribe {\n return ctx.root.subscribeField(\n pre(name) as FlatKeyOf<TValues>,\n listener as (state: FieldState<TypeAtPath<TValues, FlatKeyOf<TValues>>>) => void,\n options,\n );\n },\n touch(name: string): void {\n ctx.root.touch(pre(name) as FlatKeyOf<TValues>);\n },\n untouch(name: string): void {\n ctx.root.untouch(pre(name) as FlatKeyOf<TValues>);\n },\n };\n }\n\n /* ---- Public scoped form object ---- */\n\n type S = ScopedValues<TValues, P>;\n\n const adapter = createScopedAdapter();\n\n return {\n array: (name) =>\n adapter.array(name as string) as ArrayField<\n TypeAtPath<S, typeof name> extends readonly (infer E)[] ? E : unknown\n >,\n batch: (fn) => ctx.root.batch(fn),\n clearError: (name) => adapter.clearError(name as string),\n connect: (name, config?) => adapter.connect(name as string, config) as ConnectionResult<TypeAtPath<S, typeof name>>,\n get disposalSignal() {\n return ctx.root.disposalSignal;\n },\n dispose: () => {\n /* Scoped forms share lifecycle with parent — call parentForm.dispose() to tear down */\n },\n get disposed() {\n return ctx.isDisposed();\n },\n field: (name) => adapter.field(name as string) as FieldState<TypeAtPath<S, typeof name>>,\n fields: {\n list: scopedListFields,\n register: (name, options?) => adapter.register(name as string, options as RegisterFieldOptions<unknown>),\n remove: (name) => adapter.remove(name as string),\n setValidator: (name, validator?) => adapter.setValidator(name as string, validator),\n },\n get: (name) => adapter.get(name as string) as TypeAtPath<S, typeof name>,\n get isLoading() {\n return ctx.root.isLoading;\n },\n get isSubmitting() {\n return ctx.root.isSubmitting;\n },\n patch: scopedPatch as Form<S>['patch'],\n replace: scopedReplace as Form<S>['replace'],\n reset: scopedReset,\n resetErrors: scopedResetErrors as Form<S>['resetErrors'],\n resetField: (name) => adapter.resetField(name as string),\n // Cast is irreducible: FormSnapshot<ScopedValues<TValues,P>> and FormSnapshot<TValues> are\n // structurally unrelated generic instantiations -- TS cannot verify one against the other.\n restore: (snap) => ctx.root.restore(snap as FormSnapshot<TValues>),\n scope: (subPrefix) => createScopedForm(ctx, pre(subPrefix as string)) as Form<ScopedValues<S, typeof subPrefix>>,\n set: (name, value, options?: SetOptions) => adapter.set(name as string, value, options),\n setError: (name, message) => adapter.setError(name as string, message),\n // Cast is irreducible: FormSnapshot<TValues> and FormSnapshot<ScopedValues<TValues,P>> are\n // structurally unrelated generic instantiations -- TS cannot verify one against the other.\n snapshot: () => ctx.root.snapshot() as FormSnapshot<S>,\n get state() {\n return getScopedState();\n },\n submit: scopedSubmit as Form<S>['submit'],\n submitOrThrow: async (handler) => {\n const result = await scopedSubmit(handler);\n\n if (!result.ok) throw new ForgeValidationError(result.errors as Record<string, string>);\n\n return result.value;\n },\n subscribe: (listener, options?) => ctx.root.subscribe(listener, options),\n subscribeField: (name, listener, options?) =>\n adapter.subscribeField(name as string, listener as (state: FieldState<unknown>) => void, options),\n subscribeScoped,\n [Symbol.asyncIterator]: () => ctx.root[Symbol.asyncIterator](),\n [Symbol.dispose]() {\n this.dispose();\n },\n touch: (name) => adapter.touch(name as string),\n touchAll: scopedTouchAll,\n untouch: (name) => adapter.untouch(name as string),\n untouchAll: scopedUntouchAll,\n validate: scopedValidate as Form<S>['validate'],\n validateStream(signal?) {\n const rootIter = ctx.root.validateStream(signal);\n\n const iter: AsyncIterableIterator<{ error: string | undefined; field: string }> = {\n async next() {\n for (;;) {\n const item = await rootIter.next();\n\n if (item.done) return item;\n\n if (isScopedKey(item.value.field))\n return { done: false, value: { error: item.value.error, field: unscope(item.value.field) } };\n }\n },\n return() {\n return rootIter.return ? rootIter.return() : Promise.resolve({ done: true as const, value: undefined });\n },\n [Symbol.asyncIterator]() {\n return this;\n },\n };\n\n return iter;\n },\n values: scopedValues,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scope.js","names":[],"sources":["../../src/core/scope.ts"],"sourcesContent":["import type {\n ArrayField,\n ConnectOptions,\n ConnectionResult,\n ErrorKeyOf,\n FieldState,\n FieldValidator,\n FlatKeyOf,\n Form,\n FormSnapshot,\n FormState,\n MaybePromise,\n RegisterFieldOptions,\n ScopedValues,\n SetOptions,\n SubmitResult,\n SubscribeOptions,\n TypeAtPath,\n Unsubscribe,\n ValidateResult,\n} from '../types';\nimport type { FormContext } from './context';\nimport type { FieldOps } from './fields';\n\nimport { flattenValues, unflattenValues } from '../_utils';\nimport { ForgeSubmitError, ForgeValidationError } from '../errors';\n\n/**\n * Everything a scoped sub-form needs from its parent. Deliberately just three members —\n * `ctx` (the same `FormContext` the root form's own ops read/write, not a copy of its\n * fields) and a narrow slice of `fieldOps`'s predicate-based bulk primitives\n * (`reset`/`replace`/`patch`/`touchAll`/`untouchAll`/`resetErrors`'s shared implementations,\n * plus `runValidationCore`). Bulk scoped operations call these with an `isScopedKey`\n * predicate instead of maintaining a second copy of each loop.\n * @internal\n */\nexport interface ScopeContext<TValues extends Record<string, unknown> = Record<string, unknown>> {\n ctx: FormContext<TValues>;\n fieldOps: Pick<\n FieldOps<TValues>,\n | 'patchKeys'\n | 'replaceKeys'\n | 'resetErrorsKeys'\n | 'resetKeys'\n | 'runValidationCore'\n | 'touchAllKeys'\n | 'untouchAllKeys'\n >;\n /** The fully-featured root form — used for all simple one-field delegations. */\n root: Form<TValues>;\n}\n\n/**\n * Creates a scoped sub-form whose field paths are relative to `pfx`.\n * All simple single-field operations delegate to `scopeCtx.root`. Bulk operations\n * (reset, replace, patch, touchAll, untouchAll, resetErrors) call `scopeCtx.fieldOps`'s\n * shared predicate-based primitives with an `isScopedKey` filter. Only `validate`/`submit`\n * (which need to compute a scoped field-name subset before calling `runValidationCore`) and\n * the handful of read-only projections (`state`, `values`, `fields.list`) contain custom code.\n */\nexport function createScopedForm<TValues extends Record<string, unknown>, P extends string>(\n scopeCtx: ScopeContext<TValues>,\n pfx: P,\n): Form<ScopedValues<TValues, P>> {\n const { ctx, fieldOps, root } = scopeCtx;\n const pfxDot = `${pfx}.`;\n\n function pre(name: string): string {\n return `${pfx}.${name}`;\n }\n\n function isScopedKey(key: string): boolean {\n return key === pfx || key.startsWith(pfxDot);\n }\n\n function unscope(key: string): string {\n return key.startsWith(pfxDot) ? key.slice(pfxDot.length) : key;\n }\n\n /* ---- Non-trivial scoped implementations ---- */\n\n /**\n * Compute a scoped projection of FormState from current raw Maps.\n * Errors, touchedFields, validatingFields, isValid, isDirty, isTouched reflect only\n * fields within the prefix. isSubmitting, isLoading, isValidating, submitCount are full-form.\n */\n function getScopedState(): FormState {\n const rootState = ctx.getStateSnapshot();\n const errors = Object.fromEntries(\n Object.entries(rootState.errors)\n .filter(([k]) => isScopedKey(k))\n .map(([k, v]) => [unscope(k), v]),\n );\n const touchedFields = rootState.touchedFields.filter(isScopedKey).map(unscope);\n const validatingFields = rootState.validatingFields.filter(isScopedKey).map(unscope);\n const isValid = Object.keys(errors).length === 0;\n const isDirty = [...ctx.dirty].some(isScopedKey);\n const isTouched = [...ctx.touched].some(isScopedKey);\n const isValidating = validatingFields.length > 0;\n\n return Object.freeze({\n errors: Object.freeze(errors) as FormState['errors'],\n isDirty,\n isLoading: rootState.isLoading,\n isSubmitting: rootState.isSubmitting,\n isTouched,\n isValid,\n isValidating,\n submitCount: rootState.submitCount,\n touchedFields: Object.freeze(touchedFields) as readonly string[],\n validatingFields: Object.freeze(validatingFields) as readonly string[],\n });\n }\n\n function scopedValues(): ScopedValues<TValues, P> {\n const sub: Record<string, unknown> = {};\n\n for (const [key, value] of ctx.store) {\n if (key.startsWith(pfxDot)) sub[key.slice(pfxDot.length)] = value;\n }\n\n return unflattenValues(sub) as ScopedValues<TValues, P>;\n }\n\n /**\n * Enumerate field paths within this scope's prefix, stripped to relative paths —\n * matching `scope.state`'s relative-path convention, not `state.touchedFields`'s\n * absolute-path convention. Same \"known field\" definition `scopedTouchAll()` uses.\n */\n function scopedListFields(): readonly string[] {\n const known = new Set<string>();\n\n for (const key of ctx.store.keys()) {\n if (isScopedKey(key)) known.add(unscope(key));\n }\n\n for (const key of ctx.validators.keys()) {\n if (isScopedKey(key)) known.add(unscope(key));\n }\n\n return Object.freeze([...known]);\n }\n\n function scopedTouchAll(): void {\n ctx.ensureNotDisposed('touchAll');\n fieldOps.touchAllKeys(isScopedKey);\n ctx.requestNotify();\n }\n\n function scopedUntouchAll(): void {\n ctx.ensureNotDisposed('untouchAll');\n fieldOps.untouchAllKeys(isScopedKey);\n ctx.requestNotify();\n }\n\n function scopedReset(): void {\n ctx.ensureNotDisposed('reset');\n fieldOps.resetKeys(isScopedKey);\n ctx.requestNotify();\n }\n\n function scopedReplace(newValues: ScopedValues<TValues, P>): void {\n ctx.ensureNotDisposed('replace');\n fieldOps.replaceKeys(isScopedKey, flattenValues(newValues as Record<string, unknown>), pre);\n ctx.requestNotify();\n }\n\n function scopedPatch(partial: Record<string, unknown>): void {\n ctx.ensureNotDisposed('patch');\n ctx.requestNotify(fieldOps.patchKeys(partial, pre));\n }\n\n function scopedResetErrors(\n nextErrors?: Partial<Record<ErrorKeyOf<ScopedValues<TValues, P>>, string | undefined>>,\n ): void {\n ctx.ensureNotDisposed('resetErrors');\n fieldOps.resetErrorsKeys(isScopedKey, nextErrors ?? {}, pre);\n ctx.requestNotify();\n }\n\n async function scopedValidate(\n nameOrFieldsOrSignal?: FlatKeyOf<ScopedValues<TValues, P>> | FlatKeyOf<ScopedValues<TValues, P>>[] | AbortSignal,\n signal?: AbortSignal,\n ): Promise<ValidateResult> {\n ctx.ensureNotDisposed('validate');\n\n if (\n nameOrFieldsOrSignal !== undefined &&\n !Array.isArray(nameOrFieldsOrSignal) &&\n !(nameOrFieldsOrSignal instanceof AbortSignal)\n ) {\n // validate(name) — single field\n const prefixedName = pre(nameOrFieldsOrSignal as string) as FlatKeyOf<TValues>;\n\n await fieldOps.runValidationCore([prefixedName as string], 'partial', signal);\n\n const error = ctx.fieldErrors.get(prefixedName as string);\n\n return {\n errors: error !== undefined ? { [nameOrFieldsOrSignal as string]: error } : {},\n valid: error === undefined,\n };\n }\n\n if (Array.isArray(nameOrFieldsOrSignal)) {\n // validate(fields[]) — specific subset\n const prefixedFields = nameOrFieldsOrSignal.map((f) => pre(f as string)) as string[];\n\n await fieldOps.runValidationCore(prefixedFields, 'partial', signal);\n\n const errors: Record<string, string> = {};\n\n for (const pf of prefixedFields) {\n const msg = ctx.fieldErrors.get(pf);\n\n if (msg !== undefined) errors[unscope(pf)] = msg;\n }\n\n return { errors, valid: Object.keys(errors).length === 0 };\n }\n\n // validate(signal?) — all scoped fields\n const sig = nameOrFieldsOrSignal as AbortSignal | undefined;\n const fields = [...ctx.validators.keys()].filter(isScopedKey);\n\n await fieldOps.runValidationCore(fields, 'partial', sig);\n\n const errors: Record<string, string> = {};\n\n for (const [key, message] of ctx.fieldErrors) {\n if (isScopedKey(key)) errors[unscope(key)] = message;\n }\n\n return { errors, valid: Object.keys(errors).length === 0 };\n }\n\n async function scopedSubmit<TResult>(\n handler: (values: ScopedValues<TValues, P>) => MaybePromise<TResult>,\n ): Promise<SubmitResult<TResult>> {\n ctx.ensureNotDisposed('submit');\n\n if (ctx.isSubmittingState) throw new ForgeSubmitError('submit() called while a submission is already in progress');\n\n ctx.batch(() => {\n ctx.submitCount++;\n ctx.isSubmittingState = true;\n scopedTouchAll();\n });\n\n try {\n const fields = [...ctx.validators.keys()].filter(isScopedKey);\n\n await fieldOps.runValidationCore(fields, 'partial');\n\n ctx.ensureNotDisposed('submit');\n\n const errors: Record<string, string> = {};\n\n for (const [key, message] of ctx.fieldErrors) {\n if (isScopedKey(key)) errors[unscope(key)] = message;\n }\n\n if (Object.keys(errors).length > 0) {\n return { errors, ok: false, type: 'validation' as const };\n }\n\n return { ok: true as const, value: await handler(scopedValues()) };\n } finally {\n ctx.isSubmittingState = false;\n\n if (!ctx.disposed) ctx.requestNotify();\n }\n }\n\n /**\n * Subscribe filtered to scoped fields only — this scoped form's `subscribe()` implementation.\n * Errors, touchedFields, and validatingFields are remapped to relative paths.\n * `isValid`, `isDirty`, and `isTouched` reflect only fields within this scope's prefix.\n * `isSubmitting`, `isLoading`, `isValidating`, and `submitCount` reflect the full form.\n *\n * The listener fires only when the scoped projection changes — mutations outside this\n * prefix do not fire the listener.\n */\n function scopedSubscribe(listener: (state: FormState) => void, options?: SubscribeOptions): Unsubscribe {\n // Track the previous scoped projection for equality comparison.\n let prevState: FormState | null = null;\n\n return root.subscribe(() => {\n const next = getScopedState();\n\n // Skip if no scoped-relevant state has changed.\n if (prevState) {\n const p = prevState;\n const errKeys = Object.keys(next.errors);\n const prevErrKeys = Object.keys(p.errors);\n const errorsMatch =\n errKeys.length === prevErrKeys.length && errKeys.every((k) => next.errors[k] === p.errors[k]);\n\n const touchedMatch =\n next.touchedFields.length === p.touchedFields.length &&\n next.touchedFields.every((v, i) => v === p.touchedFields[i]);\n\n const validatingMatch =\n next.validatingFields.length === p.validatingFields.length &&\n next.validatingFields.every((v, i) => v === p.validatingFields[i]);\n\n const flagsMatch =\n next.isDirty === p.isDirty &&\n next.isLoading === p.isLoading &&\n next.isSubmitting === p.isSubmitting &&\n next.isTouched === p.isTouched &&\n next.isValid === p.isValid &&\n next.isValidating === p.isValidating &&\n next.submitCount === p.submitCount;\n\n if (flagsMatch && errorsMatch && touchedMatch && validatingMatch) return;\n }\n\n prevState = next;\n listener(next);\n }, options);\n }\n\n function createScopedAdapter() {\n return {\n array(name: string): ArrayField {\n return root.array(pre(name) as FlatKeyOf<TValues>) as ArrayField;\n },\n clearError(name: string): void {\n root.clearError(pre(name) as ErrorKeyOf<TValues>);\n },\n connect(name: string, config?: ConnectOptions): ConnectionResult<unknown> {\n return root.connect(pre(name) as FlatKeyOf<TValues>, config) as ConnectionResult<unknown>;\n },\n field(name: string): FieldState<unknown> {\n return root.field(pre(name) as FlatKeyOf<TValues>) as FieldState<unknown>;\n },\n get(name: string): unknown {\n return root.get(pre(name) as FlatKeyOf<TValues>);\n },\n register(name: string, options?: RegisterFieldOptions<unknown>): Unsubscribe {\n return root.fields.register(\n pre(name) as FlatKeyOf<TValues>,\n options as RegisterFieldOptions<TypeAtPath<TValues, FlatKeyOf<TValues>>>,\n );\n },\n remove(name: string): void {\n root.fields.remove(pre(name) as FlatKeyOf<TValues>);\n },\n resetField(name: string): void {\n root.resetField(pre(name) as FlatKeyOf<TValues>);\n },\n set(name: string, value: unknown, options?: SetOptions): void {\n root.set(pre(name) as FlatKeyOf<TValues>, value as TypeAtPath<TValues, FlatKeyOf<TValues>>, options);\n },\n setError(name: string, message: string): void {\n root.setError(pre(name) as ErrorKeyOf<TValues>, message);\n },\n setValidator(name: string, validator?: FieldValidator): void {\n root.fields.setValidator(pre(name) as FlatKeyOf<TValues>, validator);\n },\n subscribeField(\n name: string,\n listener: (state: FieldState<unknown>) => void,\n options?: SubscribeOptions,\n ): Unsubscribe {\n return root.subscribeField(\n pre(name) as FlatKeyOf<TValues>,\n listener as (state: FieldState<TypeAtPath<TValues, FlatKeyOf<TValues>>>) => void,\n options,\n );\n },\n touch(name: string): void {\n root.touch(pre(name) as FlatKeyOf<TValues>);\n },\n untouch(name: string): void {\n root.untouch(pre(name) as FlatKeyOf<TValues>);\n },\n };\n }\n\n /* ---- Public scoped form object ---- */\n\n type S = ScopedValues<TValues, P>;\n\n const adapter = createScopedAdapter();\n\n return {\n array: (name) =>\n adapter.array(name as string) as ArrayField<\n TypeAtPath<S, typeof name> extends readonly (infer E)[] ? E : unknown\n >,\n batch: (fn) => root.batch(fn),\n clearError: (name) => adapter.clearError(name as string),\n connect: (name, config?) => adapter.connect(name as string, config) as ConnectionResult<TypeAtPath<S, typeof name>>,\n get disposalSignal() {\n return root.disposalSignal;\n },\n dispose: () => {\n /* Scoped forms share lifecycle with parent — call parentForm.dispose() to tear down */\n },\n get disposed() {\n return ctx.disposed;\n },\n field: (name) => adapter.field(name as string) as FieldState<TypeAtPath<S, typeof name>>,\n fields: {\n list: scopedListFields,\n register: (name, options?) => adapter.register(name as string, options as RegisterFieldOptions<unknown>),\n remove: (name) => adapter.remove(name as string),\n setValidator: (name, validator?) => adapter.setValidator(name as string, validator),\n },\n get: (name) => adapter.get(name as string) as TypeAtPath<S, typeof name>,\n history: {\n // Casts are irreducible: FormSnapshot<S> and FormSnapshot<TValues> are structurally\n // unrelated generic instantiations -- TS cannot verify one against the other.\n restore: (snap) => root.history.restore(snap as FormSnapshot<TValues>),\n snapshot: () => root.history.snapshot() as FormSnapshot<S>,\n },\n get isLoading() {\n return root.isLoading;\n },\n get isSubmitting() {\n return root.isSubmitting;\n },\n patch: scopedPatch as Form<S>['patch'],\n replace: scopedReplace as Form<S>['replace'],\n reset: scopedReset,\n resetErrors: scopedResetErrors as Form<S>['resetErrors'],\n resetField: (name) => adapter.resetField(name as string),\n scope: (subPrefix) =>\n createScopedForm(scopeCtx, pre(subPrefix as string)) as Form<ScopedValues<S, typeof subPrefix>>,\n set: (name, value, options?: SetOptions) => adapter.set(name as string, value, options),\n setError: (name, message) => adapter.setError(name as string, message),\n get state() {\n return getScopedState();\n },\n submit: scopedSubmit as Form<S>['submit'],\n submitOrThrow: async (handler) => {\n const result = await scopedSubmit(handler);\n\n if (!result.ok) throw new ForgeValidationError(result.errors as Record<string, string>);\n\n return result.value;\n },\n // Scoped forms filter+remap; on a root form this method is the unfiltered notifier pass-through.\n subscribe: scopedSubscribe,\n subscribeField: (name, listener, options?) =>\n adapter.subscribeField(name as string, listener as (state: FieldState<unknown>) => void, options),\n [Symbol.asyncIterator]: () => root[Symbol.asyncIterator](),\n [Symbol.dispose]() {\n this.dispose();\n },\n touch: (name) => adapter.touch(name as string),\n touchAll: scopedTouchAll,\n untouch: (name) => adapter.untouch(name as string),\n untouchAll: scopedUntouchAll,\n validate: scopedValidate as Form<S>['validate'],\n values: scopedValues,\n };\n}\n"],"mappings":"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"}
package/dist/errors.cjs CHANGED
@@ -1,2 +1,2 @@
1
- var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{constructor(){super(`Cannot modify a disposed form`)}},n=class extends e{},r=class extends e{},i=class extends e{errors;constructor(e){super(`Form validation failed`),this.errors=e}};exports.ForgeConfigError=n,exports.ForgeDisposedError=t,exports.ForgeError=e,exports.ForgeSubmitError=r,exports.ForgeValidationError=i;
1
+ var e=class e extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}static is(t){return t instanceof e}},t=class extends e{constructor(e){super(e?`Cannot call ${e}() on a disposed form`:`Cannot modify a disposed form`)}},n=class extends e{},r=class extends e{},i=class extends e{errors;constructor(e){super(`Form validation failed`),this.errors=e}};exports.ForgeConfigError=n,exports.ForgeDisposedError=t,exports.ForgeError=e,exports.ForgeSubmitError=r,exports.ForgeValidationError=i;
2
2
  //# sourceMappingURL=errors.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all forge errors. Use `instanceof ForgeError` to catch any forge-originated error. */\nexport class ForgeError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ForgeError {\n return err instanceof ForgeError;\n }\n}\n\n/** Thrown when any method is called on a disposed form. */\nexport class ForgeDisposedError extends ForgeError {\n constructor() {\n super('Cannot modify a disposed form');\n }\n}\n\n/** Thrown when a form key contains reserved prototype-polluting segments. */\nexport class ForgeConfigError extends ForgeError {}\n\n/** Thrown when `submit()` is called while a submission is already in progress. */\nexport class ForgeSubmitError extends ForgeError {}\n\n/** Thrown by `submitOrThrow()` when validation fails. */\nexport class ForgeValidationError extends ForgeError {\n readonly errors: Record<string, string>;\n\n constructor(errors: Record<string, string>) {\n super('Form validation failed');\n this.errors = errors;\n }\n}\n"],"mappings":"AACA,IAAa,EAAb,MAAa,UAAmB,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAAiC,CACzC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAwC,CAAW,CACjD,aAAc,CACZ,MAAM,+BAA+B,CACvC,CACF,EAGa,EAAb,cAAsC,CAAW,CAAC,EAGrC,EAAb,cAAsC,CAAW,CAAC,EAGrC,EAAb,cAA0C,CAAW,CACnD,OAEA,YAAY,EAAgC,CAC1C,MAAM,wBAAwB,EAC9B,KAAK,OAAS,CAChB,CACF"}
1
+ {"version":3,"file":"errors.cjs","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all forge errors. Use `instanceof ForgeError` to catch any forge-originated error. */\nexport class ForgeError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ForgeError {\n return err instanceof ForgeError;\n }\n}\n\n/** Thrown when any method is called on a disposed form. */\nexport class ForgeDisposedError extends ForgeError {\n /** @param op The public method name that was called (e.g. `'set'`) — included in the\n * message so a stack trace tells you *what* to guard, not just *that* it's disposed. */\n constructor(op?: string) {\n super(op ? `Cannot call ${op}() on a disposed form` : 'Cannot modify a disposed form');\n }\n}\n\n/** Thrown when a form key contains reserved prototype-polluting segments. */\nexport class ForgeConfigError extends ForgeError {}\n\n/** Thrown when `submit()` is called while a submission is already in progress. */\nexport class ForgeSubmitError extends ForgeError {}\n\n/** Thrown by `submitOrThrow()` when validation fails. */\nexport class ForgeValidationError extends ForgeError {\n readonly errors: Record<string, string>;\n\n constructor(errors: Record<string, string>) {\n super('Form validation failed');\n this.errors = errors;\n }\n}\n"],"mappings":"AACA,IAAa,EAAb,MAAa,UAAmB,KAAM,CACpC,YAAY,EAAiB,EAAqB,CAChD,MAAM,EAAS,CAAI,EACnB,KAAK,KAAO,IAAI,OAAO,KACvB,OAAO,eAAe,KAAM,IAAI,OAAO,SAAS,CAClD,CAEA,OAAO,GAAG,EAAiC,CACzC,OAAO,aAAe,CACxB,CACF,EAGa,EAAb,cAAwC,CAAW,CAGjD,YAAY,EAAa,CACvB,MAAM,EAAK,eAAe,EAAG,uBAAyB,+BAA+B,CACvF,CACF,EAGa,EAAb,cAAsC,CAAW,CAAC,EAGrC,EAAb,cAAsC,CAAW,CAAC,EAGrC,EAAb,cAA0C,CAAW,CACnD,OAEA,YAAY,EAAgC,CAC1C,MAAM,wBAAwB,EAC9B,KAAK,OAAS,CAChB,CACF"}
package/dist/errors.d.ts CHANGED
@@ -5,7 +5,9 @@ export declare class ForgeError extends Error {
5
5
  }
6
6
  /** Thrown when any method is called on a disposed form. */
7
7
  export declare class ForgeDisposedError extends ForgeError {
8
- constructor();
8
+ /** @param op The public method name that was called (e.g. `'set'`) — included in the
9
+ * message so a stack trace tells you *what* to guard, not just *that* it's disposed. */
10
+ constructor(op?: string);
9
11
  }
10
12
  /** Thrown when a form key contains reserved prototype-polluting segments. */
11
13
  export declare class ForgeConfigError extends ForgeError {
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAMhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU;CAG3C;AAED,2DAA2D;AAC3D,qBAAa,kBAAmB,SAAQ,UAAU;;CAIjD;AAED,6EAA6E;AAC7E,qBAAa,gBAAiB,SAAQ,UAAU;CAAG;AAEnD,kFAAkF;AAClF,qBAAa,gBAAiB,SAAQ,UAAU;CAAG;AAEnD,yDAAyD;AACzD,qBAAa,oBAAqB,SAAQ,UAAU;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAE5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAI3C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY;IAMhD,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,UAAU;CAG3C;AAED,2DAA2D;AAC3D,qBAAa,kBAAmB,SAAQ,UAAU;IAChD;4FACwF;gBAC5E,EAAE,CAAC,EAAE,MAAM;CAGxB;AAED,6EAA6E;AAC7E,qBAAa,gBAAiB,SAAQ,UAAU;CAAG;AAEnD,kFAAkF;AAClF,qBAAa,gBAAiB,SAAQ,UAAU;CAAG;AAEnD,yDAAyD;AACzD,qBAAa,oBAAqB,SAAQ,UAAU;IAClD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAE5B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAI3C"}
package/dist/errors.js CHANGED
@@ -7,8 +7,8 @@ var e = class e extends Error {
7
7
  return t instanceof e;
8
8
  }
9
9
  }, t = class extends e {
10
- constructor() {
11
- super("Cannot modify a disposed form");
10
+ constructor(e) {
11
+ super(e ? `Cannot call ${e}() on a disposed form` : "Cannot modify a disposed form");
12
12
  }
13
13
  }, n = class extends e {}, r = class extends e {}, i = class extends e {
14
14
  errors;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all forge errors. Use `instanceof ForgeError` to catch any forge-originated error. */\nexport class ForgeError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ForgeError {\n return err instanceof ForgeError;\n }\n}\n\n/** Thrown when any method is called on a disposed form. */\nexport class ForgeDisposedError extends ForgeError {\n constructor() {\n super('Cannot modify a disposed form');\n }\n}\n\n/** Thrown when a form key contains reserved prototype-polluting segments. */\nexport class ForgeConfigError extends ForgeError {}\n\n/** Thrown when `submit()` is called while a submission is already in progress. */\nexport class ForgeSubmitError extends ForgeError {}\n\n/** Thrown by `submitOrThrow()` when validation fails. */\nexport class ForgeValidationError extends ForgeError {\n readonly errors: Record<string, string>;\n\n constructor(errors: Record<string, string>) {\n super('Form validation failed');\n this.errors = errors;\n }\n}\n"],"mappings":";AACA,IAAa,IAAb,MAAa,UAAmB,MAAM;CACpC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,IAAI,OAAO,MACvB,OAAO,eAAe,MAAM,IAAI,OAAO,SAAS;CAClD;CAEA,OAAO,GAAG,GAAiC;EACzC,OAAO,aAAe;CACxB;AACF,GAGa,IAAb,cAAwC,EAAW;CACjD,cAAc;EACZ,MAAM,+BAA+B;CACvC;AACF,GAGa,IAAb,cAAsC,EAAW,CAAC,GAGrC,IAAb,cAAsC,EAAW,CAAC,GAGrC,IAAb,cAA0C,EAAW;CACnD;CAEA,YAAY,GAAgC;EAE1C,AADA,MAAM,wBAAwB,GAC9B,KAAK,SAAS;CAChB;AACF"}
1
+ {"version":3,"file":"errors.js","names":[],"sources":["../src/errors.ts"],"sourcesContent":["/** Base class for all forge errors. Use `instanceof ForgeError` to catch any forge-originated error. */\nexport class ForgeError extends Error {\n constructor(message: string, opts?: ErrorOptions) {\n super(message, opts);\n this.name = new.target.name;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n\n static is(err: unknown): err is ForgeError {\n return err instanceof ForgeError;\n }\n}\n\n/** Thrown when any method is called on a disposed form. */\nexport class ForgeDisposedError extends ForgeError {\n /** @param op The public method name that was called (e.g. `'set'`) — included in the\n * message so a stack trace tells you *what* to guard, not just *that* it's disposed. */\n constructor(op?: string) {\n super(op ? `Cannot call ${op}() on a disposed form` : 'Cannot modify a disposed form');\n }\n}\n\n/** Thrown when a form key contains reserved prototype-polluting segments. */\nexport class ForgeConfigError extends ForgeError {}\n\n/** Thrown when `submit()` is called while a submission is already in progress. */\nexport class ForgeSubmitError extends ForgeError {}\n\n/** Thrown by `submitOrThrow()` when validation fails. */\nexport class ForgeValidationError extends ForgeError {\n readonly errors: Record<string, string>;\n\n constructor(errors: Record<string, string>) {\n super('Form validation failed');\n this.errors = errors;\n }\n}\n"],"mappings":";AACA,IAAa,IAAb,MAAa,UAAmB,MAAM;CACpC,YAAY,GAAiB,GAAqB;EAGhD,AAFA,MAAM,GAAS,CAAI,GACnB,KAAK,OAAO,IAAI,OAAO,MACvB,OAAO,eAAe,MAAM,IAAI,OAAO,SAAS;CAClD;CAEA,OAAO,GAAG,GAAiC;EACzC,OAAO,aAAe;CACxB;AACF,GAGa,IAAb,cAAwC,EAAW;CAGjD,YAAY,GAAa;EACvB,MAAM,IAAK,eAAe,EAAG,yBAAyB,+BAA+B;CACvF;AACF,GAGa,IAAb,cAAsC,EAAW,CAAC,GAGrC,IAAb,cAAsC,EAAW,CAAC,GAGrC,IAAb,cAA0C,EAAW;CACnD;CAEA,YAAY,GAAgC;EAE1C,AADA,MAAM,wBAAwB,GAC9B,KAAK,SAAS;CAChB;AACF"}