@vielzeug/forge 26.10.14 → 26.10.16

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.
package/dist/forge.js CHANGED
@@ -1,2 +1,568 @@
1
- import{abortable as e,isEqual as t,isPlainObject as n}from"@vielzeug/arsenal";var ForgeError=class extends Error{constructor(e,t){super(e,t),this.name=new.target.name,Object.setPrototypeOf(this,new.target.prototype)}},ForgeDisposedError=class extends ForgeError{constructor(e){super(e?`Cannot call ${e}() on a disposed form`:`Cannot modify a disposed form`)}},ForgeConfigError=class extends ForgeError{},ForgeSubmitError=class extends ForgeError{},ForgeValidationError=class extends ForgeError{},r=new Set([`__proto__`,`constructor`,`prototype`]);function isUnsafeKey(e){return!e||r.has(e)}function assertSafeKey(e){if(isUnsafeKey(e))throw new ForgeConfigError(`Invalid field key '${e}'.`)}function assertArrayIndex(e){if(!Number.isSafeInteger(e)||e<0)throw new ForgeConfigError(`Invalid array index ${e}.`)}function tag(e){return Object.prototype.toString.call(e)}function isBlobLeaf(e){return tag(e)===`[object Blob]`||tag(e)===`[object File]`}function formatValuePath(e){let t=``;for(let n of e)t+=typeof n==`number`?`[${n}]`:t?`.${n}`:n;return t}function pathSuffix(e){return e.length>0?` at '${formatValuePath(e)}'`:``}function invalidValue(e){throw new ForgeConfigError(`Form values must contain only finite JSON primitives, plain objects, arrays, Date, File, or Blob${pathSuffix(e)}.`)}function immutable(e,t=new Set,r=[]){if(e==null||typeof e==`string`||typeof e==`boolean`)return e;if(typeof e==`number`)return Number.isFinite(e)?e:invalidValue(r);if(typeof e!=`object`)return invalidValue(r);let i=e;if(tag(e)===`[object Date]`&&typeof i.getTime==`function`){let e=i.getTime();return Number.isFinite(e)?Object.freeze(new Date(e)):invalidValue(r)}if(isBlobLeaf(e))return e;if(t.has(e))throw new ForgeConfigError(`Form values must not contain circular references${pathSuffix(r)}.`);t.add(e);try{if(Array.isArray(e)){let n=[];for(let i=0;i<e.length;i++){r.push(i);try{if(!Object.hasOwn(e,i))throw new ForgeConfigError(`Form arrays must not contain empty slots${pathSuffix(r)}.`);n.push(immutable(e[i],t,r))}finally{r.pop()}}return Object.freeze(n)}if(!n(e))return invalidValue(r);let i=Object.entries(e).map(([e,n])=>{assertSafeKey(e),r.push(e);try{return[e,immutable(n,t,r)]}finally{r.pop()}});return Object.freeze(Object.fromEntries(i))}finally{t.delete(e)}}function toPlainValues$1(e,t=new WeakSet){if(e==null||typeof e==`string`||typeof e==`boolean`)return e;if(typeof e==`number`)return Number.isFinite(e)?e:void 0;if(typeof e!=`object`)return;let n=e,r=e;if(tag(n)===`[object Date]`&&typeof r.getTime==`function`){let e=r.getTime();return Number.isFinite(e)?new Date(e):void 0}if(isBlobLeaf(n))return e;if(!t.has(n)){t.add(n);try{if(Array.isArray(e)){let n=[];for(let r=0;r<e.length;r++)Object.hasOwn(e,r)&&n.push(toPlainValues$1(e[r],t));return n}let r={};for(let[e,i]of Object.entries(n))isUnsafeKey(e)||(r[e]=toPlainValues$1(i,t));return r}finally{t.delete(n)}}}function readAtPath(e,t){let r=e;for(let e of t)if(typeof e==`number`){if(!Array.isArray(r)||!Number.isSafeInteger(e)||e<0||e>=r.length||!Object.hasOwn(r,e))return;r=r[e]}else{if(!n(r)||!Object.hasOwn(r,e))return;r=r[e]}return r}function hasAtPath(e,t){let r=e;for(let e of t)if(typeof e==`number`){if(!Array.isArray(r)||!Number.isSafeInteger(e)||e<0||e>=r.length||!Object.hasOwn(r,e))return!1;r=r[e]}else{if(!n(r)||!Object.hasOwn(r,e))return!1;r=r[e]}return!0}function writeAtPath(e,t,r,i=[]){let[a,...o]=t;if(typeof a==`number`){if(assertArrayIndex(a),!Array.isArray(e))throw new ForgeConfigError(`Cannot index ${a} because the current value is not an array.`);if(a<0||a>=e.length)throw new ForgeConfigError(`Index ${a} is out of range for array of length ${e.length}.`);if(o.length===0){let t=[...e];return t[a]=immutable(r,new Set,[...i,a]),Object.freeze(t)}let t=[...e];return t[a]=writeAtPath(e[a],o,r,[...i,a]),Object.freeze(t)}if(assertSafeKey(a),!n(e))throw new ForgeConfigError(`Cannot select '${a}' because the current value is not an object.`);if(o.length===0)return Object.freeze({...e,[a]:immutable(r,new Set,[...i,a])});let s=e[a];if(s!==void 0&&!n(s)&&!Array.isArray(s))throw new ForgeConfigError(`Cannot select '${a}' because it is not an object or array.`);let c=s??{};return Object.freeze({...e,[a]:writeAtPath(c,o,r,[...i,a])})}function resetAtPath(e,t,r){let[i,...a]=r;if(typeof i==`number`){if(assertArrayIndex(i),!Array.isArray(e)||!Array.isArray(t)||i>=t.length||i>=e.length)return e;if(a.length===0){let n=[...e];return n[i]=t[i],Object.freeze(n)}let n=[...e];return n[i]=resetAtPath(e[i],t[i],a),Object.freeze(n)}if(!n(e))return e;if(a.length===0){if(Object.hasOwn(t,i))return Object.freeze({...e,[i]:t[i]});let{[i]:n,...r}=e;return Object.freeze(r)}let o=t[i];if(!n(o)&&!Array.isArray(o)){if(Object.hasOwn(t,i))return Object.freeze({...e,[i]:o});let{[i]:n,...r}=e;return Object.freeze(r)}let s=e[i],c=n(s)||Array.isArray(s)?s:{};return Object.freeze({...e,[i]:resetAtPath(c,o,a)})}function writeMeta(e,t,r){let[i,...a]=t;typeof i==`number`&&assertArrayIndex(i);let o=String(i),s={...e};if(a.length===0)r?s[o]=!0:delete s[o];else{let t=writeMeta(n(e[o])?e[o]:{},a,r);Object.keys(t).length===0?delete s[o]:s[o]=t}return Object.freeze(s)}function readMeta(e,t){let r=e;for(let e of t){if(typeof e==`number`&&(!Number.isSafeInteger(e)||e<0))return!1;let t=String(e);if(!n(r)||!Object.hasOwn(r,t))return!1;r=r[t]}return r===!0}function touchAll(e){return Array.isArray(e)?Object.freeze(Object.fromEntries(e.map((e,t)=>[String(t),n(e)||Array.isArray(e)?touchAll(e):!0]))):n(e)?Object.freeze(Object.fromEntries(Object.entries(e).map(([e,t])=>[e,n(t)||Array.isArray(t)?touchAll(t):!0]))):{}}function pathEquals(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(e[n]!==t[n])return!1;return!0}function findIssue(e,t){if(e){for(let n of e)if(pathEquals(n.path,t))return n.message}}function makeFieldState(e,n){let r=readAtPath(e.value,n),i=readAtPath(e.baseline,n);return Object.freeze({dirty:!t(r,i)||hasAtPath(e.value,n)!==hasAtPath(e.baseline,n),error:findIssue(e.issues,n),touched:readMeta(e.touched,n),value:r})}function createField(e,t){return Object.assign({get dirty(){return makeFieldState(t.readState(),e).dirty},get error(){return makeFieldState(t.readState(),e).error},reset(){t.ensureActive(`field().reset`),t.abortValidation(),t.resetValue(e)},set(n){t.ensureActive(`field().set`),t.abortValidation(),t.setValue(e,n)},get state(){return makeFieldState(t.readState(),e)},subscribe(n,r={}){t.ensureActive(`field().subscribe`);let i=makeFieldState(t.readState(),e);r.immediate&&t.invokeListener(()=>n(i));let filtered=t=>{let r=makeFieldState(t,e);(r.value!==i.value||r.error!==i.error||r.touched!==i.touched||r.dirty!==i.dirty)&&(i=r,n(r))};return t.addListener(filtered)},touch(){t.ensureActive(`field().touch`),t.setTouched(e,!0)},get touched(){return makeFieldState(t.readState(),e).touched},get value(){return makeFieldState(t.readState(),e).value}},{field(r){if(typeof r==`number`){assertArrayIndex(r);let n=readAtPath(t.readState().value,e);if(n!==void 0&&!Array.isArray(n))throw new ForgeConfigError(`Cannot index ${r} because the current field value is not an array.`);return createField([...e,r],t)}assertSafeKey(r);let i=readAtPath(t.readState().value,e);if(i!==void 0&&!n(i))throw new ForgeConfigError(`Cannot select '${r}' because the current field value is not an object.`);return createField([...e,r],t)}})}function rethrowAsync(e){queueMicrotask(()=>{throw e})}function createNotifier(e){let t=new Set,n=[],r=!1;function reportError(t){if(!e){rethrowAsync(t);return}try{e(t)}catch(e){rethrowAsync(e)}}let call=e=>{try{e()}catch(e){reportError(e)}};return{add(e){return t.add(e),()=>t.delete(e)},call,clear(){t.clear(),n.length=0},notify(e){if(n.push(e),!r){r=!0;try{for(;n.length>0;){let e=n.shift();for(let n of[...t])t.has(n)&&call(()=>n(e))}}finally{r=!1}}}}}function normalizeIssues(e){if(e!==void 0&&e.length!==0)return Object.freeze(e.map(e=>{if(!e||typeof e.message!=`string`||!Array.isArray(e.path))throw new ForgeConfigError(`Validators must return issues with a string message and array path.`);let t=e.path.map(e=>{if(typeof e==`number`){if(!Number.isSafeInteger(e)||e<0)throw new ForgeConfigError(`Invalid issue path index ${e}.`);return e}if(typeof e==`string`)return assertSafeKey(e),e;throw new ForgeConfigError(`Issue paths may contain only string keys and non-negative integer indexes.`)});return Object.freeze({message:e.message,path:Object.freeze(t)})}))}function makeFormState(e){return Object.freeze({formError:e.issues?.find(e=>e.path.length===0)?.message,hasErrors:(e.issues?.length??0)>0,issues:e.issues,submitCount:e.submitCount,submitting:e.isSubmitting,touched:Object.keys(e.touched).length>0,validating:e.isValidating,validity:e.validity})}function createForm(t){let r=t.normalize,prepare=e=>r?r(e):e,i=immutable(prepare(t.initialValues)),a=createNotifier(t.onSubscriberError),o=new AbortController,s=!1,c=!1,l=[],u,d=0,f,p={baseline:i,isSubmitting:!1,issues:void 0,isValidating:!1,submitCount:0,touched:{},validity:`unknown`,value:i},m=makeFormState(p);function ensureActive(e){if(s)throw new ForgeDisposedError(e)}function write(e){if(l.push(e),!c){c=!0;try{for(;l.length>0;)p=Object.freeze(l.shift()(p)),m=makeFormState(p),a.notify(p)}finally{c=!1}}}function abortValidation(){u?.abort()}let h={abortValidation,addListener:a.add,ensureActive,invokeListener:a.call,readState:()=>p,resetValue(e){write(t=>(d++,f=void 0,{...t,touched:writeMeta(t.touched,e,!1),validity:`unknown`,value:resetAtPath(t.value,t.baseline,e)}))},setTouched(e,t){write(n=>({...n,touched:writeMeta(n.touched,e,t)}))},setValue(e,t){write(n=>{let r=readAtPath(n.value,e),i=typeof t==`function`?t(r):t,a=prepare(i);return d++,f=void 0,{...n,validity:`unknown`,value:writeAtPath(n.value,e,a)}})}};async function validate(n){ensureActive(`validate`),abortValidation();let r=new AbortController,i=n?AbortSignal.any([r.signal,n]):r.signal;if(i.aborted)return Object.freeze({status:`aborted`});let a=p.value,o=d;u=r,f=void 0,write(e=>({...e,isValidating:!0}));try{if(i.aborted||d!==o)return Object.freeze({status:`aborted`});let n=t.validate?await e(Promise.resolve(t.validate(a,i)),i):void 0;if(i.aborted||u!==r||d!==o)return Object.freeze({status:`aborted`});let s=normalizeIssues(n),c=s===void 0?`valid`:`invalid`;return u=void 0,write(e=>({...e,issues:s,isValidating:!1,validity:c})),i.aborted||d!==o||u!==void 0?Object.freeze({status:`aborted`}):(f=c===`valid`?{revision:d,value:a}:void 0,Object.freeze(c===`valid`?{status:`valid`}:{issues:s,status:`invalid`}))}catch(e){if(i.aborted||u!==r)return Object.freeze({status:`aborted`});throw new ForgeValidationError(`Form validation failed.`,{cause:e})}finally{u===r&&(u=void 0,s||write(e=>({...e,isValidating:!1})))}}let g={get disposalSignal(){return o.signal},dispose(){s||(s=!0,l.length=0,f=void 0,o.abort(),abortValidation(),a.clear())},get disposed(){return s},field(e){if(assertSafeKey(e),!n(p.value))throw new ForgeConfigError(`Form value must be an object.`);return createField([e],h)},patch(e){ensureActive(`patch`),abortValidation(),write(t=>{let n=typeof e==`function`?e(t.value):e,r={...t.value,...n};return d++,f=void 0,{...t,issues:void 0,validity:`unknown`,value:immutable(prepare(r))}})},reset(e){ensureActive(`reset`),abortValidation();let t=e===void 0?void 0:immutable(prepare(e));write(e=>{let n=t??e.baseline;return d++,f=void 0,{...e,baseline:n,issues:void 0,touched:{},validity:`unknown`,value:n}})},set(e){ensureActive(`set`),abortValidation(),write(t=>{let n=typeof e==`function`?e(t.value):e;return d++,f=void 0,{...t,issues:void 0,validity:`unknown`,value:immutable(prepare(n))}})},get state(){return m},async submit(e,t){if(ensureActive(`submit`),p.isSubmitting)throw new ForgeSubmitError(`submit() called while a submission is already in progress`);let n=t?AbortSignal.any([o.signal,t]):o.signal;write(e=>({...e,isSubmitting:!0,submitCount:e.submitCount+1,touched:touchAll(e.value)}));try{let r=await validate(t);if(r.status===`aborted`)return Object.freeze({status:`aborted`});if(r.status===`invalid`)return Object.freeze({issues:r.issues,status:`invalid`});let i=f;if(!i||i.revision!==d||n.aborted)return Object.freeze({status:`aborted`});try{return Object.freeze({status:`ok`,value:await e(i.value,n)})}catch(e){if(n.aborted)return Object.freeze({status:`aborted`});throw e}}finally{s||write(e=>({...e,isSubmitting:!1}))}},subscribe(e,t={}){return ensureActive(`subscribe`),t.immediate&&a.call(()=>e(m)),a.add(()=>e(m))},[Symbol.dispose](){g.dispose()},validate,get value(){return p.value}};return g}function toPlainValues(e){return toPlainValues$1(e)}export{ForgeConfigError,ForgeDisposedError,ForgeError,ForgeSubmitError,ForgeValidationError,createForm,toPlainValues};
1
+ import { abortable as e, isEqual as t, isPlainObject as n } from "@vielzeug/arsenal";
2
+ //#region src/errors.ts
3
+ var ForgeError = class extends Error {
4
+ constructor(e, t) {
5
+ super(e, t), this.name = new.target.name, Object.setPrototypeOf(this, new.target.prototype);
6
+ }
7
+ }, ForgeDisposedError = class extends ForgeError {
8
+ constructor(e) {
9
+ super(e ? `Cannot call ${e}() on a disposed form` : "Cannot modify a disposed form");
10
+ }
11
+ }, ForgeConfigError = class extends ForgeError {}, ForgeSubmitError = class extends ForgeError {}, ForgeValidationError = class extends ForgeError {}, r = /* @__PURE__ */ new Set([
12
+ "__proto__",
13
+ "constructor",
14
+ "prototype"
15
+ ]);
16
+ function isUnsafeKey(e) {
17
+ return !e || r.has(e);
18
+ }
19
+ function assertSafeKey(e) {
20
+ if (isUnsafeKey(e)) throw new ForgeConfigError(`Invalid field key '${e}'.`);
21
+ }
22
+ function assertArrayIndex(e) {
23
+ if (!Number.isSafeInteger(e) || e < 0) throw new ForgeConfigError(`Invalid array index ${e}.`);
24
+ }
25
+ function tag(e) {
26
+ return Object.prototype.toString.call(e);
27
+ }
28
+ function isBlobLeaf(e) {
29
+ return tag(e) === "[object Blob]" || tag(e) === "[object File]";
30
+ }
31
+ function formatValuePath(e) {
32
+ let t = "";
33
+ for (let n of e) t += typeof n == "number" ? `[${n}]` : t ? `.${n}` : n;
34
+ return t;
35
+ }
36
+ function pathSuffix(e) {
37
+ return e.length > 0 ? ` at '${formatValuePath(e)}'` : "";
38
+ }
39
+ function invalidValue(e) {
40
+ throw new ForgeConfigError(`Form values must contain only finite JSON primitives, plain objects, arrays, Date, File, or Blob${pathSuffix(e)}.`);
41
+ }
42
+ function immutable(e, t = /* @__PURE__ */ new Set(), r = []) {
43
+ if (e == null || typeof e == "string" || typeof e == "boolean") return e;
44
+ if (typeof e == "number") return Number.isFinite(e) ? e : invalidValue(r);
45
+ if (typeof e != "object") return invalidValue(r);
46
+ let i = e;
47
+ if (tag(e) === "[object Date]" && typeof i.getTime == "function") {
48
+ let e = i.getTime();
49
+ return Number.isFinite(e) ? Object.freeze(new Date(e)) : invalidValue(r);
50
+ }
51
+ if (isBlobLeaf(e)) return e;
52
+ if (t.has(e)) throw new ForgeConfigError(`Form values must not contain circular references${pathSuffix(r)}.`);
53
+ t.add(e);
54
+ try {
55
+ if (Array.isArray(e)) {
56
+ let n = [];
57
+ for (let i = 0; i < e.length; i++) {
58
+ r.push(i);
59
+ try {
60
+ if (!Object.hasOwn(e, i)) throw new ForgeConfigError(`Form arrays must not contain empty slots${pathSuffix(r)}.`);
61
+ n.push(immutable(e[i], t, r));
62
+ } finally {
63
+ r.pop();
64
+ }
65
+ }
66
+ return Object.freeze(n);
67
+ }
68
+ if (!n(e)) return invalidValue(r);
69
+ let i = Object.entries(e).map(([e, n]) => {
70
+ assertSafeKey(e), r.push(e);
71
+ try {
72
+ return [e, immutable(n, t, r)];
73
+ } finally {
74
+ r.pop();
75
+ }
76
+ });
77
+ return Object.freeze(Object.fromEntries(i));
78
+ } finally {
79
+ t.delete(e);
80
+ }
81
+ }
82
+ function toPlainValues$1(e, t = /* @__PURE__ */ new WeakSet()) {
83
+ if (e == null || typeof e == "string" || typeof e == "boolean") return e;
84
+ if (typeof e == "number") return Number.isFinite(e) ? e : void 0;
85
+ if (typeof e != "object") return;
86
+ let n = e, r = e;
87
+ if (tag(n) === "[object Date]" && typeof r.getTime == "function") {
88
+ let e = r.getTime();
89
+ return Number.isFinite(e) ? new Date(e) : void 0;
90
+ }
91
+ if (isBlobLeaf(n)) return e;
92
+ if (!t.has(n)) {
93
+ t.add(n);
94
+ try {
95
+ if (Array.isArray(e)) {
96
+ let n = [];
97
+ for (let r = 0; r < e.length; r++) Object.hasOwn(e, r) && n.push(toPlainValues$1(e[r], t));
98
+ return n;
99
+ }
100
+ let r = {};
101
+ for (let [e, i] of Object.entries(n)) isUnsafeKey(e) || (r[e] = toPlainValues$1(i, t));
102
+ return r;
103
+ } finally {
104
+ t.delete(n);
105
+ }
106
+ }
107
+ }
108
+ function readAtPath(e, t) {
109
+ let r = e;
110
+ for (let e of t) if (typeof e == "number") {
111
+ if (!Array.isArray(r) || !Number.isSafeInteger(e) || e < 0 || e >= r.length || !Object.hasOwn(r, e)) return;
112
+ r = r[e];
113
+ } else {
114
+ if (!n(r) || !Object.hasOwn(r, e)) return;
115
+ r = r[e];
116
+ }
117
+ return r;
118
+ }
119
+ function hasAtPath(e, t) {
120
+ let r = e;
121
+ for (let e of t) if (typeof e == "number") {
122
+ if (!Array.isArray(r) || !Number.isSafeInteger(e) || e < 0 || e >= r.length || !Object.hasOwn(r, e)) return !1;
123
+ r = r[e];
124
+ } else {
125
+ if (!n(r) || !Object.hasOwn(r, e)) return !1;
126
+ r = r[e];
127
+ }
128
+ return !0;
129
+ }
130
+ function writeAtPath(e, t, r, i = []) {
131
+ let [a, ...o] = t;
132
+ if (typeof a == "number") {
133
+ if (assertArrayIndex(a), !Array.isArray(e)) throw new ForgeConfigError(`Cannot index ${a} because the current value is not an array.`);
134
+ if (a < 0 || a >= e.length) throw new ForgeConfigError(`Index ${a} is out of range for array of length ${e.length}.`);
135
+ if (o.length === 0) {
136
+ let t = [...e];
137
+ return t[a] = immutable(r, /* @__PURE__ */ new Set(), [...i, a]), Object.freeze(t);
138
+ }
139
+ let t = [...e];
140
+ return t[a] = writeAtPath(e[a], o, r, [...i, a]), Object.freeze(t);
141
+ }
142
+ if (assertSafeKey(a), !n(e)) throw new ForgeConfigError(`Cannot select '${a}' because the current value is not an object.`);
143
+ if (o.length === 0) return Object.freeze({
144
+ ...e,
145
+ [a]: immutable(r, /* @__PURE__ */ new Set(), [...i, a])
146
+ });
147
+ let s = e[a];
148
+ if (s !== void 0 && !n(s) && !Array.isArray(s)) throw new ForgeConfigError(`Cannot select '${a}' because it is not an object or array.`);
149
+ let c = s ?? {};
150
+ return Object.freeze({
151
+ ...e,
152
+ [a]: writeAtPath(c, o, r, [...i, a])
153
+ });
154
+ }
155
+ function resetAtPath(e, t, r) {
156
+ let [i, ...a] = r;
157
+ if (typeof i == "number") {
158
+ if (assertArrayIndex(i), !Array.isArray(e) || !Array.isArray(t) || i >= t.length || i >= e.length) return e;
159
+ if (a.length === 0) {
160
+ let n = [...e];
161
+ return n[i] = t[i], Object.freeze(n);
162
+ }
163
+ let n = [...e];
164
+ return n[i] = resetAtPath(e[i], t[i], a), Object.freeze(n);
165
+ }
166
+ if (!n(e)) return e;
167
+ if (a.length === 0) {
168
+ if (Object.hasOwn(t, i)) return Object.freeze({
169
+ ...e,
170
+ [i]: t[i]
171
+ });
172
+ let { [i]: n, ...r } = e;
173
+ return Object.freeze(r);
174
+ }
175
+ let o = t[i];
176
+ if (!n(o) && !Array.isArray(o)) {
177
+ if (Object.hasOwn(t, i)) return Object.freeze({
178
+ ...e,
179
+ [i]: o
180
+ });
181
+ let { [i]: n, ...r } = e;
182
+ return Object.freeze(r);
183
+ }
184
+ let s = e[i], c = n(s) || Array.isArray(s) ? s : {};
185
+ return Object.freeze({
186
+ ...e,
187
+ [i]: resetAtPath(c, o, a)
188
+ });
189
+ }
190
+ function writeMeta(e, t, r) {
191
+ let [i, ...a] = t;
192
+ typeof i == "number" && assertArrayIndex(i);
193
+ let o = String(i), s = { ...e };
194
+ if (a.length === 0) r ? s[o] = !0 : delete s[o];
195
+ else {
196
+ let t = writeMeta(n(e[o]) ? e[o] : {}, a, r);
197
+ Object.keys(t).length === 0 ? delete s[o] : s[o] = t;
198
+ }
199
+ return Object.freeze(s);
200
+ }
201
+ function readMeta(e, t) {
202
+ let r = e;
203
+ for (let e of t) {
204
+ if (typeof e == "number" && (!Number.isSafeInteger(e) || e < 0)) return !1;
205
+ let t = String(e);
206
+ if (!n(r) || !Object.hasOwn(r, t)) return !1;
207
+ r = r[t];
208
+ }
209
+ return r === !0;
210
+ }
211
+ function touchAll(e) {
212
+ return Array.isArray(e) ? Object.freeze(Object.fromEntries(e.map((e, t) => [String(t), n(e) || Array.isArray(e) ? touchAll(e) : !0]))) : n(e) ? Object.freeze(Object.fromEntries(Object.entries(e).map(([e, t]) => [e, n(t) || Array.isArray(t) ? touchAll(t) : !0]))) : {};
213
+ }
214
+ function pathEquals(e, t) {
215
+ if (e.length !== t.length) return !1;
216
+ for (let n = 0; n < e.length; n++) if (e[n] !== t[n]) return !1;
217
+ return !0;
218
+ }
219
+ function findIssue(e, t) {
220
+ if (e) {
221
+ for (let n of e) if (pathEquals(n.path, t)) return n.message;
222
+ }
223
+ }
224
+ //#endregion
225
+ //#region src/_field.ts
226
+ function makeFieldState(e, n) {
227
+ let r = readAtPath(e.value, n), i = readAtPath(e.baseline, n);
228
+ return Object.freeze({
229
+ dirty: !t(r, i) || hasAtPath(e.value, n) !== hasAtPath(e.baseline, n),
230
+ error: findIssue(e.issues, n),
231
+ touched: readMeta(e.touched, n),
232
+ value: r
233
+ });
234
+ }
235
+ function createField(e, t) {
236
+ return Object.assign({
237
+ get dirty() {
238
+ return makeFieldState(t.readState(), e).dirty;
239
+ },
240
+ get error() {
241
+ return makeFieldState(t.readState(), e).error;
242
+ },
243
+ reset() {
244
+ t.ensureActive("field().reset"), t.abortValidation(), t.resetValue(e);
245
+ },
246
+ set(n) {
247
+ t.ensureActive("field().set"), t.abortValidation(), t.setValue(e, n);
248
+ },
249
+ get state() {
250
+ return makeFieldState(t.readState(), e);
251
+ },
252
+ subscribe(n, r = {}) {
253
+ t.ensureActive("field().subscribe");
254
+ let i = makeFieldState(t.readState(), e);
255
+ r.immediate && t.invokeListener(() => n(i));
256
+ let filtered = (t) => {
257
+ let r = makeFieldState(t, e);
258
+ (r.value !== i.value || r.error !== i.error || r.touched !== i.touched || r.dirty !== i.dirty) && (i = r, n(r));
259
+ };
260
+ return t.addListener(filtered);
261
+ },
262
+ touch() {
263
+ t.ensureActive("field().touch"), t.setTouched(e, !0);
264
+ },
265
+ get touched() {
266
+ return makeFieldState(t.readState(), e).touched;
267
+ },
268
+ get value() {
269
+ return makeFieldState(t.readState(), e).value;
270
+ }
271
+ }, { field(r) {
272
+ if (typeof r == "number") {
273
+ assertArrayIndex(r);
274
+ let n = readAtPath(t.readState().value, e);
275
+ if (n !== void 0 && !Array.isArray(n)) throw new ForgeConfigError(`Cannot index ${r} because the current field value is not an array.`);
276
+ return createField([...e, r], t);
277
+ }
278
+ assertSafeKey(r);
279
+ let i = readAtPath(t.readState().value, e);
280
+ if (i !== void 0 && !n(i)) throw new ForgeConfigError(`Cannot select '${r}' because the current field value is not an object.`);
281
+ return createField([...e, r], t);
282
+ } });
283
+ }
284
+ //#endregion
285
+ //#region src/_notify.ts
286
+ function rethrowAsync(e) {
287
+ queueMicrotask(() => {
288
+ throw e;
289
+ });
290
+ }
291
+ function createNotifier(e) {
292
+ let t = /* @__PURE__ */ new Set(), n = [], r = !1;
293
+ function reportError(t) {
294
+ if (!e) rethrowAsync(t);
295
+ else try {
296
+ e(t);
297
+ } catch (e) {
298
+ rethrowAsync(e);
299
+ }
300
+ }
301
+ let call = (e) => {
302
+ try {
303
+ e();
304
+ } catch (e) {
305
+ reportError(e);
306
+ }
307
+ };
308
+ return {
309
+ add(e) {
310
+ return t.add(e), () => t.delete(e);
311
+ },
312
+ call,
313
+ clear() {
314
+ t.clear(), n.length = 0;
315
+ },
316
+ notify(e) {
317
+ if (n.push(e), !r) {
318
+ r = !0;
319
+ try {
320
+ for (; n.length > 0;) {
321
+ let e = n.shift();
322
+ for (let n of [...t]) t.has(n) && call(() => n(e));
323
+ }
324
+ } finally {
325
+ r = !1;
326
+ }
327
+ }
328
+ }
329
+ };
330
+ }
331
+ //#endregion
332
+ //#region src/form.ts
333
+ function normalizeIssues(e) {
334
+ if (e !== void 0 && e.length !== 0) return Object.freeze(e.map((e) => {
335
+ if (!e || typeof e.message != "string" || !Array.isArray(e.path)) throw new ForgeConfigError("Validators must return issues with a string message and array path.");
336
+ let t = e.path.map((e) => {
337
+ if (typeof e == "number") {
338
+ if (!Number.isSafeInteger(e) || e < 0) throw new ForgeConfigError(`Invalid issue path index ${e}.`);
339
+ return e;
340
+ }
341
+ if (typeof e == "string") return assertSafeKey(e), e;
342
+ throw new ForgeConfigError("Issue paths may contain only string keys and non-negative integer indexes.");
343
+ });
344
+ return Object.freeze({
345
+ message: e.message,
346
+ path: Object.freeze(t)
347
+ });
348
+ }));
349
+ }
350
+ function makeFormState(e) {
351
+ return Object.freeze({
352
+ formError: e.issues?.find((e) => e.path.length === 0)?.message,
353
+ hasErrors: (e.issues?.length ?? 0) > 0,
354
+ issues: e.issues,
355
+ submitCount: e.submitCount,
356
+ submitting: e.isSubmitting,
357
+ touched: Object.keys(e.touched).length > 0,
358
+ validating: e.isValidating,
359
+ validity: e.validity
360
+ });
361
+ }
362
+ function createForm(t) {
363
+ let r = t.normalize, prepare = (e) => r ? r(e) : e, i = immutable(prepare(t.initialValues)), a = createNotifier(t.onSubscriberError), o = new AbortController(), s = !1, c = !1, l = [], u, d = 0, f, p = {
364
+ baseline: i,
365
+ isSubmitting: !1,
366
+ issues: void 0,
367
+ isValidating: !1,
368
+ submitCount: 0,
369
+ touched: {},
370
+ validity: "unknown",
371
+ value: i
372
+ }, m = makeFormState(p);
373
+ function ensureActive(e) {
374
+ if (s) throw new ForgeDisposedError(e);
375
+ }
376
+ function write(e) {
377
+ if (l.push(e), !c) {
378
+ c = !0;
379
+ try {
380
+ for (; l.length > 0;) p = Object.freeze(l.shift()(p)), m = makeFormState(p), a.notify(p);
381
+ } finally {
382
+ c = !1;
383
+ }
384
+ }
385
+ }
386
+ function abortValidation() {
387
+ u?.abort();
388
+ }
389
+ let h = {
390
+ abortValidation,
391
+ addListener: a.add,
392
+ ensureActive,
393
+ invokeListener: a.call,
394
+ readState: () => p,
395
+ resetValue(e) {
396
+ write((t) => (d++, f = void 0, {
397
+ ...t,
398
+ touched: writeMeta(t.touched, e, !1),
399
+ validity: "unknown",
400
+ value: resetAtPath(t.value, t.baseline, e)
401
+ }));
402
+ },
403
+ setTouched(e, t) {
404
+ write((n) => ({
405
+ ...n,
406
+ touched: writeMeta(n.touched, e, t)
407
+ }));
408
+ },
409
+ setValue(e, t) {
410
+ write((n) => {
411
+ let r = readAtPath(n.value, e), i = typeof t == "function" ? t(r) : t, a = prepare(i);
412
+ return d++, f = void 0, {
413
+ ...n,
414
+ validity: "unknown",
415
+ value: writeAtPath(n.value, e, a)
416
+ };
417
+ });
418
+ }
419
+ };
420
+ async function validate(n) {
421
+ ensureActive("validate"), abortValidation();
422
+ let r = new AbortController(), i = n ? AbortSignal.any([r.signal, n]) : r.signal;
423
+ if (i.aborted) return Object.freeze({ status: "aborted" });
424
+ let a = p.value, o = d;
425
+ u = r, f = void 0, write((e) => ({
426
+ ...e,
427
+ isValidating: !0
428
+ }));
429
+ try {
430
+ if (i.aborted || d !== o) return Object.freeze({ status: "aborted" });
431
+ let n = t.validate ? await e(Promise.resolve(t.validate(a, i)), i) : void 0;
432
+ if (i.aborted || u !== r || d !== o) return Object.freeze({ status: "aborted" });
433
+ let s = normalizeIssues(n), c = s === void 0 ? "valid" : "invalid";
434
+ return u = void 0, write((e) => ({
435
+ ...e,
436
+ issues: s,
437
+ isValidating: !1,
438
+ validity: c
439
+ })), i.aborted || d !== o || u !== void 0 ? Object.freeze({ status: "aborted" }) : (f = c === "valid" ? {
440
+ revision: d,
441
+ value: a
442
+ } : void 0, Object.freeze(c === "valid" ? { status: "valid" } : {
443
+ issues: s,
444
+ status: "invalid"
445
+ }));
446
+ } catch (e) {
447
+ if (i.aborted || u !== r) return Object.freeze({ status: "aborted" });
448
+ throw new ForgeValidationError("Form validation failed.", { cause: e });
449
+ } finally {
450
+ u === r && (u = void 0, s || write((e) => ({
451
+ ...e,
452
+ isValidating: !1
453
+ })));
454
+ }
455
+ }
456
+ let g = {
457
+ get disposalSignal() {
458
+ return o.signal;
459
+ },
460
+ dispose() {
461
+ s || (s = !0, l.length = 0, f = void 0, o.abort(), abortValidation(), a.clear());
462
+ },
463
+ get disposed() {
464
+ return s;
465
+ },
466
+ field(e) {
467
+ if (assertSafeKey(e), !n(p.value)) throw new ForgeConfigError("Form value must be an object.");
468
+ return createField([e], h);
469
+ },
470
+ patch(e) {
471
+ ensureActive("patch"), abortValidation(), write((t) => {
472
+ let n = typeof e == "function" ? e(t.value) : e, r = {
473
+ ...t.value,
474
+ ...n
475
+ };
476
+ return d++, f = void 0, {
477
+ ...t,
478
+ issues: void 0,
479
+ validity: "unknown",
480
+ value: immutable(prepare(r))
481
+ };
482
+ });
483
+ },
484
+ reset(e) {
485
+ ensureActive("reset"), abortValidation();
486
+ let t = e === void 0 ? void 0 : immutable(prepare(e));
487
+ write((e) => {
488
+ let n = t ?? e.baseline;
489
+ return d++, f = void 0, {
490
+ ...e,
491
+ baseline: n,
492
+ issues: void 0,
493
+ touched: {},
494
+ validity: "unknown",
495
+ value: n
496
+ };
497
+ });
498
+ },
499
+ set(e) {
500
+ ensureActive("set"), abortValidation(), write((t) => {
501
+ let n = typeof e == "function" ? e(t.value) : e;
502
+ return d++, f = void 0, {
503
+ ...t,
504
+ issues: void 0,
505
+ validity: "unknown",
506
+ value: immutable(prepare(n))
507
+ };
508
+ });
509
+ },
510
+ get state() {
511
+ return m;
512
+ },
513
+ async submit(e, t) {
514
+ if (ensureActive("submit"), p.isSubmitting) throw new ForgeSubmitError("submit() called while a submission is already in progress");
515
+ let n = t ? AbortSignal.any([o.signal, t]) : o.signal;
516
+ write((e) => ({
517
+ ...e,
518
+ isSubmitting: !0,
519
+ submitCount: e.submitCount + 1,
520
+ touched: touchAll(e.value)
521
+ }));
522
+ try {
523
+ let r = await validate(t);
524
+ if (r.status === "aborted") return Object.freeze({ status: "aborted" });
525
+ if (r.status === "invalid") return Object.freeze({
526
+ issues: r.issues,
527
+ status: "invalid"
528
+ });
529
+ let i = f;
530
+ if (!i || i.revision !== d || n.aborted) return Object.freeze({ status: "aborted" });
531
+ try {
532
+ return Object.freeze({
533
+ status: "ok",
534
+ value: await e(i.value, n)
535
+ });
536
+ } catch (e) {
537
+ if (n.aborted) return Object.freeze({ status: "aborted" });
538
+ throw e;
539
+ }
540
+ } finally {
541
+ s || write((e) => ({
542
+ ...e,
543
+ isSubmitting: !1
544
+ }));
545
+ }
546
+ },
547
+ subscribe(e, t = {}) {
548
+ return ensureActive("subscribe"), t.immediate && a.call(() => e(m)), a.add(() => e(m));
549
+ },
550
+ [Symbol.dispose]() {
551
+ g.dispose();
552
+ },
553
+ validate,
554
+ get value() {
555
+ return p.value;
556
+ }
557
+ };
558
+ return g;
559
+ }
560
+ //#endregion
561
+ //#region src/plain.ts
562
+ function toPlainValues(e) {
563
+ return toPlainValues$1(e);
564
+ }
565
+ //#endregion
566
+ export { ForgeConfigError, ForgeDisposedError, ForgeError, ForgeSubmitError, ForgeValidationError, createForm, toPlainValues };
567
+
2
568
  //# sourceMappingURL=forge.js.map