@vielzeug/forge 1.3.1 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_utils.cjs +1 -1
- package/dist/_utils.cjs.map +1 -1
- package/dist/_utils.d.ts.map +1 -1
- package/dist/_utils.js +1 -0
- package/dist/_utils.js.map +1 -1
- package/dist/core/array.cjs +1 -1
- package/dist/core/array.cjs.map +1 -1
- package/dist/core/array.d.ts.map +1 -1
- package/dist/core/array.js +63 -32
- package/dist/core/array.js.map +1 -1
- package/dist/core/asyncQueue.cjs.map +1 -1
- package/dist/core/asyncQueue.d.ts +2 -2
- package/dist/core/asyncQueue.js.map +1 -1
- package/dist/core/context.cjs +1 -1
- package/dist/core/context.cjs.map +1 -1
- package/dist/core/context.d.ts +2 -5
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js +72 -109
- package/dist/core/context.js.map +1 -1
- package/dist/core/fields.cjs +2 -0
- package/dist/core/fields.cjs.map +1 -0
- package/dist/core/fields.d.ts +52 -0
- package/dist/core/fields.d.ts.map +1 -0
- package/dist/core/fields.js +310 -0
- package/dist/core/fields.js.map +1 -0
- package/dist/core/lifecycle.cjs +1 -1
- package/dist/core/lifecycle.cjs.map +1 -1
- package/dist/core/lifecycle.d.ts +3 -1
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +10 -14
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/notifier.cjs +2 -0
- package/dist/core/notifier.cjs.map +1 -0
- package/dist/core/notifier.d.ts +33 -0
- package/dist/core/notifier.d.ts.map +1 -0
- package/dist/core/notifier.js +78 -0
- package/dist/core/notifier.js.map +1 -0
- package/dist/core/observe.cjs +1 -1
- package/dist/core/observe.cjs.map +1 -1
- package/dist/core/observe.d.ts +8 -6
- package/dist/core/observe.d.ts.map +1 -1
- package/dist/core/observe.js +34 -45
- package/dist/core/observe.js.map +1 -1
- package/dist/core/scope.cjs +1 -1
- package/dist/core/scope.cjs.map +1 -1
- package/dist/core/scope.d.ts +6 -3
- package/dist/core/scope.d.ts.map +1 -1
- package/dist/core/scope.js +105 -156
- package/dist/core/scope.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +2 -2
- package/dist/errors.js.map +1 -1
- package/dist/forge.cjs +1 -1
- package/dist/forge.cjs.map +1 -1
- package/dist/forge.iife.js +1 -1
- package/dist/forge.iife.js.map +1 -1
- package/dist/forge.js +1 -1
- package/dist/forge.js.map +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.cjs.map +1 -1
- package/dist/form.d.ts.map +1 -1
- package/dist/form.js +45 -56
- package/dist/form.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +4 -4
- package/dist/types.cjs +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.ts +53 -36
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
- package/dist/core/validation.cjs +0 -2
- package/dist/core/validation.cjs.map +0 -1
- package/dist/core/validation.d.ts +0 -23
- package/dist/core/validation.d.ts.map +0 -1
- package/dist/core/validation.js +0 -173
- package/dist/core/validation.js.map +0 -1
- package/dist/core/values.cjs +0 -2
- package/dist/core/values.cjs.map +0 -1
- package/dist/core/values.d.ts +0 -31
- package/dist/core/values.d.ts.map +0 -1
- package/dist/core/values.js +0 -149
- package/dist/core/values.js.map +0 -1
package/dist/_utils.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("./_dev.cjs"),t=require("./errors.cjs");require("@vielzeug/arsenal");var n=new Set([`__proto__`,`constructor`,`prototype`]);function r(e){return e.split(`.`).every(e=>!n.has(e))}function i(e){if(o(e),!r(e))throw new t.ForgeConfigError(`Unsafe key '${e}': segments __proto__, constructor, and prototype are reserved.`)}var a=new Set;function o(t){t.includes(`.`)&&(t.split(`.`).length<=5||a.has(t)||(a.add(t),e.devOnly(()=>{e.warn(`Path '${s(t,120)}' exceeds typed depth limits and may be treated as an untyped string path.`)})))}function s(e,t=200){return e.replace(/\p{C}/gu,`?`).slice(0,t)}function c(...e){let t=e.filter(e=>e!=null);if(t.length!==0)return t.length===1?t[0]:AbortSignal.any(t)}exports.anySignal=c,exports.assertSafeKey=i,exports.isSafeKey=r,exports.sanitizeForLog=s;
|
|
1
|
+
const e=require("./_dev.cjs"),t=require("./errors.cjs");require("./types.cjs"),require("@vielzeug/arsenal");var n=new Set([`__proto__`,`constructor`,`prototype`]);function r(e){return e.split(`.`).every(e=>!n.has(e))}function i(e){if(o(e),!r(e))throw new t.ForgeConfigError(`Unsafe key '${e}': segments __proto__, constructor, and prototype are reserved.`)}var a=new Set;function o(t){t.includes(`.`)&&(t.split(`.`).length<=5||a.has(t)||(a.add(t),e.devOnly(()=>{e.warn(`Path '${s(t,120)}' exceeds typed depth limits and may be treated as an untyped string path.`)})))}function s(e,t=200){return e.replace(/\p{C}/gu,`?`).slice(0,t)}function c(...e){let t=e.filter(e=>e!=null);if(t.length!==0)return t.length===1?t[0]:AbortSignal.any(t)}exports.anySignal=c,exports.assertSafeKey=i,exports.isSafeKey=r,exports.sanitizeForLog=s;
|
|
2
2
|
//# sourceMappingURL=_utils.cjs.map
|
package/dist/_utils.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.cjs","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["import { devOnly, warn } from './_dev';\nimport { 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 warnIfDeepPathTypeFallback(key);\n\n if (!isSafeKey(key))\n throw new ForgeConfigError(`Unsafe key '${key}': segments __proto__, constructor, and prototype are reserved.`);\n}\n\nconst warnedDeepPaths = new Set<string>();\n\n/**\n * FlatKeyOf intentionally caps recursive path typing depth for TS performance
|
|
1
|
+
{"version":3,"file":"_utils.cjs","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["import { devOnly, warn } from './_dev';\nimport { ForgeConfigError } from './errors';\nimport { MAX_TYPED_PATH_DEPTH } from './types';\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 warnIfDeepPathTypeFallback(key);\n\n if (!isSafeKey(key))\n throw new ForgeConfigError(`Unsafe key '${key}': segments __proto__, constructor, and prototype are reserved.`);\n}\n\nconst warnedDeepPaths = new Set<string>();\n\n/**\n * FlatKeyOf intentionally caps recursive path typing depth for TS performance (see\n * `MAX_TYPED_PATH_DEPTH` in types.ts). Warn once per deep key in dev so callers notice\n * when path type inference likely fell back to `string`.\n */\nfunction warnIfDeepPathTypeFallback(key: string): void {\n if (!key.includes('.')) return;\n\n const depth = key.split('.').length;\n\n if (depth <= MAX_TYPED_PATH_DEPTH || warnedDeepPaths.has(key)) return;\n\n warnedDeepPaths.add(key);\n\n devOnly(() => {\n warn(`Path '${sanitizeForLog(key, 120)}' exceeds typed depth limits and may be treated as an untyped string path.`);\n });\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":"4GAMA,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,CAG/C,GAFA,EAA2B,CAAG,EAE1B,CAAC,EAAU,CAAG,EAChB,MAAM,IAAI,EAAA,iBAAiB,eAAe,EAAI,gEAAgE,CAClH,CAEA,IAAM,EAAkB,IAAI,IAO5B,SAAS,EAA2B,EAAmB,CAChD,EAAI,SAAS,GAAG,IAEP,EAAI,MAAM,GAAG,CAAC,CAAC,QAAA,GAEQ,EAAgB,IAAI,CAAG,IAE5D,EAAgB,IAAI,CAAG,EAEvB,EAAA,YAAc,CACZ,EAAA,KAAK,SAAS,EAAe,EAAK,GAAG,EAAE,2EAA2E,CACpH,CAAC,GACH,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.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.d.ts","sourceRoot":"","sources":["../src/_utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"_utils.d.ts","sourceRoot":"","sources":["../src/_utils.ts"],"names":[],"mappings":"AAIA,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,CAK/C;AAuBD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,SAAM,GAAG,MAAM,CAEpE"}
|
package/dist/_utils.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { devOnly as e, warn as t } from "./_dev.js";
|
|
2
2
|
import { ForgeConfigError as n } from "./errors.js";
|
|
3
|
+
import "./types.js";
|
|
3
4
|
import { flattenPaths as r, unflattenPaths as i } from "@vielzeug/arsenal";
|
|
4
5
|
//#region src/_utils.ts
|
|
5
6
|
var a = /* @__PURE__ */ new Set([
|
package/dist/_utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_utils.js","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["import { devOnly, warn } from './_dev';\nimport { 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 warnIfDeepPathTypeFallback(key);\n\n if (!isSafeKey(key))\n throw new ForgeConfigError(`Unsafe key '${key}': segments __proto__, constructor, and prototype are reserved.`);\n}\n\nconst warnedDeepPaths = new Set<string>();\n\n/**\n * FlatKeyOf intentionally caps recursive path typing depth for TS performance
|
|
1
|
+
{"version":3,"file":"_utils.js","names":[],"sources":["../src/_utils.ts"],"sourcesContent":["import { devOnly, warn } from './_dev';\nimport { ForgeConfigError } from './errors';\nimport { MAX_TYPED_PATH_DEPTH } from './types';\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 warnIfDeepPathTypeFallback(key);\n\n if (!isSafeKey(key))\n throw new ForgeConfigError(`Unsafe key '${key}': segments __proto__, constructor, and prototype are reserved.`);\n}\n\nconst warnedDeepPaths = new Set<string>();\n\n/**\n * FlatKeyOf intentionally caps recursive path typing depth for TS performance (see\n * `MAX_TYPED_PATH_DEPTH` in types.ts). Warn once per deep key in dev so callers notice\n * when path type inference likely fell back to `string`.\n */\nfunction warnIfDeepPathTypeFallback(key: string): void {\n if (!key.includes('.')) return;\n\n const depth = key.split('.').length;\n\n if (depth <= MAX_TYPED_PATH_DEPTH || warnedDeepPaths.has(key)) return;\n\n warnedDeepPaths.add(key);\n\n devOnly(() => {\n warn(`Path '${sanitizeForLog(key, 120)}' exceeds typed depth limits and may be treated as an untyped string path.`);\n });\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":";;;;;AAMA,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;CAG/C,IAFA,EAA2B,CAAG,GAE1B,CAAC,EAAU,CAAG,GAChB,MAAM,IAAI,EAAiB,eAAe,EAAI,gEAAgE;AAClH;AAEA,IAAM,oBAAkB,IAAI,IAAY;AAOxC,SAAS,EAA2B,GAAmB;CAChD,EAAI,SAAS,GAAG,MAEP,EAAI,MAAM,GAAG,CAAC,CAAC,UAAA,KAEQ,EAAgB,IAAI,CAAG,MAE5D,EAAgB,IAAI,CAAG,GAEvB,QAAc;EACZ,EAAK,SAAS,EAAe,GAAK,GAAG,EAAE,2EAA2E;CACpH,CAAC;AACH;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"}
|
package/dist/core/array.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function e(e
|
|
1
|
+
const e=require("../_dev.cjs"),t=require("../_utils.cjs");function n(n,r,i){let a=n;function o(n,r){e.devOnly(()=>{e.warn(`array('${t.sanitizeForLog(a,80)}').${n}(): field is not an array (got ${r===null?`null`:typeof r}) — no-op.`)})}return{append(e){let t=r.get(a);if(t!==void 0&&!Array.isArray(t)){o(`append`,t);return}i(n,Array.isArray(t)?[...t,e]:[e])},insert(e,t){let s=r.get(a);if(!Array.isArray(s)){o(`insert`,s);return}let c=[...s];c.splice(e,0,t),i(n,c)},move(e,t){let s=r.get(a);if(!Array.isArray(s)){o(`move`,s);return}let c=[...s];c.splice(t,0,c.splice(e,1)[0]),i(n,c)},prepend(e){let t=r.get(a);if(t!==void 0&&!Array.isArray(t)){o(`prepend`,t);return}i(n,Array.isArray(t)?[e,...t]:[e])},remove(e){let t=r.get(a);if(!Array.isArray(t)){o(`remove`,t);return}i(n,t.filter((t,n)=>n!==e))},replace(e,t){let s=r.get(a);if(!Array.isArray(s)){o(`replace`,s);return}let c=[...s];c[e]=t,i(n,c)},swap(e,t){let s=r.get(a);if(!Array.isArray(s)){o(`swap`,s);return}let c=[...s];[c[e],c[t]]=[c[t],c[e]],i(n,c)}}}exports.createArrayField=n;
|
|
2
2
|
//# sourceMappingURL=array.cjs.map
|
package/dist/core/array.cjs.map
CHANGED
|
@@ -1 +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":"
|
|
1
|
+
{"version":3,"file":"array.cjs","names":[],"sources":["../../src/core/array.ts"],"sourcesContent":["import type { ArrayField, FlatKeyOf, TypeAtPath } from '../types';\n\nimport { devOnly, warn } from '../_dev';\nimport { sanitizeForLog } from '../_utils';\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 // Every mutating method below no-ops when the field isn't (yet) an array, instead of\n // throwing — a field can legitimately not exist yet. But a silent no-op with zero signal\n // is a debugging trap for the common mistake (typo'd field name, forgot to append() first\n // to seed the array). Warn once per call in dev so it's discoverable without being a\n // breaking runtime error for the legitimate \"not initialized yet\" case.\n function warnNotArray(apiLabel: string, current: unknown): void {\n devOnly(() => {\n warn(\n `array('${sanitizeForLog(key, 80)}').${apiLabel}(): field is not an array ` +\n `(got ${current === null ? 'null' : typeof current}) — no-op.`,\n );\n });\n }\n\n return {\n append(value: T) {\n const current = store.get(key);\n\n if (current !== undefined && !Array.isArray(current)) {\n warnNotArray('append', current);\n\n return;\n }\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)) {\n warnNotArray('insert', current);\n\n return;\n }\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)) {\n warnNotArray('move', current);\n\n return;\n }\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)) {\n warnNotArray('prepend', current);\n\n return;\n }\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)) {\n warnNotArray('remove', current);\n\n return;\n }\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)) {\n warnNotArray('replace', current);\n\n return;\n }\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)) {\n warnNotArray('swap', current);\n\n return;\n }\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":"0DAaA,SAAgB,EACd,EACA,EACA,EAC+C,CAG/C,IAAM,EAAM,EAOZ,SAAS,EAAa,EAAkB,EAAwB,CAC9D,EAAA,YAAc,CACZ,EAAA,KACE,UAAU,EAAA,eAAe,EAAK,EAAE,EAAE,KAAK,EAAS,iCACtC,IAAY,KAAO,OAAS,OAAO,EAAQ,WACvD,CACF,CAAC,CACH,CAEA,MAAO,CACL,OAAO,EAAU,CACf,IAAM,EAAU,EAAM,IAAI,CAAG,EAE7B,GAAI,IAAY,IAAA,IAAa,CAAC,MAAM,QAAQ,CAAO,EAAG,CACpD,EAAa,SAAU,CAAO,EAE9B,MACF,CAEA,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,CAC3B,EAAa,SAAU,CAAO,EAE9B,MACF,CAEA,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,CAC3B,EAAa,OAAQ,CAAO,EAE5B,MACF,CAEA,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,EAE7B,GAAI,IAAY,IAAA,IAAa,CAAC,MAAM,QAAQ,CAAO,EAAG,CACpD,EAAa,UAAW,CAAO,EAE/B,MACF,CAEA,EAAI,EAAO,MAAM,QAAQ,CAAO,EAAI,CAAC,EAAO,GAAG,CAAO,EAAI,CAAC,CAAK,CAA4B,CAC9F,EACA,OAAO,EAAe,CACpB,IAAM,EAAU,EAAM,IAAI,CAAG,EAE7B,GAAI,CAAC,MAAM,QAAQ,CAAO,EAAG,CAC3B,EAAa,SAAU,CAAO,EAE9B,MACF,CAEA,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,CAC3B,EAAa,UAAW,CAAO,EAE/B,MACF,CAEA,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,CAC3B,EAAa,OAAQ,CAAO,EAE5B,MACF,CAEA,IAAM,EAAO,CAAC,GAAG,CAAO,EAExB,CAAC,EAAK,GAAI,EAAK,IAAM,CAAC,EAAK,GAAI,EAAK,EAAE,EACtC,EAAI,EAAM,CAA8B,CAC1C,CACF,CACF"}
|
package/dist/core/array.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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;AAMlE,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,CA8G/C"}
|
package/dist/core/array.js
CHANGED
|
@@ -1,46 +1,77 @@
|
|
|
1
|
+
import { devOnly as e, warn as t } from "../_dev.js";
|
|
2
|
+
import { sanitizeForLog as n } from "../_utils.js";
|
|
1
3
|
//#region src/core/array.ts
|
|
2
|
-
function
|
|
3
|
-
let
|
|
4
|
+
function r(r, i, a) {
|
|
5
|
+
let o = r;
|
|
6
|
+
function s(r, i) {
|
|
7
|
+
e(() => {
|
|
8
|
+
t(`array('${n(o, 80)}').${r}(): field is not an array (got ${i === null ? "null" : typeof i}) — no-op.`);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
4
11
|
return {
|
|
5
|
-
append(
|
|
6
|
-
let
|
|
7
|
-
|
|
12
|
+
append(e) {
|
|
13
|
+
let t = i.get(o);
|
|
14
|
+
if (t !== void 0 && !Array.isArray(t)) {
|
|
15
|
+
s("append", t);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
a(r, Array.isArray(t) ? [...t, e] : [e]);
|
|
8
19
|
},
|
|
9
|
-
insert(
|
|
10
|
-
let
|
|
11
|
-
if (!Array.isArray(
|
|
12
|
-
|
|
13
|
-
|
|
20
|
+
insert(e, t) {
|
|
21
|
+
let n = i.get(o);
|
|
22
|
+
if (!Array.isArray(n)) {
|
|
23
|
+
s("insert", n);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
let c = [...n];
|
|
27
|
+
c.splice(e, 0, t), a(r, c);
|
|
14
28
|
},
|
|
15
|
-
move(
|
|
16
|
-
let
|
|
17
|
-
if (!Array.isArray(
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
move(e, t) {
|
|
30
|
+
let n = i.get(o);
|
|
31
|
+
if (!Array.isArray(n)) {
|
|
32
|
+
s("move", n);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
let c = [...n];
|
|
36
|
+
c.splice(t, 0, c.splice(e, 1)[0]), a(r, c);
|
|
20
37
|
},
|
|
21
|
-
prepend(
|
|
22
|
-
let
|
|
23
|
-
|
|
38
|
+
prepend(e) {
|
|
39
|
+
let t = i.get(o);
|
|
40
|
+
if (t !== void 0 && !Array.isArray(t)) {
|
|
41
|
+
s("prepend", t);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
a(r, Array.isArray(t) ? [e, ...t] : [e]);
|
|
24
45
|
},
|
|
25
|
-
remove(
|
|
26
|
-
let
|
|
27
|
-
Array.isArray(
|
|
46
|
+
remove(e) {
|
|
47
|
+
let t = i.get(o);
|
|
48
|
+
if (!Array.isArray(t)) {
|
|
49
|
+
s("remove", t);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
a(r, t.filter((t, n) => n !== e));
|
|
28
53
|
},
|
|
29
|
-
replace(
|
|
30
|
-
let
|
|
31
|
-
if (!Array.isArray(
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
replace(e, t) {
|
|
55
|
+
let n = i.get(o);
|
|
56
|
+
if (!Array.isArray(n)) {
|
|
57
|
+
s("replace", n);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
let c = [...n];
|
|
61
|
+
c[e] = t, a(r, c);
|
|
34
62
|
},
|
|
35
|
-
swap(
|
|
36
|
-
let
|
|
37
|
-
if (!Array.isArray(
|
|
38
|
-
|
|
39
|
-
|
|
63
|
+
swap(e, t) {
|
|
64
|
+
let n = i.get(o);
|
|
65
|
+
if (!Array.isArray(n)) {
|
|
66
|
+
s("swap", n);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
let c = [...n];
|
|
70
|
+
[c[e], c[t]] = [c[t], c[e]], a(r, c);
|
|
40
71
|
}
|
|
41
72
|
};
|
|
42
73
|
}
|
|
43
74
|
//#endregion
|
|
44
|
-
export {
|
|
75
|
+
export { r as createArrayField };
|
|
45
76
|
|
|
46
77
|
//# sourceMappingURL=array.js.map
|
package/dist/core/array.js.map
CHANGED
|
@@ -1 +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":"
|
|
1
|
+
{"version":3,"file":"array.js","names":[],"sources":["../../src/core/array.ts"],"sourcesContent":["import type { ArrayField, FlatKeyOf, TypeAtPath } from '../types';\n\nimport { devOnly, warn } from '../_dev';\nimport { sanitizeForLog } from '../_utils';\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 // Every mutating method below no-ops when the field isn't (yet) an array, instead of\n // throwing — a field can legitimately not exist yet. But a silent no-op with zero signal\n // is a debugging trap for the common mistake (typo'd field name, forgot to append() first\n // to seed the array). Warn once per call in dev so it's discoverable without being a\n // breaking runtime error for the legitimate \"not initialized yet\" case.\n function warnNotArray(apiLabel: string, current: unknown): void {\n devOnly(() => {\n warn(\n `array('${sanitizeForLog(key, 80)}').${apiLabel}(): field is not an array ` +\n `(got ${current === null ? 'null' : typeof current}) — no-op.`,\n );\n });\n }\n\n return {\n append(value: T) {\n const current = store.get(key);\n\n if (current !== undefined && !Array.isArray(current)) {\n warnNotArray('append', current);\n\n return;\n }\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)) {\n warnNotArray('insert', current);\n\n return;\n }\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)) {\n warnNotArray('move', current);\n\n return;\n }\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)) {\n warnNotArray('prepend', current);\n\n return;\n }\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)) {\n warnNotArray('remove', current);\n\n return;\n }\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)) {\n warnNotArray('replace', current);\n\n return;\n }\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)) {\n warnNotArray('swap', current);\n\n return;\n }\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":";;;AAaA,SAAgB,EACd,GACA,GACA,GAC+C;CAG/C,IAAM,IAAM;CAOZ,SAAS,EAAa,GAAkB,GAAwB;EAC9D,QAAc;GACZ,EACE,UAAU,EAAe,GAAK,EAAE,EAAE,KAAK,EAAS,iCACtC,MAAY,OAAO,SAAS,OAAO,EAAQ,WACvD;EACF,CAAC;CACH;CAEA,OAAO;EACL,OAAO,GAAU;GACf,IAAM,IAAU,EAAM,IAAI,CAAG;GAE7B,IAAI,MAAY,KAAA,KAAa,CAAC,MAAM,QAAQ,CAAO,GAAG;IACpD,EAAa,UAAU,CAAO;IAE9B;GACF;GAEA,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;IAC3B,EAAa,UAAU,CAAO;IAE9B;GACF;GAEA,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;IAC3B,EAAa,QAAQ,CAAO;IAE5B;GACF;GAEA,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;GAE7B,IAAI,MAAY,KAAA,KAAa,CAAC,MAAM,QAAQ,CAAO,GAAG;IACpD,EAAa,WAAW,CAAO;IAE/B;GACF;GAEA,EAAI,GAAO,MAAM,QAAQ,CAAO,IAAI,CAAC,GAAO,GAAG,CAAO,IAAI,CAAC,CAAK,CAA4B;EAC9F;EACA,OAAO,GAAe;GACpB,IAAM,IAAU,EAAM,IAAI,CAAG;GAE7B,IAAI,CAAC,MAAM,QAAQ,CAAO,GAAG;IAC3B,EAAa,UAAU,CAAO;IAE9B;GACF;GAEA,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;IAC3B,EAAa,WAAW,CAAO;IAE/B;GACF;GAEA,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;IAC3B,EAAa,QAAQ,CAAO;IAE5B;GACF;GAEA,IAAM,IAAO,CAAC,GAAG,CAAO;GAGxB,AADA,CAAC,EAAK,IAAI,EAAK,MAAM,CAAC,EAAK,IAAI,EAAK,EAAE,GACtC,EAAI,GAAM,CAA8B;EAC1C;CACF;AACF"}
|
|
@@ -1 +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 *
|
|
1
|
+
{"version":3,"file":"asyncQueue.cjs","names":[],"sources":["../../src/core/asyncQueue.ts"],"sourcesContent":["/**\n * A minimal push-based async queue exposing an `AsyncIterableIterator`.\n * Used by `form[Symbol.asyncIterator]()` to turn a `subscribe()` callback into a pull-based\n * `for await` stream without hand-rolling `waitingResolve`/`done` plumbing at the call site.\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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* A minimal push-based async queue exposing an `AsyncIterableIterator`.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Used by `form[Symbol.asyncIterator]()` to turn a `subscribe()` callback into a pull-based
|
|
4
|
+
* `for await` stream without hand-rolling `waitingResolve`/`done` plumbing at the call site.
|
|
5
5
|
*
|
|
6
6
|
* - `push()` delivers an item to a waiting `next()` call, or buffers it for the next one.
|
|
7
7
|
* - `finish()` marks the queue complete; any items already buffered are still drained by
|
|
@@ -1 +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 *
|
|
1
|
+
{"version":3,"file":"asyncQueue.js","names":[],"sources":["../../src/core/asyncQueue.ts"],"sourcesContent":["/**\n * A minimal push-based async queue exposing an `AsyncIterableIterator`.\n * Used by `form[Symbol.asyncIterator]()` to turn a `subscribe()` callback into a pull-based\n * `for await` stream without hand-rolling `waitingResolve`/`done` plumbing at the call site.\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"}
|
package/dist/core/context.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require("../errors.cjs")
|
|
1
|
+
const e=require("../errors.cjs");require("../types.cjs");const t=require("../_utils.cjs"),n=require("./notifier.cjs");let r=require("@vielzeug/ripple"),i=require("@vielzeug/arsenal");function a(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 o(o){let s=new Map;for(let[e,n]of Object.entries(o.validators??{}))t.assertSafeKey(e),s.set(e,n);let c=a(o.validator),l=typeof o.defaultValues==`function`,u=typeof o.defaultValues==`function`?void 0:o.defaultValues,d=new Map(Object.entries((0,i.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=!1,w=0,T=!1;function E(){b=null}function D(){x=null}function O(){return x??=Object.freeze(Object.fromEntries(p))}function k(){return Object.freeze({errors:O(),isDirty:h.size>0,isLoading:l,isSubmitting:C,isTouched:m.size>0,isValid:p.size===0,isValidating:g.size>0,submitCount:w,touchedFields:Object.freeze([...m]),validatingFields:Object.freeze([...g.keys()])})}function A(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)}}let j=n.createNotifier({buildFieldState:A,computeState:k,invalidateCaches(){E(),D()}});function M(t){if(T)throw new e.ForgeDisposedError(t)}function N(e){M(`batch`);try{(0,r.batch)(e)}catch(e){throw j.requestNotify(),e}}function P(){T=!0,y.abort();for(let e of v.values())e.abort();v.clear(),_.clear(),S.clear(),j.dispose()}return{arrayCache:S,baseline:d,batch:N,get cachedValues(){return b},set cachedValues(e){b=e},computeErrors:O,dirty:h,dispose:P,disposeController:y,get disposed(){return T},ensureNotDisposed:M,fieldCtrls:v,fieldErrors:p,formValidator:c,getFieldSnapshot:j.getFieldSnapshot,getStateSnapshot:j.getStateSnapshot,invalidateErrors:D,invalidateValues:E,get isSubmittingState(){return C},set isSubmittingState(e){C=e},get loadingState(){return l},set loadingState(e){l=e},requestNotify:j.requestNotify,runCtrls:_,store:f,get submitCount(){return w},set submitCount(e){w=e},subscribe:j.subscribe,subscribeField:j.subscribeField,touched:m,validatingRuns:g,validators:s}}exports.createFormContext=o;
|
|
2
2
|
//# sourceMappingURL=context.cjs.map
|
|
@@ -1 +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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"}
|
|
1
|
+
{"version":3,"file":"context.cjs","names":[],"sources":["../../src/core/context.ts"],"sourcesContent":["import { batch as rippleBatch } from '@vielzeug/ripple';\n\nimport { assertSafeKey, flattenValues, isSafeKey } from '../_utils';\nimport { ForgeDisposedError } from '../errors';\nimport {\n type ArrayField,\n type FieldState,\n type FieldValidator,\n FORM_ERROR,\n type FormOptions,\n type FormState,\n type FormValidator,\n type SafeParseSchema,\n type SubscribeOptions,\n type Unsubscribe,\n} from '../types';\nimport { createNotifier } from './notifier';\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 for the field/validator Maps + lifecycle primitives, passed to every\n * `createForm()` sub-module factory (`createFieldOps`, `createObserveOps`, `createLifecycleOps`).\n * Mirrors the `ScopeContext` pattern already established in `scope.ts`.\n *\n * Notably absent: signals, subscriptions, and derived-state caching. Those have no dependency\n * on the field/validator Maps below — only on \"what does current state look like,\" computed\n * here via `computeState`/`buildFieldState` — so they live in their own `Notifier` instance\n * (`core/notifier.ts`) instead of this shared bag. `requestNotify`/`getStateSnapshot`/\n * `getFieldSnapshot`/`subscribe`/`subscribeField` below are thin pass-throughs to that\n * notifier, kept on `FormContext` purely so the other ops modules don't need two objects.\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 cachedValues: TValues | null;\n computeErrors(): Readonly<Record<string, string>>;\n dirty: Set<string>;\n dispose(): void;\n disposeController: AbortController;\n disposed: boolean;\n ensureNotDisposed(op?: string): void;\n fieldCtrls: Map<string, AbortController>;\n fieldErrors: Map<string, string>;\n formValidator: FormValidator<TValues> | undefined;\n getFieldSnapshot(name: string): 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 runCtrls: Set<AbortController>;\n store: Map<string, unknown>;\n submitCount: number;\n subscribe(listener: (state: FormState) => void, options?: SubscribeOptions): Unsubscribe;\n subscribeField(name: string, listener: (state: FieldState<unknown>) => void, options?: SubscribeOptions): Unsubscribe;\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: the field/validator Maps,\n * the notifier that turns mutations into signal updates, and the caches derived from both.\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\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 arrayCache = new Map<string, ArrayField>();\n\n /* ---- Submission state ---- */\n\n let isSubmittingState = false;\n let submitCount = 0;\n\n /* ---- Lifecycle ---- */\n\n let disposed = false;\n\n /* ======== Derived state (fed to the notifier below) ======== */\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 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 const notifier = createNotifier({\n buildFieldState,\n computeState,\n invalidateCaches() {\n invalidateValues();\n invalidateErrors();\n },\n });\n\n /* ======== Lifecycle guards ======== */\n\n function ensureNotDisposed(op?: string): void {\n if (disposed) throw new ForgeDisposedError(op);\n }\n\n /* ======== Batch ======== */\n\n function batch(fn: () => void): void {\n ensureNotDisposed('batch');\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 notifier.requestNotify();\n throw e;\n }\n }\n\n function dispose(): void {\n disposed = true;\n disposeController.abort();\n\n for (const ctrl of fieldCtrls.values()) ctrl.abort();\n\n fieldCtrls.clear();\n runCtrls.clear();\n arrayCache.clear();\n notifier.dispose();\n }\n\n return {\n arrayCache,\n baseline,\n batch,\n get cachedValues() {\n return cachedValues;\n },\n set cachedValues(value) {\n cachedValues = value;\n },\n computeErrors,\n dirty,\n dispose,\n disposeController,\n get disposed() {\n return disposed;\n },\n ensureNotDisposed,\n fieldCtrls,\n fieldErrors,\n formValidator,\n getFieldSnapshot: notifier.getFieldSnapshot,\n getStateSnapshot: notifier.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: notifier.requestNotify,\n runCtrls,\n store,\n get submitCount() {\n return submitCount;\n },\n set submitCount(value) {\n submitCount = value;\n },\n subscribe: notifier.subscribe,\n subscribeField: notifier.subscribeField,\n touched,\n validatingRuns,\n validators,\n };\n}\n"],"mappings":"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"}
|
package/dist/core/context.d.ts
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { type FormOptions } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
* Builds the raw mutable state + shared primitives for a form
|
|
4
|
-
*
|
|
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.
|
|
3
|
+
* Builds the raw mutable state + shared primitives for a form: the field/validator Maps,
|
|
4
|
+
* the notifier that turns mutations into signal updates, and the caches derived from both.
|
|
8
5
|
*/
|
|
9
6
|
export declare function createFormContext<TValues extends Record<string, unknown> = Record<string, unknown>>(init: FormOptions<TValues>): FormContext<TValues>;
|
|
10
7
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAIA,OAAO,
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/core/context.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,KAAK,WAAW,EAMjB,MAAM,UAAU,CAAC;AAoFlB;;;GAGG;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,CA0LtB"}
|