@vielzeug/forge 1.1.2

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 (108) hide show
  1. package/README.md +70 -0
  2. package/dist/_dev.cjs +2 -0
  3. package/dist/_dev.cjs.map +1 -0
  4. package/dist/_dev.d.ts +2 -0
  5. package/dist/_dev.d.ts.map +1 -0
  6. package/dist/_dev.js +9 -0
  7. package/dist/_dev.js.map +1 -0
  8. package/dist/_utils.cjs +2 -0
  9. package/dist/_utils.cjs.map +1 -0
  10. package/dist/_utils.d.ts +12 -0
  11. package/dist/_utils.d.ts.map +1 -0
  12. package/dist/_utils.js +25 -0
  13. package/dist/_utils.js.map +1 -0
  14. package/dist/adapters/form-data.cjs +2 -0
  15. package/dist/adapters/form-data.cjs.map +1 -0
  16. package/dist/adapters/form-data.d.ts +8 -0
  17. package/dist/adapters/form-data.d.ts.map +1 -0
  18. package/dist/adapters/form-data.js +14 -0
  19. package/dist/adapters/form-data.js.map +1 -0
  20. package/dist/adapters/validators.cjs +2 -0
  21. package/dist/adapters/validators.cjs.map +1 -0
  22. package/dist/adapters/validators.d.ts +44 -0
  23. package/dist/adapters/validators.d.ts.map +1 -0
  24. package/dist/adapters/validators.js +20 -0
  25. package/dist/adapters/validators.js.map +1 -0
  26. package/dist/core/array.cjs +2 -0
  27. package/dist/core/array.cjs.map +1 -0
  28. package/dist/core/array.d.ts +10 -0
  29. package/dist/core/array.d.ts.map +1 -0
  30. package/dist/core/array.js +46 -0
  31. package/dist/core/array.js.map +1 -0
  32. package/dist/core/asyncQueue.cjs +2 -0
  33. package/dist/core/asyncQueue.cjs.map +1 -0
  34. package/dist/core/asyncQueue.d.ts +22 -0
  35. package/dist/core/asyncQueue.d.ts.map +1 -0
  36. package/dist/core/asyncQueue.js +67 -0
  37. package/dist/core/asyncQueue.js.map +1 -0
  38. package/dist/core/context.cjs +2 -0
  39. package/dist/core/context.cjs.map +1 -0
  40. package/dist/core/context.d.ts +10 -0
  41. package/dist/core/context.d.ts.map +1 -0
  42. package/dist/core/context.js +176 -0
  43. package/dist/core/context.js.map +1 -0
  44. package/dist/core/lifecycle.cjs +2 -0
  45. package/dist/core/lifecycle.cjs.map +1 -0
  46. package/dist/core/lifecycle.d.ts +13 -0
  47. package/dist/core/lifecycle.d.ts.map +1 -0
  48. package/dist/core/lifecycle.js +42 -0
  49. package/dist/core/lifecycle.js.map +1 -0
  50. package/dist/core/observe.cjs +2 -0
  51. package/dist/core/observe.cjs.map +1 -0
  52. package/dist/core/observe.d.ts +18 -0
  53. package/dist/core/observe.d.ts.map +1 -0
  54. package/dist/core/observe.js +90 -0
  55. package/dist/core/observe.js.map +1 -0
  56. package/dist/core/scope.cjs +2 -0
  57. package/dist/core/scope.cjs.map +1 -0
  58. package/dist/core/scope.d.ts +8 -0
  59. package/dist/core/scope.d.ts.map +1 -0
  60. package/dist/core/scope.js +239 -0
  61. package/dist/core/scope.js.map +1 -0
  62. package/dist/core/validation.cjs +2 -0
  63. package/dist/core/validation.cjs.map +1 -0
  64. package/dist/core/validation.d.ts +23 -0
  65. package/dist/core/validation.d.ts.map +1 -0
  66. package/dist/core/validation.js +173 -0
  67. package/dist/core/validation.js.map +1 -0
  68. package/dist/core/values.cjs +2 -0
  69. package/dist/core/values.cjs.map +1 -0
  70. package/dist/core/values.d.ts +31 -0
  71. package/dist/core/values.d.ts.map +1 -0
  72. package/dist/core/values.js +149 -0
  73. package/dist/core/values.js.map +1 -0
  74. package/dist/devtools.cjs +2 -0
  75. package/dist/devtools.cjs.map +1 -0
  76. package/dist/devtools.d.ts +40 -0
  77. package/dist/devtools.d.ts.map +1 -0
  78. package/dist/devtools.js +29 -0
  79. package/dist/devtools.js.map +1 -0
  80. package/dist/errors.cjs +2 -0
  81. package/dist/errors.cjs.map +1 -0
  82. package/dist/errors.d.ts +21 -0
  83. package/dist/errors.d.ts.map +1 -0
  84. package/dist/errors.js +22 -0
  85. package/dist/errors.js.map +1 -0
  86. package/dist/forge.cjs +2 -0
  87. package/dist/forge.cjs.map +1 -0
  88. package/dist/forge.iife.js +2 -0
  89. package/dist/forge.iife.js.map +1 -0
  90. package/dist/forge.js +2 -0
  91. package/dist/forge.js.map +1 -0
  92. package/dist/form.cjs +2 -0
  93. package/dist/form.cjs.map +1 -0
  94. package/dist/form.d.ts +6 -0
  95. package/dist/form.d.ts.map +1 -0
  96. package/dist/form.js +89 -0
  97. package/dist/form.js.map +1 -0
  98. package/dist/index.cjs +1 -0
  99. package/dist/index.d.ts +5 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +5 -0
  102. package/dist/types.cjs +2 -0
  103. package/dist/types.cjs.map +1 -0
  104. package/dist/types.d.ts +391 -0
  105. package/dist/types.d.ts.map +1 -0
  106. package/dist/types.js +21 -0
  107. package/dist/types.js.map +1 -0
  108. package/package.json +56 -0
@@ -0,0 +1,176 @@
1
+ import { ForgeDisposedError as e } from "../errors.js";
2
+ import { assertSafeKey as t, flattenValues as n, isSafeKey as r } from "../_utils.js";
3
+ import "../types.js";
4
+ import { batch as i, signal as a } from "@vielzeug/ripple";
5
+ //#region src/core/context.ts
6
+ function o(e) {
7
+ if (!e) return;
8
+ if (typeof e == "function") return e;
9
+ let t = e;
10
+ return (e, n) => {
11
+ if (n?.aborted) return;
12
+ let i = t.safeParse(e);
13
+ if (i.success) return;
14
+ let a = {};
15
+ for (let e of i.error.issues) {
16
+ let t = e.path.join(".") || "_form";
17
+ r(t) && (a[t] || (a[t] = e.message));
18
+ }
19
+ return a;
20
+ };
21
+ }
22
+ function s(r) {
23
+ let s = /* @__PURE__ */ new Map();
24
+ for (let [e, n] of Object.entries(r.validators ?? {})) t(e), s.set(e, n);
25
+ let c = o(r.validator), l = r.connect ?? {}, u = typeof r.defaultValues == "function", d = typeof r.defaultValues == "function" ? void 0 : r.defaultValues, f = new Map(Object.entries(n(d ?? {}))), p = new Map(f), m = /* @__PURE__ */ new Map(), h = /* @__PURE__ */ new Set(), g = /* @__PURE__ */ new Set(), _ = /* @__PURE__ */ new Map(), v = /* @__PURE__ */ new Set(), y = /* @__PURE__ */ new Map(), b = new AbortController(), x = null, S = null, C = /* @__PURE__ */ new Map(), w = /* @__PURE__ */ new Map(), T = /* @__PURE__ */ new Map(), E = !1, D = 0, O = !1, k = /* @__PURE__ */ new Map(), A = /* @__PURE__ */ new Set();
26
+ function j(e) {
27
+ return k.has(e) || k.set(e, a(R(e), { equals: (e, t) => e.value === t.value && e.error === t.error && e.hasError === t.hasError && e.touched === t.touched && e.dirty === t.dirty })), k.get(e);
28
+ }
29
+ function M() {
30
+ x = null;
31
+ }
32
+ function N() {
33
+ S = null;
34
+ }
35
+ function P() {
36
+ return S ??= Object.freeze(Object.fromEntries(m));
37
+ }
38
+ function F() {
39
+ return Object.freeze({
40
+ errors: P(),
41
+ isDirty: g.size > 0,
42
+ isLoading: u,
43
+ isSubmitting: E,
44
+ isTouched: h.size > 0,
45
+ isValid: m.size === 0,
46
+ isValidating: _.size > 0,
47
+ submitCount: D,
48
+ touchedFields: Object.freeze([...h]),
49
+ validatingFields: Object.freeze([..._.keys()])
50
+ });
51
+ }
52
+ let I = a(F());
53
+ function L() {
54
+ return I.value;
55
+ }
56
+ function R(e) {
57
+ let t = m.get(e);
58
+ return {
59
+ dirty: g.has(e),
60
+ error: t,
61
+ hasError: t !== void 0,
62
+ touched: h.has(e),
63
+ value: p.get(e)
64
+ };
65
+ }
66
+ function z(e) {
67
+ let t = C.get(e);
68
+ if (t) return t;
69
+ let n = Object.freeze(R(e));
70
+ return C.set(e, n), n;
71
+ }
72
+ function B(e) {
73
+ if (!O) if (M(), S = null, e === void 0) C.clear(), i(() => {
74
+ I.value = F();
75
+ for (let [e, t] of k) t.value = R(e);
76
+ });
77
+ else if (typeof e == "string") C.delete(e), i(() => {
78
+ I.value = F();
79
+ let t = k.get(e);
80
+ t && (t.value = R(e));
81
+ });
82
+ else {
83
+ let t = [...e];
84
+ for (let e of t) C.delete(e);
85
+ i(() => {
86
+ I.value = F();
87
+ for (let e of t) {
88
+ let t = k.get(e);
89
+ t && (t.value = R(e));
90
+ }
91
+ });
92
+ }
93
+ }
94
+ function V() {
95
+ if (O) throw new e();
96
+ }
97
+ function H(e) {
98
+ V();
99
+ try {
100
+ i(e);
101
+ } catch (e) {
102
+ throw B(), e;
103
+ }
104
+ }
105
+ return {
106
+ arrayCache: w,
107
+ baseline: f,
108
+ batch: H,
109
+ buildFieldState: R,
110
+ get cachedErrors() {
111
+ return S;
112
+ },
113
+ set cachedErrors(e) {
114
+ S = e;
115
+ },
116
+ get cachedValues() {
117
+ return x;
118
+ },
119
+ set cachedValues(e) {
120
+ x = e;
121
+ },
122
+ computeErrors: P,
123
+ computeState: F,
124
+ connectDefaults: l,
125
+ dirty: g,
126
+ disposeController: b,
127
+ get disposed() {
128
+ return O;
129
+ },
130
+ set disposed(e) {
131
+ O = e;
132
+ },
133
+ ensureNotDisposed: V,
134
+ fieldCtrls: y,
135
+ fieldErrors: m,
136
+ fieldSignals: k,
137
+ fieldStateCache: C,
138
+ formStateSignal: I,
139
+ formValidator: c,
140
+ getFieldSnapshot: z,
141
+ getOrCreateFieldSignal: j,
142
+ getStateSnapshot: L,
143
+ invalidateErrors: N,
144
+ invalidateValues: M,
145
+ get isSubmittingState() {
146
+ return E;
147
+ },
148
+ set isSubmittingState(e) {
149
+ E = e;
150
+ },
151
+ get loadingState() {
152
+ return u;
153
+ },
154
+ set loadingState(e) {
155
+ u = e;
156
+ },
157
+ requestNotify: B,
158
+ rippleSubs: A,
159
+ runCtrls: v,
160
+ scopeCache: T,
161
+ store: p,
162
+ get submitCount() {
163
+ return D;
164
+ },
165
+ set submitCount(e) {
166
+ D = e;
167
+ },
168
+ touched: h,
169
+ validatingRuns: _,
170
+ validators: s
171
+ };
172
+ }
173
+ //#endregion
174
+ export { s as createFormContext };
175
+
176
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["import { batch as rippleBatch, signal, type Signal } from '@vielzeug/ripple';\n\nimport { assertSafeKey, flattenValues, isSafeKey } from '../_utils';\nimport { ForgeDisposedError } from '../errors';\nimport {\n type ArrayField,\n type ConnectOptions,\n type FieldState,\n type FieldValidator,\n FORM_ERROR,\n type Form,\n type FormOptions,\n type FormState,\n type FormValidator,\n type SafeParseSchema,\n} from '../types';\n\n/**\n * Resolves the `validator` option to a FormValidator.\n * Auto-detects SafeParseSchema objects (duck-typed via `safeParse`) and wraps them,\n * enabling direct use of @vielzeug/spell, Zod, Valibot schemas without an explicit wrapper call.\n */\nfunction resolveFormValidator<TValues extends Record<string, unknown>>(\n raw: FormValidator<TValues> | SafeParseSchema | undefined,\n): FormValidator<TValues> | undefined {\n if (!raw) return undefined;\n\n if (typeof raw === 'function') return raw;\n\n const schema = raw as SafeParseSchema;\n\n return (values, signal) => {\n if (signal?.aborted) return undefined;\n\n const result = schema.safeParse(values);\n\n if (result.success) return undefined;\n\n const errors: Partial<Record<string, string>> = {};\n\n for (const issue of result.error.issues) {\n const key = issue.path.join('.') || FORM_ERROR;\n\n // Security: `issue.path` is schema-controlled (untrusted duck-typed input, per\n // SafeParseSchema) — reject reserved segments before it can become an error key.\n if (!isSafeKey(key)) continue;\n\n if (!errors[key]) errors[key] = issue.message;\n }\n\n return errors as Partial<Record<string, string>>;\n };\n}\n\n/**\n * Shared mutable state + primitives passed to every createForm() sub-module factory\n * (`createValueOps`, `createValidationOps`, `createObserveOps`, `createLifecycleOps`).\n * Mirrors the `ScopeContext` pattern already established in `internal/scope.ts`.\n * @internal\n */\nexport type FormContext<TValues extends Record<string, unknown> = Record<string, unknown>> = {\n arrayCache: Map<string, ArrayField>;\n baseline: Map<string, unknown>;\n batch(fn: () => void): void;\n buildFieldState(name: string): FieldState<unknown>;\n cachedErrors: Readonly<Record<string, string>> | null;\n cachedValues: TValues | null;\n computeErrors(): Readonly<Record<string, string>>;\n computeState(): FormState;\n connectDefaults: ConnectOptions;\n dirty: Set<string>;\n disposeController: AbortController;\n disposed: boolean;\n ensureNotDisposed(): void;\n fieldCtrls: Map<string, AbortController>;\n fieldErrors: Map<string, string>;\n fieldSignals: Map<string, Signal<FieldState<unknown>>>;\n fieldStateCache: Map<string, FieldState<unknown>>;\n formStateSignal: Signal<FormState>;\n formValidator: FormValidator<TValues> | undefined;\n getFieldSnapshot(name: string): FieldState<unknown>;\n getOrCreateFieldSignal(key: string): Signal<FieldState<unknown>>;\n getStateSnapshot(): FormState;\n invalidateErrors(): void;\n invalidateValues(): void;\n isSubmittingState: boolean;\n loadingState: boolean;\n requestNotify(target?: string | Iterable<string>): void;\n rippleSubs: Set<{ dispose(): void }>;\n runCtrls: Set<AbortController>;\n scopeCache: Map<string, Form<never>>;\n store: Map<string, unknown>;\n submitCount: number;\n touched: Set<string>;\n validatingRuns: Map<string, Set<symbol>>;\n validators: Map<string, FieldValidator<unknown>>;\n};\n\n/**\n * Builds the raw mutable state + shared primitives for a form. This is the \"Core state\" +\n * \"Notification helpers\" sections of the original monolithic `createForm()` body, factored\n * out so `internal/values.ts`, `internal/validation.ts`, `internal/observe.ts`, and\n * `internal/lifecycle.ts` can each operate on the same shared state without closing over\n * ad-hoc free variables.\n */\nexport function createFormContext<TValues extends Record<string, unknown> = Record<string, unknown>>(\n init: FormOptions<TValues>,\n): FormContext<TValues> {\n /* ---- Validators ---- */\n\n const validators = new Map<string, FieldValidator<unknown>>();\n\n for (const [name, validator] of Object.entries(init.validators ?? {})) {\n assertSafeKey(name);\n validators.set(name, validator as FieldValidator<unknown>);\n }\n\n const formValidator: FormValidator<TValues> | undefined = resolveFormValidator(init.validator);\n const connectDefaults: ConnectOptions = init.connect ?? {};\n\n /* ---- Core state ---- */\n\n let loadingState = typeof init.defaultValues === 'function';\n\n const staticValues = typeof init.defaultValues !== 'function' ? init.defaultValues : undefined;\n const baseline = new Map<string, unknown>(Object.entries(flattenValues(staticValues ?? {})));\n const store = new Map<string, unknown>(baseline);\n const fieldErrors = new Map<string, string>();\n const touched = new Set<string>();\n const dirty = new Set<string>();\n\n /* ---- Validation tracking ---- */\n\n /**\n * Symbol-based ref-counting for concurrent validation runs per field.\n * Each runValidationCore() call mints a unique symbol and adds it to the field's Set.\n * The field leaves `validatingFields` only when its Set is empty — impossible to miscount.\n */\n const validatingRuns = new Map<string, Set<symbol>>();\n const runCtrls = new Set<AbortController>();\n const fieldCtrls = new Map<string, AbortController>();\n const disposeController = new AbortController();\n\n /* ---- Caches ---- */\n\n let cachedValues: TValues | null = null;\n let cachedErrors: Readonly<Record<string, string>> | null = null;\n const fieldStateCache = new Map<string, FieldState<unknown>>();\n const arrayCache = new Map<string, ArrayField>();\n const scopeCache = new Map<string, Form<never>>();\n\n /* ---- Submission state ---- */\n\n let isSubmittingState = false;\n let submitCount = 0;\n\n /* ---- Lifecycle ---- */\n\n let disposed = false;\n\n /* ---- Reactive signals ---- */\n\n const fieldSignals = new Map<string, Signal<FieldState<unknown>>>();\n const rippleSubs = new Set<{ dispose(): void }>();\n\n function getOrCreateFieldSignal(key: string): Signal<FieldState<unknown>> {\n if (!fieldSignals.has(key)) {\n fieldSignals.set(\n key,\n signal<FieldState<unknown>>(buildFieldState(key), {\n equals: (a, b) =>\n a.value === b.value &&\n a.error === b.error &&\n a.hasError === b.hasError &&\n a.touched === b.touched &&\n a.dirty === b.dirty,\n }),\n );\n }\n\n return fieldSignals.get(key)!;\n }\n\n /* ======== Notification helpers ======== */\n\n function invalidateValues(): void {\n cachedValues = null;\n }\n\n function invalidateErrors(): void {\n cachedErrors = null;\n }\n\n function computeErrors(): Readonly<Record<string, string>> {\n return (cachedErrors ??= Object.freeze(Object.fromEntries(fieldErrors)));\n }\n\n function computeState(): FormState {\n return Object.freeze({\n errors: computeErrors(),\n isDirty: dirty.size > 0,\n isLoading: loadingState,\n isSubmitting: isSubmittingState,\n isTouched: touched.size > 0,\n isValid: fieldErrors.size === 0,\n isValidating: validatingRuns.size > 0,\n submitCount,\n touchedFields: Object.freeze([...touched]) as readonly string[],\n validatingFields: Object.freeze([...validatingRuns.keys()]) as readonly string[],\n });\n }\n\n const formStateSignal = signal<FormState>(computeState());\n\n function getStateSnapshot(): FormState {\n return formStateSignal.value;\n }\n\n function buildFieldState(name: string): FieldState<unknown> {\n const error = fieldErrors.get(name);\n\n return {\n dirty: dirty.has(name),\n error,\n hasError: error !== undefined,\n touched: touched.has(name),\n value: store.get(name),\n };\n }\n\n function getFieldSnapshot(name: string): FieldState<unknown> {\n const cached = fieldStateCache.get(name);\n\n if (cached) return cached;\n\n const snap = Object.freeze(buildFieldState(name));\n\n fieldStateCache.set(name, snap);\n\n return snap;\n }\n\n /**\n * R4: Unified notification — replaces requestNotify(field?) + requestNotifyFields(fields).\n * - undefined → full-form refresh (all field signals + form signal)\n * - string → single field + form signal\n * - Iterable → targeted set of fields + form signal\n * rippleBatch deduplicates signal writes within the synchronous call stack.\n */\n function requestNotify(target?: string | Iterable<string>): void {\n if (disposed) return;\n\n invalidateValues();\n cachedErrors = null;\n\n if (target === undefined) {\n fieldStateCache.clear();\n rippleBatch(() => {\n formStateSignal.value = computeState();\n\n for (const [name, sig] of fieldSignals) sig.value = buildFieldState(name);\n });\n } else if (typeof target === 'string') {\n fieldStateCache.delete(target);\n rippleBatch(() => {\n formStateSignal.value = computeState();\n\n const sig = fieldSignals.get(target);\n\n if (sig) sig.value = buildFieldState(target);\n });\n } else {\n // Materialize before rippleBatch so the iterable isn't consumed inside the callback.\n const fields = [...target];\n\n for (const field of fields) fieldStateCache.delete(field);\n\n rippleBatch(() => {\n formStateSignal.value = computeState();\n\n for (const field of fields) {\n const sig = fieldSignals.get(field);\n\n if (sig) sig.value = buildFieldState(field);\n }\n });\n }\n }\n\n /* ======== Lifecycle guards ======== */\n\n function ensureNotDisposed(): void {\n if (disposed) throw new ForgeDisposedError();\n }\n\n /* ======== Batch ======== */\n\n function batch(fn: () => void): void {\n ensureNotDisposed();\n\n try {\n rippleBatch(fn);\n } catch (e) {\n // rippleBatch clears its pending-subscriber queue on error to prevent\n // stale flushes on future unrelated writes. Re-notify here so subscribers\n // still see the partial mutations that succeeded before the throw.\n requestNotify();\n throw e;\n }\n }\n\n return {\n arrayCache,\n baseline,\n batch,\n buildFieldState,\n get cachedErrors() {\n return cachedErrors;\n },\n set cachedErrors(value) {\n cachedErrors = value;\n },\n get cachedValues() {\n return cachedValues;\n },\n set cachedValues(value) {\n cachedValues = value;\n },\n computeErrors,\n computeState,\n connectDefaults,\n dirty,\n disposeController,\n get disposed() {\n return disposed;\n },\n set disposed(value) {\n disposed = value;\n },\n ensureNotDisposed,\n fieldCtrls,\n fieldErrors,\n fieldSignals,\n fieldStateCache,\n formStateSignal,\n formValidator,\n getFieldSnapshot,\n getOrCreateFieldSignal,\n getStateSnapshot,\n invalidateErrors,\n invalidateValues,\n get isSubmittingState() {\n return isSubmittingState;\n },\n set isSubmittingState(value) {\n isSubmittingState = value;\n },\n get loadingState() {\n return loadingState;\n },\n set loadingState(value) {\n loadingState = value;\n },\n requestNotify,\n rippleSubs,\n runCtrls,\n scopeCache,\n store,\n get submitCount() {\n return submitCount;\n },\n set submitCount(value) {\n submitCount = value;\n },\n touched,\n validatingRuns,\n validators,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../_utils.cjs");function t(t){function n(){t.disposed=!0,t.disposeController.abort();for(let e of t.fieldCtrls.values())e.abort();t.fieldCtrls.clear(),t.runCtrls.clear(),t.arrayCache.clear(),t.scopeCache.clear();for(let e of t.rippleSubs)e.dispose();t.rippleSubs.clear(),t.fieldSignals.clear()}function r(){return t.ensureNotDisposed(),Object.freeze({baseline:Object.freeze(Object.fromEntries(t.baseline)),dirty:Object.freeze([...t.dirty]),errors:Object.freeze(Object.fromEntries(t.fieldErrors)),store:Object.freeze(Object.fromEntries(t.store)),submitCount:t.submitCount,touched:Object.freeze([...t.touched])})}function i(n){t.ensureNotDisposed();for(let e of t.runCtrls)e.abort();for(let e of t.fieldCtrls.values())e.abort();t.runCtrls.clear(),t.fieldCtrls.clear(),t.validatingRuns.clear(),t.store.clear(),t.baseline.clear(),t.fieldErrors.clear(),t.touched.clear(),t.dirty.clear();for(let[r,i]of Object.entries(n.store))e.isSafeKey(r)&&t.store.set(r,i);for(let[r,i]of Object.entries(n.baseline))e.isSafeKey(r)&&t.baseline.set(r,i);for(let[r,i]of Object.entries(n.errors))e.isSafeKey(r)&&t.fieldErrors.set(r,i);for(let r of n.touched)e.isSafeKey(r)&&t.touched.add(r);for(let r of n.dirty)e.isSafeKey(r)&&t.dirty.add(r);t.submitCount=n.submitCount,t.invalidateErrors(),t.invalidateValues(),t.requestNotify()}return{dispose:n,restore:i,snapshot:r}}exports.createLifecycleOps=t;
2
+ //# sourceMappingURL=lifecycle.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.cjs","names":[],"sources":["../../src/core/lifecycle.ts"],"sourcesContent":["import type { FormSnapshot } from '../types';\nimport type { FormContext } from './context';\n\nimport { isSafeKey } from '../_utils';\n\n/**\n * Lifecycle operations: `dispose`, `snapshot`, `restore`. Moved verbatim from `createForm()`'s\n * \"Lifecycle: dispose\" and \"Snapshot / Restore\" sections.\n */\nexport function createLifecycleOps<TValues extends Record<string, unknown>>(ctx: FormContext<TValues>) {\n function dispose(): void {\n ctx.disposed = true;\n ctx.disposeController.abort();\n\n for (const ctrl of ctx.fieldCtrls.values()) ctrl.abort();\n\n ctx.fieldCtrls.clear();\n ctx.runCtrls.clear();\n ctx.arrayCache.clear();\n ctx.scopeCache.clear();\n\n for (const sub of ctx.rippleSubs) sub.dispose();\n\n ctx.rippleSubs.clear();\n ctx.fieldSignals.clear();\n }\n\n function snapshot(): FormSnapshot<TValues> {\n ctx.ensureNotDisposed();\n\n // Cast is irreducible: baseline/store are typed Partial<Record<FlatKeyOf<TValues>, unknown>>, a\n // TValues-dependent mapped type TS cannot verify a plain Object.fromEntries() result against for\n // a generic TValues param -- no runtime behavior is affected, only static verification.\n return Object.freeze({\n baseline: Object.freeze(Object.fromEntries(ctx.baseline)),\n dirty: Object.freeze([...ctx.dirty]),\n errors: Object.freeze(Object.fromEntries(ctx.fieldErrors)),\n store: Object.freeze(Object.fromEntries(ctx.store)),\n submitCount: ctx.submitCount,\n touched: Object.freeze([...ctx.touched]),\n }) as FormSnapshot<TValues>;\n }\n\n function restore(snap: FormSnapshot<TValues>): void {\n ctx.ensureNotDisposed();\n\n for (const ctrl of ctx.runCtrls) ctrl.abort();\n for (const ctrl of ctx.fieldCtrls.values()) ctrl.abort();\n\n ctx.runCtrls.clear();\n ctx.fieldCtrls.clear();\n ctx.validatingRuns.clear();\n ctx.store.clear();\n ctx.baseline.clear();\n ctx.fieldErrors.clear();\n ctx.touched.clear();\n ctx.dirty.clear();\n\n // Security: snap may be an externally-sourced blob (e.g. JSON.parse'd persisted state).\n // Unlike patch()/replace(), restore() writes flat keys directly into the internal Maps —\n // it must apply the same silent-drop defense-in-depth as flattenValues() does for those.\n for (const [k, v] of Object.entries(snap.store)) if (isSafeKey(k)) ctx.store.set(k, v);\n for (const [k, v] of Object.entries(snap.baseline)) if (isSafeKey(k)) ctx.baseline.set(k, v);\n for (const [k, v] of Object.entries(snap.errors)) if (isSafeKey(k)) ctx.fieldErrors.set(k, v);\n for (const t of snap.touched) if (isSafeKey(t)) ctx.touched.add(t);\n for (const d of snap.dirty) if (isSafeKey(d)) ctx.dirty.add(d);\n\n ctx.submitCount = snap.submitCount;\n\n ctx.invalidateErrors();\n ctx.invalidateValues();\n ctx.requestNotify();\n }\n\n return { dispose, restore, snapshot };\n}\n\nexport type LifecycleOps<TValues extends Record<string, unknown>> = ReturnType<typeof createLifecycleOps<TValues>>;\n"],"mappings":"iCASA,SAAgB,EAA4D,EAA2B,CACrG,SAAS,GAAgB,CACvB,EAAI,SAAW,GACf,EAAI,kBAAkB,MAAM,EAE5B,IAAK,IAAM,KAAQ,EAAI,WAAW,OAAO,EAAG,EAAK,MAAM,EAEvD,EAAI,WAAW,MAAM,EACrB,EAAI,SAAS,MAAM,EACnB,EAAI,WAAW,MAAM,EACrB,EAAI,WAAW,MAAM,EAErB,IAAK,IAAM,KAAO,EAAI,WAAY,EAAI,QAAQ,EAE9C,EAAI,WAAW,MAAM,EACrB,EAAI,aAAa,MAAM,CACzB,CAEA,SAAS,GAAkC,CAMzC,OALA,EAAI,kBAAkB,EAKf,OAAO,OAAO,CACnB,SAAU,OAAO,OAAO,OAAO,YAAY,EAAI,QAAQ,CAAC,EACxD,MAAO,OAAO,OAAO,CAAC,GAAG,EAAI,KAAK,CAAC,EACnC,OAAQ,OAAO,OAAO,OAAO,YAAY,EAAI,WAAW,CAAC,EACzD,MAAO,OAAO,OAAO,OAAO,YAAY,EAAI,KAAK,CAAC,EAClD,YAAa,EAAI,YACjB,QAAS,OAAO,OAAO,CAAC,GAAG,EAAI,OAAO,CAAC,CACzC,CAAC,CACH,CAEA,SAAS,EAAQ,EAAmC,CAClD,EAAI,kBAAkB,EAEtB,IAAK,IAAM,KAAQ,EAAI,SAAU,EAAK,MAAM,EAC5C,IAAK,IAAM,KAAQ,EAAI,WAAW,OAAO,EAAG,EAAK,MAAM,EAEvD,EAAI,SAAS,MAAM,EACnB,EAAI,WAAW,MAAM,EACrB,EAAI,eAAe,MAAM,EACzB,EAAI,MAAM,MAAM,EAChB,EAAI,SAAS,MAAM,EACnB,EAAI,YAAY,MAAM,EACtB,EAAI,QAAQ,MAAM,EAClB,EAAI,MAAM,MAAM,EAKhB,IAAK,GAAM,CAAC,EAAG,KAAM,OAAO,QAAQ,EAAK,KAAK,EAAO,EAAA,UAAU,CAAC,GAAG,EAAI,MAAM,IAAI,EAAG,CAAC,EACrF,IAAK,GAAM,CAAC,EAAG,KAAM,OAAO,QAAQ,EAAK,QAAQ,EAAO,EAAA,UAAU,CAAC,GAAG,EAAI,SAAS,IAAI,EAAG,CAAC,EAC3F,IAAK,GAAM,CAAC,EAAG,KAAM,OAAO,QAAQ,EAAK,MAAM,EAAO,EAAA,UAAU,CAAC,GAAG,EAAI,YAAY,IAAI,EAAG,CAAC,EAC5F,IAAK,IAAM,KAAK,EAAK,QAAa,EAAA,UAAU,CAAC,GAAG,EAAI,QAAQ,IAAI,CAAC,EACjE,IAAK,IAAM,KAAK,EAAK,MAAW,EAAA,UAAU,CAAC,GAAG,EAAI,MAAM,IAAI,CAAC,EAE7D,EAAI,YAAc,EAAK,YAEvB,EAAI,iBAAiB,EACrB,EAAI,iBAAiB,EACrB,EAAI,cAAc,CACpB,CAEA,MAAO,CAAE,UAAS,UAAS,UAAS,CACtC"}
@@ -0,0 +1,13 @@
1
+ import type { FormSnapshot } from '../types';
2
+ import type { FormContext } from './context';
3
+ /**
4
+ * Lifecycle operations: `dispose`, `snapshot`, `restore`. Moved verbatim from `createForm()`'s
5
+ * "Lifecycle: dispose" and "Snapshot / Restore" sections.
6
+ */
7
+ export declare function createLifecycleOps<TValues extends Record<string, unknown>>(ctx: FormContext<TValues>): {
8
+ dispose: () => void;
9
+ restore: (snap: FormSnapshot<TValues>) => void;
10
+ snapshot: () => FormSnapshot<TValues>;
11
+ };
12
+ export type LifecycleOps<TValues extends Record<string, unknown>> = ReturnType<typeof createLifecycleOps<TValues>>;
13
+ //# sourceMappingURL=lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/core/lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAI7C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC;mBAC/E,IAAI;oBAiCD,YAAY,CAAC,OAAO,CAAC,KAAG,IAAI;oBAhB9B,YAAY,CAAC,OAAO,CAAC;EAgD3C;AAED,MAAM,MAAM,YAAY,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,UAAU,CAAC,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { isSafeKey as e } from "../_utils.js";
2
+ //#region src/core/lifecycle.ts
3
+ function t(t) {
4
+ function n() {
5
+ t.disposed = !0, t.disposeController.abort();
6
+ for (let e of t.fieldCtrls.values()) e.abort();
7
+ t.fieldCtrls.clear(), t.runCtrls.clear(), t.arrayCache.clear(), t.scopeCache.clear();
8
+ for (let e of t.rippleSubs) e.dispose();
9
+ t.rippleSubs.clear(), t.fieldSignals.clear();
10
+ }
11
+ function r() {
12
+ return t.ensureNotDisposed(), Object.freeze({
13
+ baseline: Object.freeze(Object.fromEntries(t.baseline)),
14
+ dirty: Object.freeze([...t.dirty]),
15
+ errors: Object.freeze(Object.fromEntries(t.fieldErrors)),
16
+ store: Object.freeze(Object.fromEntries(t.store)),
17
+ submitCount: t.submitCount,
18
+ touched: Object.freeze([...t.touched])
19
+ });
20
+ }
21
+ function i(n) {
22
+ t.ensureNotDisposed();
23
+ for (let e of t.runCtrls) e.abort();
24
+ for (let e of t.fieldCtrls.values()) e.abort();
25
+ t.runCtrls.clear(), t.fieldCtrls.clear(), t.validatingRuns.clear(), t.store.clear(), t.baseline.clear(), t.fieldErrors.clear(), t.touched.clear(), t.dirty.clear();
26
+ for (let [r, i] of Object.entries(n.store)) e(r) && t.store.set(r, i);
27
+ for (let [r, i] of Object.entries(n.baseline)) e(r) && t.baseline.set(r, i);
28
+ for (let [r, i] of Object.entries(n.errors)) e(r) && t.fieldErrors.set(r, i);
29
+ for (let r of n.touched) e(r) && t.touched.add(r);
30
+ for (let r of n.dirty) e(r) && t.dirty.add(r);
31
+ t.submitCount = n.submitCount, t.invalidateErrors(), t.invalidateValues(), t.requestNotify();
32
+ }
33
+ return {
34
+ dispose: n,
35
+ restore: i,
36
+ snapshot: r
37
+ };
38
+ }
39
+ //#endregion
40
+ export { t as createLifecycleOps };
41
+
42
+ //# sourceMappingURL=lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lifecycle.js","names":[],"sources":["../../src/core/lifecycle.ts"],"sourcesContent":["import type { FormSnapshot } from '../types';\nimport type { FormContext } from './context';\n\nimport { isSafeKey } from '../_utils';\n\n/**\n * Lifecycle operations: `dispose`, `snapshot`, `restore`. Moved verbatim from `createForm()`'s\n * \"Lifecycle: dispose\" and \"Snapshot / Restore\" sections.\n */\nexport function createLifecycleOps<TValues extends Record<string, unknown>>(ctx: FormContext<TValues>) {\n function dispose(): void {\n ctx.disposed = true;\n ctx.disposeController.abort();\n\n for (const ctrl of ctx.fieldCtrls.values()) ctrl.abort();\n\n ctx.fieldCtrls.clear();\n ctx.runCtrls.clear();\n ctx.arrayCache.clear();\n ctx.scopeCache.clear();\n\n for (const sub of ctx.rippleSubs) sub.dispose();\n\n ctx.rippleSubs.clear();\n ctx.fieldSignals.clear();\n }\n\n function snapshot(): FormSnapshot<TValues> {\n ctx.ensureNotDisposed();\n\n // Cast is irreducible: baseline/store are typed Partial<Record<FlatKeyOf<TValues>, unknown>>, a\n // TValues-dependent mapped type TS cannot verify a plain Object.fromEntries() result against for\n // a generic TValues param -- no runtime behavior is affected, only static verification.\n return Object.freeze({\n baseline: Object.freeze(Object.fromEntries(ctx.baseline)),\n dirty: Object.freeze([...ctx.dirty]),\n errors: Object.freeze(Object.fromEntries(ctx.fieldErrors)),\n store: Object.freeze(Object.fromEntries(ctx.store)),\n submitCount: ctx.submitCount,\n touched: Object.freeze([...ctx.touched]),\n }) as FormSnapshot<TValues>;\n }\n\n function restore(snap: FormSnapshot<TValues>): void {\n ctx.ensureNotDisposed();\n\n for (const ctrl of ctx.runCtrls) ctrl.abort();\n for (const ctrl of ctx.fieldCtrls.values()) ctrl.abort();\n\n ctx.runCtrls.clear();\n ctx.fieldCtrls.clear();\n ctx.validatingRuns.clear();\n ctx.store.clear();\n ctx.baseline.clear();\n ctx.fieldErrors.clear();\n ctx.touched.clear();\n ctx.dirty.clear();\n\n // Security: snap may be an externally-sourced blob (e.g. JSON.parse'd persisted state).\n // Unlike patch()/replace(), restore() writes flat keys directly into the internal Maps —\n // it must apply the same silent-drop defense-in-depth as flattenValues() does for those.\n for (const [k, v] of Object.entries(snap.store)) if (isSafeKey(k)) ctx.store.set(k, v);\n for (const [k, v] of Object.entries(snap.baseline)) if (isSafeKey(k)) ctx.baseline.set(k, v);\n for (const [k, v] of Object.entries(snap.errors)) if (isSafeKey(k)) ctx.fieldErrors.set(k, v);\n for (const t of snap.touched) if (isSafeKey(t)) ctx.touched.add(t);\n for (const d of snap.dirty) if (isSafeKey(d)) ctx.dirty.add(d);\n\n ctx.submitCount = snap.submitCount;\n\n ctx.invalidateErrors();\n ctx.invalidateValues();\n ctx.requestNotify();\n }\n\n return { dispose, restore, snapshot };\n}\n\nexport type LifecycleOps<TValues extends Record<string, unknown>> = ReturnType<typeof createLifecycleOps<TValues>>;\n"],"mappings":";;AASA,SAAgB,EAA4D,GAA2B;CACrG,SAAS,IAAgB;EAEvB,AADA,EAAI,WAAW,IACf,EAAI,kBAAkB,MAAM;EAE5B,KAAK,IAAM,KAAQ,EAAI,WAAW,OAAO,GAAG,EAAK,MAAM;EAKvD,AAHA,EAAI,WAAW,MAAM,GACrB,EAAI,SAAS,MAAM,GACnB,EAAI,WAAW,MAAM,GACrB,EAAI,WAAW,MAAM;EAErB,KAAK,IAAM,KAAO,EAAI,YAAY,EAAI,QAAQ;EAG9C,AADA,EAAI,WAAW,MAAM,GACrB,EAAI,aAAa,MAAM;CACzB;CAEA,SAAS,IAAkC;EAMzC,OALA,EAAI,kBAAkB,GAKf,OAAO,OAAO;GACnB,UAAU,OAAO,OAAO,OAAO,YAAY,EAAI,QAAQ,CAAC;GACxD,OAAO,OAAO,OAAO,CAAC,GAAG,EAAI,KAAK,CAAC;GACnC,QAAQ,OAAO,OAAO,OAAO,YAAY,EAAI,WAAW,CAAC;GACzD,OAAO,OAAO,OAAO,OAAO,YAAY,EAAI,KAAK,CAAC;GAClD,aAAa,EAAI;GACjB,SAAS,OAAO,OAAO,CAAC,GAAG,EAAI,OAAO,CAAC;EACzC,CAAC;CACH;CAEA,SAAS,EAAQ,GAAmC;EAClD,EAAI,kBAAkB;EAEtB,KAAK,IAAM,KAAQ,EAAI,UAAU,EAAK,MAAM;EAC5C,KAAK,IAAM,KAAQ,EAAI,WAAW,OAAO,GAAG,EAAK,MAAM;EASvD,AAPA,EAAI,SAAS,MAAM,GACnB,EAAI,WAAW,MAAM,GACrB,EAAI,eAAe,MAAM,GACzB,EAAI,MAAM,MAAM,GAChB,EAAI,SAAS,MAAM,GACnB,EAAI,YAAY,MAAM,GACtB,EAAI,QAAQ,MAAM,GAClB,EAAI,MAAM,MAAM;EAKhB,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,EAAK,KAAK,GAAG,AAAI,EAAU,CAAC,KAAG,EAAI,MAAM,IAAI,GAAG,CAAC;EACrF,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,EAAK,QAAQ,GAAG,AAAI,EAAU,CAAC,KAAG,EAAI,SAAS,IAAI,GAAG,CAAC;EAC3F,KAAK,IAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,EAAK,MAAM,GAAG,AAAI,EAAU,CAAC,KAAG,EAAI,YAAY,IAAI,GAAG,CAAC;EAC5F,KAAK,IAAM,KAAK,EAAK,SAAS,AAAI,EAAU,CAAC,KAAG,EAAI,QAAQ,IAAI,CAAC;EACjE,KAAK,IAAM,KAAK,EAAK,OAAO,AAAI,EAAU,CAAC,KAAG,EAAI,MAAM,IAAI,CAAC;EAM7D,AAJA,EAAI,cAAc,EAAK,aAEvB,EAAI,iBAAiB,GACrB,EAAI,iBAAiB,GACrB,EAAI,cAAc;CACpB;CAEA,OAAO;EAAE;EAAS;EAAS;CAAS;AACtC"}
@@ -0,0 +1,2 @@
1
+ const e=require("../_utils.cjs"),t=require("./asyncQueue.cjs");let n=require("@vielzeug/arsenal"),r=require("@vielzeug/ripple");function i(i,a){function o(e,t){if(i.disposed)return()=>{};let n=(0,r.watch)(i.formStateSignal,t=>{e(t)});return i.rippleSubs.add(n),t?.sync&&e(i.formStateSignal.value),()=>{n.dispose(),i.rippleSubs.delete(n)}}function s(t,n,a){if(i.disposed)return()=>{};let o=t;e.assertSafeKey(o);let s=i.getOrCreateFieldSignal(o),c=(0,r.watch)(s,e=>{n(e)});return i.rippleSubs.add(c),a?.sync&&n(s.value),()=>{c.dispose(),i.rippleSubs.delete(c)}}function c(t,r){i.ensureNotDisposed();let o=t;e.assertSafeKey(o);let s=r?.touchOnBlur??i.connectDefaults.touchOnBlur??!1,c=r?.validateOnBlur??i.connectDefaults.validateOnBlur??!1,l=r?.validateOnChange??i.connectDefaults.validateOnChange??!1,u=r?.validateOnTouch??i.connectDefaults.validateOnTouch??!1,d=r?.debounce??i.connectDefaults.debounce??0,f=null;function p(){d>0?(f!==null&&clearTimeout(f),f=setTimeout(()=>{f=null,!i.disposed&&a.validateFields([t]).catch(e=>{if(!(0,n.isAbortError)(e))throw e})},d)):a.validateFields([t]).catch(e=>{if(!(0,n.isAbortError)(e))throw e})}let m=!1;return{get dirty(){return i.dirty.has(o)},dispose(){m=!0,f!==null&&(clearTimeout(f),f=null)},get disposed(){return m},get error(){return i.fieldErrors.get(o)},onBlur:()=>{i.disposed||(s&&a.touch(t),c&&p())},onChange:e=>{i.disposed||(a.set(t,e),(l||u&&i.touched.has(o))&&p())},[Symbol.dispose](){this.dispose()},get touched(){return i.touched.has(o)},get value(){return i.store.get(o)}}}function l(){let e=t.createAsyncQueue(()=>n());e.push(i.getStateSnapshot());let n=o(t=>{e.push(t)});return i.disposeController.signal.addEventListener(`abort`,()=>e.terminate(),{once:!0}),e.iterator}return{connect:c,subscribe:o,subscribeField:s,[Symbol.asyncIterator]:l}}exports.createObserveOps=i;
2
+ //# sourceMappingURL=observe.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.cjs","names":[],"sources":["../../src/core/observe.ts"],"sourcesContent":["import { isAbortError } from '@vielzeug/arsenal';\nimport { watch } from '@vielzeug/ripple';\n\nimport type { FormContext } from './context';\nimport type { ValidationOps } from './validation';\nimport type { ValueOps } from './values';\n\nimport { assertSafeKey } from '../_utils';\nimport {\n type ConnectionResult,\n type ConnectOptions,\n type FieldState,\n type FlatKeyOf,\n type FormState,\n type SubscribeOptions,\n type TypeAtPath,\n type Unsubscribe,\n} from '../types';\nimport { createAsyncQueue } from './asyncQueue';\n\ntype ObserveDeps<TValues extends Record<string, unknown>> = Pick<ValueOps<TValues>, 'set' | 'touch'> &\n Pick<ValidationOps<TValues>, 'validateFields'>;\n\n/**\n * Observation operations: `subscribe`/`subscribeField`, `connect` (per-binding debounce timer),\n * and the `[Symbol.asyncIterator]` implementation. Moved verbatim from `createForm()`'s\n * \"Subscriptions\", \"Connect\", and \"Async iterator\" sections.\n */\nexport function createObserveOps<TValues extends Record<string, unknown>>(\n ctx: FormContext<TValues>,\n deps: ObserveDeps<TValues>,\n) {\n function subscribe(listener: (state: FormState) => void, options?: SubscribeOptions): Unsubscribe {\n if (ctx.disposed) return () => {};\n\n // Wrap listener so it always returns void — ripple watch throws on non-function returns.\n const sub = watch(ctx.formStateSignal, (state) => {\n listener(state);\n });\n\n ctx.rippleSubs.add(sub);\n\n if (options?.sync) listener(ctx.formStateSignal.value);\n\n return () => {\n sub.dispose();\n ctx.rippleSubs.delete(sub);\n };\n }\n\n function subscribeField<K extends FlatKeyOf<TValues>>(\n name: K,\n listener: (state: FieldState<TypeAtPath<TValues, K>>) => void,\n options?: SubscribeOptions,\n ): Unsubscribe {\n if (ctx.disposed) return () => {};\n\n const key = name as string;\n\n assertSafeKey(key);\n\n const sig = ctx.getOrCreateFieldSignal(key);\n // Wrap listener so it always returns void — ripple watch throws on non-function returns.\n const sub = watch(sig, (state) => {\n (listener as (state: FieldState<unknown>) => void)(state);\n });\n\n ctx.rippleSubs.add(sub);\n\n if (options?.sync) listener(sig.value as FieldState<TypeAtPath<TValues, K>>);\n\n return () => {\n sub.dispose();\n ctx.rippleSubs.delete(sub);\n };\n }\n\n /* ======== R5: Connect — per-binding debounce timer ======== */\n\n function connect<K extends FlatKeyOf<TValues>>(\n name: K,\n config?: ConnectOptions,\n ): ConnectionResult<TypeAtPath<TValues, K>> {\n ctx.ensureNotDisposed();\n\n const key = name as string;\n\n assertSafeKey(key);\n\n const touchOnBlur = config?.touchOnBlur ?? ctx.connectDefaults.touchOnBlur ?? false;\n const validateOnBlur = config?.validateOnBlur ?? ctx.connectDefaults.validateOnBlur ?? false;\n const validateOnChange = config?.validateOnChange ?? ctx.connectDefaults.validateOnChange ?? false;\n const validateOnTouch = config?.validateOnTouch ?? ctx.connectDefaults.validateOnTouch ?? false;\n const debounceMs = config?.debounce ?? ctx.connectDefaults.debounce ?? 0;\n\n // R5: each connect() call owns its own timer — cancelling one binding never affects another.\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n function scheduleValidation(): void {\n if (debounceMs > 0) {\n if (debounceTimer !== null) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n\n if (ctx.disposed) return;\n\n void deps.validateFields([name]).catch((err: unknown) => {\n if (!isAbortError(err)) throw err;\n });\n }, debounceMs);\n } else {\n void deps.validateFields([name]).catch((err: unknown) => {\n if (!isAbortError(err)) throw err;\n });\n }\n }\n\n let bindingDisposed = false;\n\n return {\n get dirty() {\n return ctx.dirty.has(key);\n },\n /** Cancels this binding's own debounce timer. Does not affect other bindings for the same field. */\n dispose() {\n bindingDisposed = true;\n\n if (debounceTimer !== null) {\n clearTimeout(debounceTimer);\n debounceTimer = null;\n }\n },\n get disposed() {\n return bindingDisposed;\n },\n get error() {\n return ctx.fieldErrors.get(key);\n },\n onBlur: () => {\n if (ctx.disposed) return;\n\n if (touchOnBlur) deps.touch(name);\n\n if (validateOnBlur) scheduleValidation();\n },\n onChange: (value: TypeAtPath<TValues, K>) => {\n if (ctx.disposed) return;\n\n deps.set(name, value);\n\n const shouldValidate = validateOnChange || (validateOnTouch && ctx.touched.has(key));\n\n if (shouldValidate) scheduleValidation();\n },\n [Symbol.dispose]() {\n this.dispose();\n },\n get touched() {\n return ctx.touched.has(key);\n },\n get value() {\n return ctx.store.get(key) as TypeAtPath<TValues, K>;\n },\n };\n }\n\n /* ======== Async iterator (for await...of form) ======== */\n\n function createAsyncIterator(): AsyncIterableIterator<FormState> {\n const queue = createAsyncQueue<FormState>(() => unsubscribe());\n\n queue.push(ctx.getStateSnapshot());\n\n const unsubscribe = subscribe((state) => {\n queue.push(state);\n });\n\n ctx.disposeController.signal.addEventListener('abort', () => queue.terminate(), { once: true });\n\n return queue.iterator;\n }\n\n return { connect, subscribe, subscribeField, [Symbol.asyncIterator]: createAsyncIterator };\n}\n"],"mappings":"gIA4BA,SAAgB,EACd,EACA,EACA,CACA,SAAS,EAAU,EAAsC,EAAyC,CAChG,GAAI,EAAI,SAAU,UAAa,CAAC,EAGhC,IAAM,GAAA,EAAA,EAAA,MAAA,CAAY,EAAI,gBAAkB,GAAU,CAChD,EAAS,CAAK,CAChB,CAAC,EAMD,OAJA,EAAI,WAAW,IAAI,CAAG,EAElB,GAAS,MAAM,EAAS,EAAI,gBAAgB,KAAK,MAExC,CACX,EAAI,QAAQ,EACZ,EAAI,WAAW,OAAO,CAAG,CAC3B,CACF,CAEA,SAAS,EACP,EACA,EACA,EACa,CACb,GAAI,EAAI,SAAU,UAAa,CAAC,EAEhC,IAAM,EAAM,EAEZ,EAAA,cAAc,CAAG,EAEjB,IAAM,EAAM,EAAI,uBAAuB,CAAG,EAEpC,GAAA,EAAA,EAAA,MAAA,CAAY,EAAM,GAAU,CAChC,EAAmD,CAAK,CAC1D,CAAC,EAMD,OAJA,EAAI,WAAW,IAAI,CAAG,EAElB,GAAS,MAAM,EAAS,EAAI,KAA2C,MAE9D,CACX,EAAI,QAAQ,EACZ,EAAI,WAAW,OAAO,CAAG,CAC3B,CACF,CAIA,SAAS,EACP,EACA,EAC0C,CAC1C,EAAI,kBAAkB,EAEtB,IAAM,EAAM,EAEZ,EAAA,cAAc,CAAG,EAEjB,IAAM,EAAc,GAAQ,aAAe,EAAI,gBAAgB,aAAe,GACxE,EAAiB,GAAQ,gBAAkB,EAAI,gBAAgB,gBAAkB,GACjF,EAAmB,GAAQ,kBAAoB,EAAI,gBAAgB,kBAAoB,GACvF,EAAkB,GAAQ,iBAAmB,EAAI,gBAAgB,iBAAmB,GACpF,EAAa,GAAQ,UAAY,EAAI,gBAAgB,UAAY,EAGnE,EAAsD,KAE1D,SAAS,GAA2B,CAC9B,EAAa,GACX,IAAkB,MAAM,aAAa,CAAa,EAEtD,EAAgB,eAAiB,CAC/B,EAAgB,KAEZ,GAAI,UAER,EAAU,eAAe,CAAC,CAAI,CAAC,CAAC,CAAC,MAAO,GAAiB,CACvD,GAAI,EAAA,EAAA,EAAA,aAAA,CAAc,CAAG,EAAG,MAAM,CAChC,CAAC,CACH,EAAG,CAAU,GAEb,EAAU,eAAe,CAAC,CAAI,CAAC,CAAC,CAAC,MAAO,GAAiB,CACvD,GAAI,EAAA,EAAA,EAAA,aAAA,CAAc,CAAG,EAAG,MAAM,CAChC,CAAC,CAEL,CAEA,IAAI,EAAkB,GAEtB,MAAO,CACL,IAAI,OAAQ,CACV,OAAO,EAAI,MAAM,IAAI,CAAG,CAC1B,EAEA,SAAU,CACR,EAAkB,GAEd,IAAkB,OACpB,aAAa,CAAa,EAC1B,EAAgB,KAEpB,EACA,IAAI,UAAW,CACb,OAAO,CACT,EACA,IAAI,OAAQ,CACV,OAAO,EAAI,YAAY,IAAI,CAAG,CAChC,EACA,WAAc,CACR,EAAI,WAEJ,GAAa,EAAK,MAAM,CAAI,EAE5B,GAAgB,EAAmB,EACzC,EACA,SAAW,GAAkC,CACvC,EAAI,WAER,EAAK,IAAI,EAAM,CAAK,GAEG,GAAqB,GAAmB,EAAI,QAAQ,IAAI,CAAG,IAE9D,EAAmB,EACzC,EACA,CAAC,OAAO,UAAW,CACjB,KAAK,QAAQ,CACf,EACA,IAAI,SAAU,CACZ,OAAO,EAAI,QAAQ,IAAI,CAAG,CAC5B,EACA,IAAI,OAAQ,CACV,OAAO,EAAI,MAAM,IAAI,CAAG,CAC1B,CACF,CACF,CAIA,SAAS,GAAwD,CAC/D,IAAM,EAAQ,EAAA,qBAAkC,EAAY,CAAC,EAE7D,EAAM,KAAK,EAAI,iBAAiB,CAAC,EAEjC,IAAM,EAAc,EAAW,GAAU,CACvC,EAAM,KAAK,CAAK,CAClB,CAAC,EAID,OAFA,EAAI,kBAAkB,OAAO,iBAAiB,YAAe,EAAM,UAAU,EAAG,CAAE,KAAM,EAAK,CAAC,EAEvF,EAAM,QACf,CAEA,MAAO,CAAE,UAAS,YAAW,kBAAiB,OAAO,eAAgB,CAAoB,CAC3F"}
@@ -0,0 +1,18 @@
1
+ import type { FormContext } from './context';
2
+ import type { ValidationOps } from './validation';
3
+ import type { ValueOps } from './values';
4
+ import { type ConnectionResult, type ConnectOptions, type FieldState, type FlatKeyOf, type FormState, type SubscribeOptions, type TypeAtPath, type Unsubscribe } from '../types';
5
+ type ObserveDeps<TValues extends Record<string, unknown>> = Pick<ValueOps<TValues>, 'set' | 'touch'> & Pick<ValidationOps<TValues>, 'validateFields'>;
6
+ /**
7
+ * Observation operations: `subscribe`/`subscribeField`, `connect` (per-binding debounce timer),
8
+ * and the `[Symbol.asyncIterator]` implementation. Moved verbatim from `createForm()`'s
9
+ * "Subscriptions", "Connect", and "Async iterator" sections.
10
+ */
11
+ export declare function createObserveOps<TValues extends Record<string, unknown>>(ctx: FormContext<TValues>, deps: ObserveDeps<TValues>): {
12
+ connect: <K extends FlatKeyOf<TValues>>(name: K, config?: ConnectOptions) => ConnectionResult<TypeAtPath<TValues, K>>;
13
+ subscribe: (listener: (state: FormState) => void, options?: SubscribeOptions) => Unsubscribe;
14
+ subscribeField: <K extends FlatKeyOf<TValues>>(name: K, listener: (state: FieldState<TypeAtPath<TValues, K>>) => void, options?: SubscribeOptions) => Unsubscribe;
15
+ [Symbol.asyncIterator]: () => AsyncIterableIterator<FormState>;
16
+ };
17
+ export {};
18
+ //# sourceMappingURL=observe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.d.ts","sourceRoot":"","sources":["../../src/core/observe.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGzC,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,WAAW,EACjB,MAAM,UAAU,CAAC;AAGlB,KAAK,WAAW,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,GAClG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC;AAEjD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtE,GAAG,EAAE,WAAW,CAAC,OAAO,CAAC,EACzB,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC;cAiDT,CAAC,SAAS,SAAS,CAAC,OAAO,CAAC,QACrC,CAAC,WACE,cAAc,KACtB,gBAAgB,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;0BAlDd,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,YAAY,gBAAgB,KAAG,WAAW;qBAkBzE,CAAC,SAAS,SAAS,CAAC,OAAO,CAAC,QAC5C,CAAC,YACG,CAAC,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,YACnD,gBAAgB,KACzB,WAAW;kCAmHkB,qBAAqB,CAAC,SAAS,CAAC;EAejE"}
@@ -0,0 +1,90 @@
1
+ import { assertSafeKey as e } from "../_utils.js";
2
+ import { createAsyncQueue as t } from "./asyncQueue.js";
3
+ import { isAbortError as n } from "@vielzeug/arsenal";
4
+ import { watch as r } from "@vielzeug/ripple";
5
+ //#region src/core/observe.ts
6
+ function i(i, a) {
7
+ function o(e, t) {
8
+ if (i.disposed) return () => {};
9
+ let n = r(i.formStateSignal, (t) => {
10
+ e(t);
11
+ });
12
+ return i.rippleSubs.add(n), t?.sync && e(i.formStateSignal.value), () => {
13
+ n.dispose(), i.rippleSubs.delete(n);
14
+ };
15
+ }
16
+ function s(t, n, a) {
17
+ if (i.disposed) return () => {};
18
+ let o = t;
19
+ e(o);
20
+ let s = i.getOrCreateFieldSignal(o), c = r(s, (e) => {
21
+ n(e);
22
+ });
23
+ return i.rippleSubs.add(c), a?.sync && n(s.value), () => {
24
+ c.dispose(), i.rippleSubs.delete(c);
25
+ };
26
+ }
27
+ function c(t, r) {
28
+ i.ensureNotDisposed();
29
+ let o = t;
30
+ e(o);
31
+ let s = r?.touchOnBlur ?? i.connectDefaults.touchOnBlur ?? !1, c = r?.validateOnBlur ?? i.connectDefaults.validateOnBlur ?? !1, l = r?.validateOnChange ?? i.connectDefaults.validateOnChange ?? !1, u = r?.validateOnTouch ?? i.connectDefaults.validateOnTouch ?? !1, d = r?.debounce ?? i.connectDefaults.debounce ?? 0, f = null;
32
+ function p() {
33
+ d > 0 ? (f !== null && clearTimeout(f), f = setTimeout(() => {
34
+ f = null, !i.disposed && a.validateFields([t]).catch((e) => {
35
+ if (!n(e)) throw e;
36
+ });
37
+ }, d)) : a.validateFields([t]).catch((e) => {
38
+ if (!n(e)) throw e;
39
+ });
40
+ }
41
+ let m = !1;
42
+ return {
43
+ get dirty() {
44
+ return i.dirty.has(o);
45
+ },
46
+ dispose() {
47
+ m = !0, f !== null && (clearTimeout(f), f = null);
48
+ },
49
+ get disposed() {
50
+ return m;
51
+ },
52
+ get error() {
53
+ return i.fieldErrors.get(o);
54
+ },
55
+ onBlur: () => {
56
+ i.disposed || (s && a.touch(t), c && p());
57
+ },
58
+ onChange: (e) => {
59
+ i.disposed || (a.set(t, e), (l || u && i.touched.has(o)) && p());
60
+ },
61
+ [Symbol.dispose]() {
62
+ this.dispose();
63
+ },
64
+ get touched() {
65
+ return i.touched.has(o);
66
+ },
67
+ get value() {
68
+ return i.store.get(o);
69
+ }
70
+ };
71
+ }
72
+ function l() {
73
+ let e = t(() => n());
74
+ e.push(i.getStateSnapshot());
75
+ let n = o((t) => {
76
+ e.push(t);
77
+ });
78
+ return i.disposeController.signal.addEventListener("abort", () => e.terminate(), { once: !0 }), e.iterator;
79
+ }
80
+ return {
81
+ connect: c,
82
+ subscribe: o,
83
+ subscribeField: s,
84
+ [Symbol.asyncIterator]: l
85
+ };
86
+ }
87
+ //#endregion
88
+ export { i as createObserveOps };
89
+
90
+ //# sourceMappingURL=observe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"observe.js","names":[],"sources":["../../src/core/observe.ts"],"sourcesContent":["import { isAbortError } from '@vielzeug/arsenal';\nimport { watch } from '@vielzeug/ripple';\n\nimport type { FormContext } from './context';\nimport type { ValidationOps } from './validation';\nimport type { ValueOps } from './values';\n\nimport { assertSafeKey } from '../_utils';\nimport {\n type ConnectionResult,\n type ConnectOptions,\n type FieldState,\n type FlatKeyOf,\n type FormState,\n type SubscribeOptions,\n type TypeAtPath,\n type Unsubscribe,\n} from '../types';\nimport { createAsyncQueue } from './asyncQueue';\n\ntype ObserveDeps<TValues extends Record<string, unknown>> = Pick<ValueOps<TValues>, 'set' | 'touch'> &\n Pick<ValidationOps<TValues>, 'validateFields'>;\n\n/**\n * Observation operations: `subscribe`/`subscribeField`, `connect` (per-binding debounce timer),\n * and the `[Symbol.asyncIterator]` implementation. Moved verbatim from `createForm()`'s\n * \"Subscriptions\", \"Connect\", and \"Async iterator\" sections.\n */\nexport function createObserveOps<TValues extends Record<string, unknown>>(\n ctx: FormContext<TValues>,\n deps: ObserveDeps<TValues>,\n) {\n function subscribe(listener: (state: FormState) => void, options?: SubscribeOptions): Unsubscribe {\n if (ctx.disposed) return () => {};\n\n // Wrap listener so it always returns void — ripple watch throws on non-function returns.\n const sub = watch(ctx.formStateSignal, (state) => {\n listener(state);\n });\n\n ctx.rippleSubs.add(sub);\n\n if (options?.sync) listener(ctx.formStateSignal.value);\n\n return () => {\n sub.dispose();\n ctx.rippleSubs.delete(sub);\n };\n }\n\n function subscribeField<K extends FlatKeyOf<TValues>>(\n name: K,\n listener: (state: FieldState<TypeAtPath<TValues, K>>) => void,\n options?: SubscribeOptions,\n ): Unsubscribe {\n if (ctx.disposed) return () => {};\n\n const key = name as string;\n\n assertSafeKey(key);\n\n const sig = ctx.getOrCreateFieldSignal(key);\n // Wrap listener so it always returns void — ripple watch throws on non-function returns.\n const sub = watch(sig, (state) => {\n (listener as (state: FieldState<unknown>) => void)(state);\n });\n\n ctx.rippleSubs.add(sub);\n\n if (options?.sync) listener(sig.value as FieldState<TypeAtPath<TValues, K>>);\n\n return () => {\n sub.dispose();\n ctx.rippleSubs.delete(sub);\n };\n }\n\n /* ======== R5: Connect — per-binding debounce timer ======== */\n\n function connect<K extends FlatKeyOf<TValues>>(\n name: K,\n config?: ConnectOptions,\n ): ConnectionResult<TypeAtPath<TValues, K>> {\n ctx.ensureNotDisposed();\n\n const key = name as string;\n\n assertSafeKey(key);\n\n const touchOnBlur = config?.touchOnBlur ?? ctx.connectDefaults.touchOnBlur ?? false;\n const validateOnBlur = config?.validateOnBlur ?? ctx.connectDefaults.validateOnBlur ?? false;\n const validateOnChange = config?.validateOnChange ?? ctx.connectDefaults.validateOnChange ?? false;\n const validateOnTouch = config?.validateOnTouch ?? ctx.connectDefaults.validateOnTouch ?? false;\n const debounceMs = config?.debounce ?? ctx.connectDefaults.debounce ?? 0;\n\n // R5: each connect() call owns its own timer — cancelling one binding never affects another.\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n function scheduleValidation(): void {\n if (debounceMs > 0) {\n if (debounceTimer !== null) clearTimeout(debounceTimer);\n\n debounceTimer = setTimeout(() => {\n debounceTimer = null;\n\n if (ctx.disposed) return;\n\n void deps.validateFields([name]).catch((err: unknown) => {\n if (!isAbortError(err)) throw err;\n });\n }, debounceMs);\n } else {\n void deps.validateFields([name]).catch((err: unknown) => {\n if (!isAbortError(err)) throw err;\n });\n }\n }\n\n let bindingDisposed = false;\n\n return {\n get dirty() {\n return ctx.dirty.has(key);\n },\n /** Cancels this binding's own debounce timer. Does not affect other bindings for the same field. */\n dispose() {\n bindingDisposed = true;\n\n if (debounceTimer !== null) {\n clearTimeout(debounceTimer);\n debounceTimer = null;\n }\n },\n get disposed() {\n return bindingDisposed;\n },\n get error() {\n return ctx.fieldErrors.get(key);\n },\n onBlur: () => {\n if (ctx.disposed) return;\n\n if (touchOnBlur) deps.touch(name);\n\n if (validateOnBlur) scheduleValidation();\n },\n onChange: (value: TypeAtPath<TValues, K>) => {\n if (ctx.disposed) return;\n\n deps.set(name, value);\n\n const shouldValidate = validateOnChange || (validateOnTouch && ctx.touched.has(key));\n\n if (shouldValidate) scheduleValidation();\n },\n [Symbol.dispose]() {\n this.dispose();\n },\n get touched() {\n return ctx.touched.has(key);\n },\n get value() {\n return ctx.store.get(key) as TypeAtPath<TValues, K>;\n },\n };\n }\n\n /* ======== Async iterator (for await...of form) ======== */\n\n function createAsyncIterator(): AsyncIterableIterator<FormState> {\n const queue = createAsyncQueue<FormState>(() => unsubscribe());\n\n queue.push(ctx.getStateSnapshot());\n\n const unsubscribe = subscribe((state) => {\n queue.push(state);\n });\n\n ctx.disposeController.signal.addEventListener('abort', () => queue.terminate(), { once: true });\n\n return queue.iterator;\n }\n\n return { connect, subscribe, subscribeField, [Symbol.asyncIterator]: createAsyncIterator };\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../errors.cjs");require("../_utils.cjs");let t=require("@vielzeug/arsenal");function n(r,i){let a=`${i}.`;function o(e){return`${i}.${e}`}function s(e){return e===i||e.startsWith(a)}function c(e){return e.startsWith(a)?e.slice(a.length):e}function l(){let e=r.getStateSnapshot(),t=Object.fromEntries(Object.entries(e.errors).filter(([e])=>s(e)).map(([e,t])=>[c(e),t])),n=e.touchedFields.filter(s).map(c),i=e.validatingFields.filter(s).map(c),a=Object.keys(t).length===0,o=[...r.dirty].some(s),l=[...r.touched].some(s),u=i.length>0;return Object.freeze({errors:Object.freeze(t),isDirty:o,isLoading:e.isLoading,isSubmitting:e.isSubmitting,isTouched:l,isValid:a,isValidating:u,submitCount:e.submitCount,touchedFields:Object.freeze(n),validatingFields:Object.freeze(i)})}function u(){let e={};for(let[t,n]of r.store)t.startsWith(a)&&(e[t.slice(a.length)]=n);return(0,t.unflattenPaths)(e)}function d(){let e=new Set;for(let t of r.store.keys())s(t)&&e.add(c(t));for(let t of r.validators.keys())s(t)&&e.add(c(t));return Object.freeze([...e])}function f(){r.ensureNotDisposed();for(let e of r.store.keys())s(e)&&r.touched.add(e);for(let e of r.validators.keys())s(e)&&r.touched.add(e);r.requestNotify()}function p(){r.ensureNotDisposed();for(let e of[...r.touched])s(e)&&r.touched.delete(e);r.requestNotify()}function m(){r.ensureNotDisposed();for(let e of[...r.store.keys()])s(e)&&(r.fieldCtrls.get(e)?.abort(),r.fieldCtrls.delete(e),r.store.set(e,r.baseline.get(e)),r.dirty.delete(e),r.touched.delete(e),r.fieldErrors.delete(e)&&r.invalidateErrors());r.requestNotify()}function h(e){r.ensureNotDisposed();for(let e of[...r.fieldCtrls.keys()])s(e)&&(r.fieldCtrls.get(e)?.abort(),r.fieldCtrls.delete(e));let n=(0,t.flattenPaths)(e);for(let e of[...r.store.keys()])s(e)&&(r.store.delete(e),r.baseline.delete(e),r.dirty.delete(e),r.touched.delete(e),r.fieldErrors.delete(e));r.invalidateErrors();for(let[e,t]of Object.entries(n)){let n=o(e);r.store.set(n,t),r.baseline.set(n,t)}r.requestNotify()}function g(e){r.ensureNotDisposed();let n=(0,t.flattenPaths)(e),i=[];for(let[e,t]of Object.entries(n)){let n=o(e);r.baseline.set(n,t),r.store.set(n,t),r.dirty.delete(n),i.push(n)}r.requestNotify(i)}function _(e){r.ensureNotDisposed();for(let e of[...r.fieldErrors.keys()])s(e)&&r.fieldErrors.delete(e);if(e)for(let[t,n]of Object.entries(e))typeof n==`string`&&r.fieldErrors.set(o(t),n);r.invalidateErrors(),r.requestNotify()}async function v(e,t){if(r.ensureNotDisposed(),e!==void 0&&!Array.isArray(e)&&!(e instanceof AbortSignal)){let n=o(e);await r.runValidationCore([n],`partial`,t);let i=r.fieldErrors.get(n);return{errors:i===void 0?{}:{[e]:i},valid:i===void 0}}if(Array.isArray(e)){let n=e.map(e=>o(e));await r.runValidationCore(n,`partial`,t);let i={};for(let e of n){let t=r.fieldErrors.get(e);t!==void 0&&(i[c(e)]=t)}return{errors:i,valid:Object.keys(i).length===0}}let n=e,i=[...r.validators.keys()].filter(s);await r.runValidationCore(i,`partial`,n);let a={};for(let[e,t]of r.fieldErrors)s(e)&&(a[c(e)]=t);return{errors:a,valid:Object.keys(a).length===0}}async function y(t){if(r.ensureNotDisposed(),r.isSubmitting())throw new e.ForgeSubmitError(`submit() called while a submission is already in progress`);r.root.batch(()=>{r.incrementSubmitCount(),r.setSubmitting(!0),f()});try{let e=[...r.validators.keys()].filter(s);await r.runValidationCore(e,`partial`),r.ensureNotDisposed();let n={};for(let[e,t]of r.fieldErrors)s(e)&&(n[c(e)]=t);return Object.keys(n).length>0?{errors:n,ok:!1,type:`validation`}:{ok:!0,value:await t(u())}}finally{r.setSubmitting(!1),r.isDisposed()||r.requestNotify()}}function b(e,t){let n=null;return r.root.subscribe(()=>{let t=l();if(n){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]);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}n=t,e(t)},t)}return{array:e=>r.root.array(o(e)),batch:e=>r.root.batch(e),clearError:e=>r.root.clearError(o(e)),connect:(e,t)=>r.root.connect(o(e),t),get disposalSignal(){return r.root.disposalSignal},dispose:()=>{},get disposed(){return r.isDisposed()},field:e=>r.root.field(o(e)),fields:{list:d,register:(e,t)=>r.root.fields.register(o(e),t),remove:e=>r.root.fields.remove(o(e)),setValidator:(e,t)=>r.root.fields.setValidator(o(e),t)},get:e=>r.root.get(o(e)),get isLoading(){return r.root.isLoading},get isSubmitting(){return r.root.isSubmitting},patch:g,replace:h,reset:m,resetErrors:_,resetField:e=>r.root.resetField(o(e)),restore:e=>r.root.restore(e),scope:e=>n(r,o(e)),set:(e,t,n)=>r.root.set(o(e),t,n),setError:(e,t)=>r.root.setError(o(e),t),snapshot:()=>r.root.snapshot(),get state(){return l()},submit:y,submitOrThrow:async t=>{let n=await y(t);if(!n.ok)throw new e.ForgeValidationError(n.errors);return n.value},subscribe:(e,t)=>r.root.subscribe(e,t),subscribeField:(e,t,n)=>r.root.subscribeField(o(e),t,n),subscribeScoped:b,[Symbol.asyncIterator]:()=>r.root[Symbol.asyncIterator](),[Symbol.dispose](){this.dispose()},touch:e=>r.root.touch(o(e)),touchAll:f,untouch:e=>r.root.untouch(o(e)),untouchAll:p,validate:v,validateStream(e){let t=r.root.validateStream(e);return{async next(){for(;;){let e=await t.next();if(e.done)return e;if(s(e.value.field))return{done:!1,value:{error:e.value.error,field:c(e.value.field)}}}},return(){return t.return?t.return():Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}}},values:u}}exports.createScopedForm=n;
2
+ //# sourceMappingURL=scope.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.cjs","names":[],"sources":["../../src/core/scope.ts"],"sourcesContent":["import type {\n ArrayField,\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 /* ---- Public scoped form object ---- */\n\n type S = ScopedValues<TValues, P>;\n\n return {\n array: (name) =>\n ctx.root.array(pre(name as string) as FlatKeyOf<TValues>) as ArrayField<\n TypeAtPath<S, typeof name> extends readonly (infer E)[] ? E : unknown\n >,\n batch: (fn) => ctx.root.batch(fn),\n clearError: (name) => ctx.root.clearError(pre(name as string) as ErrorKeyOf<TValues>),\n connect: (name, config?) =>\n ctx.root.connect(pre(name as string) as FlatKeyOf<TValues>, config) as ConnectionResult<\n TypeAtPath<S, typeof name>\n >,\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) =>\n ctx.root.field(pre(name as string) as FlatKeyOf<TValues>) as FieldState<TypeAtPath<S, typeof name>>,\n fields: {\n list: scopedListFields,\n register: (name, options?) =>\n ctx.root.fields.register(\n pre(name as string) as FlatKeyOf<TValues>,\n options as RegisterFieldOptions<TypeAtPath<TValues, FlatKeyOf<TValues>>>,\n ),\n remove: (name) => ctx.root.fields.remove(pre(name as string) as FlatKeyOf<TValues>),\n setValidator: (name, validator?) =>\n ctx.root.fields.setValidator(pre(name as string) as FlatKeyOf<TValues>, validator),\n },\n get: (name) => ctx.root.get(pre(name as string) as FlatKeyOf<TValues>) 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) => ctx.root.resetField(pre(name as string) as FlatKeyOf<TValues>),\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) =>\n ctx.root.set(\n pre(name as string) as FlatKeyOf<TValues>,\n value as TypeAtPath<TValues, FlatKeyOf<TValues>>,\n options,\n ),\n setError: (name, message) => ctx.root.setError(pre(name as string) as ErrorKeyOf<TValues>, 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 ctx.root.subscribeField(\n pre(name as string) as FlatKeyOf<TValues>,\n listener as (state: FieldState<TypeAtPath<TValues, FlatKeyOf<TValues>>>) => void,\n options,\n ),\n subscribeScoped,\n [Symbol.asyncIterator]: () => ctx.root[Symbol.asyncIterator](),\n [Symbol.dispose]() {\n this.dispose();\n },\n touch: (name) => ctx.root.touch(pre(name as string) as FlatKeyOf<TValues>),\n touchAll: scopedTouchAll,\n untouch: (name) => ctx.root.untouch(pre(name as string) as FlatKeyOf<TValues>),\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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"}
@@ -0,0 +1,8 @@
1
+ import type { Form, ScopedValues } from '../types';
2
+ /**
3
+ * Creates a scoped sub-form whose field paths are relative to `pfx`.
4
+ * All simple single-field operations delegate to `ctx.root`.
5
+ * Only prefix-aware bulk operations (submit, validate, replace, reset, etc.) contain custom code.
6
+ */
7
+ export declare function createScopedForm<TValues extends Record<string, unknown>, P extends string>(ctx: ScopeContext<TValues>, pfx: P): Form<ScopedValues<TValues, P>>;
8
+ //# sourceMappingURL=scope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../../src/core/scope.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAOV,IAAI,EAKJ,YAAY,EAOb,MAAM,UAAU,CAAC;AA2ClB;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,EACxF,GAAG,EAAE,YAAY,CAAC,OAAO,CAAC,EAC1B,GAAG,EAAE,CAAC,GACL,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAochC"}