attaform 0.17.2 → 0.18.1
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 +77 -36
- package/dist/chunks/devtools.cjs +10 -37
- package/dist/chunks/devtools.cjs.map +1 -1
- package/dist/chunks/devtools.mjs +10 -37
- package/dist/chunks/devtools.mjs.map +1 -1
- package/dist/chunks/indexeddb.cjs +4 -4
- package/dist/chunks/indexeddb.cjs.map +1 -1
- package/dist/chunks/indexeddb.mjs +1 -1
- package/dist/chunks/local-storage.cjs +2 -2
- package/dist/chunks/local-storage.cjs.map +1 -1
- package/dist/chunks/local-storage.mjs +1 -1
- package/dist/chunks/session-storage.cjs +2 -2
- package/dist/chunks/session-storage.cjs.map +1 -1
- package/dist/chunks/session-storage.mjs +1 -1
- package/dist/index.cjs +42 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +159 -196
- package/dist/index.d.mts +159 -196
- package/dist/index.d.ts +159 -196
- package/dist/index.mjs +5 -7
- package/dist/index.mjs.map +1 -1
- package/dist/nuxt.cjs +31 -40
- package/dist/nuxt.cjs.map +1 -1
- package/dist/nuxt.d.cts +8 -1
- package/dist/nuxt.d.mts +8 -1
- package/dist/nuxt.d.ts +8 -1
- package/dist/nuxt.mjs +32 -41
- package/dist/nuxt.mjs.map +1 -1
- package/dist/runtime/components/AttaformDevtoolsPanel.d.vue.ts +7 -0
- package/dist/runtime/components/AttaformDevtoolsPanel.vue +453 -0
- package/dist/runtime/components/AttaformDevtoolsPanel.vue.d.ts +7 -0
- package/dist/runtime/components/DevtoolsValueTree.d.vue.ts +37 -0
- package/dist/runtime/components/DevtoolsValueTree.vue +192 -0
- package/dist/runtime/components/DevtoolsValueTree.vue.d.ts +37 -0
- package/dist/runtime/plugins/attaform.cjs +17 -6
- package/dist/runtime/plugins/attaform.cjs.map +1 -1
- package/dist/runtime/plugins/attaform.mjs +15 -4
- package/dist/runtime/plugins/attaform.mjs.map +1 -1
- package/dist/shared/{attaform.C0iFnTN0.d.ts → attaform.2b7M2mww.d.mts} +57 -23
- package/dist/shared/attaform.5UhpSVFI.cjs +63 -0
- package/dist/shared/attaform.5UhpSVFI.cjs.map +1 -0
- package/dist/shared/attaform.BDdFdjeX.mjs +57 -0
- package/dist/shared/attaform.BDdFdjeX.mjs.map +1 -0
- package/dist/shared/{attaform.Dee2rU1P.cjs → attaform.BqK_L4gK.cjs} +310 -24
- package/dist/shared/attaform.BqK_L4gK.cjs.map +1 -0
- package/dist/shared/attaform.Bubm_slq.cjs.map +1 -1
- package/dist/shared/attaform.CXpzmj38.mjs.map +1 -1
- package/dist/shared/{attaform.Drt6fivF.mjs → attaform.CtNUB9nf.mjs} +74 -76
- package/dist/shared/attaform.CtNUB9nf.mjs.map +1 -0
- package/dist/shared/{attaform.C5MH4lNh.d.mts → attaform.DF8wo-ry.d.ts} +4 -4
- package/dist/shared/attaform.DK9aj0N8.d.ts +1651 -0
- package/dist/shared/{attaform.BPRHR3Zs.cjs → attaform.DUHru0OF.cjs} +83 -85
- package/dist/shared/attaform.DUHru0OF.cjs.map +1 -0
- package/dist/shared/{attaform.C6lbmMUe.d.ts → attaform.DVLB6CAn.d.mts} +4 -4
- package/dist/shared/{attaform.C_5aB6EQ.d.ts → attaform.Dj9mwbaV.d.cts} +756 -148
- package/dist/shared/{attaform.C_5aB6EQ.d.mts → attaform.Dj9mwbaV.d.mts} +756 -148
- package/dist/shared/{attaform.C_5aB6EQ.d.cts → attaform.Dj9mwbaV.d.ts} +756 -148
- package/dist/shared/{attaform.BV40t5y2.cjs → attaform.Dlk1jMuv.cjs} +245 -108
- package/dist/shared/attaform.Dlk1jMuv.cjs.map +1 -0
- package/dist/shared/attaform.DoSuaKMd.d.cts +1651 -0
- package/dist/shared/{attaform.B3ZaPIzS.mjs → attaform.DsC3rZHG.mjs} +1804 -219
- package/dist/shared/attaform.DsC3rZHG.mjs.map +1 -0
- package/dist/shared/{attaform.Cer8JO_P.cjs → attaform.II89Pcf4.cjs} +1860 -272
- package/dist/shared/attaform.II89Pcf4.cjs.map +1 -0
- package/dist/shared/{attaform.CHorcsIU.d.cts → attaform.M33WKVV4.d.cts} +57 -23
- package/dist/shared/{attaform.CIEQgJnM.mjs → attaform.Xhg0AYNa.mjs} +300 -26
- package/dist/shared/attaform.Xhg0AYNa.mjs.map +1 -0
- package/dist/shared/{attaform.CpERWz3u.mjs → attaform.Xt0A3QUd.mjs} +232 -95
- package/dist/shared/attaform.Xt0A3QUd.mjs.map +1 -0
- package/dist/shared/attaform.iTqxvl-P.d.mts +1651 -0
- package/dist/shared/{attaform.CuE-bS1C.d.mts → attaform.tsNFcEW7.d.ts} +57 -23
- package/dist/shared/{attaform.DtMN-MAm.d.cts → attaform.tts_OM7j.d.cts} +4 -4
- package/dist/vite.cjs +288 -2
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.mjs +288 -2
- package/dist/vite.mjs.map +1 -1
- package/dist/zod-v3.cjs +11 -8
- package/dist/zod-v3.cjs.map +1 -1
- package/dist/zod-v3.d.cts +6 -6
- package/dist/zod-v3.d.mts +6 -6
- package/dist/zod-v3.d.ts +6 -6
- package/dist/zod-v3.mjs +3 -3
- package/dist/zod-v4.cjs +11 -8
- package/dist/zod-v4.cjs.map +1 -1
- package/dist/zod-v4.d.cts +5 -5
- package/dist/zod-v4.d.mts +5 -5
- package/dist/zod-v4.d.ts +5 -5
- package/dist/zod-v4.mjs +3 -3
- package/dist/zod.cjs +15 -16
- package/dist/zod.cjs.map +1 -1
- package/dist/zod.d.cts +127 -40
- package/dist/zod.d.mts +127 -40
- package/dist/zod.d.ts +127 -40
- package/dist/zod.mjs +7 -11
- package/dist/zod.mjs.map +1 -1
- package/package.json +18 -7
- package/dist/shared/attaform.B1jvxsOF.d.mts +0 -156
- package/dist/shared/attaform.B3ZaPIzS.mjs.map +0 -1
- package/dist/shared/attaform.BBM2muQ9.cjs +0 -101
- package/dist/shared/attaform.BBM2muQ9.cjs.map +0 -1
- package/dist/shared/attaform.BPRHR3Zs.cjs.map +0 -1
- package/dist/shared/attaform.BV40t5y2.cjs.map +0 -1
- package/dist/shared/attaform.C6qzEdIM.d.cts +0 -156
- package/dist/shared/attaform.C8LVFVVe.cjs +0 -32
- package/dist/shared/attaform.C8LVFVVe.cjs.map +0 -1
- package/dist/shared/attaform.CIEQgJnM.mjs.map +0 -1
- package/dist/shared/attaform.CTwNcpLE.d.ts +0 -156
- package/dist/shared/attaform.Cer8JO_P.cjs.map +0 -1
- package/dist/shared/attaform.CpERWz3u.mjs.map +0 -1
- package/dist/shared/attaform.Dee2rU1P.cjs.map +0 -1
- package/dist/shared/attaform.Drt6fivF.mjs.map +0 -1
- package/dist/shared/attaform.Vo-Kft0t.mjs +0 -29
- package/dist/shared/attaform.Vo-Kft0t.mjs.map +0 -1
- package/dist/shared/attaform.h1sq3BFu.mjs +0 -92
- package/dist/shared/attaform.h1sq3BFu.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attaform.BDdFdjeX.mjs","sources":["../../src/runtime/core/serialize.ts","../../src/runtime/core/devtools-shared.ts"],"sourcesContent":["import type { App } from 'vue'\nimport type { FormKey } from '../types/types-api'\nimport { pathKeyToDotted, type PathKey } from './paths'\nimport { getRegistryFromApp, type SerializedFormData } from './registry'\n\n/**\n * Serialised snapshot of every form in a Vue app, produced by\n * `renderAttaformState` and consumed by `hydrateAttaformState`.\n *\n * JSON-safe — pass to `JSON.stringify`, `devalue`, or any other\n * serialiser before embedding in your SSR payload.\n */\nexport type SerializedAttaformState = {\n /** Tuples of `[formKey, snapshot]` for every form in the app. */\n readonly forms: ReadonlyArray<readonly [FormKey, SerializedFormData]>\n}\n\n/**\n * Snapshot every form on a Vue app for SSR. Call from your server\n * entry after rendering the app:\n *\n * ```ts\n * import { renderToString } from '@vue/server-renderer'\n * import { renderAttaformState, escapeForInlineScript } from 'attaform'\n *\n * const html = await renderToString(app)\n * const state = renderAttaformState(app)\n * const payload = escapeForInlineScript(JSON.stringify(state))\n *\n * return `\n * ${html}\n * <script>window.__ATTAFORM_STATE__ = ${payload}</script>\n * `\n * ```\n *\n * Pair with `hydrateAttaformState` on the client to restore the\n * forms in their server-rendered state. Nuxt users don't need this —\n * `attaform/nuxt` wires SSR automatically.\n */\nexport function renderAttaformState(app: App): SerializedAttaformState {\n const registry = getRegistryFromApp(app)\n const forms: Array<readonly [FormKey, SerializedFormData]> = []\n for (const [key, state] of registry.forms) {\n // Skip the blank field when the set is empty so the\n // wire payload stays minimal for forms that don't use it. The\n // optional shape on the consuming side handles the absence\n // cleanly (defaults to \"no blank paths\"). PathKey → dotted at\n // the boundary so the wire shape matches the rest of the\n // public path notation.\n const transientList: string[] = []\n for (const pk of state.blankPaths) {\n const d = pathKeyToDotted(pk as PathKey)\n if (d !== null) transientList.push(d)\n }\n forms.push([\n key,\n {\n form: state.form.value,\n schemaErrors: Array.from(state.schemaErrors.entries()),\n userErrors: Array.from(state.userErrors.entries()),\n fields: Array.from(state.fields.entries()),\n ...(transientList.length > 0 ? { blankPaths: transientList } : {}),\n },\n ])\n }\n return { forms }\n}\n\n/**\n * Restore forms from a server-rendered snapshot on the client. Call\n * from your client entry before mounting:\n *\n * ```ts\n * import { createApp } from 'vue'\n * import { createAttaform, hydrateAttaformState } from 'attaform'\n *\n * const app = createApp(App).use(createAttaform())\n * hydrateAttaformState(app, window.__ATTAFORM_STATE__)\n * app.mount('#app')\n * ```\n *\n * The next `useForm({ key })` call for each serialised form picks up\n * the snapshot transparently — no further action is required.\n */\nexport function hydrateAttaformState(app: App, payload: SerializedAttaformState): void {\n const registry = getRegistryFromApp(app)\n for (const [key, data] of payload.forms) {\n registry.pendingHydration.set(key, data)\n }\n}\n","/**\n * Shared building blocks for Attaform's two devtools surfaces — the Vue\n * DevTools (Chrome-extension) inspector wired up in `./devtools.ts`, and\n * the Nuxt DevTools (overlay) panel wired up via `../../nuxt.ts` +\n * `../pages/_attaform_devtools.vue`.\n *\n * Centralizing the redaction policy and the window-bridge contract here\n * keeps both surfaces aligned: a future tightening of the sensitive-name\n * heuristic, or a new field added to the bridge, lands in one file.\n */\nimport type { AttaformRegistry } from './registry'\nimport type { Segment } from './paths'\n\nexport const REDACTED = '[redacted]'\n\n/**\n * Walk `value` and replace any leaf whose enclosing path matches the\n * sensitive-name heuristic with the string `'[redacted]'`. Returns a\n * new tree (no mutation of the input). Object keys + array indices are\n * preserved; only the leaf payloads change.\n *\n * Applied to BOTH devtools surfaces' Form-value rendering AND every\n * timeline event payload — leaks via either surface are treatable as\n * \"any developer with the panel open during user testing can read a\n * customer's password,\" which is exactly the failure mode the\n * sensitive-name guard exists to prevent on the storage side.\n *\n * Leaves whose path doesn't match a pattern pass through untouched.\n * `acknowledgeSensitive: true` on persistence does NOT bypass this — if\n * the consumer opted into persisting the value, they still shouldn't\n * see it in DevTools timelines that grow unbounded.\n *\n * Implementation note: tracks an `inSensitiveSubtree` flag through the\n * recursion instead of allocating a fresh path array per node + calling\n * `isSensitivePath` per leaf. Once any ancestor segment matches the\n * heuristic, the flag stays set for every descendant — the leaf simply\n * returns `REDACTED` without re-scanning the path. For a 100-leaf form:\n * ~100 path allocations + ~100 full-path regex sweeps → 0 path\n * allocations + ~100 single-segment regex sweeps, with whole-subtree\n * short-circuit when sensitive ancestors are found early.\n */\nexport function redactSensitiveLeaves(\n value: unknown,\n matchSensitive: (segment: Segment) => boolean\n): unknown {\n return redactImpl(value, false, matchSensitive)\n}\n\nfunction redactImpl(\n value: unknown,\n inSensitiveSubtree: boolean,\n matchSensitive: (segment: Segment) => boolean\n): unknown {\n if (value === null || value === undefined) return value\n if (typeof value !== 'object') {\n return inSensitiveSubtree ? REDACTED : value\n }\n if (Array.isArray(value)) {\n // Numeric segments never match the sensitive-name heuristic\n // (segmentMatchesSensitive rejects non-string segments), so the\n // flag passes through unchanged when descending into arrays.\n return value.map((item) => redactImpl(item, inSensitiveSubtree, matchSensitive))\n }\n // Non-plain object (Map / Set / Date / class instance) — redact\n // wholesale if we're already in a sensitive subtree; otherwise pass\n // through. DevTools rendering of these is already heuristic, so we\n // don't try to descend into them.\n //\n // Use `Object.prototype.toString.call(value)` rather than a\n // `getPrototypeOf` comparison because `Object.prototype` is\n // realm-scoped — the Nuxt DevTools overlay panel runs in an iframe\n // whose Vue runtime is separate from the host's, so the host's\n // reactive proxies have a prototype that doesn't equal the panel's\n // `Object.prototype`. The `toString` tag check is realm-aware via\n // `@@toStringTag` and returns `'[object Object]'` for plain objects\n // (including Vue reactive proxies of plain objects) regardless of\n // which iframe they were created in.\n if (Object.prototype.toString.call(value) !== '[object Object]') {\n return inSensitiveSubtree ? REDACTED : value\n }\n const out: Record<string, unknown> = {}\n for (const key of Object.keys(value as Record<string, unknown>)) {\n const childSensitive = inSensitiveSubtree || matchSensitive(key)\n out[key] = redactImpl((value as Record<string, unknown>)[key], childSensitive, matchSensitive)\n }\n return out\n}\n\n/**\n * Property key on `window` that the Nuxt-side dev plugin attaches the\n * bridge object to. The iframe-mounted overlay panel reads\n * `window.parent[DEVTOOLS_WINDOW_KEY]` to reach the host app's registry.\n *\n * Underscored + namespaced to make accidental collision with consumer\n * globals vanishingly unlikely. Stable across versions — bumping it\n * would silently disconnect older library builds from newer overlay\n * panels in the same browser tab during a library upgrade.\n */\nexport const DEVTOOLS_WINDOW_KEY = '__attaform_devtools__'\n\n/**\n * Shape of the object the host plugin attaches to `window` in dev mode.\n * The iframe overlay panel reads this to discover the live registry and\n * render its forms.\n *\n * Single-registry assumption: the latest `createAttaform()` install\n * wins. Multi-app pages (rare; typically only seen in micro-frontend\n * setups) will only see one app's forms in the panel. Documented but\n * not actively supported — the alternative (a Set of registries with\n * union-rendering) is a future call if a real consumer hits it.\n */\nexport interface AttaformDevtoolsBridge {\n registry: AttaformRegistry\n /**\n * The library version, surfaced in the panel's footer for support /\n * bug-report context. Read from `package.json` at host-plugin init.\n */\n version: string\n}\n\ndeclare global {\n interface Window {\n [DEVTOOLS_WINDOW_KEY]?: AttaformDevtoolsBridge\n }\n}\n"],"names":[],"mappings":";;AAuCO,SAAS,oBAAoB,GAAA,EAAmC;AACrE,EAAA,MAAM,QAAA,GAAW,mBAAmB,GAAG,CAAA;AACvC,EAAA,MAAM,QAAuD,EAAC;AAC9D,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,KAAK,CAAA,IAAK,SAAS,KAAA,EAAO;AAOzC,IAAA,MAAM,gBAA0B,EAAC;AACjC,IAAA,KAAA,MAAW,EAAA,IAAM,MAAM,UAAA,EAAY;AACjC,MAAA,MAAM,CAAA,GAAI,gBAAgB,EAAa,CAAA;AACvC,MAAA,IAAI,CAAA,KAAM,IAAA,EAAM,aAAA,CAAc,IAAA,CAAK,CAAC,CAAA;AAAA,IACtC;AACA,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,GAAA;AAAA,MACA;AAAA,QACE,IAAA,EAAM,MAAM,IAAA,CAAK,KAAA;AAAA,QACjB,cAAc,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,SAAS,CAAA;AAAA,QACrD,YAAY,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,UAAA,CAAW,SAAS,CAAA;AAAA,QACjD,QAAQ,KAAA,CAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,SAAS,CAAA;AAAA,QACzC,GAAI,cAAc,MAAA,GAAS,CAAA,GAAI,EAAE,UAAA,EAAY,aAAA,KAAkB;AAAC;AAClE,KACD,CAAA;AAAA,EACH;AACA,EAAA,OAAO,EAAE,KAAA,EAAM;AACjB;AAkBO,SAAS,oBAAA,CAAqB,KAAU,OAAA,EAAwC;AACrF,EAAA,MAAM,QAAA,GAAW,mBAAmB,GAAG,CAAA;AACvC,EAAA,KAAA,MAAW,CAAC,GAAA,EAAK,IAAI,CAAA,IAAK,QAAQ,KAAA,EAAO;AACvC,IAAA,QAAA,CAAS,gBAAA,CAAiB,GAAA,CAAI,GAAA,EAAK,IAAI,CAAA;AAAA,EACzC;AACF;;AC5EO,MAAM,QAAA,GAAW;AA4BjB,SAAS,qBAAA,CACd,OACA,cAAA,EACS;AACT,EAAA,OAAO,UAAA,CAAW,KAAA,EAAO,KAAA,EAAO,cAAc,CAAA;AAChD;AAEA,SAAS,UAAA,CACP,KAAA,EACA,kBAAA,EACA,cAAA,EACS;AACT,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,MAAA,EAAW,OAAO,KAAA;AAClD,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,qBAAqB,QAAA,GAAW,KAAA;AAAA,EACzC;AACA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AAIxB,IAAA,OAAO,KAAA,CAAM,IAAI,CAAC,IAAA,KAAS,WAAW,IAAA,EAAM,kBAAA,EAAoB,cAAc,CAAC,CAAA;AAAA,EACjF;AAeA,EAAA,IAAI,OAAO,SAAA,CAAU,QAAA,CAAS,IAAA,CAAK,KAAK,MAAM,iBAAA,EAAmB;AAC/D,IAAA,OAAO,qBAAqB,QAAA,GAAW,KAAA;AAAA,EACzC;AACA,EAAA,MAAM,MAA+B,EAAC;AACtC,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,KAAgC,CAAA,EAAG;AAC/D,IAAA,MAAM,cAAA,GAAiB,kBAAA,IAAsB,cAAA,CAAe,GAAG,CAAA;AAC/D,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,UAAA,CAAY,MAAkC,GAAG,CAAA,EAAG,gBAAgB,cAAc,CAAA;AAAA,EAC/F;AACA,EAAA,OAAO,GAAA;AACT;AAYO,MAAM,mBAAA,GAAsB;;;;"}
|
|
@@ -78,43 +78,118 @@ function detectSSR(options = {}) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
const kAttaformRegistry = Symbol.for("attaform:registry");
|
|
81
|
+
const kAttaformAncestorWizard = Symbol.for(
|
|
82
|
+
"attaform:ancestor-wizard"
|
|
83
|
+
);
|
|
84
|
+
const kAttaformWizardActiveStepResolver = Symbol.for(
|
|
85
|
+
"attaform:wizard-active-step-resolver"
|
|
86
|
+
);
|
|
81
87
|
const kFormContext = Symbol.for("attaform:form-context");
|
|
82
88
|
const kFormInstanceId = Symbol.for("attaform:form-instance-id");
|
|
83
89
|
function createRegistry(options = {}) {
|
|
84
90
|
const ssr = detectSSR(options);
|
|
85
91
|
const defaults = Object.freeze({ ...options.defaults ?? {} });
|
|
86
92
|
const forms = vue.shallowReactive(/* @__PURE__ */ new Map());
|
|
93
|
+
const wizards = vue.shallowReactive(/* @__PURE__ */ new Map());
|
|
87
94
|
const pendingHydration = vue.shallowReactive(/* @__PURE__ */ new Map());
|
|
88
95
|
const consumers = /* @__PURE__ */ new Map();
|
|
89
96
|
const evicting = /* @__PURE__ */ new Set();
|
|
97
|
+
const pendingEvictions = /* @__PURE__ */ new Map();
|
|
98
|
+
function cancelPendingEviction(key) {
|
|
99
|
+
const pending = pendingEvictions.get(key);
|
|
100
|
+
if (pending === void 0) return;
|
|
101
|
+
pending.cancelled = true;
|
|
102
|
+
pendingEvictions.delete(key);
|
|
103
|
+
}
|
|
90
104
|
function trackConsumer(key) {
|
|
105
|
+
cancelPendingEviction(key);
|
|
91
106
|
consumers.set(key, (consumers.get(key) ?? 0) + 1);
|
|
92
107
|
let disposed = false;
|
|
93
108
|
return () => {
|
|
94
109
|
if (disposed) return;
|
|
95
110
|
disposed = true;
|
|
96
111
|
const remaining = (consumers.get(key) ?? 1) - 1;
|
|
97
|
-
if (remaining
|
|
112
|
+
if (remaining > 0) {
|
|
113
|
+
consumers.set(key, remaining);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
consumers.delete(key);
|
|
117
|
+
const token = { cancelled: false };
|
|
118
|
+
pendingEvictions.set(key, token);
|
|
119
|
+
queueMicrotask(() => {
|
|
120
|
+
if (token.cancelled) return;
|
|
121
|
+
if (pendingEvictions.get(key) !== token) return;
|
|
122
|
+
pendingEvictions.delete(key);
|
|
98
123
|
const state = forms.get(key);
|
|
99
|
-
consumers.delete(key);
|
|
100
124
|
forms.delete(key);
|
|
101
|
-
if (state
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
125
|
+
if (state === void 0) return;
|
|
126
|
+
evicting.add(state);
|
|
127
|
+
void state.awaitPendingWrites().catch(() => void 0).finally(() => {
|
|
128
|
+
evicting.delete(state);
|
|
129
|
+
state.dispose();
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
const wizardConsumers = /* @__PURE__ */ new Map();
|
|
135
|
+
const pendingWizardEvictions = /* @__PURE__ */ new Map();
|
|
136
|
+
function cancelPendingWizardEviction(key) {
|
|
137
|
+
const pending = pendingWizardEvictions.get(key);
|
|
138
|
+
if (pending === void 0) return;
|
|
139
|
+
pending.cancelled = true;
|
|
140
|
+
pendingWizardEvictions.delete(key);
|
|
141
|
+
}
|
|
142
|
+
function trackWizardConsumer(key) {
|
|
143
|
+
cancelPendingWizardEviction(key);
|
|
144
|
+
wizardConsumers.set(key, (wizardConsumers.get(key) ?? 0) + 1);
|
|
145
|
+
let disposed = false;
|
|
146
|
+
return () => {
|
|
147
|
+
if (disposed) return;
|
|
148
|
+
disposed = true;
|
|
149
|
+
const remaining = (wizardConsumers.get(key) ?? 1) - 1;
|
|
150
|
+
if (remaining > 0) {
|
|
151
|
+
wizardConsumers.set(key, remaining);
|
|
152
|
+
return;
|
|
110
153
|
}
|
|
154
|
+
wizardConsumers.delete(key);
|
|
155
|
+
const token = { cancelled: false };
|
|
156
|
+
pendingWizardEvictions.set(key, token);
|
|
157
|
+
queueMicrotask(() => {
|
|
158
|
+
if (token.cancelled) return;
|
|
159
|
+
if (pendingWizardEvictions.get(key) !== token) return;
|
|
160
|
+
pendingWizardEvictions.delete(key);
|
|
161
|
+
wizards.delete(key);
|
|
162
|
+
});
|
|
111
163
|
};
|
|
112
164
|
}
|
|
113
165
|
async function shutdown() {
|
|
114
166
|
const states = [...forms.values(), ...evicting];
|
|
115
167
|
await Promise.allSettled(states.map((state) => state.awaitPendingWrites()));
|
|
116
168
|
}
|
|
117
|
-
|
|
169
|
+
const prefetchEnqueued = /* @__PURE__ */ new Set();
|
|
170
|
+
const prefetchSkipped = /* @__PURE__ */ new Set();
|
|
171
|
+
function enqueuePrefetch(key) {
|
|
172
|
+
prefetchEnqueued.add(key);
|
|
173
|
+
}
|
|
174
|
+
function skipPrefetch(key) {
|
|
175
|
+
prefetchSkipped.add(key);
|
|
176
|
+
}
|
|
177
|
+
function shouldPrefetch(key) {
|
|
178
|
+
return prefetchEnqueued.has(key) && !prefetchSkipped.has(key);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
forms,
|
|
182
|
+
wizards,
|
|
183
|
+
pendingHydration,
|
|
184
|
+
ssr,
|
|
185
|
+
defaults,
|
|
186
|
+
trackConsumer,
|
|
187
|
+
trackWizardConsumer,
|
|
188
|
+
enqueuePrefetch,
|
|
189
|
+
skipPrefetch,
|
|
190
|
+
shouldPrefetch,
|
|
191
|
+
shutdown
|
|
192
|
+
};
|
|
118
193
|
}
|
|
119
194
|
function useRegistry() {
|
|
120
195
|
const instance = vue.getCurrentInstance();
|
|
@@ -284,6 +359,17 @@ function useRegister() {
|
|
|
284
359
|
if ("registerValue" in rawAttrs) {
|
|
285
360
|
capturedRegisterValue.value = rawAttrs["registerValue"];
|
|
286
361
|
delete rawAttrs["registerValue"];
|
|
362
|
+
} else {
|
|
363
|
+
const dirs = instance.vnode.dirs;
|
|
364
|
+
if (dirs !== null && dirs !== void 0) {
|
|
365
|
+
for (const dir of dirs) {
|
|
366
|
+
const marked = dir.dir?.[V_REGISTER_MARKER];
|
|
367
|
+
if (marked === true) {
|
|
368
|
+
capturedRegisterValue.value = dir.value;
|
|
369
|
+
break;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
287
373
|
}
|
|
288
374
|
if ("value" in rawAttrs) delete rawAttrs["value"];
|
|
289
375
|
};
|
|
@@ -634,6 +720,12 @@ const getModelAssigner = (el, vnode, registerValue) => {
|
|
|
634
720
|
};
|
|
635
721
|
}
|
|
636
722
|
const defaultAssigner = (value) => {
|
|
723
|
+
if (value === void 0 && registerValue.acceptsUndefined) {
|
|
724
|
+
return registerValue.setValueWithInternalPath(
|
|
725
|
+
void 0,
|
|
726
|
+
computePersistMeta(el, registerValue)
|
|
727
|
+
);
|
|
728
|
+
}
|
|
637
729
|
const r = runTransforms(value, registerValue);
|
|
638
730
|
if (!r.ok) return false;
|
|
639
731
|
const coerced = applyCoerce(r.value, registerValue);
|
|
@@ -642,9 +734,10 @@ const getModelAssigner = (el, vnode, registerValue) => {
|
|
|
642
734
|
defaultAssigner[DEFAULT_ASSIGNER_TAG] = true;
|
|
643
735
|
return defaultAssigner;
|
|
644
736
|
};
|
|
645
|
-
function syncPersistOptIn(el, value, oldValue) {
|
|
737
|
+
function syncPersistOptIn(el, value, oldValue, vnodeType) {
|
|
646
738
|
const wasOptedIn = isRegisterValue(oldValue) && oldValue.persist === true;
|
|
647
|
-
const
|
|
739
|
+
const isFileInput = el.tagName === "INPUT" && (vnodeType === "file" || el.type === "file");
|
|
740
|
+
const wantsOptIn = !isFileInput && isRegisterValue(value) && value.persist === true;
|
|
648
741
|
if (!wasOptedIn && !wantsOptIn) return;
|
|
649
742
|
const elementId = getOrAssignElementId(el);
|
|
650
743
|
if (wasOptedIn) {
|
|
@@ -770,7 +863,13 @@ const vRegisterText = {
|
|
|
770
863
|
}
|
|
771
864
|
if (isRegisterValue(value)) writeLastTypedForm(value, typedString);
|
|
772
865
|
}
|
|
773
|
-
|
|
866
|
+
if (domValue === "" && isRegisterValue(value) && !value.acceptsString && !value.acceptsUndefined) {
|
|
867
|
+
writeLastTypedForm(value, null);
|
|
868
|
+
value.markBlank();
|
|
869
|
+
return;
|
|
870
|
+
}
|
|
871
|
+
const commit = domValue === "" && isRegisterValue(value) && value.acceptsUndefined ? void 0 : domValue;
|
|
872
|
+
el[assignKey]?.(commit);
|
|
774
873
|
if (isRegisterValue(value) && isDefaultAssigner(el[assignKey])) {
|
|
775
874
|
const storage = value.innerRef.value;
|
|
776
875
|
if (storage !== domValue) {
|
|
@@ -1122,7 +1221,7 @@ const SUPPORTED_TAGS = /* @__PURE__ */ new Set(["INPUT", "TEXTAREA", "SELECT"]);
|
|
|
1122
1221
|
const warnedUnsupportedElements = __DEV__ ? /* @__PURE__ */ new WeakSet() : null;
|
|
1123
1222
|
const vRegisterDynamic = {
|
|
1124
1223
|
created(el, binding, vnode) {
|
|
1125
|
-
syncPersistOptIn(el, binding.value, void 0);
|
|
1224
|
+
syncPersistOptIn(el, binding.value, void 0, vnode.props?.["type"]);
|
|
1126
1225
|
syncMultiTabOptOut(binding.value, void 0);
|
|
1127
1226
|
callModelHook(el, binding, vnode, null, "created");
|
|
1128
1227
|
if (__DEV__ && warnedUnsupportedElements !== null && !SUPPORTED_TAGS.has(el.tagName) && !warnedUnsupportedElements.has(el)) {
|
|
@@ -1144,7 +1243,7 @@ const vRegisterDynamic = {
|
|
|
1144
1243
|
callModelHook(el, binding, vnode, null, "mounted");
|
|
1145
1244
|
},
|
|
1146
1245
|
beforeUpdate(el, binding, vnode, prevVNode) {
|
|
1147
|
-
syncPersistOptIn(el, binding.value, binding.oldValue);
|
|
1246
|
+
syncPersistOptIn(el, binding.value, binding.oldValue, vnode.props?.["type"]);
|
|
1148
1247
|
syncMultiTabOptOut(binding.value, binding.oldValue);
|
|
1149
1248
|
syncElementRegistration(el, binding.value, binding.oldValue);
|
|
1150
1249
|
callModelHook(el, binding, vnode, prevVNode, "beforeUpdate");
|
|
@@ -1165,18 +1264,83 @@ const vRegisterDynamic = {
|
|
|
1165
1264
|
delete el[assignKey];
|
|
1166
1265
|
}
|
|
1167
1266
|
};
|
|
1168
|
-
|
|
1267
|
+
function isBlankFileValue(value) {
|
|
1268
|
+
if (value === null || value === void 0) return true;
|
|
1269
|
+
if (Array.isArray(value) && value.length === 0) return true;
|
|
1270
|
+
if (typeof FileList !== "undefined" && value instanceof FileList && value.length === 0)
|
|
1271
|
+
return true;
|
|
1272
|
+
return false;
|
|
1273
|
+
}
|
|
1274
|
+
function readFilesFromInput(el) {
|
|
1275
|
+
const files = el.files;
|
|
1276
|
+
if (el.multiple) {
|
|
1277
|
+
return files === null ? [] : Array.from(files);
|
|
1278
|
+
}
|
|
1279
|
+
if (files === null || files.length === 0) return null;
|
|
1280
|
+
return files.item(0);
|
|
1281
|
+
}
|
|
1282
|
+
const warnedPersistedFileForms = __DEV__ ? /* @__PURE__ */ new WeakMap() : null;
|
|
1283
|
+
function maybeWarnPersistedFile(value) {
|
|
1284
|
+
if (!__DEV__ || warnedPersistedFileForms === null) return;
|
|
1285
|
+
if (value.persist !== true) return;
|
|
1286
|
+
let warnedPaths = warnedPersistedFileForms.get(value.persistOptIns);
|
|
1287
|
+
if (warnedPaths === void 0) {
|
|
1288
|
+
warnedPaths = /* @__PURE__ */ new Set();
|
|
1289
|
+
warnedPersistedFileForms.set(value.persistOptIns, warnedPaths);
|
|
1290
|
+
}
|
|
1291
|
+
if (warnedPaths.has(value.path)) return;
|
|
1292
|
+
warnedPaths.add(value.path);
|
|
1293
|
+
vue.warn(
|
|
1294
|
+
`[attaform] register('${value.path}', { persist: true }) on <input type="file"> \u2014 files can't ride a refresh (browsers block programmatic writes to <input type="file">), so this path won't be saved. For long-lived flows, upload on selection and persist the resulting URL or ID in a sibling string field.`
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
const fileScopeKey = Symbol.for("attaform:file-scope");
|
|
1298
|
+
const vRegisterFile = {
|
|
1169
1299
|
created(el, { value }) {
|
|
1170
1300
|
if (!isRegisterValue(value)) return;
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1301
|
+
const input = el;
|
|
1302
|
+
value.registerElement(input);
|
|
1303
|
+
maybeWarnPersistedFile(value);
|
|
1304
|
+
const currentRaw = value.innerRef.value;
|
|
1305
|
+
if (isBlankFileValue(currentRaw)) {
|
|
1306
|
+
const blankShape = input.multiple ? [] : null;
|
|
1307
|
+
value.setValueWithInternalPath(blankShape, { blank: true });
|
|
1308
|
+
}
|
|
1309
|
+
addEventListener(input, "change", () => {
|
|
1310
|
+
const next = readFilesFromInput(input);
|
|
1311
|
+
const blank = isBlankFileValue(next);
|
|
1312
|
+
value.setValueWithInternalPath(next, blank ? { blank: true } : void 0);
|
|
1313
|
+
});
|
|
1314
|
+
const scope = vue.effectScope(true);
|
|
1315
|
+
scope.run(() => {
|
|
1316
|
+
vue.watch(
|
|
1317
|
+
value.innerRef,
|
|
1318
|
+
(next) => {
|
|
1319
|
+
if (!isBlankFileValue(next)) return;
|
|
1320
|
+
value.setValueWithInternalPath(next, { blank: true });
|
|
1321
|
+
if (input.value !== "") input.value = "";
|
|
1322
|
+
},
|
|
1323
|
+
{ flush: "post" }
|
|
1175
1324
|
);
|
|
1325
|
+
});
|
|
1326
|
+
input[fileScopeKey] = () => scope.stop();
|
|
1327
|
+
},
|
|
1328
|
+
beforeUpdate(el, { value }) {
|
|
1329
|
+
if (!isRegisterValue(value)) return;
|
|
1330
|
+
const input = el;
|
|
1331
|
+
const currentRaw = value.innerRef.value;
|
|
1332
|
+
if (isBlankFileValue(currentRaw)) {
|
|
1333
|
+
value.setValueWithInternalPath(currentRaw, { blank: true });
|
|
1334
|
+
if (input.value !== "") input.value = "";
|
|
1176
1335
|
}
|
|
1177
1336
|
},
|
|
1178
1337
|
beforeUnmount(el, { value }) {
|
|
1179
1338
|
removeTrackedListeners(el);
|
|
1339
|
+
const stop = el[fileScopeKey];
|
|
1340
|
+
if (stop !== void 0) {
|
|
1341
|
+
stop();
|
|
1342
|
+
delete el[fileScopeKey];
|
|
1343
|
+
}
|
|
1180
1344
|
if (!isRegisterValue(value)) return;
|
|
1181
1345
|
value.deregisterElement(el);
|
|
1182
1346
|
}
|
|
@@ -1185,7 +1349,7 @@ function resolveDynamicModel(tagName, type) {
|
|
|
1185
1349
|
if (tagName === "SELECT") return vRegisterSelect;
|
|
1186
1350
|
if (tagName === "TEXTAREA") return vRegisterText;
|
|
1187
1351
|
if (typeof type !== "string") return vRegisterText;
|
|
1188
|
-
if (type === "file") return
|
|
1352
|
+
if (type === "file") return vRegisterFile;
|
|
1189
1353
|
if (type === "checkbox") return vRegisterCheckbox;
|
|
1190
1354
|
if (type === "radio") return vRegisterRadio;
|
|
1191
1355
|
return vRegisterText;
|
|
@@ -1195,7 +1359,9 @@ function callModelHook(el, binding, vnode, prevVNode, hook) {
|
|
|
1195
1359
|
const fn = modelToUse[hook];
|
|
1196
1360
|
fn?.(el, binding, vnode, prevVNode);
|
|
1197
1361
|
}
|
|
1362
|
+
const V_REGISTER_MARKER = Symbol.for("attaform:v-register-directive");
|
|
1198
1363
|
const vRegister = vRegisterDynamic;
|
|
1364
|
+
vRegisterDynamic[V_REGISTER_MARKER] = true;
|
|
1199
1365
|
|
|
1200
1366
|
function installAttaformOnApp(app, options, source) {
|
|
1201
1367
|
if (app._attaform !== void 0) {
|
|
@@ -1232,19 +1398,133 @@ function createAttaform(options = {}) {
|
|
|
1232
1398
|
return plugin;
|
|
1233
1399
|
}
|
|
1234
1400
|
|
|
1401
|
+
const INTEGER_SEGMENT = /^(?:0|[1-9]\d*)$/;
|
|
1402
|
+
function normalizeSegment(raw) {
|
|
1403
|
+
if (typeof raw === "number") {
|
|
1404
|
+
if (!Number.isInteger(raw) || raw < 0) {
|
|
1405
|
+
throw new InvalidPathError(
|
|
1406
|
+
`Path segments must be non-negative integers when numeric; got ${String(raw)}`
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
1409
|
+
return raw;
|
|
1410
|
+
}
|
|
1411
|
+
if (INTEGER_SEGMENT.test(raw)) return Number(raw);
|
|
1412
|
+
return raw;
|
|
1413
|
+
}
|
|
1414
|
+
function parseDottedPath(path) {
|
|
1415
|
+
if (path.length === 0) return [""];
|
|
1416
|
+
const rawSegments = path.split(".");
|
|
1417
|
+
const segments = [];
|
|
1418
|
+
for (const raw of rawSegments) {
|
|
1419
|
+
if (raw.length === 0) {
|
|
1420
|
+
throw new InvalidPathError(
|
|
1421
|
+
`Path '${path}' has an empty segment; use the array form for empty keys.`
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
segments.push(normalizeSegment(raw));
|
|
1425
|
+
}
|
|
1426
|
+
return segments;
|
|
1427
|
+
}
|
|
1428
|
+
const CANONICAL_STRING_CACHE_MAX = 128;
|
|
1429
|
+
const canonicalStringCache = /* @__PURE__ */ new Map();
|
|
1430
|
+
const PATHKEY_TO_SEGMENTS_MAX = 4096;
|
|
1431
|
+
const pathKeyToSegments = /* @__PURE__ */ new Map();
|
|
1432
|
+
function rememberSegmentsForPathKey(key, segments) {
|
|
1433
|
+
if (!pathKeyToSegments.has(key) && pathKeyToSegments.size >= PATHKEY_TO_SEGMENTS_MAX) {
|
|
1434
|
+
const oldest = pathKeyToSegments.keys().next().value;
|
|
1435
|
+
if (oldest !== void 0) pathKeyToSegments.delete(oldest);
|
|
1436
|
+
}
|
|
1437
|
+
pathKeyToSegments.set(key, segments);
|
|
1438
|
+
}
|
|
1439
|
+
function segmentsForPathKey(key) {
|
|
1440
|
+
const cached = pathKeyToSegments.get(key);
|
|
1441
|
+
if (cached !== void 0) return cached;
|
|
1442
|
+
let parsed;
|
|
1443
|
+
try {
|
|
1444
|
+
parsed = JSON.parse(key);
|
|
1445
|
+
} catch {
|
|
1446
|
+
return null;
|
|
1447
|
+
}
|
|
1448
|
+
if (!Array.isArray(parsed)) return null;
|
|
1449
|
+
const segments = [];
|
|
1450
|
+
for (const raw of parsed) {
|
|
1451
|
+
if (typeof raw !== "string" && typeof raw !== "number") return null;
|
|
1452
|
+
segments.push(normalizeSegment(raw));
|
|
1453
|
+
}
|
|
1454
|
+
rememberSegmentsForPathKey(key, segments);
|
|
1455
|
+
return segments;
|
|
1456
|
+
}
|
|
1457
|
+
function canonicalizePath(input) {
|
|
1458
|
+
if (typeof input === "string") {
|
|
1459
|
+
const cached = canonicalStringCache.get(input);
|
|
1460
|
+
if (cached !== void 0) return cached;
|
|
1461
|
+
const segments2 = parseDottedPath(input);
|
|
1462
|
+
const key2 = JSON.stringify(segments2);
|
|
1463
|
+
const entry = { segments: segments2, key: key2 };
|
|
1464
|
+
if (canonicalStringCache.size >= CANONICAL_STRING_CACHE_MAX) {
|
|
1465
|
+
const oldest = canonicalStringCache.keys().next().value;
|
|
1466
|
+
if (oldest !== void 0) canonicalStringCache.delete(oldest);
|
|
1467
|
+
}
|
|
1468
|
+
canonicalStringCache.set(input, entry);
|
|
1469
|
+
rememberSegmentsForPathKey(key2, segments2);
|
|
1470
|
+
return entry;
|
|
1471
|
+
}
|
|
1472
|
+
const segments = Array.from(input).map(normalizeSegment);
|
|
1473
|
+
const key = JSON.stringify(segments);
|
|
1474
|
+
rememberSegmentsForPathKey(key, segments);
|
|
1475
|
+
return { segments, key };
|
|
1476
|
+
}
|
|
1477
|
+
function segmentsToDotted(segments) {
|
|
1478
|
+
return segments.join(".");
|
|
1479
|
+
}
|
|
1480
|
+
function pathKeyToDotted(key) {
|
|
1481
|
+
const segments = segmentsForPathKey(key);
|
|
1482
|
+
if (segments === null) return null;
|
|
1483
|
+
return segmentsToDotted(segments);
|
|
1484
|
+
}
|
|
1485
|
+
function coerceToPathKey(input) {
|
|
1486
|
+
if (input.length > 0 && input.charCodeAt(0) === 91) {
|
|
1487
|
+
try {
|
|
1488
|
+
const parsed = JSON.parse(input);
|
|
1489
|
+
if (Array.isArray(parsed) && parsed.every((s) => typeof s === "string" || typeof s === "number")) {
|
|
1490
|
+
return input;
|
|
1491
|
+
}
|
|
1492
|
+
} catch {
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
return canonicalizePath(input).key;
|
|
1496
|
+
}
|
|
1497
|
+
const ROOT_PATH = Object.freeze([]);
|
|
1498
|
+
const ROOT_PATH_KEY = "[]";
|
|
1499
|
+
const FORM_ERRORS_PATH = Object.freeze([""]);
|
|
1500
|
+
const FORM_ERRORS_PATH_KEY = '[""]';
|
|
1501
|
+
function isPathPrefix(prefix, path) {
|
|
1502
|
+
if (path.length < prefix.length) return false;
|
|
1503
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
1504
|
+
if (path[i] !== prefix[i]) return false;
|
|
1505
|
+
}
|
|
1506
|
+
return true;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1235
1509
|
exports.AnonPersistError = AnonPersistError;
|
|
1236
1510
|
exports.AttaformError = AttaformError;
|
|
1237
1511
|
exports.DEFAULT_SENSITIVE_NAMES = DEFAULT_SENSITIVE_NAMES;
|
|
1512
|
+
exports.FORM_ERRORS_PATH = FORM_ERRORS_PATH;
|
|
1513
|
+
exports.FORM_ERRORS_PATH_KEY = FORM_ERRORS_PATH_KEY;
|
|
1238
1514
|
exports.InvalidPathError = InvalidPathError;
|
|
1239
1515
|
exports.InvalidUseFormConfigError = InvalidUseFormConfigError;
|
|
1240
1516
|
exports.OutsideSetupError = OutsideSetupError;
|
|
1517
|
+
exports.ROOT_PATH = ROOT_PATH;
|
|
1518
|
+
exports.ROOT_PATH_KEY = ROOT_PATH_KEY;
|
|
1241
1519
|
exports.RegistryNotInstalledError = RegistryNotInstalledError;
|
|
1242
1520
|
exports.ReservedFormKeyError = ReservedFormKeyError;
|
|
1243
1521
|
exports.SensitivePersistFieldError = SensitivePersistFieldError;
|
|
1244
1522
|
exports.SubmitErrorHandlerError = SubmitErrorHandlerError;
|
|
1245
1523
|
exports.__DEV__ = __DEV__;
|
|
1246
1524
|
exports.assignKey = assignKey;
|
|
1525
|
+
exports.canonicalizePath = canonicalizePath;
|
|
1247
1526
|
exports.captureUserCallSite = captureUserCallSite;
|
|
1527
|
+
exports.coerceToPathKey = coerceToPathKey;
|
|
1248
1528
|
exports.createAttaform = createAttaform;
|
|
1249
1529
|
exports.createIsSensitivePath = createIsSensitivePath;
|
|
1250
1530
|
exports.createPersistOptInRegistry = createPersistOptInRegistry;
|
|
@@ -1253,13 +1533,19 @@ exports.createSegmentMatchesSensitive = createSegmentMatchesSensitive;
|
|
|
1253
1533
|
exports.enforceSensitiveCheck = enforceSensitiveCheck;
|
|
1254
1534
|
exports.ensureAttaformInstalled = ensureAttaformInstalled;
|
|
1255
1535
|
exports.getRegistryFromApp = getRegistryFromApp;
|
|
1536
|
+
exports.isPathPrefix = isPathPrefix;
|
|
1256
1537
|
exports.isRegisterValue = isRegisterValue;
|
|
1257
1538
|
exports.isSensitivePath = isSensitivePath;
|
|
1539
|
+
exports.kAttaformAncestorWizard = kAttaformAncestorWizard;
|
|
1258
1540
|
exports.kAttaformRegistry = kAttaformRegistry;
|
|
1541
|
+
exports.kAttaformWizardActiveStepResolver = kAttaformWizardActiveStepResolver;
|
|
1259
1542
|
exports.kFormContext = kFormContext;
|
|
1260
1543
|
exports.kFormInstanceId = kFormInstanceId;
|
|
1544
|
+
exports.parseDottedPath = parseDottedPath;
|
|
1545
|
+
exports.pathKeyToDotted = pathKeyToDotted;
|
|
1261
1546
|
exports.segmentMatchesSensitive = segmentMatchesSensitive;
|
|
1547
|
+
exports.segmentsForPathKey = segmentsForPathKey;
|
|
1262
1548
|
exports.useRegister = useRegister;
|
|
1263
1549
|
exports.useRegistry = useRegistry;
|
|
1264
1550
|
exports.vRegister = vRegister;
|
|
1265
|
-
//# sourceMappingURL=attaform.
|
|
1551
|
+
//# sourceMappingURL=attaform.BqK_L4gK.cjs.map
|