attaform 0.15.0 → 0.16.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.
Files changed (98) hide show
  1. package/README.md +21 -11
  2. package/dist/chunks/devtools.cjs +4 -4
  3. package/dist/chunks/devtools.cjs.map +1 -1
  4. package/dist/chunks/devtools.mjs +2 -2
  5. package/dist/chunks/indexeddb.cjs +4 -4
  6. package/dist/chunks/indexeddb.cjs.map +1 -1
  7. package/dist/chunks/indexeddb.mjs +1 -1
  8. package/dist/chunks/local-storage.cjs +2 -2
  9. package/dist/chunks/local-storage.cjs.map +1 -1
  10. package/dist/chunks/local-storage.mjs +1 -1
  11. package/dist/chunks/session-storage.cjs +2 -2
  12. package/dist/chunks/session-storage.cjs.map +1 -1
  13. package/dist/chunks/session-storage.mjs +1 -1
  14. package/dist/index.cjs +23 -22
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +76 -71
  17. package/dist/index.d.mts +76 -71
  18. package/dist/index.d.ts +76 -71
  19. package/dist/index.mjs +6 -6
  20. package/dist/nuxt.cjs +5 -11
  21. package/dist/nuxt.cjs.map +1 -1
  22. package/dist/nuxt.d.cts +8 -0
  23. package/dist/nuxt.d.mts +8 -0
  24. package/dist/nuxt.d.ts +8 -0
  25. package/dist/nuxt.mjs +6 -12
  26. package/dist/nuxt.mjs.map +1 -1
  27. package/dist/runtime/plugins/attaform.cjs +3 -2
  28. package/dist/runtime/plugins/attaform.cjs.map +1 -1
  29. package/dist/runtime/plugins/attaform.mjs +2 -1
  30. package/dist/runtime/plugins/attaform.mjs.map +1 -1
  31. package/dist/shared/{attaform.BwaYWtMs.d.cts → attaform.B7rzpK1U.d.cts} +34 -5
  32. package/dist/shared/{attaform.BwaYWtMs.d.mts → attaform.B7rzpK1U.d.mts} +34 -5
  33. package/dist/shared/{attaform.BwaYWtMs.d.ts → attaform.B7rzpK1U.d.ts} +34 -5
  34. package/dist/shared/attaform.BAuJTWuT.d.mts +84 -0
  35. package/dist/shared/{attaform.CRk8NhlD.mjs → attaform.BfMxsfmE.mjs} +428 -49
  36. package/dist/shared/attaform.BfMxsfmE.mjs.map +1 -0
  37. package/dist/shared/attaform.Bp1c-uGF.cjs +1561 -0
  38. package/dist/shared/attaform.Bp1c-uGF.cjs.map +1 -0
  39. package/dist/shared/{attaform.CDJVeoJU.cjs → attaform.C9Ph2SMx.cjs} +49 -42
  40. package/dist/shared/{attaform.qxyip_aN.mjs.map → attaform.C9Ph2SMx.cjs.map} +1 -1
  41. package/dist/shared/attaform.CINUMjPq.mjs +29 -0
  42. package/dist/shared/attaform.CINUMjPq.mjs.map +1 -0
  43. package/dist/shared/attaform.CJttVxRj.cjs +32 -0
  44. package/dist/shared/attaform.CJttVxRj.cjs.map +1 -0
  45. package/dist/shared/{attaform.CPx7zTgS.d.mts → attaform.CVv9Oh0a.d.mts} +9 -7
  46. package/dist/shared/{attaform.riAENZQM.d.ts → attaform.CWCx2r0x.d.ts} +9 -7
  47. package/dist/shared/attaform.CvOXSpCb.mjs +1908 -0
  48. package/dist/shared/attaform.CvOXSpCb.mjs.map +1 -0
  49. package/dist/shared/{attaform.qxyip_aN.mjs → attaform.DILbdvfo.mjs} +12 -5
  50. package/dist/shared/{attaform.CDJVeoJU.cjs.map → attaform.DILbdvfo.mjs.map} +1 -1
  51. package/dist/shared/attaform.DdnithOf.mjs +1555 -0
  52. package/dist/shared/attaform.DdnithOf.mjs.map +1 -0
  53. package/dist/shared/attaform.DfrYByDj.cjs +1916 -0
  54. package/dist/shared/attaform.DfrYByDj.cjs.map +1 -0
  55. package/dist/shared/{attaform.D-eHWfVx.d.cts → attaform.Dq5BabH1.d.cts} +9 -7
  56. package/dist/shared/{attaform.BOi138GE.cjs → attaform.c_NzdRyc.cjs} +4 -4
  57. package/dist/shared/{attaform.BOi138GE.cjs.map → attaform.c_NzdRyc.cjs.map} +1 -1
  58. package/dist/shared/{attaform.DXye3JKf.mjs → attaform.jrxE_xZw.mjs} +2 -2
  59. package/dist/shared/{attaform.DXye3JKf.mjs.map → attaform.jrxE_xZw.mjs.map} +1 -1
  60. package/dist/shared/attaform.ls_7jBYc.d.ts +84 -0
  61. package/dist/shared/{attaform.BgYBU8gV.cjs → attaform.rIRYSUI1.cjs} +461 -61
  62. package/dist/shared/attaform.rIRYSUI1.cjs.map +1 -0
  63. package/dist/shared/attaform.xIcmqscx.d.cts +84 -0
  64. package/dist/vite.cjs +62 -9
  65. package/dist/vite.cjs.map +1 -1
  66. package/dist/vite.d.cts +23 -32
  67. package/dist/vite.d.mts +23 -32
  68. package/dist/vite.d.ts +23 -32
  69. package/dist/vite.mjs +62 -9
  70. package/dist/vite.mjs.map +1 -1
  71. package/dist/zod-v3.cjs +9 -1553
  72. package/dist/zod-v3.cjs.map +1 -1
  73. package/dist/zod-v3.d.cts +1 -1
  74. package/dist/zod-v3.d.mts +1 -1
  75. package/dist/zod-v3.d.ts +1 -1
  76. package/dist/zod-v3.mjs +3 -1553
  77. package/dist/zod-v3.mjs.map +1 -1
  78. package/dist/zod-v4.cjs +21 -0
  79. package/dist/zod-v4.cjs.map +1 -0
  80. package/dist/zod-v4.d.cts +104 -0
  81. package/dist/zod-v4.d.mts +104 -0
  82. package/dist/zod-v4.d.ts +104 -0
  83. package/dist/zod-v4.mjs +4 -0
  84. package/dist/zod-v4.mjs.map +1 -0
  85. package/dist/zod.cjs +19 -1900
  86. package/dist/zod.cjs.map +1 -1
  87. package/dist/zod.d.cts +28 -156
  88. package/dist/zod.d.mts +28 -156
  89. package/dist/zod.d.ts +28 -156
  90. package/dist/zod.mjs +19 -1896
  91. package/dist/zod.mjs.map +1 -1
  92. package/package.json +6 -2
  93. package/dist/shared/attaform.BgYBU8gV.cjs.map +0 -1
  94. package/dist/shared/attaform.CRk8NhlD.mjs.map +0 -1
  95. package/dist/shared/attaform.RypIkgVy.cjs +0 -417
  96. package/dist/shared/attaform.RypIkgVy.cjs.map +0 -1
  97. package/dist/shared/attaform.a99dQV7Q.mjs +0 -392
  98. package/dist/shared/attaform.a99dQV7Q.mjs.map +0 -1
package/dist/vite.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.cjs","sources":["../src/vite.ts"],"sourcesContent":["/**\n * `attaform/vite` — Vite plugin that registers the compile-time\n * node transforms with @vitejs/plugin-vue.\n *\n * Usage (bare Vue 3 consumers):\n *\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n *\n * The transforms inject `:value`, `:checked`, and `:selected` bindings into\n * elements that use the `v-register` directive — load-bearing for SSR\n * initial-render correctness. Omitting this plugin under CSR is tolerable\n * (one-frame flash on mount); omitting it under SSR produces visibly wrong\n * initial HTML.\n *\n * Implementation note: this plugin mutates @vitejs/plugin-vue's options via\n * the documented but somewhat informal `api.options` surface used by\n * VueUse, Vite PWA, and other Vue ecosystem plugins. If you're using a\n * custom Vue plugin wrapper, fall back to `attaform/transforms`\n * and wire them yourself.\n */\nimport type { Plugin } from 'vite'\nimport { inputTextAreaNodeTransform } from './runtime/lib/core/transforms/input-text-area-transform'\nimport { selectNodeTransform } from './runtime/lib/core/transforms/select-transform'\nimport { vRegisterHintTransform } from './runtime/lib/core/transforms/v-register-hint-transform'\nimport { vRegisterPreambleTransform } from './runtime/lib/core/transforms/v-register-preamble-transform'\n\n/** Options for `attaform()`. Reserved for future use; pass `{}` or omit. */\nexport type AttaformVitePluginOptions = Record<string, never>\n\ninterface VitePluginVueApi {\n options?: {\n template?: {\n compilerOptions?: {\n nodeTransforms?: unknown[]\n }\n }\n }\n}\n\n/**\n * Vite plugin that wires the form library's compile-time template\n * transforms into `@vitejs/plugin-vue`. Required for SSR and for\n * hydration accuracy under bare Vue 3.\n *\n * ```ts\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n * ```\n *\n * Place the call after `vue()` in the plugins array. Nuxt projects\n * don't need this — `attaform/nuxt` handles it.\n */\nexport function attaform(_options: AttaformVitePluginOptions = {}): Plugin {\n // Unused-var suppression until options exist.\n void _options\n return {\n name: 'attaform',\n enforce: 'pre',\n configResolved(resolved) {\n const vuePlugin = resolved.plugins.find((p) => p.name === 'vite:vue')\n // Two distinct failure modes — separate error messages so the\n // consumer's fix is unambiguous:\n // 1. plugin not in the plugins array → install + register vue()\n // 2. plugin found but version-incompatible (no `api.options`) →\n // version mismatch with @vitejs/plugin-vue\n if (vuePlugin === undefined) {\n throw new Error(\n '[attaform/vite] @vitejs/plugin-vue is not installed (or not registered before attaform()). ' +\n 'Install @vitejs/plugin-vue and place `attaform()` after `vue()` in your plugins array.'\n )\n }\n const api = (vuePlugin as unknown as { api?: VitePluginVueApi }).api\n if (api?.options === undefined) {\n throw new Error(\n '[attaform/vite] Found @vitejs/plugin-vue but it does not expose `api.options`. ' +\n 'This usually means a version-incompatible @vitejs/plugin-vue (or a wrapper plugin re-exporting it). ' +\n 'Pin @vitejs/plugin-vue to a version compatible with the documented `api.options.template.compilerOptions.nodeTransforms` surface.'\n )\n }\n api.options.template ??= {}\n api.options.template.compilerOptions ??= {}\n const existing = api.options.template.compilerOptions.nodeTransforms ?? []\n // Idempotent install: if a previous attaform() invocation\n // (vite + nuxt module + manual `plugins: [attaform()]`) has\n // already pushed our transforms, skip — re-pushing would double\n // every binding the AST emits, breaking the IIFE-wrapping\n // invariants downstream transforms depend on. We detect the\n // sentinel via reference equality; user-supplied transforms with\n // the same name don't collide.\n if (existing.includes(vRegisterPreambleTransform as unknown)) return\n // vRegisterPreambleTransform MUST come before vRegisterHintTransform\n // — the preamble's pre-order captures each `v-register` expression\n // in its raw (un-wrapped) form, and the hint then mutates the same\n // directive's `exp` to wrap it. Reversing the order would have the\n // preamble pick up an already-wrapped IIFE, double-wrapping it\n // when injected at the root.\n api.options.template.compilerOptions.nodeTransforms = [\n ...existing,\n selectNodeTransform,\n inputTextAreaNodeTransform,\n vRegisterPreambleTransform,\n vRegisterHintTransform,\n ]\n },\n }\n}\n"],"names":["vRegisterPreambleTransform","selectNodeTransform","inputTextAreaNodeTransform","vRegisterHintTransform"],"mappings":";;;;AA+DO,SAAS,QAAA,CAAS,QAAA,GAAsC,EAAC,EAAW;AAGzE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IACT,eAAe,QAAA,EAAU;AArE7B,MAAA,IAAA,EAAA,EAAA,EAAA;AAsEM,MAAA,MAAM,SAAA,GAAY,SAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,UAAU,CAAA;AAMpE,MAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SAEF;AAAA,MACF;AACA,MAAA,MAAM,MAAO,SAAA,CAAoD,GAAA;AACjE,MAAA,IAAI,GAAA,EAAK,YAAY,MAAA,EAAW;AAC9B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SAGF;AAAA,MACF;AACA,MAAA,CAAA,EAAA,GAAA,GAAA,CAAI,OAAA,EAAQ,QAAA,KAAZ,EAAA,CAAY,QAAA,GAAa,EAAC,CAAA;AAC1B,MAAA,CAAA,EAAA,GAAA,GAAA,CAAI,OAAA,CAAQ,QAAA,EAAS,eAAA,KAArB,EAAA,CAAqB,kBAAoB,EAAC,CAAA;AAC1C,MAAA,MAAM,WAAW,GAAA,CAAI,OAAA,CAAQ,QAAA,CAAS,eAAA,CAAgB,kBAAkB,EAAC;AAQzE,MAAA,IAAI,QAAA,CAAS,QAAA,CAASA,qDAAqC,CAAA,EAAG;AAO9D,MAAA,GAAA,CAAI,OAAA,CAAQ,QAAA,CAAS,eAAA,CAAgB,cAAA,GAAiB;AAAA,QACpD,GAAG,QAAA;AAAA,QACHC,8CAAA;AAAA,QACAC,qDAAA;AAAA,QACAF,qDAAA;AAAA,QACAG;AAAA,OACF;AAAA,IACF;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"vite.cjs","sources":["../src/vite.ts"],"sourcesContent":["/**\n * `attaform/vite` — Vite plugin that wires the compile-time node\n * transforms with @vitejs/plugin-vue AND rewrites `attaform/zod`\n * imports to either `attaform/zod-v3` or `attaform/zod-v4` at build\n * time, based on the consumer's installed Zod major. The result is\n * one Zod adapter shipped per bundle, with no manual subpath choice.\n *\n * Usage (bare Vue 3 consumers):\n *\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n *\n * The transforms inject `:value`, `:checked`, and `:selected` bindings\n * into elements that use the `v-register` directive — load-bearing for\n * SSR initial-render correctness. Omitting this plugin under CSR is\n * tolerable (one-frame flash on mount); omitting it under SSR produces\n * visibly wrong initial HTML.\n *\n * The `resolveZodAlias` option (default `true`) controls the build-time\n * `attaform/zod` rewrite. Set to `false` if your project intentionally\n * mixes Zod versions or has a non-standard Zod resolution; the unified\n * `attaform/zod` entry's runtime dispatch covers that case at the cost\n * of bundling both adapters.\n *\n * Implementation note: this plugin mutates @vitejs/plugin-vue's options\n * via the documented but somewhat informal `api.options` surface used\n * by VueUse, Vite PWA, and other Vue ecosystem plugins. If you're\n * using a custom Vue plugin wrapper, fall back to `attaform/transforms`\n * and wire them yourself.\n */\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { join } from 'node:path'\nimport type { Plugin } from 'vite'\nimport { inputTextAreaNodeTransform } from './runtime/lib/core/transforms/input-text-area-transform'\nimport { selectNodeTransform } from './runtime/lib/core/transforms/select-transform'\nimport { vRegisterHintTransform } from './runtime/lib/core/transforms/v-register-hint-transform'\nimport { vRegisterPreambleTransform } from './runtime/lib/core/transforms/v-register-preamble-transform'\n\n/** Options for `attaform()`. */\nexport interface AttaformVitePluginOptions {\n /**\n * Rewrite `attaform/zod` imports at build time to either\n * `attaform/zod-v3` or `attaform/zod-v4`, based on the consumer's\n * installed Zod major. Default `true` — produces a leaner bundle\n * for the common case of one Zod version per project.\n *\n * Set to `false` to fall through to the unified entry's runtime\n * dispatch. Useful when:\n * - your project intentionally has both `zod` and `zod-v3`\n * installed (e.g. via a pnpm alias) and the schema-shape\n * dispatch is the right behavior;\n * - your monorepo's Zod resolution is non-standard and the\n * plugin's detection (`import.meta.resolve('zod/package.json')`)\n * would land on the wrong copy.\n */\n resolveZodAlias?: boolean\n}\n\ninterface VitePluginVueApi {\n options?: {\n template?: {\n compilerOptions?: {\n nodeTransforms?: unknown[]\n }\n }\n }\n}\n\nconst ZOD_UNIFIED_SPECIFIER = 'attaform/zod'\nconst ZOD_V3_SPECIFIER = 'attaform/zod-v3'\nconst ZOD_V4_SPECIFIER = 'attaform/zod-v4'\n\n/**\n * Read the consumer's installed Zod major by resolving\n * `zod/package.json` from their project root. ESM resolution\n * (`import.meta.resolve`) is sync and stable on Node 20.6+, follows\n * pnpm symlinks, and works with attaform's ESM-only `exports` map.\n *\n * Returns:\n * - `{ major: 3 | 4 }` when zod is resolvable AND its `version`\n * field parses to a known major;\n * - `{ major: 'missing' }` when zod can't be resolved at all;\n * - `{ major: 'unknown' }` for any other failure (corrupted\n * package.json, unexpected version string, monorepo edge case).\n */\nfunction detectZodMajor(\n consumerRootDir: string\n): { major: 3 } | { major: 4 } | { major: 'missing' } | { major: 'unknown' } {\n const consumerURL = pathToFileURL(join(consumerRootDir, 'package.json')).href\n let resolved: string\n try {\n resolved = import.meta.resolve('zod/package.json', consumerURL)\n } catch {\n return { major: 'missing' }\n }\n try {\n const pkg = JSON.parse(readFileSync(fileURLToPath(resolved), 'utf8')) as { version?: unknown }\n const version = pkg.version\n if (typeof version !== 'string') return { major: 'unknown' }\n const major = Number.parseInt(version.split('.')[0] ?? '', 10)\n if (major === 3) return { major: 3 }\n if (major === 4) return { major: 4 }\n return { major: 'unknown' }\n } catch {\n return { major: 'unknown' }\n }\n}\n\n/**\n * Vite plugin that wires the form library's compile-time template\n * transforms into `@vitejs/plugin-vue` and rewrites the unified\n * `attaform/zod` import to the matching adapter subpath. Required\n * for SSR and for hydration accuracy under bare Vue 3.\n *\n * ```ts\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n * ```\n *\n * Place the call after `vue()` in the plugins array. Nuxt projects\n * don't need this — `attaform/nuxt` handles it.\n */\nexport function attaform(options: AttaformVitePluginOptions = {}): Plugin {\n const resolveZodAlias = options.resolveZodAlias !== false\n // Resolution is computed once per plugin instance from the resolved\n // Vite root in `configResolved`, then cached for every `resolveId`\n // call (the hook fires many times during dev/build).\n let aliasTarget: string | null = null\n let warnedAboutDetection = false\n\n return {\n name: 'attaform',\n enforce: 'pre',\n configResolved(resolved) {\n const vuePlugin = resolved.plugins.find((p) => p.name === 'vite:vue')\n // Two distinct failure modes — separate error messages so the\n // consumer's fix is unambiguous:\n // 1. plugin not in the plugins array → install + register vue()\n // 2. plugin found but version-incompatible (no `api.options`) →\n // version mismatch with @vitejs/plugin-vue\n if (vuePlugin === undefined) {\n throw new Error(\n '[attaform/vite] @vitejs/plugin-vue is not installed (or not registered before attaform()). ' +\n 'Install @vitejs/plugin-vue and place `attaform()` after `vue()` in your plugins array.'\n )\n }\n const api = (vuePlugin as unknown as { api?: VitePluginVueApi }).api\n if (api?.options === undefined) {\n throw new Error(\n '[attaform/vite] Found @vitejs/plugin-vue but it does not expose `api.options`. ' +\n 'This usually means a version-incompatible @vitejs/plugin-vue (or a wrapper plugin re-exporting it). ' +\n 'Pin @vitejs/plugin-vue to a version compatible with the documented `api.options.template.compilerOptions.nodeTransforms` surface.'\n )\n }\n api.options.template ??= {}\n api.options.template.compilerOptions ??= {}\n const existing = api.options.template.compilerOptions.nodeTransforms ?? []\n // Idempotent install: if a previous attaform() invocation\n // (vite + nuxt module + manual `plugins: [attaform()]`) has\n // already pushed our transforms, skip — re-pushing would double\n // every binding the AST emits, breaking the IIFE-wrapping\n // invariants downstream transforms depend on. We detect the\n // sentinel via reference equality; user-supplied transforms with\n // the same name don't collide.\n if (!existing.includes(vRegisterPreambleTransform as unknown)) {\n // vRegisterPreambleTransform MUST come before vRegisterHintTransform\n // — the preamble's pre-order captures each `v-register` expression\n // in its raw (un-wrapped) form, and the hint then mutates the same\n // directive's `exp` to wrap it. Reversing the order would have the\n // preamble pick up an already-wrapped IIFE, double-wrapping it\n // when injected at the root.\n api.options.template.compilerOptions.nodeTransforms = [\n ...existing,\n selectNodeTransform,\n inputTextAreaNodeTransform,\n vRegisterPreambleTransform,\n vRegisterHintTransform,\n ]\n }\n\n // Build-time alias resolution. Skip cleanly when the user opted\n // out so consumers with non-standard Zod setups don't see a\n // \"zod is not installed\" error from this plugin.\n if (!resolveZodAlias) return\n const detection = detectZodMajor(resolved.root)\n if (detection.major === 'missing') {\n throw new Error(\n '[attaform/vite] zod is not installed. attaform requires zod as a peer dependency. ' +\n 'Install `zod@^3` or `zod@^4`, OR pass `attaform({ resolveZodAlias: false })` ' +\n 'to keep the runtime-dispatch unified entry (and silence this check).'\n )\n }\n if (detection.major === 'unknown') {\n // Detection landed on a zod resolution but couldn't classify\n // the version — log once and fall through to runtime dispatch.\n // The build still works; the consumer just ships both adapters.\n if (!warnedAboutDetection) {\n warnedAboutDetection = true\n console.warn(\n '[attaform/vite] Could not classify the installed Zod major (corrupted package.json, ' +\n 'monorepo edge case, or an unexpected version string). Falling through to runtime ' +\n 'dispatch — both Zod adapters will ship in the bundle. ' +\n 'Pass `attaform({ resolveZodAlias: false })` to silence this warning.'\n )\n }\n return\n }\n aliasTarget = detection.major === 4 ? ZOD_V4_SPECIFIER : ZOD_V3_SPECIFIER\n },\n resolveId(source) {\n // Intercept ONLY the exact unified specifier. Explicit subpaths\n // (`attaform/zod-v3`, `attaform/zod-v4`) and the root entry\n // (`attaform`) pass through unchanged — that's the documented\n // escape hatch for power users.\n if (!resolveZodAlias) return null\n if (aliasTarget === null) return null\n if (source !== ZOD_UNIFIED_SPECIFIER) return null\n return aliasTarget\n },\n }\n}\n"],"names":["pathToFileURL","join","readFileSync","fileURLToPath","vRegisterPreambleTransform","selectNodeTransform","inputTextAreaNodeTransform","vRegisterHintTransform"],"mappings":"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"}
package/dist/vite.d.cts CHANGED
@@ -1,38 +1,29 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
- /**
4
- * `attaform/vite` — Vite plugin that registers the compile-time
5
- * node transforms with @vitejs/plugin-vue.
6
- *
7
- * Usage (bare Vue 3 consumers):
8
- *
9
- * // vite.config.ts
10
- * import vue from '@vitejs/plugin-vue'
11
- * import { attaform } from 'attaform/vite'
12
- *
13
- * export default defineConfig({
14
- * plugins: [vue(), attaform()],
15
- * })
16
- *
17
- * The transforms inject `:value`, `:checked`, and `:selected` bindings into
18
- * elements that use the `v-register` directive — load-bearing for SSR
19
- * initial-render correctness. Omitting this plugin under CSR is tolerable
20
- * (one-frame flash on mount); omitting it under SSR produces visibly wrong
21
- * initial HTML.
22
- *
23
- * Implementation note: this plugin mutates @vitejs/plugin-vue's options via
24
- * the documented but somewhat informal `api.options` surface used by
25
- * VueUse, Vite PWA, and other Vue ecosystem plugins. If you're using a
26
- * custom Vue plugin wrapper, fall back to `attaform/transforms`
27
- * and wire them yourself.
28
- */
29
-
30
- /** Options for `attaform()`. Reserved for future use; pass `{}` or omit. */
31
- type AttaformVitePluginOptions = Record<string, never>;
3
+ /** Options for `attaform()`. */
4
+ interface AttaformVitePluginOptions {
5
+ /**
6
+ * Rewrite `attaform/zod` imports at build time to either
7
+ * `attaform/zod-v3` or `attaform/zod-v4`, based on the consumer's
8
+ * installed Zod major. Default `true` — produces a leaner bundle
9
+ * for the common case of one Zod version per project.
10
+ *
11
+ * Set to `false` to fall through to the unified entry's runtime
12
+ * dispatch. Useful when:
13
+ * - your project intentionally has both `zod` and `zod-v3`
14
+ * installed (e.g. via a pnpm alias) and the schema-shape
15
+ * dispatch is the right behavior;
16
+ * - your monorepo's Zod resolution is non-standard and the
17
+ * plugin's detection (`import.meta.resolve('zod/package.json')`)
18
+ * would land on the wrong copy.
19
+ */
20
+ resolveZodAlias?: boolean;
21
+ }
32
22
  /**
33
23
  * Vite plugin that wires the form library's compile-time template
34
- * transforms into `@vitejs/plugin-vue`. Required for SSR and for
35
- * hydration accuracy under bare Vue 3.
24
+ * transforms into `@vitejs/plugin-vue` and rewrites the unified
25
+ * `attaform/zod` import to the matching adapter subpath. Required
26
+ * for SSR and for hydration accuracy under bare Vue 3.
36
27
  *
37
28
  * ```ts
38
29
  * // vite.config.ts
@@ -47,7 +38,7 @@ type AttaformVitePluginOptions = Record<string, never>;
47
38
  * Place the call after `vue()` in the plugins array. Nuxt projects
48
39
  * don't need this — `attaform/nuxt` handles it.
49
40
  */
50
- declare function attaform(_options?: AttaformVitePluginOptions): Plugin;
41
+ declare function attaform(options?: AttaformVitePluginOptions): Plugin;
51
42
 
52
43
  export { attaform };
53
44
  export type { AttaformVitePluginOptions };
package/dist/vite.d.mts CHANGED
@@ -1,38 +1,29 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
- /**
4
- * `attaform/vite` — Vite plugin that registers the compile-time
5
- * node transforms with @vitejs/plugin-vue.
6
- *
7
- * Usage (bare Vue 3 consumers):
8
- *
9
- * // vite.config.ts
10
- * import vue from '@vitejs/plugin-vue'
11
- * import { attaform } from 'attaform/vite'
12
- *
13
- * export default defineConfig({
14
- * plugins: [vue(), attaform()],
15
- * })
16
- *
17
- * The transforms inject `:value`, `:checked`, and `:selected` bindings into
18
- * elements that use the `v-register` directive — load-bearing for SSR
19
- * initial-render correctness. Omitting this plugin under CSR is tolerable
20
- * (one-frame flash on mount); omitting it under SSR produces visibly wrong
21
- * initial HTML.
22
- *
23
- * Implementation note: this plugin mutates @vitejs/plugin-vue's options via
24
- * the documented but somewhat informal `api.options` surface used by
25
- * VueUse, Vite PWA, and other Vue ecosystem plugins. If you're using a
26
- * custom Vue plugin wrapper, fall back to `attaform/transforms`
27
- * and wire them yourself.
28
- */
29
-
30
- /** Options for `attaform()`. Reserved for future use; pass `{}` or omit. */
31
- type AttaformVitePluginOptions = Record<string, never>;
3
+ /** Options for `attaform()`. */
4
+ interface AttaformVitePluginOptions {
5
+ /**
6
+ * Rewrite `attaform/zod` imports at build time to either
7
+ * `attaform/zod-v3` or `attaform/zod-v4`, based on the consumer's
8
+ * installed Zod major. Default `true` — produces a leaner bundle
9
+ * for the common case of one Zod version per project.
10
+ *
11
+ * Set to `false` to fall through to the unified entry's runtime
12
+ * dispatch. Useful when:
13
+ * - your project intentionally has both `zod` and `zod-v3`
14
+ * installed (e.g. via a pnpm alias) and the schema-shape
15
+ * dispatch is the right behavior;
16
+ * - your monorepo's Zod resolution is non-standard and the
17
+ * plugin's detection (`import.meta.resolve('zod/package.json')`)
18
+ * would land on the wrong copy.
19
+ */
20
+ resolveZodAlias?: boolean;
21
+ }
32
22
  /**
33
23
  * Vite plugin that wires the form library's compile-time template
34
- * transforms into `@vitejs/plugin-vue`. Required for SSR and for
35
- * hydration accuracy under bare Vue 3.
24
+ * transforms into `@vitejs/plugin-vue` and rewrites the unified
25
+ * `attaform/zod` import to the matching adapter subpath. Required
26
+ * for SSR and for hydration accuracy under bare Vue 3.
36
27
  *
37
28
  * ```ts
38
29
  * // vite.config.ts
@@ -47,7 +38,7 @@ type AttaformVitePluginOptions = Record<string, never>;
47
38
  * Place the call after `vue()` in the plugins array. Nuxt projects
48
39
  * don't need this — `attaform/nuxt` handles it.
49
40
  */
50
- declare function attaform(_options?: AttaformVitePluginOptions): Plugin;
41
+ declare function attaform(options?: AttaformVitePluginOptions): Plugin;
51
42
 
52
43
  export { attaform };
53
44
  export type { AttaformVitePluginOptions };
package/dist/vite.d.ts CHANGED
@@ -1,38 +1,29 @@
1
1
  import { Plugin } from 'vite';
2
2
 
3
- /**
4
- * `attaform/vite` — Vite plugin that registers the compile-time
5
- * node transforms with @vitejs/plugin-vue.
6
- *
7
- * Usage (bare Vue 3 consumers):
8
- *
9
- * // vite.config.ts
10
- * import vue from '@vitejs/plugin-vue'
11
- * import { attaform } from 'attaform/vite'
12
- *
13
- * export default defineConfig({
14
- * plugins: [vue(), attaform()],
15
- * })
16
- *
17
- * The transforms inject `:value`, `:checked`, and `:selected` bindings into
18
- * elements that use the `v-register` directive — load-bearing for SSR
19
- * initial-render correctness. Omitting this plugin under CSR is tolerable
20
- * (one-frame flash on mount); omitting it under SSR produces visibly wrong
21
- * initial HTML.
22
- *
23
- * Implementation note: this plugin mutates @vitejs/plugin-vue's options via
24
- * the documented but somewhat informal `api.options` surface used by
25
- * VueUse, Vite PWA, and other Vue ecosystem plugins. If you're using a
26
- * custom Vue plugin wrapper, fall back to `attaform/transforms`
27
- * and wire them yourself.
28
- */
29
-
30
- /** Options for `attaform()`. Reserved for future use; pass `{}` or omit. */
31
- type AttaformVitePluginOptions = Record<string, never>;
3
+ /** Options for `attaform()`. */
4
+ interface AttaformVitePluginOptions {
5
+ /**
6
+ * Rewrite `attaform/zod` imports at build time to either
7
+ * `attaform/zod-v3` or `attaform/zod-v4`, based on the consumer's
8
+ * installed Zod major. Default `true` — produces a leaner bundle
9
+ * for the common case of one Zod version per project.
10
+ *
11
+ * Set to `false` to fall through to the unified entry's runtime
12
+ * dispatch. Useful when:
13
+ * - your project intentionally has both `zod` and `zod-v3`
14
+ * installed (e.g. via a pnpm alias) and the schema-shape
15
+ * dispatch is the right behavior;
16
+ * - your monorepo's Zod resolution is non-standard and the
17
+ * plugin's detection (`import.meta.resolve('zod/package.json')`)
18
+ * would land on the wrong copy.
19
+ */
20
+ resolveZodAlias?: boolean;
21
+ }
32
22
  /**
33
23
  * Vite plugin that wires the form library's compile-time template
34
- * transforms into `@vitejs/plugin-vue`. Required for SSR and for
35
- * hydration accuracy under bare Vue 3.
24
+ * transforms into `@vitejs/plugin-vue` and rewrites the unified
25
+ * `attaform/zod` import to the matching adapter subpath. Required
26
+ * for SSR and for hydration accuracy under bare Vue 3.
36
27
  *
37
28
  * ```ts
38
29
  * // vite.config.ts
@@ -47,7 +38,7 @@ type AttaformVitePluginOptions = Record<string, never>;
47
38
  * Place the call after `vue()` in the plugins array. Nuxt projects
48
39
  * don't need this — `attaform/nuxt` handles it.
49
40
  */
50
- declare function attaform(_options?: AttaformVitePluginOptions): Plugin;
41
+ declare function attaform(options?: AttaformVitePluginOptions): Plugin;
51
42
 
52
43
  export { attaform };
53
44
  export type { AttaformVitePluginOptions };
package/dist/vite.mjs CHANGED
@@ -1,6 +1,35 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { pathToFileURL, fileURLToPath } from 'node:url';
3
+ import { join } from 'node:path';
1
4
  import { a as vRegisterPreambleTransform, s as selectNodeTransform, i as inputTextAreaNodeTransform, v as vRegisterHintTransform } from './shared/attaform.CXpzmj38.mjs';
2
5
 
3
- function attaform(_options = {}) {
6
+ const ZOD_UNIFIED_SPECIFIER = "attaform/zod";
7
+ const ZOD_V3_SPECIFIER = "attaform/zod-v3";
8
+ const ZOD_V4_SPECIFIER = "attaform/zod-v4";
9
+ function detectZodMajor(consumerRootDir) {
10
+ const consumerURL = pathToFileURL(join(consumerRootDir, "package.json")).href;
11
+ let resolved;
12
+ try {
13
+ resolved = import.meta.resolve("zod/package.json", consumerURL);
14
+ } catch {
15
+ return { major: "missing" };
16
+ }
17
+ try {
18
+ const pkg = JSON.parse(readFileSync(fileURLToPath(resolved), "utf8"));
19
+ const version = pkg.version;
20
+ if (typeof version !== "string") return { major: "unknown" };
21
+ const major = Number.parseInt(version.split(".")[0] ?? "", 10);
22
+ if (major === 3) return { major: 3 };
23
+ if (major === 4) return { major: 4 };
24
+ return { major: "unknown" };
25
+ } catch {
26
+ return { major: "unknown" };
27
+ }
28
+ }
29
+ function attaform(options = {}) {
30
+ const resolveZodAlias = options.resolveZodAlias !== false;
31
+ let aliasTarget = null;
32
+ let warnedAboutDetection = false;
4
33
  return {
5
34
  name: "attaform",
6
35
  enforce: "pre",
@@ -21,14 +50,38 @@ function attaform(_options = {}) {
21
50
  (_a = api.options).template ?? (_a.template = {});
22
51
  (_b = api.options.template).compilerOptions ?? (_b.compilerOptions = {});
23
52
  const existing = api.options.template.compilerOptions.nodeTransforms ?? [];
24
- if (existing.includes(vRegisterPreambleTransform)) return;
25
- api.options.template.compilerOptions.nodeTransforms = [
26
- ...existing,
27
- selectNodeTransform,
28
- inputTextAreaNodeTransform,
29
- vRegisterPreambleTransform,
30
- vRegisterHintTransform
31
- ];
53
+ if (!existing.includes(vRegisterPreambleTransform)) {
54
+ api.options.template.compilerOptions.nodeTransforms = [
55
+ ...existing,
56
+ selectNodeTransform,
57
+ inputTextAreaNodeTransform,
58
+ vRegisterPreambleTransform,
59
+ vRegisterHintTransform
60
+ ];
61
+ }
62
+ if (!resolveZodAlias) return;
63
+ const detection = detectZodMajor(resolved.root);
64
+ if (detection.major === "missing") {
65
+ throw new Error(
66
+ "[attaform/vite] zod is not installed. attaform requires zod as a peer dependency. Install `zod@^3` or `zod@^4`, OR pass `attaform({ resolveZodAlias: false })` to keep the runtime-dispatch unified entry (and silence this check)."
67
+ );
68
+ }
69
+ if (detection.major === "unknown") {
70
+ if (!warnedAboutDetection) {
71
+ warnedAboutDetection = true;
72
+ console.warn(
73
+ "[attaform/vite] Could not classify the installed Zod major (corrupted package.json, monorepo edge case, or an unexpected version string). Falling through to runtime dispatch \u2014 both Zod adapters will ship in the bundle. Pass `attaform({ resolveZodAlias: false })` to silence this warning."
74
+ );
75
+ }
76
+ return;
77
+ }
78
+ aliasTarget = detection.major === 4 ? ZOD_V4_SPECIFIER : ZOD_V3_SPECIFIER;
79
+ },
80
+ resolveId(source) {
81
+ if (!resolveZodAlias) return null;
82
+ if (aliasTarget === null) return null;
83
+ if (source !== ZOD_UNIFIED_SPECIFIER) return null;
84
+ return aliasTarget;
32
85
  }
33
86
  };
34
87
  }
package/dist/vite.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"vite.mjs","sources":["../src/vite.ts"],"sourcesContent":["/**\n * `attaform/vite` — Vite plugin that registers the compile-time\n * node transforms with @vitejs/plugin-vue.\n *\n * Usage (bare Vue 3 consumers):\n *\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n *\n * The transforms inject `:value`, `:checked`, and `:selected` bindings into\n * elements that use the `v-register` directive — load-bearing for SSR\n * initial-render correctness. Omitting this plugin under CSR is tolerable\n * (one-frame flash on mount); omitting it under SSR produces visibly wrong\n * initial HTML.\n *\n * Implementation note: this plugin mutates @vitejs/plugin-vue's options via\n * the documented but somewhat informal `api.options` surface used by\n * VueUse, Vite PWA, and other Vue ecosystem plugins. If you're using a\n * custom Vue plugin wrapper, fall back to `attaform/transforms`\n * and wire them yourself.\n */\nimport type { Plugin } from 'vite'\nimport { inputTextAreaNodeTransform } from './runtime/lib/core/transforms/input-text-area-transform'\nimport { selectNodeTransform } from './runtime/lib/core/transforms/select-transform'\nimport { vRegisterHintTransform } from './runtime/lib/core/transforms/v-register-hint-transform'\nimport { vRegisterPreambleTransform } from './runtime/lib/core/transforms/v-register-preamble-transform'\n\n/** Options for `attaform()`. Reserved for future use; pass `{}` or omit. */\nexport type AttaformVitePluginOptions = Record<string, never>\n\ninterface VitePluginVueApi {\n options?: {\n template?: {\n compilerOptions?: {\n nodeTransforms?: unknown[]\n }\n }\n }\n}\n\n/**\n * Vite plugin that wires the form library's compile-time template\n * transforms into `@vitejs/plugin-vue`. Required for SSR and for\n * hydration accuracy under bare Vue 3.\n *\n * ```ts\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n * ```\n *\n * Place the call after `vue()` in the plugins array. Nuxt projects\n * don't need this — `attaform/nuxt` handles it.\n */\nexport function attaform(_options: AttaformVitePluginOptions = {}): Plugin {\n // Unused-var suppression until options exist.\n void _options\n return {\n name: 'attaform',\n enforce: 'pre',\n configResolved(resolved) {\n const vuePlugin = resolved.plugins.find((p) => p.name === 'vite:vue')\n // Two distinct failure modes — separate error messages so the\n // consumer's fix is unambiguous:\n // 1. plugin not in the plugins array → install + register vue()\n // 2. plugin found but version-incompatible (no `api.options`) →\n // version mismatch with @vitejs/plugin-vue\n if (vuePlugin === undefined) {\n throw new Error(\n '[attaform/vite] @vitejs/plugin-vue is not installed (or not registered before attaform()). ' +\n 'Install @vitejs/plugin-vue and place `attaform()` after `vue()` in your plugins array.'\n )\n }\n const api = (vuePlugin as unknown as { api?: VitePluginVueApi }).api\n if (api?.options === undefined) {\n throw new Error(\n '[attaform/vite] Found @vitejs/plugin-vue but it does not expose `api.options`. ' +\n 'This usually means a version-incompatible @vitejs/plugin-vue (or a wrapper plugin re-exporting it). ' +\n 'Pin @vitejs/plugin-vue to a version compatible with the documented `api.options.template.compilerOptions.nodeTransforms` surface.'\n )\n }\n api.options.template ??= {}\n api.options.template.compilerOptions ??= {}\n const existing = api.options.template.compilerOptions.nodeTransforms ?? []\n // Idempotent install: if a previous attaform() invocation\n // (vite + nuxt module + manual `plugins: [attaform()]`) has\n // already pushed our transforms, skip — re-pushing would double\n // every binding the AST emits, breaking the IIFE-wrapping\n // invariants downstream transforms depend on. We detect the\n // sentinel via reference equality; user-supplied transforms with\n // the same name don't collide.\n if (existing.includes(vRegisterPreambleTransform as unknown)) return\n // vRegisterPreambleTransform MUST come before vRegisterHintTransform\n // — the preamble's pre-order captures each `v-register` expression\n // in its raw (un-wrapped) form, and the hint then mutates the same\n // directive's `exp` to wrap it. Reversing the order would have the\n // preamble pick up an already-wrapped IIFE, double-wrapping it\n // when injected at the root.\n api.options.template.compilerOptions.nodeTransforms = [\n ...existing,\n selectNodeTransform,\n inputTextAreaNodeTransform,\n vRegisterPreambleTransform,\n vRegisterHintTransform,\n ]\n },\n }\n}\n"],"names":[],"mappings":";;AA+DO,SAAS,QAAA,CAAS,QAAA,GAAsC,EAAC,EAAW;AAGzE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IACT,eAAe,QAAA,EAAU;AArE7B,MAAA,IAAA,EAAA,EAAA,EAAA;AAsEM,MAAA,MAAM,SAAA,GAAY,SAAS,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,UAAU,CAAA;AAMpE,MAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SAEF;AAAA,MACF;AACA,MAAA,MAAM,MAAO,SAAA,CAAoD,GAAA;AACjE,MAAA,IAAI,GAAA,EAAK,YAAY,MAAA,EAAW;AAC9B,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SAGF;AAAA,MACF;AACA,MAAA,CAAA,EAAA,GAAA,GAAA,CAAI,OAAA,EAAQ,QAAA,KAAZ,EAAA,CAAY,QAAA,GAAa,EAAC,CAAA;AAC1B,MAAA,CAAA,EAAA,GAAA,GAAA,CAAI,OAAA,CAAQ,QAAA,EAAS,eAAA,KAArB,EAAA,CAAqB,kBAAoB,EAAC,CAAA;AAC1C,MAAA,MAAM,WAAW,GAAA,CAAI,OAAA,CAAQ,QAAA,CAAS,eAAA,CAAgB,kBAAkB,EAAC;AAQzE,MAAA,IAAI,QAAA,CAAS,QAAA,CAAS,0BAAqC,CAAA,EAAG;AAO9D,MAAA,GAAA,CAAI,OAAA,CAAQ,QAAA,CAAS,eAAA,CAAgB,cAAA,GAAiB;AAAA,QACpD,GAAG,QAAA;AAAA,QACH,mBAAA;AAAA,QACA,0BAAA;AAAA,QACA,0BAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"vite.mjs","sources":["../src/vite.ts"],"sourcesContent":["/**\n * `attaform/vite` — Vite plugin that wires the compile-time node\n * transforms with @vitejs/plugin-vue AND rewrites `attaform/zod`\n * imports to either `attaform/zod-v3` or `attaform/zod-v4` at build\n * time, based on the consumer's installed Zod major. The result is\n * one Zod adapter shipped per bundle, with no manual subpath choice.\n *\n * Usage (bare Vue 3 consumers):\n *\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n *\n * The transforms inject `:value`, `:checked`, and `:selected` bindings\n * into elements that use the `v-register` directive — load-bearing for\n * SSR initial-render correctness. Omitting this plugin under CSR is\n * tolerable (one-frame flash on mount); omitting it under SSR produces\n * visibly wrong initial HTML.\n *\n * The `resolveZodAlias` option (default `true`) controls the build-time\n * `attaform/zod` rewrite. Set to `false` if your project intentionally\n * mixes Zod versions or has a non-standard Zod resolution; the unified\n * `attaform/zod` entry's runtime dispatch covers that case at the cost\n * of bundling both adapters.\n *\n * Implementation note: this plugin mutates @vitejs/plugin-vue's options\n * via the documented but somewhat informal `api.options` surface used\n * by VueUse, Vite PWA, and other Vue ecosystem plugins. If you're\n * using a custom Vue plugin wrapper, fall back to `attaform/transforms`\n * and wire them yourself.\n */\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { join } from 'node:path'\nimport type { Plugin } from 'vite'\nimport { inputTextAreaNodeTransform } from './runtime/lib/core/transforms/input-text-area-transform'\nimport { selectNodeTransform } from './runtime/lib/core/transforms/select-transform'\nimport { vRegisterHintTransform } from './runtime/lib/core/transforms/v-register-hint-transform'\nimport { vRegisterPreambleTransform } from './runtime/lib/core/transforms/v-register-preamble-transform'\n\n/** Options for `attaform()`. */\nexport interface AttaformVitePluginOptions {\n /**\n * Rewrite `attaform/zod` imports at build time to either\n * `attaform/zod-v3` or `attaform/zod-v4`, based on the consumer's\n * installed Zod major. Default `true` — produces a leaner bundle\n * for the common case of one Zod version per project.\n *\n * Set to `false` to fall through to the unified entry's runtime\n * dispatch. Useful when:\n * - your project intentionally has both `zod` and `zod-v3`\n * installed (e.g. via a pnpm alias) and the schema-shape\n * dispatch is the right behavior;\n * - your monorepo's Zod resolution is non-standard and the\n * plugin's detection (`import.meta.resolve('zod/package.json')`)\n * would land on the wrong copy.\n */\n resolveZodAlias?: boolean\n}\n\ninterface VitePluginVueApi {\n options?: {\n template?: {\n compilerOptions?: {\n nodeTransforms?: unknown[]\n }\n }\n }\n}\n\nconst ZOD_UNIFIED_SPECIFIER = 'attaform/zod'\nconst ZOD_V3_SPECIFIER = 'attaform/zod-v3'\nconst ZOD_V4_SPECIFIER = 'attaform/zod-v4'\n\n/**\n * Read the consumer's installed Zod major by resolving\n * `zod/package.json` from their project root. ESM resolution\n * (`import.meta.resolve`) is sync and stable on Node 20.6+, follows\n * pnpm symlinks, and works with attaform's ESM-only `exports` map.\n *\n * Returns:\n * - `{ major: 3 | 4 }` when zod is resolvable AND its `version`\n * field parses to a known major;\n * - `{ major: 'missing' }` when zod can't be resolved at all;\n * - `{ major: 'unknown' }` for any other failure (corrupted\n * package.json, unexpected version string, monorepo edge case).\n */\nfunction detectZodMajor(\n consumerRootDir: string\n): { major: 3 } | { major: 4 } | { major: 'missing' } | { major: 'unknown' } {\n const consumerURL = pathToFileURL(join(consumerRootDir, 'package.json')).href\n let resolved: string\n try {\n resolved = import.meta.resolve('zod/package.json', consumerURL)\n } catch {\n return { major: 'missing' }\n }\n try {\n const pkg = JSON.parse(readFileSync(fileURLToPath(resolved), 'utf8')) as { version?: unknown }\n const version = pkg.version\n if (typeof version !== 'string') return { major: 'unknown' }\n const major = Number.parseInt(version.split('.')[0] ?? '', 10)\n if (major === 3) return { major: 3 }\n if (major === 4) return { major: 4 }\n return { major: 'unknown' }\n } catch {\n return { major: 'unknown' }\n }\n}\n\n/**\n * Vite plugin that wires the form library's compile-time template\n * transforms into `@vitejs/plugin-vue` and rewrites the unified\n * `attaform/zod` import to the matching adapter subpath. Required\n * for SSR and for hydration accuracy under bare Vue 3.\n *\n * ```ts\n * // vite.config.ts\n * import vue from '@vitejs/plugin-vue'\n * import { attaform } from 'attaform/vite'\n *\n * export default defineConfig({\n * plugins: [vue(), attaform()],\n * })\n * ```\n *\n * Place the call after `vue()` in the plugins array. Nuxt projects\n * don't need this — `attaform/nuxt` handles it.\n */\nexport function attaform(options: AttaformVitePluginOptions = {}): Plugin {\n const resolveZodAlias = options.resolveZodAlias !== false\n // Resolution is computed once per plugin instance from the resolved\n // Vite root in `configResolved`, then cached for every `resolveId`\n // call (the hook fires many times during dev/build).\n let aliasTarget: string | null = null\n let warnedAboutDetection = false\n\n return {\n name: 'attaform',\n enforce: 'pre',\n configResolved(resolved) {\n const vuePlugin = resolved.plugins.find((p) => p.name === 'vite:vue')\n // Two distinct failure modes — separate error messages so the\n // consumer's fix is unambiguous:\n // 1. plugin not in the plugins array → install + register vue()\n // 2. plugin found but version-incompatible (no `api.options`) →\n // version mismatch with @vitejs/plugin-vue\n if (vuePlugin === undefined) {\n throw new Error(\n '[attaform/vite] @vitejs/plugin-vue is not installed (or not registered before attaform()). ' +\n 'Install @vitejs/plugin-vue and place `attaform()` after `vue()` in your plugins array.'\n )\n }\n const api = (vuePlugin as unknown as { api?: VitePluginVueApi }).api\n if (api?.options === undefined) {\n throw new Error(\n '[attaform/vite] Found @vitejs/plugin-vue but it does not expose `api.options`. ' +\n 'This usually means a version-incompatible @vitejs/plugin-vue (or a wrapper plugin re-exporting it). ' +\n 'Pin @vitejs/plugin-vue to a version compatible with the documented `api.options.template.compilerOptions.nodeTransforms` surface.'\n )\n }\n api.options.template ??= {}\n api.options.template.compilerOptions ??= {}\n const existing = api.options.template.compilerOptions.nodeTransforms ?? []\n // Idempotent install: if a previous attaform() invocation\n // (vite + nuxt module + manual `plugins: [attaform()]`) has\n // already pushed our transforms, skip — re-pushing would double\n // every binding the AST emits, breaking the IIFE-wrapping\n // invariants downstream transforms depend on. We detect the\n // sentinel via reference equality; user-supplied transforms with\n // the same name don't collide.\n if (!existing.includes(vRegisterPreambleTransform as unknown)) {\n // vRegisterPreambleTransform MUST come before vRegisterHintTransform\n // — the preamble's pre-order captures each `v-register` expression\n // in its raw (un-wrapped) form, and the hint then mutates the same\n // directive's `exp` to wrap it. Reversing the order would have the\n // preamble pick up an already-wrapped IIFE, double-wrapping it\n // when injected at the root.\n api.options.template.compilerOptions.nodeTransforms = [\n ...existing,\n selectNodeTransform,\n inputTextAreaNodeTransform,\n vRegisterPreambleTransform,\n vRegisterHintTransform,\n ]\n }\n\n // Build-time alias resolution. Skip cleanly when the user opted\n // out so consumers with non-standard Zod setups don't see a\n // \"zod is not installed\" error from this plugin.\n if (!resolveZodAlias) return\n const detection = detectZodMajor(resolved.root)\n if (detection.major === 'missing') {\n throw new Error(\n '[attaform/vite] zod is not installed. attaform requires zod as a peer dependency. ' +\n 'Install `zod@^3` or `zod@^4`, OR pass `attaform({ resolveZodAlias: false })` ' +\n 'to keep the runtime-dispatch unified entry (and silence this check).'\n )\n }\n if (detection.major === 'unknown') {\n // Detection landed on a zod resolution but couldn't classify\n // the version — log once and fall through to runtime dispatch.\n // The build still works; the consumer just ships both adapters.\n if (!warnedAboutDetection) {\n warnedAboutDetection = true\n console.warn(\n '[attaform/vite] Could not classify the installed Zod major (corrupted package.json, ' +\n 'monorepo edge case, or an unexpected version string). Falling through to runtime ' +\n 'dispatch — both Zod adapters will ship in the bundle. ' +\n 'Pass `attaform({ resolveZodAlias: false })` to silence this warning.'\n )\n }\n return\n }\n aliasTarget = detection.major === 4 ? ZOD_V4_SPECIFIER : ZOD_V3_SPECIFIER\n },\n resolveId(source) {\n // Intercept ONLY the exact unified specifier. Explicit subpaths\n // (`attaform/zod-v3`, `attaform/zod-v4`) and the root entry\n // (`attaform`) pass through unchanged — that's the documented\n // escape hatch for power users.\n if (!resolveZodAlias) return null\n if (aliasTarget === null) return null\n if (source !== ZOD_UNIFIED_SPECIFIER) return null\n return aliasTarget\n },\n }\n}\n"],"names":[],"mappings":"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"}