@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.
- package/README.md +70 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +9 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_utils.cjs +2 -0
- package/dist/_utils.cjs.map +1 -0
- package/dist/_utils.d.ts +12 -0
- package/dist/_utils.d.ts.map +1 -0
- package/dist/_utils.js +25 -0
- package/dist/_utils.js.map +1 -0
- package/dist/adapters/form-data.cjs +2 -0
- package/dist/adapters/form-data.cjs.map +1 -0
- package/dist/adapters/form-data.d.ts +8 -0
- package/dist/adapters/form-data.d.ts.map +1 -0
- package/dist/adapters/form-data.js +14 -0
- package/dist/adapters/form-data.js.map +1 -0
- package/dist/adapters/validators.cjs +2 -0
- package/dist/adapters/validators.cjs.map +1 -0
- package/dist/adapters/validators.d.ts +44 -0
- package/dist/adapters/validators.d.ts.map +1 -0
- package/dist/adapters/validators.js +20 -0
- package/dist/adapters/validators.js.map +1 -0
- package/dist/core/array.cjs +2 -0
- package/dist/core/array.cjs.map +1 -0
- package/dist/core/array.d.ts +10 -0
- package/dist/core/array.d.ts.map +1 -0
- package/dist/core/array.js +46 -0
- package/dist/core/array.js.map +1 -0
- package/dist/core/asyncQueue.cjs +2 -0
- package/dist/core/asyncQueue.cjs.map +1 -0
- package/dist/core/asyncQueue.d.ts +22 -0
- package/dist/core/asyncQueue.d.ts.map +1 -0
- package/dist/core/asyncQueue.js +67 -0
- package/dist/core/asyncQueue.js.map +1 -0
- package/dist/core/context.cjs +2 -0
- package/dist/core/context.cjs.map +1 -0
- package/dist/core/context.d.ts +10 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +176 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/lifecycle.cjs +2 -0
- package/dist/core/lifecycle.cjs.map +1 -0
- package/dist/core/lifecycle.d.ts +13 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +42 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/observe.cjs +2 -0
- package/dist/core/observe.cjs.map +1 -0
- package/dist/core/observe.d.ts +18 -0
- package/dist/core/observe.d.ts.map +1 -0
- package/dist/core/observe.js +90 -0
- package/dist/core/observe.js.map +1 -0
- package/dist/core/scope.cjs +2 -0
- package/dist/core/scope.cjs.map +1 -0
- package/dist/core/scope.d.ts +8 -0
- package/dist/core/scope.d.ts.map +1 -0
- package/dist/core/scope.js +239 -0
- package/dist/core/scope.js.map +1 -0
- package/dist/core/validation.cjs +2 -0
- package/dist/core/validation.cjs.map +1 -0
- package/dist/core/validation.d.ts +23 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +173 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/core/values.cjs +2 -0
- package/dist/core/values.cjs.map +1 -0
- package/dist/core/values.d.ts +31 -0
- package/dist/core/values.d.ts.map +1 -0
- package/dist/core/values.js +149 -0
- package/dist/core/values.js.map +1 -0
- package/dist/devtools.cjs +2 -0
- package/dist/devtools.cjs.map +1 -0
- package/dist/devtools.d.ts +40 -0
- package/dist/devtools.d.ts.map +1 -0
- package/dist/devtools.js +29 -0
- package/dist/devtools.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +22 -0
- package/dist/errors.js.map +1 -0
- package/dist/forge.cjs +2 -0
- package/dist/forge.cjs.map +1 -0
- package/dist/forge.iife.js +2 -0
- package/dist/forge.iife.js.map +1 -0
- package/dist/forge.js +2 -0
- package/dist/forge.js.map +1 -0
- package/dist/form.cjs +2 -0
- package/dist/form.cjs.map +1 -0
- package/dist/form.d.ts +6 -0
- package/dist/form.d.ts.map +1 -0
- package/dist/form.js +89 -0
- package/dist/form.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/types.cjs +2 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.ts +391 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +21 -0
- package/dist/types.js.map +1 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# @vielzeug/forge
|
|
2
|
+
|
|
3
|
+
> Framework-agnostic typed form state with path-safe fields, unified validation API, deterministic submit flow, and browser-friendly helpers.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@vielzeug/forge) [](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
<details>
|
|
8
|
+
<summary>Quick Reference</summary>
|
|
9
|
+
|
|
10
|
+
**Package:** `@vielzeug/forge` · **Category:** Forms
|
|
11
|
+
|
|
12
|
+
**Key exports:** `createForm`, `toFormData`, `ValidationModes`, `FORM_ERROR`
|
|
13
|
+
|
|
14
|
+
**When to use:** Typed form state with field validation, dirty tracking, submission handling, and browser helpers. Works with any UI framework or vanilla JS.
|
|
15
|
+
|
|
16
|
+
**Related:** [@vielzeug/spell](https://vielzeug.dev/spell/) · [@vielzeug/ripple](https://vielzeug.dev/ripple/) · [@vielzeug/courier](https://vielzeug.dev/courier/)
|
|
17
|
+
|
|
18
|
+
</details>
|
|
19
|
+
|
|
20
|
+
`@vielzeug/forge` is part of Vielzeug and ships as a zero-dependency TypeScript package with ESM+CJS output.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
pnpm add @vielzeug/forge
|
|
26
|
+
npm install @vielzeug/forge
|
|
27
|
+
yarn add @vielzeug/forge
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createForm } from '@vielzeug/forge';
|
|
34
|
+
|
|
35
|
+
const form = createForm({
|
|
36
|
+
defaultValues: { email: '', password: '' },
|
|
37
|
+
validators: {
|
|
38
|
+
email: (v) => (!String(v).includes('@') ? 'Invalid email' : undefined),
|
|
39
|
+
password: (v) => (String(v).length < 8 ? 'Min 8 chars' : undefined),
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
form.set('email', 'alice@example.com');
|
|
44
|
+
|
|
45
|
+
const result = await form.validate();
|
|
46
|
+
console.log(result.valid, result.errors);
|
|
47
|
+
|
|
48
|
+
const submission = await form.submit(async (values) => {
|
|
49
|
+
await fetch('/api/login', {
|
|
50
|
+
body: JSON.stringify(values),
|
|
51
|
+
headers: { 'Content-Type': 'application/json' },
|
|
52
|
+
method: 'POST',
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!submission.ok && submission.type === 'validation') {
|
|
57
|
+
console.log(submission.errors);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Documentation
|
|
62
|
+
|
|
63
|
+
- [Overview](https://vielzeug.dev/forge/)
|
|
64
|
+
- [Usage Guide](https://vielzeug.dev/forge/usage)
|
|
65
|
+
- [API Reference](https://vielzeug.dev/forge/api)
|
|
66
|
+
- [Examples](https://vielzeug.dev/forge/examples)
|
|
67
|
+
|
|
68
|
+
## License
|
|
69
|
+
|
|
70
|
+
MIT © [Helmuth Saatkamp](https://github.com/helmuthdu) — part of the [Vielzeug](https://github.com/helmuthdu/vielzeug) monorepo.
|
package/dist/_dev.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.cjs","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __FORGE_PROD__?: boolean }).__FORGE_PROD__;\n\n/** @internal @security Messages may include user-supplied form field paths. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/forge] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":"AAAA,IAAM,EAAQ,CAAE,WAA4C,eAG5D,SAAgB,EAAK,EAAmB,CAClC,GAAO,QAAQ,KAAK,qBAAqB,GAAK,CACpD"}
|
package/dist/_dev.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.d.ts","sourceRoot":"","sources":["../src/_dev.ts"],"names":[],"mappings":""}
|
package/dist/_dev.js
ADDED
package/dist/_dev.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_dev.js","names":[],"sources":["../src/_dev.ts"],"sourcesContent":["const isDev = !(globalThis as { __FORGE_PROD__?: boolean }).__FORGE_PROD__;\n\n/** @internal @security Messages may include user-supplied form field paths. */\nexport function warn(msg: string): void {\n if (isDev) console.warn(`[@vielzeug/forge] ${msg}`);\n}\n\n/** @internal — Run fn only in dev builds. Use when dev-only logic goes beyond a single warn() / error() call. */\nexport function devOnly(fn: () => void): void {\n if (isDev) fn();\n}\n"],"mappings":";AAAA,IAAM,IAAQ,CAAE,WAA4C;AAG5D,SAAgB,EAAK,GAAmB;CACtC,AAAI,KAAO,QAAQ,KAAK,qBAAqB,GAAK;AACpD"}
|
package/dist/_utils.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./errors.cjs");require("@vielzeug/arsenal");var t=new Set([`__proto__`,`constructor`,`prototype`]);function n(e){return e.split(`.`).every(e=>!t.has(e))}function r(t){if(!n(t))throw new e.ForgeConfigError(`Unsafe key '${t}': segments __proto__, constructor, and prototype are reserved.`)}function i(e,t=200){return e.replace(/\p{C}/gu,`?`).slice(0,t)}function a(...e){let t=e.filter(e=>e!=null);if(t.length!==0)return t.length===1?t[0]:AbortSignal.any(t)}exports.anySignal=a,exports.assertSafeKey=r,exports.isSafeKey=n,exports.sanitizeForLog=i;
|
|
2
|
+
//# sourceMappingURL=_utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_utils.cjs","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["import { ForgeConfigError } from './errors';\n\nexport { flattenPaths as flattenValues, isPlainObject, unflattenPaths as unflattenValues } from '@vielzeug/arsenal';\n\nconst UNSAFE = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** Returns `true` when a dot-notation path contains no prototype-polluting segments. */\nexport function isSafeKey(path: string): boolean {\n return path.split('.').every((segment) => !UNSAFE.has(segment));\n}\n\n/** R2: Single assertion helper — replaces 5 copy-pasted guard blocks. */\nexport function assertSafeKey(key: string): void {\n if (!isSafeKey(key))\n throw new ForgeConfigError(`Unsafe key '${key}': segments __proto__, constructor, and prototype are reserved.`);\n}\n\n/**\n * Strips control characters (which could otherwise inject terminal escape sequences into\n * `console.warn` output) and caps length before interpolating caller-controlled text into a\n * dev warning. Mirrors the sanitization already applied to field keys in `warnIfArrayItemKey`.\n */\nexport function sanitizeForLog(text: string, maxLength = 200): string {\n return text.replace(/\\p{C}/gu, '?').slice(0, maxLength);\n}\n\n/**\n * Merges multiple AbortSignals into one that aborts when any of them aborts.\n * Nullish values are silently ignored.\n * Returns `undefined` when no non-null signals are provided.\n *\n * @internal Inlined here — `anySignal` was removed from `@vielzeug/arsenal`.\n */\nexport function anySignal(...signals: ReadonlyArray<AbortSignal | null | undefined>): AbortSignal | undefined {\n const active = signals.filter((s): s is AbortSignal => s != null);\n\n if (active.length === 0) return undefined;\n\n if (active.length === 1) return active[0];\n\n return AbortSignal.any(active);\n}\n"],"mappings":"6DAIA,IAAM,EAAS,IAAI,IAAI,CAAC,YAAa,cAAe,WAAW,CAAC,EAGhE,SAAgB,EAAU,EAAuB,CAC/C,OAAO,EAAK,MAAM,GAAG,CAAC,CAAC,MAAO,GAAY,CAAC,EAAO,IAAI,CAAO,CAAC,CAChE,CAGA,SAAgB,EAAc,EAAmB,CAC/C,GAAI,CAAC,EAAU,CAAG,EAChB,MAAM,IAAI,EAAA,iBAAiB,eAAe,EAAI,gEAAgE,CAClH,CAOA,SAAgB,EAAe,EAAc,EAAY,IAAa,CACpE,OAAO,EAAK,QAAQ,UAAW,GAAG,CAAC,CAAC,MAAM,EAAG,CAAS,CACxD,CASA,SAAgB,EAAU,GAAG,EAAiF,CAC5G,IAAM,EAAS,EAAQ,OAAQ,GAAwB,GAAK,IAAI,EAE5D,KAAO,SAAW,EAItB,OAFI,EAAO,SAAW,EAAU,EAAO,GAEhC,YAAY,IAAI,CAAM,CAC/B"}
|
package/dist/_utils.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { flattenPaths as flattenValues, isPlainObject, unflattenPaths as unflattenValues } from '@vielzeug/arsenal';
|
|
2
|
+
/** Returns `true` when a dot-notation path contains no prototype-polluting segments. */
|
|
3
|
+
export declare function isSafeKey(path: string): boolean;
|
|
4
|
+
/** R2: Single assertion helper — replaces 5 copy-pasted guard blocks. */
|
|
5
|
+
export declare function assertSafeKey(key: string): void;
|
|
6
|
+
/**
|
|
7
|
+
* Strips control characters (which could otherwise inject terminal escape sequences into
|
|
8
|
+
* `console.warn` output) and caps length before interpolating caller-controlled text into a
|
|
9
|
+
* dev warning. Mirrors the sanitization already applied to field keys in `warnIfArrayItemKey`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function sanitizeForLog(text: string, maxLength?: number): string;
|
|
12
|
+
//# sourceMappingURL=_utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_utils.d.ts","sourceRoot":"","sources":["../src/_utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,IAAI,aAAa,EAAE,aAAa,EAAE,cAAc,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIpH,wFAAwF;AACxF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE/C;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAG/C;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,MAAM,CAEpE"}
|
package/dist/_utils.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ForgeConfigError as e } from "./errors.js";
|
|
2
|
+
import { flattenPaths as t, unflattenPaths as n } from "@vielzeug/arsenal";
|
|
3
|
+
//#region src/_utils.ts
|
|
4
|
+
var r = /* @__PURE__ */ new Set([
|
|
5
|
+
"__proto__",
|
|
6
|
+
"constructor",
|
|
7
|
+
"prototype"
|
|
8
|
+
]);
|
|
9
|
+
function i(e) {
|
|
10
|
+
return e.split(".").every((e) => !r.has(e));
|
|
11
|
+
}
|
|
12
|
+
function a(t) {
|
|
13
|
+
if (!i(t)) throw new e(`Unsafe key '${t}': segments __proto__, constructor, and prototype are reserved.`);
|
|
14
|
+
}
|
|
15
|
+
function o(e, t = 200) {
|
|
16
|
+
return e.replace(/\p{C}/gu, "?").slice(0, t);
|
|
17
|
+
}
|
|
18
|
+
function s(...e) {
|
|
19
|
+
let t = e.filter((e) => e != null);
|
|
20
|
+
if (t.length !== 0) return t.length === 1 ? t[0] : AbortSignal.any(t);
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { s as anySignal, a as assertSafeKey, t as flattenValues, i as isSafeKey, o as sanitizeForLog, n as unflattenValues };
|
|
24
|
+
|
|
25
|
+
//# sourceMappingURL=_utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"_utils.js","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["import { ForgeConfigError } from './errors';\n\nexport { flattenPaths as flattenValues, isPlainObject, unflattenPaths as unflattenValues } from '@vielzeug/arsenal';\n\nconst UNSAFE = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** Returns `true` when a dot-notation path contains no prototype-polluting segments. */\nexport function isSafeKey(path: string): boolean {\n return path.split('.').every((segment) => !UNSAFE.has(segment));\n}\n\n/** R2: Single assertion helper — replaces 5 copy-pasted guard blocks. */\nexport function assertSafeKey(key: string): void {\n if (!isSafeKey(key))\n throw new ForgeConfigError(`Unsafe key '${key}': segments __proto__, constructor, and prototype are reserved.`);\n}\n\n/**\n * Strips control characters (which could otherwise inject terminal escape sequences into\n * `console.warn` output) and caps length before interpolating caller-controlled text into a\n * dev warning. Mirrors the sanitization already applied to field keys in `warnIfArrayItemKey`.\n */\nexport function sanitizeForLog(text: string, maxLength = 200): string {\n return text.replace(/\\p{C}/gu, '?').slice(0, maxLength);\n}\n\n/**\n * Merges multiple AbortSignals into one that aborts when any of them aborts.\n * Nullish values are silently ignored.\n * Returns `undefined` when no non-null signals are provided.\n *\n * @internal Inlined here — `anySignal` was removed from `@vielzeug/arsenal`.\n */\nexport function anySignal(...signals: ReadonlyArray<AbortSignal | null | undefined>): AbortSignal | undefined {\n const active = signals.filter((s): s is AbortSignal => s != null);\n\n if (active.length === 0) return undefined;\n\n if (active.length === 1) return active[0];\n\n return AbortSignal.any(active);\n}\n"],"mappings":";;;AAIA,IAAM,oBAAS,IAAI,IAAI;CAAC;CAAa;CAAe;AAAW,CAAC;AAGhE,SAAgB,EAAU,GAAuB;CAC/C,OAAO,EAAK,MAAM,GAAG,CAAC,CAAC,OAAO,MAAY,CAAC,EAAO,IAAI,CAAO,CAAC;AAChE;AAGA,SAAgB,EAAc,GAAmB;CAC/C,IAAI,CAAC,EAAU,CAAG,GAChB,MAAM,IAAI,EAAiB,eAAe,EAAI,gEAAgE;AAClH;AAOA,SAAgB,EAAe,GAAc,IAAY,KAAa;CACpE,OAAO,EAAK,QAAQ,WAAW,GAAG,CAAC,CAAC,MAAM,GAAG,CAAS;AACxD;AASA,SAAgB,EAAU,GAAG,GAAiF;CAC5G,IAAM,IAAS,EAAQ,QAAQ,MAAwB,KAAK,IAAI;CAE5D,MAAO,WAAW,GAItB,OAFI,EAAO,WAAW,IAAU,EAAO,KAEhC,YAAY,IAAI,CAAM;AAC/B"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
require("../_utils.cjs");let e=require("@vielzeug/arsenal");function t(t){let n=new FormData;for(let[r,i]of Object.entries((0,e.flattenPaths)(t)))if(i!=null)if(i instanceof File||i instanceof Blob)n.append(r,i);else if(i instanceof FileList)for(let e=0;e<i.length;e++)n.append(r,i[e]);else if(Array.isArray(i))for(let e of i)n.append(r,e instanceof File||e instanceof Blob?e:String(e));else n.append(r,String(i));return n}exports.toFormData=t;
|
|
2
|
+
//# sourceMappingURL=form-data.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-data.cjs","names":[],"sources":["../../src/adapters/form-data.ts"],"sourcesContent":["import { flattenValues } from '../_utils';\n\n/**\n * Converts a form values object into a `FormData` instance.\n * Nested objects are flattened to dot-notation keys (e.g. `user.name`).\n * `File`, `Blob`, and `FileList` values are appended as-is; all others are coerced to strings.\n * `null` and `undefined` values are omitted.\n */\nexport function toFormData(values: Record<string, unknown>): FormData {\n const fd = new FormData();\n\n for (const [name, value] of Object.entries(flattenValues(values))) {\n if (value === null || value === undefined) continue;\n\n if (value instanceof File || value instanceof Blob) {\n fd.append(name, value);\n } else if (value instanceof FileList) {\n for (let i = 0; i < value.length; i++) fd.append(name, value[i]);\n } else if (Array.isArray(value)) {\n for (const item of value) {\n fd.append(name, item instanceof File || item instanceof Blob ? item : String(item));\n }\n } else {\n fd.append(name, String(value));\n }\n }\n\n return fd;\n}\n"],"mappings":"4DAQA,SAAgB,EAAW,EAA2C,CACpE,IAAM,EAAK,IAAI,SAEf,IAAK,GAAM,CAAC,EAAM,KAAU,OAAO,SAAA,EAAA,EAAA,aAAA,CAAsB,CAAM,CAAC,EAC1D,MAAU,KAEd,GAAI,aAAiB,MAAQ,aAAiB,KAC5C,EAAG,OAAO,EAAM,CAAK,OAChB,GAAI,aAAiB,SAC1B,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,IAAK,EAAG,OAAO,EAAM,EAAM,EAAE,OAC1D,GAAI,MAAM,QAAQ,CAAK,EAC5B,IAAK,IAAM,KAAQ,EACjB,EAAG,OAAO,EAAM,aAAgB,MAAQ,aAAgB,KAAO,EAAO,OAAO,CAAI,CAAC,OAGpF,EAAG,OAAO,EAAM,OAAO,CAAK,CAAC,EAIjC,OAAO,CACT"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a form values object into a `FormData` instance.
|
|
3
|
+
* Nested objects are flattened to dot-notation keys (e.g. `user.name`).
|
|
4
|
+
* `File`, `Blob`, and `FileList` values are appended as-is; all others are coerced to strings.
|
|
5
|
+
* `null` and `undefined` values are omitted.
|
|
6
|
+
*/
|
|
7
|
+
export declare function toFormData(values: Record<string, unknown>): FormData;
|
|
8
|
+
//# sourceMappingURL=form-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-data.d.ts","sourceRoot":"","sources":["../../src/adapters/form-data.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CAoBpE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { flattenValues as e } from "../_utils.js";
|
|
2
|
+
//#region src/adapters/form-data.ts
|
|
3
|
+
function t(t) {
|
|
4
|
+
let n = new FormData();
|
|
5
|
+
for (let [r, i] of Object.entries(e(t))) if (i != null) if (i instanceof File || i instanceof Blob) n.append(r, i);
|
|
6
|
+
else if (i instanceof FileList) for (let e = 0; e < i.length; e++) n.append(r, i[e]);
|
|
7
|
+
else if (Array.isArray(i)) for (let e of i) n.append(r, e instanceof File || e instanceof Blob ? e : String(e));
|
|
8
|
+
else n.append(r, String(i));
|
|
9
|
+
return n;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { t as toFormData };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=form-data.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-data.js","names":[],"sources":["../../src/adapters/form-data.ts"],"sourcesContent":["import { flattenValues } from '../_utils';\n\n/**\n * Converts a form values object into a `FormData` instance.\n * Nested objects are flattened to dot-notation keys (e.g. `user.name`).\n * `File`, `Blob`, and `FileList` values are appended as-is; all others are coerced to strings.\n * `null` and `undefined` values are omitted.\n */\nexport function toFormData(values: Record<string, unknown>): FormData {\n const fd = new FormData();\n\n for (const [name, value] of Object.entries(flattenValues(values))) {\n if (value === null || value === undefined) continue;\n\n if (value instanceof File || value instanceof Blob) {\n fd.append(name, value);\n } else if (value instanceof FileList) {\n for (let i = 0; i < value.length; i++) fd.append(name, value[i]);\n } else if (Array.isArray(value)) {\n for (const item of value) {\n fd.append(name, item instanceof File || item instanceof Blob ? item : String(item));\n }\n } else {\n fd.append(name, String(value));\n }\n }\n\n return fd;\n}\n"],"mappings":";;AAQA,SAAgB,EAAW,GAA2C;CACpE,IAAM,IAAK,IAAI,SAAS;CAExB,KAAK,IAAM,CAAC,GAAM,MAAU,OAAO,QAAQ,EAAc,CAAM,CAAC,GAC1D,SAAU,MAEd,IAAI,aAAiB,QAAQ,aAAiB,MAC5C,EAAG,OAAO,GAAM,CAAK;MAChB,IAAI,aAAiB,UAC1B,KAAK,IAAI,IAAI,GAAG,IAAI,EAAM,QAAQ,KAAK,EAAG,OAAO,GAAM,EAAM,EAAE;MAC1D,IAAI,MAAM,QAAQ,CAAK,GAC5B,KAAK,IAAM,KAAQ,GACjB,EAAG,OAAO,GAAM,aAAgB,QAAQ,aAAgB,OAAO,IAAO,OAAO,CAAI,CAAC;MAGpF,EAAG,OAAO,GAAM,OAAO,CAAK,CAAC;CAIjC,OAAO;AACT"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});function e(...e){return async(t,n)=>{for(let r of e){if(n?.aborted)return;let e=await r(t,n);if(e!==void 0)return e}}}function t(e){return t=>{let n=e.safeParse(t);if(!n.success)return n.error.issues[0]?.message}}exports.composeValidators=e,exports.fieldValidator=t;
|
|
2
|
+
//# sourceMappingURL=validators.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.cjs","names":[],"sources":["../../src/adapters/validators.ts"],"sourcesContent":["import type { FieldValidator, SafeParseSchema } from '../types';\n\n/**\n * Chains multiple field validators, running them in order and returning the first error message.\n * Validators after the first error are skipped (short-circuit). Signal aborts are respected between steps.\n *\n * Works naturally with {@link fieldValidator} — mix schema-based and custom validators in one chain:\n *\n * @example\n * import { s } from '@vielzeug/spell';\n * import { composeValidators, fieldValidator } from '@vielzeug/forge/validators';\n *\n * const passwordValidator = composeValidators(\n * fieldValidator(s.string().min(8, 'At least 8 characters')),\n * async (value, signal) => {\n * const isCompromised = await checkBreachedPasswords(value, signal);\n * return isCompromised ? 'Password found in breach database' : undefined;\n * },\n * );\n *\n * const form = createForm({\n * validators: { password: passwordValidator },\n * });\n */\nexport function composeValidators<V = unknown>(...validators: FieldValidator<V>[]): FieldValidator<V> {\n return async (value, signal) => {\n for (const validator of validators) {\n if (signal?.aborted) return undefined;\n\n const result = await validator(value, signal);\n\n if (result !== undefined) return result;\n }\n\n return undefined;\n };\n}\n\n/**\n * Wraps a `safeParse`-compatible field schema into a `FieldValidator`.\n * The first validation error message becomes the field error.\n *\n * Works with `@vielzeug/spell`, Zod, Valibot, and any Standard Schema compliant library —\n * no hard dependency required; resolved structurally via `SafeParseSchema`.\n *\n * @example\n * import { s } from '@vielzeug/spell';\n * import { fieldValidator } from '@vielzeug/forge/validators';\n *\n * const form = createForm({\n * validators: {\n * email: fieldValidator(s.string().email('Invalid email address')),\n * age: fieldValidator(s.number().min(18, 'Must be 18 or older')),\n * },\n * });\n */\nexport function fieldValidator<V = unknown>(schema: SafeParseSchema): FieldValidator<V> {\n return (value) => {\n const result = schema.safeParse(value);\n\n if (result.success) return undefined;\n\n return result.error.issues[0]?.message;\n };\n}\n"],"mappings":"mEAwBA,SAAgB,EAA+B,GAAG,EAAoD,CACpG,OAAO,MAAO,EAAO,IAAW,CAC9B,IAAK,IAAM,KAAa,EAAY,CAClC,GAAI,GAAQ,QAAS,OAErB,IAAM,EAAS,MAAM,EAAU,EAAO,CAAM,EAE5C,GAAI,IAAW,IAAA,GAAW,OAAO,CACnC,CAGF,CACF,CAoBA,SAAgB,EAA4B,EAA4C,CACtF,MAAQ,IAAU,CAChB,IAAM,EAAS,EAAO,UAAU,CAAK,EAEjC,MAAO,QAEX,OAAO,EAAO,MAAM,OAAO,EAAE,EAAE,OACjC,CACF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { FieldValidator, SafeParseSchema } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Chains multiple field validators, running them in order and returning the first error message.
|
|
4
|
+
* Validators after the first error are skipped (short-circuit). Signal aborts are respected between steps.
|
|
5
|
+
*
|
|
6
|
+
* Works naturally with {@link fieldValidator} — mix schema-based and custom validators in one chain:
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { s } from '@vielzeug/spell';
|
|
10
|
+
* import { composeValidators, fieldValidator } from '@vielzeug/forge/validators';
|
|
11
|
+
*
|
|
12
|
+
* const passwordValidator = composeValidators(
|
|
13
|
+
* fieldValidator(s.string().min(8, 'At least 8 characters')),
|
|
14
|
+
* async (value, signal) => {
|
|
15
|
+
* const isCompromised = await checkBreachedPasswords(value, signal);
|
|
16
|
+
* return isCompromised ? 'Password found in breach database' : undefined;
|
|
17
|
+
* },
|
|
18
|
+
* );
|
|
19
|
+
*
|
|
20
|
+
* const form = createForm({
|
|
21
|
+
* validators: { password: passwordValidator },
|
|
22
|
+
* });
|
|
23
|
+
*/
|
|
24
|
+
export declare function composeValidators<V = unknown>(...validators: FieldValidator<V>[]): FieldValidator<V>;
|
|
25
|
+
/**
|
|
26
|
+
* Wraps a `safeParse`-compatible field schema into a `FieldValidator`.
|
|
27
|
+
* The first validation error message becomes the field error.
|
|
28
|
+
*
|
|
29
|
+
* Works with `@vielzeug/spell`, Zod, Valibot, and any Standard Schema compliant library —
|
|
30
|
+
* no hard dependency required; resolved structurally via `SafeParseSchema`.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* import { s } from '@vielzeug/spell';
|
|
34
|
+
* import { fieldValidator } from '@vielzeug/forge/validators';
|
|
35
|
+
*
|
|
36
|
+
* const form = createForm({
|
|
37
|
+
* validators: {
|
|
38
|
+
* email: fieldValidator(s.string().email('Invalid email address')),
|
|
39
|
+
* age: fieldValidator(s.number().min(18, 'Must be 18 or older')),
|
|
40
|
+
* },
|
|
41
|
+
* });
|
|
42
|
+
*/
|
|
43
|
+
export declare function fieldValidator<V = unknown>(schema: SafeParseSchema): FieldValidator<V>;
|
|
44
|
+
//# sourceMappingURL=validators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.d.ts","sourceRoot":"","sources":["../../src/adapters/validators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CAYpG;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,cAAc,CAAC,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,eAAe,GAAG,cAAc,CAAC,CAAC,CAAC,CAQtF"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/adapters/validators.ts
|
|
2
|
+
function e(...e) {
|
|
3
|
+
return async (t, n) => {
|
|
4
|
+
for (let r of e) {
|
|
5
|
+
if (n?.aborted) return;
|
|
6
|
+
let e = await r(t, n);
|
|
7
|
+
if (e !== void 0) return e;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function t(e) {
|
|
12
|
+
return (t) => {
|
|
13
|
+
let n = e.safeParse(t);
|
|
14
|
+
if (!n.success) return n.error.issues[0]?.message;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { e as composeValidators, t as fieldValidator };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","names":[],"sources":["../../src/adapters/validators.ts"],"sourcesContent":["import type { FieldValidator, SafeParseSchema } from '../types';\n\n/**\n * Chains multiple field validators, running them in order and returning the first error message.\n * Validators after the first error are skipped (short-circuit). Signal aborts are respected between steps.\n *\n * Works naturally with {@link fieldValidator} — mix schema-based and custom validators in one chain:\n *\n * @example\n * import { s } from '@vielzeug/spell';\n * import { composeValidators, fieldValidator } from '@vielzeug/forge/validators';\n *\n * const passwordValidator = composeValidators(\n * fieldValidator(s.string().min(8, 'At least 8 characters')),\n * async (value, signal) => {\n * const isCompromised = await checkBreachedPasswords(value, signal);\n * return isCompromised ? 'Password found in breach database' : undefined;\n * },\n * );\n *\n * const form = createForm({\n * validators: { password: passwordValidator },\n * });\n */\nexport function composeValidators<V = unknown>(...validators: FieldValidator<V>[]): FieldValidator<V> {\n return async (value, signal) => {\n for (const validator of validators) {\n if (signal?.aborted) return undefined;\n\n const result = await validator(value, signal);\n\n if (result !== undefined) return result;\n }\n\n return undefined;\n };\n}\n\n/**\n * Wraps a `safeParse`-compatible field schema into a `FieldValidator`.\n * The first validation error message becomes the field error.\n *\n * Works with `@vielzeug/spell`, Zod, Valibot, and any Standard Schema compliant library —\n * no hard dependency required; resolved structurally via `SafeParseSchema`.\n *\n * @example\n * import { s } from '@vielzeug/spell';\n * import { fieldValidator } from '@vielzeug/forge/validators';\n *\n * const form = createForm({\n * validators: {\n * email: fieldValidator(s.string().email('Invalid email address')),\n * age: fieldValidator(s.number().min(18, 'Must be 18 or older')),\n * },\n * });\n */\nexport function fieldValidator<V = unknown>(schema: SafeParseSchema): FieldValidator<V> {\n return (value) => {\n const result = schema.safeParse(value);\n\n if (result.success) return undefined;\n\n return result.error.issues[0]?.message;\n };\n}\n"],"mappings":";AAwBA,SAAgB,EAA+B,GAAG,GAAoD;CACpG,OAAO,OAAO,GAAO,MAAW;EAC9B,KAAK,IAAM,KAAa,GAAY;GAClC,IAAI,GAAQ,SAAS;GAErB,IAAM,IAAS,MAAM,EAAU,GAAO,CAAM;GAE5C,IAAI,MAAW,KAAA,GAAW,OAAO;EACnC;CAGF;AACF;AAoBA,SAAgB,EAA4B,GAA4C;CACtF,QAAQ,MAAU;EAChB,IAAM,IAAS,EAAO,UAAU,CAAK;EAEjC,OAAO,SAEX,OAAO,EAAO,MAAM,OAAO,EAAE,EAAE;CACjC;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e,t,n){let r=e;return{append(i){let a=t.get(r);a!==void 0&&!Array.isArray(a)||n(e,Array.isArray(a)?[...a,i]:[i])},insert(i,a){let o=t.get(r);if(!Array.isArray(o))return;let s=[...o];s.splice(i,0,a),n(e,s)},move(i,a){let o=t.get(r);if(!Array.isArray(o))return;let s=[...o];s.splice(a,0,s.splice(i,1)[0]),n(e,s)},prepend(i){let a=t.get(r);a!==void 0&&!Array.isArray(a)||n(e,Array.isArray(a)?[i,...a]:[i])},remove(i){let a=t.get(r);Array.isArray(a)&&n(e,a.filter((e,t)=>t!==i))},replace(i,a){let o=t.get(r);if(!Array.isArray(o))return;let s=[...o];s[i]=a,n(e,s)},swap(i,a){let o=t.get(r);if(!Array.isArray(o))return;let s=[...o];[s[i],s[a]]=[s[a],s[i]],n(e,s)}}}exports.createArrayField=e;
|
|
2
|
+
//# sourceMappingURL=array.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.cjs","names":[],"sources":["../../src/core/array.ts"],"sourcesContent":["import type { ArrayField, FlatKeyOf, TypeAtPath } from '../types';\n\n// Resolves the element type of an array field — mirrored from types.ts.\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : unknown;\n\n/**\n * Builds a cached typed ArrayField helper for a specific field name.\n * The helper closes over `store` and `set` from the parent form closure.\n * R4: Return type is now `ArrayField<ElementOf<V>>` so callers get type-safe append/insert/etc.\n */\nexport function createArrayField<TValues extends Record<string, unknown>, K extends FlatKeyOf<TValues>>(\n name: K,\n store: Map<string, unknown>,\n set: (name: string, value: unknown) => void,\n): ArrayField<ElementOf<TypeAtPath<TValues, K>>> {\n type T = ElementOf<TypeAtPath<TValues, K>>;\n\n const key = name as string;\n\n return {\n append(value: T) {\n const current = store.get(key);\n\n if (current !== undefined && !Array.isArray(current)) return;\n\n set(name, (Array.isArray(current) ? [...current, value] : [value]) as TypeAtPath<TValues, K>);\n },\n insert(index: number, value: T) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n next.splice(index, 0, value);\n set(name, next as TypeAtPath<TValues, K>);\n },\n move(from: number, to: number) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n next.splice(to, 0, next.splice(from, 1)[0]);\n set(name, next as TypeAtPath<TValues, K>);\n },\n prepend(value: T) {\n const current = store.get(key);\n\n if (current !== undefined && !Array.isArray(current)) return;\n\n set(name, (Array.isArray(current) ? [value, ...current] : [value]) as TypeAtPath<TValues, K>);\n },\n remove(index: number) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n set(name, current.filter((_, i) => i !== index) as TypeAtPath<TValues, K>);\n },\n replace(index: number, value: T) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n next[index] = value;\n set(name, next as TypeAtPath<TValues, K>);\n },\n swap(a: number, b: number) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n [next[a], next[b]] = [next[b], next[a]];\n set(name, next as TypeAtPath<TValues, K>);\n },\n };\n}\n"],"mappings":"AAUA,SAAgB,EACd,EACA,EACA,EAC+C,CAG/C,IAAM,EAAM,EAEZ,MAAO,CACL,OAAO,EAAU,CACf,IAAM,EAAU,EAAM,IAAI,CAAG,EAEzB,IAAY,IAAA,IAAa,CAAC,MAAM,QAAQ,CAAO,GAEnD,EAAI,EAAO,MAAM,QAAQ,CAAO,EAAI,CAAC,GAAG,EAAS,CAAK,EAAI,CAAC,CAAK,CAA4B,CAC9F,EACA,OAAO,EAAe,EAAU,CAC9B,IAAM,EAAU,EAAM,IAAI,CAAG,EAE7B,GAAI,CAAC,MAAM,QAAQ,CAAO,EAAG,OAE7B,IAAM,EAAO,CAAC,GAAG,CAAO,EAExB,EAAK,OAAO,EAAO,EAAG,CAAK,EAC3B,EAAI,EAAM,CAA8B,CAC1C,EACA,KAAK,EAAc,EAAY,CAC7B,IAAM,EAAU,EAAM,IAAI,CAAG,EAE7B,GAAI,CAAC,MAAM,QAAQ,CAAO,EAAG,OAE7B,IAAM,EAAO,CAAC,GAAG,CAAO,EAExB,EAAK,OAAO,EAAI,EAAG,EAAK,OAAO,EAAM,CAAC,CAAC,CAAC,EAAE,EAC1C,EAAI,EAAM,CAA8B,CAC1C,EACA,QAAQ,EAAU,CAChB,IAAM,EAAU,EAAM,IAAI,CAAG,EAEzB,IAAY,IAAA,IAAa,CAAC,MAAM,QAAQ,CAAO,GAEnD,EAAI,EAAO,MAAM,QAAQ,CAAO,EAAI,CAAC,EAAO,GAAG,CAAO,EAAI,CAAC,CAAK,CAA4B,CAC9F,EACA,OAAO,EAAe,CACpB,IAAM,EAAU,EAAM,IAAI,CAAG,EAExB,MAAM,QAAQ,CAAO,GAE1B,EAAI,EAAM,EAAQ,QAAQ,EAAG,IAAM,IAAM,CAAK,CAA2B,CAC3E,EACA,QAAQ,EAAe,EAAU,CAC/B,IAAM,EAAU,EAAM,IAAI,CAAG,EAE7B,GAAI,CAAC,MAAM,QAAQ,CAAO,EAAG,OAE7B,IAAM,EAAO,CAAC,GAAG,CAAO,EAExB,EAAK,GAAS,EACd,EAAI,EAAM,CAA8B,CAC1C,EACA,KAAK,EAAW,EAAW,CACzB,IAAM,EAAU,EAAM,IAAI,CAAG,EAE7B,GAAI,CAAC,MAAM,QAAQ,CAAO,EAAG,OAE7B,IAAM,EAAO,CAAC,GAAG,CAAO,EAExB,CAAC,EAAK,GAAI,EAAK,IAAM,CAAC,EAAK,GAAI,EAAK,EAAE,EACtC,EAAI,EAAM,CAA8B,CAC1C,CACF,CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ArrayField, FlatKeyOf, TypeAtPath } from '../types';
|
|
2
|
+
type ElementOf<T> = T extends readonly (infer E)[] ? E : unknown;
|
|
3
|
+
/**
|
|
4
|
+
* Builds a cached typed ArrayField helper for a specific field name.
|
|
5
|
+
* The helper closes over `store` and `set` from the parent form closure.
|
|
6
|
+
* R4: Return type is now `ArrayField<ElementOf<V>>` so callers get type-safe append/insert/etc.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createArrayField<TValues extends Record<string, unknown>, K extends FlatKeyOf<TValues>>(name: K, store: Map<string, unknown>, set: (name: string, value: unknown) => void): ArrayField<ElementOf<TypeAtPath<TValues, K>>>;
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=array.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.d.ts","sourceRoot":"","sources":["../../src/core/array.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAGlE,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,SAAS,CAAC,OAAO,CAAC,EACpG,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3B,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,GAC1C,UAAU,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAoE/C"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region src/core/array.ts
|
|
2
|
+
function e(e, t, n) {
|
|
3
|
+
let r = e;
|
|
4
|
+
return {
|
|
5
|
+
append(i) {
|
|
6
|
+
let a = t.get(r);
|
|
7
|
+
a !== void 0 && !Array.isArray(a) || n(e, Array.isArray(a) ? [...a, i] : [i]);
|
|
8
|
+
},
|
|
9
|
+
insert(i, a) {
|
|
10
|
+
let o = t.get(r);
|
|
11
|
+
if (!Array.isArray(o)) return;
|
|
12
|
+
let s = [...o];
|
|
13
|
+
s.splice(i, 0, a), n(e, s);
|
|
14
|
+
},
|
|
15
|
+
move(i, a) {
|
|
16
|
+
let o = t.get(r);
|
|
17
|
+
if (!Array.isArray(o)) return;
|
|
18
|
+
let s = [...o];
|
|
19
|
+
s.splice(a, 0, s.splice(i, 1)[0]), n(e, s);
|
|
20
|
+
},
|
|
21
|
+
prepend(i) {
|
|
22
|
+
let a = t.get(r);
|
|
23
|
+
a !== void 0 && !Array.isArray(a) || n(e, Array.isArray(a) ? [i, ...a] : [i]);
|
|
24
|
+
},
|
|
25
|
+
remove(i) {
|
|
26
|
+
let a = t.get(r);
|
|
27
|
+
Array.isArray(a) && n(e, a.filter((e, t) => t !== i));
|
|
28
|
+
},
|
|
29
|
+
replace(i, a) {
|
|
30
|
+
let o = t.get(r);
|
|
31
|
+
if (!Array.isArray(o)) return;
|
|
32
|
+
let s = [...o];
|
|
33
|
+
s[i] = a, n(e, s);
|
|
34
|
+
},
|
|
35
|
+
swap(i, a) {
|
|
36
|
+
let o = t.get(r);
|
|
37
|
+
if (!Array.isArray(o)) return;
|
|
38
|
+
let s = [...o];
|
|
39
|
+
[s[i], s[a]] = [s[a], s[i]], n(e, s);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { e as createArrayField };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=array.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"array.js","names":[],"sources":["../../src/core/array.ts"],"sourcesContent":["import type { ArrayField, FlatKeyOf, TypeAtPath } from '../types';\n\n// Resolves the element type of an array field — mirrored from types.ts.\ntype ElementOf<T> = T extends readonly (infer E)[] ? E : unknown;\n\n/**\n * Builds a cached typed ArrayField helper for a specific field name.\n * The helper closes over `store` and `set` from the parent form closure.\n * R4: Return type is now `ArrayField<ElementOf<V>>` so callers get type-safe append/insert/etc.\n */\nexport function createArrayField<TValues extends Record<string, unknown>, K extends FlatKeyOf<TValues>>(\n name: K,\n store: Map<string, unknown>,\n set: (name: string, value: unknown) => void,\n): ArrayField<ElementOf<TypeAtPath<TValues, K>>> {\n type T = ElementOf<TypeAtPath<TValues, K>>;\n\n const key = name as string;\n\n return {\n append(value: T) {\n const current = store.get(key);\n\n if (current !== undefined && !Array.isArray(current)) return;\n\n set(name, (Array.isArray(current) ? [...current, value] : [value]) as TypeAtPath<TValues, K>);\n },\n insert(index: number, value: T) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n next.splice(index, 0, value);\n set(name, next as TypeAtPath<TValues, K>);\n },\n move(from: number, to: number) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n next.splice(to, 0, next.splice(from, 1)[0]);\n set(name, next as TypeAtPath<TValues, K>);\n },\n prepend(value: T) {\n const current = store.get(key);\n\n if (current !== undefined && !Array.isArray(current)) return;\n\n set(name, (Array.isArray(current) ? [value, ...current] : [value]) as TypeAtPath<TValues, K>);\n },\n remove(index: number) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n set(name, current.filter((_, i) => i !== index) as TypeAtPath<TValues, K>);\n },\n replace(index: number, value: T) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n next[index] = value;\n set(name, next as TypeAtPath<TValues, K>);\n },\n swap(a: number, b: number) {\n const current = store.get(key);\n\n if (!Array.isArray(current)) return;\n\n const next = [...current];\n\n [next[a], next[b]] = [next[b], next[a]];\n set(name, next as TypeAtPath<TValues, K>);\n },\n };\n}\n"],"mappings":";AAUA,SAAgB,EACd,GACA,GACA,GAC+C;CAG/C,IAAM,IAAM;CAEZ,OAAO;EACL,OAAO,GAAU;GACf,IAAM,IAAU,EAAM,IAAI,CAAG;GAEzB,MAAY,KAAA,KAAa,CAAC,MAAM,QAAQ,CAAO,KAEnD,EAAI,GAAO,MAAM,QAAQ,CAAO,IAAI,CAAC,GAAG,GAAS,CAAK,IAAI,CAAC,CAAK,CAA4B;EAC9F;EACA,OAAO,GAAe,GAAU;GAC9B,IAAM,IAAU,EAAM,IAAI,CAAG;GAE7B,IAAI,CAAC,MAAM,QAAQ,CAAO,GAAG;GAE7B,IAAM,IAAO,CAAC,GAAG,CAAO;GAGxB,AADA,EAAK,OAAO,GAAO,GAAG,CAAK,GAC3B,EAAI,GAAM,CAA8B;EAC1C;EACA,KAAK,GAAc,GAAY;GAC7B,IAAM,IAAU,EAAM,IAAI,CAAG;GAE7B,IAAI,CAAC,MAAM,QAAQ,CAAO,GAAG;GAE7B,IAAM,IAAO,CAAC,GAAG,CAAO;GAGxB,AADA,EAAK,OAAO,GAAI,GAAG,EAAK,OAAO,GAAM,CAAC,CAAC,CAAC,EAAE,GAC1C,EAAI,GAAM,CAA8B;EAC1C;EACA,QAAQ,GAAU;GAChB,IAAM,IAAU,EAAM,IAAI,CAAG;GAEzB,MAAY,KAAA,KAAa,CAAC,MAAM,QAAQ,CAAO,KAEnD,EAAI,GAAO,MAAM,QAAQ,CAAO,IAAI,CAAC,GAAO,GAAG,CAAO,IAAI,CAAC,CAAK,CAA4B;EAC9F;EACA,OAAO,GAAe;GACpB,IAAM,IAAU,EAAM,IAAI,CAAG;GAExB,MAAM,QAAQ,CAAO,KAE1B,EAAI,GAAM,EAAQ,QAAQ,GAAG,MAAM,MAAM,CAAK,CAA2B;EAC3E;EACA,QAAQ,GAAe,GAAU;GAC/B,IAAM,IAAU,EAAM,IAAI,CAAG;GAE7B,IAAI,CAAC,MAAM,QAAQ,CAAO,GAAG;GAE7B,IAAM,IAAO,CAAC,GAAG,CAAO;GAGxB,AADA,EAAK,KAAS,GACd,EAAI,GAAM,CAA8B;EAC1C;EACA,KAAK,GAAW,GAAW;GACzB,IAAM,IAAU,EAAM,IAAI,CAAG;GAE7B,IAAI,CAAC,MAAM,QAAQ,CAAO,GAAG;GAE7B,IAAM,IAAO,CAAC,GAAG,CAAO;GAGxB,AADA,CAAC,EAAK,IAAI,EAAK,MAAM,CAAC,EAAK,IAAI,EAAK,EAAE,GACtC,EAAI,GAAM,CAA8B;EAC1C;CACF;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){let t=[],n=null,r=null,i=!1,a=null;function o(e){if(!i)if(n){let t=n;n=null,r=null,t({done:!1,value:e})}else t.push(e)}function s(e){if(!i)if(i=!0,r){let t=r;n=null,r=null,t(e)}else a={err:e}}function c(){if(!i&&(i=!0,n)){let e=n;n=null,r=null,e({done:!0,value:void 0})}}function l(){i||(t=[],c(),e?.())}return{fail:s,finish:c,iterator:{next(){if(a){let{err:e}=a;return a=null,Promise.reject(e)}return t.length>0?Promise.resolve({done:!1,value:t.shift()}):i?Promise.resolve({done:!0,value:void 0}):new Promise((e,t)=>{n=e,r=t})},return(){return l(),Promise.resolve({done:!0,value:void 0})},[Symbol.asyncIterator](){return this}},push:o,terminate:l}}exports.createAsyncQueue=e;
|
|
2
|
+
//# sourceMappingURL=asyncQueue.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncQueue.cjs","names":[],"sources":["../../src/core/asyncQueue.ts"],"sourcesContent":["/**\n * A minimal push-based async queue exposing an `AsyncIterableIterator`.\n * Shared by `validateStream()` and `form[Symbol.asyncIterator]()`, which otherwise hand-roll\n * near-identical `queue`/`waitingResolve`/`done` plumbing.\n *\n * - `push()` delivers an item to a waiting `next()` call, or buffers it for the next one.\n * - `finish()` marks the queue complete; any items already buffered are still drained by\n * subsequent `next()` calls before `{ done: true }` is returned.\n * - `fail()` marks the queue complete and rejects the next `next()` call with `err`.\n * - Calling `iterator.return()` (e.g. via `for-await...of` `break`) hard-terminates the queue:\n * any buffered-but-undelivered items are discarded and `onTerminate` fires.\n */\nexport type AsyncQueue<T> = {\n fail(err: unknown): void;\n finish(): void;\n iterator: AsyncIterableIterator<T>;\n push(item: T): void;\n /** Hard-terminates the queue: drops any buffered items, marks it done, and fires `onTerminate`. */\n terminate(): void;\n};\n\nexport function createAsyncQueue<T>(onTerminate?: () => void): AsyncQueue<T> {\n type Resolver = (result: IteratorResult<T, undefined>) => void;\n type Rejecter = (err: unknown) => void;\n\n let buffer: T[] = [];\n let waitingResolve: Resolver | null = null;\n let waitingReject: Rejecter | null = null;\n let done = false;\n let pendingError: { err: unknown } | null = null;\n\n function push(item: T): void {\n if (done) return;\n\n if (waitingResolve) {\n const resolve = waitingResolve;\n\n waitingResolve = null;\n waitingReject = null;\n resolve({ done: false, value: item });\n } else {\n buffer.push(item);\n }\n }\n\n function fail(err: unknown): void {\n if (done) return;\n\n done = true;\n\n if (waitingReject) {\n const reject = waitingReject;\n\n waitingResolve = null;\n waitingReject = null;\n reject(err);\n } else {\n pendingError = { err };\n }\n }\n\n function finish(): void {\n if (done) return;\n\n done = true;\n\n if (waitingResolve) {\n const resolve = waitingResolve;\n\n waitingResolve = null;\n waitingReject = null;\n resolve({ done: true, value: undefined });\n }\n }\n\n function terminate(): void {\n if (done) return;\n\n buffer = [];\n finish();\n onTerminate?.();\n }\n\n const iterator: AsyncIterableIterator<T> = {\n next(): Promise<IteratorResult<T, undefined>> {\n if (pendingError) {\n const { err } = pendingError;\n\n pendingError = null;\n\n return Promise.reject(err);\n }\n\n if (buffer.length > 0) return Promise.resolve({ done: false, value: buffer.shift()! });\n\n if (done) return Promise.resolve({ done: true, value: undefined });\n\n return new Promise<IteratorResult<T, undefined>>((resolve, reject) => {\n waitingResolve = resolve;\n waitingReject = reject;\n });\n },\n\n return(): Promise<IteratorResult<T, undefined>> {\n terminate();\n\n return Promise.resolve({ done: true, value: undefined });\n },\n\n [Symbol.asyncIterator]() {\n return this;\n },\n };\n\n return { fail, finish, iterator, push, terminate };\n}\n"],"mappings":"AAqBA,SAAgB,EAAoB,EAAyC,CAI3E,IAAI,EAAc,CAAC,EACf,EAAkC,KAClC,EAAiC,KACjC,EAAO,GACP,EAAwC,KAE5C,SAAS,EAAK,EAAe,CACvB,MAEJ,GAAI,EAAgB,CAClB,IAAM,EAAU,EAEhB,EAAiB,KACjB,EAAgB,KAChB,EAAQ,CAAE,KAAM,GAAO,MAAO,CAAK,CAAC,CACtC,MACE,EAAO,KAAK,CAAI,CAEpB,CAEA,SAAS,EAAK,EAAoB,CAC5B,MAIJ,GAFA,EAAO,GAEH,EAAe,CACjB,IAAM,EAAS,EAEf,EAAiB,KACjB,EAAgB,KAChB,EAAO,CAAG,CACZ,KACE,GAAe,CAAE,KAAI,CAEzB,CAEA,SAAS,GAAe,CAClB,QAEJ,EAAO,GAEH,GAAgB,CAClB,IAAM,EAAU,EAEhB,EAAiB,KACjB,EAAgB,KAChB,EAAQ,CAAE,KAAM,GAAM,MAAO,IAAA,EAAU,CAAC,CAC1C,CACF,CAEA,SAAS,GAAkB,CACrB,IAEJ,EAAS,CAAC,EACV,EAAO,EACP,IAAc,EAChB,CAiCA,MAAO,CAAE,OAAM,SAAQ,SAAA,CA9BrB,MAA8C,CAC5C,GAAI,EAAc,CAChB,GAAM,CAAE,OAAQ,EAIhB,MAFA,GAAe,KAER,QAAQ,OAAO,CAAG,CAC3B,CAMA,OAJI,EAAO,OAAS,EAAU,QAAQ,QAAQ,CAAE,KAAM,GAAO,MAAO,EAAO,MAAM,CAAG,CAAC,EAEjF,EAAa,QAAQ,QAAQ,CAAE,KAAM,GAAM,MAAO,IAAA,EAAU,CAAC,EAE1D,IAAI,SAAuC,EAAS,IAAW,CACpE,EAAiB,EACjB,EAAgB,CAClB,CAAC,CACH,EAEA,QAAgD,CAG9C,OAFA,EAAU,EAEH,QAAQ,QAAQ,CAAE,KAAM,GAAM,MAAO,IAAA,EAAU,CAAC,CACzD,EAEA,CAAC,OAAO,gBAAiB,CACvB,OAAO,IACT,CAGqB,EAAU,OAAM,WAAU,CACnD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A minimal push-based async queue exposing an `AsyncIterableIterator`.
|
|
3
|
+
* Shared by `validateStream()` and `form[Symbol.asyncIterator]()`, which otherwise hand-roll
|
|
4
|
+
* near-identical `queue`/`waitingResolve`/`done` plumbing.
|
|
5
|
+
*
|
|
6
|
+
* - `push()` delivers an item to a waiting `next()` call, or buffers it for the next one.
|
|
7
|
+
* - `finish()` marks the queue complete; any items already buffered are still drained by
|
|
8
|
+
* subsequent `next()` calls before `{ done: true }` is returned.
|
|
9
|
+
* - `fail()` marks the queue complete and rejects the next `next()` call with `err`.
|
|
10
|
+
* - Calling `iterator.return()` (e.g. via `for-await...of` `break`) hard-terminates the queue:
|
|
11
|
+
* any buffered-but-undelivered items are discarded and `onTerminate` fires.
|
|
12
|
+
*/
|
|
13
|
+
export type AsyncQueue<T> = {
|
|
14
|
+
fail(err: unknown): void;
|
|
15
|
+
finish(): void;
|
|
16
|
+
iterator: AsyncIterableIterator<T>;
|
|
17
|
+
push(item: T): void;
|
|
18
|
+
/** Hard-terminates the queue: drops any buffered items, marks it done, and fires `onTerminate`. */
|
|
19
|
+
terminate(): void;
|
|
20
|
+
};
|
|
21
|
+
export declare function createAsyncQueue<T>(onTerminate?: () => void): AsyncQueue<T>;
|
|
22
|
+
//# sourceMappingURL=asyncQueue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncQueue.d.ts","sourceRoot":"","sources":["../../src/core/asyncQueue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,UAAU,CAAC,CAAC,IAAI;IAC1B,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,MAAM,IAAI,IAAI,CAAC;IACf,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACpB,mGAAmG;IACnG,SAAS,IAAI,IAAI,CAAC;CACnB,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,CA8F3E"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//#region src/core/asyncQueue.ts
|
|
2
|
+
function e(e) {
|
|
3
|
+
let t = [], n = null, r = null, i = !1, a = null;
|
|
4
|
+
function o(e) {
|
|
5
|
+
if (!i) if (n) {
|
|
6
|
+
let t = n;
|
|
7
|
+
n = null, r = null, t({
|
|
8
|
+
done: !1,
|
|
9
|
+
value: e
|
|
10
|
+
});
|
|
11
|
+
} else t.push(e);
|
|
12
|
+
}
|
|
13
|
+
function s(e) {
|
|
14
|
+
if (!i) if (i = !0, r) {
|
|
15
|
+
let t = r;
|
|
16
|
+
n = null, r = null, t(e);
|
|
17
|
+
} else a = { err: e };
|
|
18
|
+
}
|
|
19
|
+
function c() {
|
|
20
|
+
if (!i && (i = !0, n)) {
|
|
21
|
+
let e = n;
|
|
22
|
+
n = null, r = null, e({
|
|
23
|
+
done: !0,
|
|
24
|
+
value: void 0
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function l() {
|
|
29
|
+
i || (t = [], c(), e?.());
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
fail: s,
|
|
33
|
+
finish: c,
|
|
34
|
+
iterator: {
|
|
35
|
+
next() {
|
|
36
|
+
if (a) {
|
|
37
|
+
let { err: e } = a;
|
|
38
|
+
return a = null, Promise.reject(e);
|
|
39
|
+
}
|
|
40
|
+
return t.length > 0 ? Promise.resolve({
|
|
41
|
+
done: !1,
|
|
42
|
+
value: t.shift()
|
|
43
|
+
}) : i ? Promise.resolve({
|
|
44
|
+
done: !0,
|
|
45
|
+
value: void 0
|
|
46
|
+
}) : new Promise((e, t) => {
|
|
47
|
+
n = e, r = t;
|
|
48
|
+
});
|
|
49
|
+
},
|
|
50
|
+
return() {
|
|
51
|
+
return l(), Promise.resolve({
|
|
52
|
+
done: !0,
|
|
53
|
+
value: void 0
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
[Symbol.asyncIterator]() {
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
push: o,
|
|
61
|
+
terminate: l
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { e as createAsyncQueue };
|
|
66
|
+
|
|
67
|
+
//# sourceMappingURL=asyncQueue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asyncQueue.js","names":[],"sources":["../../src/core/asyncQueue.ts"],"sourcesContent":["/**\n * A minimal push-based async queue exposing an `AsyncIterableIterator`.\n * Shared by `validateStream()` and `form[Symbol.asyncIterator]()`, which otherwise hand-roll\n * near-identical `queue`/`waitingResolve`/`done` plumbing.\n *\n * - `push()` delivers an item to a waiting `next()` call, or buffers it for the next one.\n * - `finish()` marks the queue complete; any items already buffered are still drained by\n * subsequent `next()` calls before `{ done: true }` is returned.\n * - `fail()` marks the queue complete and rejects the next `next()` call with `err`.\n * - Calling `iterator.return()` (e.g. via `for-await...of` `break`) hard-terminates the queue:\n * any buffered-but-undelivered items are discarded and `onTerminate` fires.\n */\nexport type AsyncQueue<T> = {\n fail(err: unknown): void;\n finish(): void;\n iterator: AsyncIterableIterator<T>;\n push(item: T): void;\n /** Hard-terminates the queue: drops any buffered items, marks it done, and fires `onTerminate`. */\n terminate(): void;\n};\n\nexport function createAsyncQueue<T>(onTerminate?: () => void): AsyncQueue<T> {\n type Resolver = (result: IteratorResult<T, undefined>) => void;\n type Rejecter = (err: unknown) => void;\n\n let buffer: T[] = [];\n let waitingResolve: Resolver | null = null;\n let waitingReject: Rejecter | null = null;\n let done = false;\n let pendingError: { err: unknown } | null = null;\n\n function push(item: T): void {\n if (done) return;\n\n if (waitingResolve) {\n const resolve = waitingResolve;\n\n waitingResolve = null;\n waitingReject = null;\n resolve({ done: false, value: item });\n } else {\n buffer.push(item);\n }\n }\n\n function fail(err: unknown): void {\n if (done) return;\n\n done = true;\n\n if (waitingReject) {\n const reject = waitingReject;\n\n waitingResolve = null;\n waitingReject = null;\n reject(err);\n } else {\n pendingError = { err };\n }\n }\n\n function finish(): void {\n if (done) return;\n\n done = true;\n\n if (waitingResolve) {\n const resolve = waitingResolve;\n\n waitingResolve = null;\n waitingReject = null;\n resolve({ done: true, value: undefined });\n }\n }\n\n function terminate(): void {\n if (done) return;\n\n buffer = [];\n finish();\n onTerminate?.();\n }\n\n const iterator: AsyncIterableIterator<T> = {\n next(): Promise<IteratorResult<T, undefined>> {\n if (pendingError) {\n const { err } = pendingError;\n\n pendingError = null;\n\n return Promise.reject(err);\n }\n\n if (buffer.length > 0) return Promise.resolve({ done: false, value: buffer.shift()! });\n\n if (done) return Promise.resolve({ done: true, value: undefined });\n\n return new Promise<IteratorResult<T, undefined>>((resolve, reject) => {\n waitingResolve = resolve;\n waitingReject = reject;\n });\n },\n\n return(): Promise<IteratorResult<T, undefined>> {\n terminate();\n\n return Promise.resolve({ done: true, value: undefined });\n },\n\n [Symbol.asyncIterator]() {\n return this;\n },\n };\n\n return { fail, finish, iterator, push, terminate };\n}\n"],"mappings":";AAqBA,SAAgB,EAAoB,GAAyC;CAI3E,IAAI,IAAc,CAAC,GACf,IAAkC,MAClC,IAAiC,MACjC,IAAO,IACP,IAAwC;CAE5C,SAAS,EAAK,GAAe;EACvB,QAEJ,IAAI,GAAgB;GAClB,IAAM,IAAU;GAIhB,AAFA,IAAiB,MACjB,IAAgB,MAChB,EAAQ;IAAE,MAAM;IAAO,OAAO;GAAK,CAAC;EACtC,OACE,EAAO,KAAK,CAAI;CAEpB;CAEA,SAAS,EAAK,GAAoB;EAC5B,QAIJ,IAFA,IAAO,IAEH,GAAe;GACjB,IAAM,IAAS;GAIf,AAFA,IAAiB,MACjB,IAAgB,MAChB,EAAO,CAAG;EACZ,OACE,IAAe,EAAE,OAAI;CAEzB;CAEA,SAAS,IAAe;EAClB,WAEJ,IAAO,IAEH,IAAgB;GAClB,IAAM,IAAU;GAIhB,AAFA,IAAiB,MACjB,IAAgB,MAChB,EAAQ;IAAE,MAAM;IAAM,OAAO,KAAA;GAAU,CAAC;EAC1C;CACF;CAEA,SAAS,IAAkB;EACrB,MAEJ,IAAS,CAAC,GACV,EAAO,GACP,IAAc;CAChB;CAiCA,OAAO;EAAE;EAAM;EAAQ,UAAA;GA9BrB,OAA8C;IAC5C,IAAI,GAAc;KAChB,IAAM,EAAE,WAAQ;KAIhB,OAFA,IAAe,MAER,QAAQ,OAAO,CAAG;IAC3B;IAMA,OAJI,EAAO,SAAS,IAAU,QAAQ,QAAQ;KAAE,MAAM;KAAO,OAAO,EAAO,MAAM;IAAG,CAAC,IAEjF,IAAa,QAAQ,QAAQ;KAAE,MAAM;KAAM,OAAO,KAAA;IAAU,CAAC,IAE1D,IAAI,SAAuC,GAAS,MAAW;KAEpE,AADA,IAAiB,GACjB,IAAgB;IAClB,CAAC;GACH;GAEA,SAAgD;IAG9C,OAFA,EAAU,GAEH,QAAQ,QAAQ;KAAE,MAAM;KAAM,OAAO,KAAA;IAAU,CAAC;GACzD;GAEA,CAAC,OAAO,iBAAiB;IACvB,OAAO;GACT;EAGqB;EAAU;EAAM;CAAU;AACnD"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("../errors.cjs"),t=require("../_utils.cjs");require("../types.cjs");let n=require("@vielzeug/ripple"),r=require("@vielzeug/arsenal");function i(e){if(!e)return;if(typeof e==`function`)return e;let n=e;return(e,r)=>{if(r?.aborted)return;let i=n.safeParse(e);if(i.success)return;let a={};for(let e of i.error.issues){let n=e.path.join(`.`)||`_form`;t.isSafeKey(n)&&(a[n]||(a[n]=e.message))}return a}}function a(a){let o=new Map;for(let[e,n]of Object.entries(a.validators??{}))t.assertSafeKey(e),o.set(e,n);let s=i(a.validator),c=a.connect??{},l=typeof a.defaultValues==`function`,u=typeof a.defaultValues==`function`?void 0:a.defaultValues,d=new Map(Object.entries((0,r.flattenPaths)(u??{}))),f=new Map(d),p=new Map,m=new Set,h=new Set,g=new Map,_=new Set,v=new Map,y=new AbortController,b=null,x=null,S=new Map,C=new Map,w=new Map,T=!1,E=0,D=!1,O=new Map,k=new Set;function A(e){return O.has(e)||O.set(e,(0,n.signal)(L(e),{equals:(e,t)=>e.value===t.value&&e.error===t.error&&e.hasError===t.hasError&&e.touched===t.touched&&e.dirty===t.dirty})),O.get(e)}function j(){b=null}function M(){x=null}function N(){return x??=Object.freeze(Object.fromEntries(p))}function P(){return Object.freeze({errors:N(),isDirty:h.size>0,isLoading:l,isSubmitting:T,isTouched:m.size>0,isValid:p.size===0,isValidating:g.size>0,submitCount:E,touchedFields:Object.freeze([...m]),validatingFields:Object.freeze([...g.keys()])})}let F=(0,n.signal)(P());function I(){return F.value}function L(e){let t=p.get(e);return{dirty:h.has(e),error:t,hasError:t!==void 0,touched:m.has(e),value:f.get(e)}}function R(e){let t=S.get(e);if(t)return t;let n=Object.freeze(L(e));return S.set(e,n),n}function z(e){if(!D)if(j(),x=null,e===void 0)S.clear(),(0,n.batch)(()=>{F.value=P();for(let[e,t]of O)t.value=L(e)});else if(typeof e==`string`)S.delete(e),(0,n.batch)(()=>{F.value=P();let t=O.get(e);t&&(t.value=L(e))});else{let t=[...e];for(let e of t)S.delete(e);(0,n.batch)(()=>{F.value=P();for(let e of t){let t=O.get(e);t&&(t.value=L(e))}})}}function B(){if(D)throw new e.ForgeDisposedError}function V(e){B();try{(0,n.batch)(e)}catch(e){throw z(),e}}return{arrayCache:C,baseline:d,batch:V,buildFieldState:L,get cachedErrors(){return x},set cachedErrors(e){x=e},get cachedValues(){return b},set cachedValues(e){b=e},computeErrors:N,computeState:P,connectDefaults:c,dirty:h,disposeController:y,get disposed(){return D},set disposed(e){D=e},ensureNotDisposed:B,fieldCtrls:v,fieldErrors:p,fieldSignals:O,fieldStateCache:S,formStateSignal:F,formValidator:s,getFieldSnapshot:R,getOrCreateFieldSignal:A,getStateSnapshot:I,invalidateErrors:M,invalidateValues:j,get isSubmittingState(){return T},set isSubmittingState(e){T=e},get loadingState(){return l},set loadingState(e){l=e},requestNotify:z,rippleSubs:k,runCtrls:_,scopeCache:w,store:f,get submitCount(){return E},set submitCount(e){E=e},touched:m,validatingRuns:g,validators:o}}exports.createFormContext=a;
|
|
2
|
+
//# sourceMappingURL=context.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.cjs","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,10 @@
|
|
|
1
|
+
import { type FormOptions } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Builds the raw mutable state + shared primitives for a form. This is the "Core state" +
|
|
4
|
+
* "Notification helpers" sections of the original monolithic `createForm()` body, factored
|
|
5
|
+
* out so `internal/values.ts`, `internal/validation.ts`, `internal/observe.ts`, and
|
|
6
|
+
* `internal/lifecycle.ts` can each operate on the same shared state without closing over
|
|
7
|
+
* ad-hoc free variables.
|
|
8
|
+
*/
|
|
9
|
+
export declare function createFormContext<TValues extends Record<string, unknown> = Record<string, unknown>>(init: FormOptions<TValues>): FormContext<TValues>;
|
|
10
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAIA,OAAO,EAOL,KAAK,WAAW,EAIjB,MAAM,UAAU,CAAC;AAmFlB;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjG,IAAI,EAAE,WAAW,CAAC,OAAO,CAAC,GACzB,WAAW,CAAC,OAAO,CAAC,CA+QtB"}
|