mikuru 1.0.19 → 1.0.21

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 (62) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/README.md +23 -13
  3. package/dist/compiler/analyzeTemplate.js +116 -12
  4. package/dist/compiler/analyzeTemplate.js.map +1 -1
  5. package/dist/compiler/compile.js +2 -2
  6. package/dist/compiler/compile.js.map +1 -1
  7. package/dist/compiler/compileHydration.d.ts +2 -0
  8. package/dist/compiler/compileHydration.js +27 -0
  9. package/dist/compiler/compileHydration.js.map +1 -0
  10. package/dist/compiler/compileSsr.d.ts +2 -0
  11. package/dist/compiler/compileSsr.js +21 -0
  12. package/dist/compiler/compileSsr.js.map +1 -0
  13. package/dist/compiler/generate.d.ts +6 -1
  14. package/dist/compiler/generate.js +1399 -93
  15. package/dist/compiler/generate.js.map +1 -1
  16. package/dist/compiler/generateHydration.d.ts +6 -0
  17. package/dist/compiler/generateHydration.js +1553 -0
  18. package/dist/compiler/generateHydration.js.map +1 -0
  19. package/dist/compiler/generateSsr.d.ts +2 -0
  20. package/dist/compiler/generateSsr.js +915 -0
  21. package/dist/compiler/generateSsr.js.map +1 -0
  22. package/dist/compiler/index.d.ts +3 -1
  23. package/dist/compiler/index.js +2 -0
  24. package/dist/compiler/index.js.map +1 -1
  25. package/dist/compiler/parseTemplate.js +16 -1
  26. package/dist/compiler/parseTemplate.js.map +1 -1
  27. package/dist/compiler/sourceMap.d.ts +2 -2
  28. package/dist/compiler/sourceMap.js +110 -6
  29. package/dist/compiler/sourceMap.js.map +1 -1
  30. package/dist/compiler/types.d.ts +8 -0
  31. package/dist/index.d.ts +6 -3
  32. package/dist/index.js +3 -1
  33. package/dist/index.js.map +1 -1
  34. package/dist/router/index.d.ts +8 -0
  35. package/dist/router/index.js +133 -3
  36. package/dist/router/index.js.map +1 -1
  37. package/dist/runtime/asyncComponent.d.ts +22 -2
  38. package/dist/runtime/asyncComponent.js +84 -2
  39. package/dist/runtime/asyncComponent.js.map +1 -1
  40. package/dist/runtime/devtools.d.ts +51 -0
  41. package/dist/runtime/devtools.js +113 -0
  42. package/dist/runtime/devtools.js.map +1 -0
  43. package/dist/runtime/dom.d.ts +5 -1
  44. package/dist/runtime/dom.js +100 -3
  45. package/dist/runtime/dom.js.map +1 -1
  46. package/dist/runtime/index.d.ts +7 -5
  47. package/dist/runtime/index.js +3 -2
  48. package/dist/runtime/index.js.map +1 -1
  49. package/dist/runtime/lifecycle.d.ts +6 -0
  50. package/dist/runtime/lifecycle.js +66 -10
  51. package/dist/runtime/lifecycle.js.map +1 -1
  52. package/dist/runtime/reactivity.d.ts +33 -1
  53. package/dist/runtime/reactivity.js +254 -13
  54. package/dist/runtime/reactivity.js.map +1 -1
  55. package/dist/server.d.ts +33 -0
  56. package/dist/server.js +285 -0
  57. package/dist/server.js.map +1 -0
  58. package/dist/vite.d.ts +1 -0
  59. package/dist/vite.js +39 -18
  60. package/dist/vite.js.map +1 -1
  61. package/package.json +110 -100
  62. package/types/env.d.ts +58 -29
@@ -0,0 +1,1553 @@
1
+ import { compileTemplateExpression, parseForExpression, validateAssignableExpression } from "./parseExpression.js";
2
+ export function generateHydration(descriptor, root, options = {}) {
3
+ const context = {
4
+ lines: [],
5
+ index: 0,
6
+ teleportIndex: 0,
7
+ source: descriptor.source,
8
+ filename: descriptor.filename
9
+ };
10
+ const script = splitScript(descriptor.script ?? "");
11
+ if (options.includeImports !== false) {
12
+ for (const importLine of script.imports) {
13
+ emit(context, 0, importLine);
14
+ }
15
+ emit(context, 0, "import { effect, setAttribute, unwrap } from \"mikuru/runtime\";");
16
+ emit(context, 0, "");
17
+ }
18
+ emit(context, 0, "export function hydrate(target, props = {}) {");
19
+ emit(context, 1, `const __mikuru_componentInfo = { component: ${quote(descriptor.filename ?? "anonymous.mikuru")}, filename: ${quote(descriptor.filename ?? "anonymous.mikuru")} };`);
20
+ emit(context, 1, "const __mikuru_cleanup = [];");
21
+ emit(context, 1, "const __mikuru_afterUnmount = [];");
22
+ emit(context, 1, "const __mikuru_mounted = [];");
23
+ emit(context, 1, "const __mikuru_context = { parent: props.__mikuru_context, provides: new Map(), errorHandler: props.__mikuru_context?.errorHandler, ...__mikuru_componentInfo };");
24
+ emit(context, 1, "const __mikuru_try = (fn) => { try { return fn(); } catch (error) { setTimeout(() => { throw error; }); } };");
25
+ emit(context, 1, "const __mikuru_previousRegistrar = globalThis.__mikuru_currentRegistrar;");
26
+ emit(context, 1, "globalThis.__mikuru_currentRegistrar = {");
27
+ emit(context, 2, "registerMounted: (fn) => __mikuru_mounted.push(fn),");
28
+ emit(context, 2, "registerBeforeUnmount: (fn) => __mikuru_cleanup.push(fn),");
29
+ emit(context, 2, "registerUnmounted: (fn) => __mikuru_afterUnmount.push(fn),");
30
+ emit(context, 2, "provide: (key, value) => __mikuru_context.provides.set(key, value),");
31
+ emit(context, 2, "inject: (key) => {");
32
+ emit(context, 3, "for (let context = __mikuru_context; context; context = context.parent) {");
33
+ emit(context, 4, "if (context.provides?.has(key)) return { found: true, value: context.provides.get(key) };");
34
+ emit(context, 3, "}");
35
+ emit(context, 3, "return { found: false };");
36
+ emit(context, 2, "},");
37
+ emit(context, 2, "registerEffect: (fn) => Promise.resolve().then(fn)");
38
+ emit(context, 1, "};");
39
+ emit(context, 1, "const __mikuru_warn = (message) => { if (typeof console !== \"undefined\" && console.warn) console.warn(`[Mikuru hydration] ${message}`); };");
40
+ emit(context, 1, "const __mikuru_describeNode = (node) => { if (!node) return \"missing\"; if (node.nodeType === 1) return `<${node.tagName?.toLowerCase?.() ?? \"element\"}>`; if (node.nodeType === 3) return `text(${JSON.stringify(node.nodeValue ?? \"\")})`; if (node.nodeType === 8) return `comment(${JSON.stringify(node.nodeValue ?? \"\")})`; return `nodeType(${node.nodeType})`; };");
41
+ emit(context, 1, "const __mikuru_restoreRegistrar = () => { if (__mikuru_previousRegistrar === undefined) { delete globalThis.__mikuru_currentRegistrar; } else { globalThis.__mikuru_currentRegistrar = __mikuru_previousRegistrar; } };");
42
+ emit(context, 1, "const __mikuru_recovery = {};");
43
+ emit(context, 1, "let __mikuru_recovered;");
44
+ emit(context, 1, "const __mikuru_recover = (message) => {");
45
+ emit(context, 2, "if (props.__mikuru_hydration?.recover === false) { __mikuru_warn(message + \".\"); return; }");
46
+ emit(context, 2, "__mikuru_warn(message + \"; remounting.\");");
47
+ emit(context, 2, "for (const cleanup of __mikuru_cleanup.splice(0).reverse()) __mikuru_try(cleanup);");
48
+ emit(context, 2, "for (const cb of __mikuru_afterUnmount.splice(0).reverse()) __mikuru_try(cb);");
49
+ emit(context, 2, "__mikuru_restoreRegistrar();");
50
+ emit(context, 2, "if (target.nodeType === 1) { target.innerHTML = \"\"; }");
51
+ emit(context, 2, "__mikuru_recovered = mount(target, props);");
52
+ emit(context, 2, "throw __mikuru_recovery;");
53
+ emit(context, 1, "};");
54
+ emit(context, 1, "const __mikuru_findComment = (parent, value) => Array.from(parent.childNodes ?? []).find((node) => node.nodeType === 8 && node.nodeValue === value);");
55
+ emit(context, 1, "const __mikuru_findNextComment = (node, value) => { for (let cursor = node.nextSibling; cursor; cursor = cursor.nextSibling) { if (cursor.nodeType === 8 && cursor.nodeValue === value) return cursor; } return undefined; };");
56
+ emit(context, 1, "const __mikuru_setRef = (target, value, multiple = false) => {");
57
+ emit(context, 2, "if (typeof target === \"function\") {");
58
+ emit(context, 3, "target(value);");
59
+ emit(context, 3, "return () => target(null);");
60
+ emit(context, 2, "}");
61
+ emit(context, 2, "if (!target || typeof target !== \"object\" || !(\"value\" in target)) {");
62
+ emit(context, 3, "return () => {};");
63
+ emit(context, 2, "}");
64
+ emit(context, 2, "if (multiple) {");
65
+ emit(context, 3, "const list = Array.isArray(target.value) ? target.value : [];");
66
+ emit(context, 3, "if (target.value !== list) { target.value = list; }");
67
+ emit(context, 3, "list.push(value);");
68
+ emit(context, 3, "return () => { const index = list.indexOf(value); if (index >= 0) { list.splice(index, 1); } };");
69
+ emit(context, 2, "}");
70
+ emit(context, 2, "target.value = value;");
71
+ emit(context, 2, "return () => { if (target.value === value) { target.value = null; } };");
72
+ emit(context, 1, "};");
73
+ if (script.body.trim()) {
74
+ emitRaw(context, script.body.trim(), 1);
75
+ emit(context, 1, "");
76
+ }
77
+ emit(context, 1, "const __mikuru_root = target.nodeType === 1 && target.tagName?.toLowerCase() === " + quote(root.tag.toLowerCase()) + " ? target : target.firstElementChild;");
78
+ emit(context, 1, `if (!__mikuru_root || __mikuru_root.tagName?.toLowerCase() !== ${quote(root.tag.toLowerCase())}) { __mikuru_warn("Root mismatch: expected <${root.tag.toLowerCase()}>, got " + __mikuru_describeNode(__mikuru_root) + "; falling back to mount()."); __mikuru_restoreRegistrar(); return mount(target, props); }`);
79
+ emit(context, 1, "try {");
80
+ hydrateElement(context, root, "__mikuru_root", 2);
81
+ emit(context, 1, "} catch (error) {");
82
+ emit(context, 2, "if (error === __mikuru_recovery) { return __mikuru_recovered; }");
83
+ emit(context, 2, "throw error;");
84
+ emit(context, 1, "}");
85
+ emit(context, 1, "for (const cb of __mikuru_mounted.splice(0)) { __mikuru_try(cb); }");
86
+ emit(context, 1, "__mikuru_restoreRegistrar();");
87
+ emit(context, 1, "return {");
88
+ emit(context, 2, "element: __mikuru_root,");
89
+ emit(context, 2, "unmount() { for (const cleanup of __mikuru_cleanup.splice(0).reverse()) __mikuru_try(cleanup); for (const cb of __mikuru_afterUnmount.splice(0).reverse()) __mikuru_try(cb); }");
90
+ emit(context, 1, "};");
91
+ emit(context, 0, "}");
92
+ return `${context.lines.join("\n")}\n`;
93
+ }
94
+ function hydrateNode(context, node, nodeVar, indent) {
95
+ if (node.type === "text") {
96
+ hydrateText(context, node, nodeVar, indent);
97
+ return;
98
+ }
99
+ hydrateElement(context, node, nodeVar, indent);
100
+ }
101
+ function hydrateElement(context, node, elementVar, indent) {
102
+ if (getAttr(node, "v-pre")) {
103
+ hydratePreElement(context, node, elementVar, indent);
104
+ return;
105
+ }
106
+ if (node.tag === "Teleport") {
107
+ hydrateTeleport(context, node, elementVar, indent);
108
+ return;
109
+ }
110
+ if (node.tag === "KeepAlive") {
111
+ hydrateKeepAliveElement(context, node, elementVar, indent);
112
+ return;
113
+ }
114
+ if (node.tag === "AsyncBoundary") {
115
+ hydrateAsyncBoundaryElement(context, node, elementVar, indent);
116
+ return;
117
+ }
118
+ if (node.tag === "ErrorBoundary") {
119
+ hydrateErrorBoundaryElement(context, node, elementVar, indent);
120
+ return;
121
+ }
122
+ if (node.tag === "TransitionGroup") {
123
+ hydrateTransitionGroupElement(context, node, elementVar, indent);
124
+ return;
125
+ }
126
+ if (node.tag === "Transition") {
127
+ hydrateTransitionElement(context, node, elementVar, indent);
128
+ return;
129
+ }
130
+ if (isComponentTag(node.tag)) {
131
+ hydrateComponent(context, node, elementVar, indent);
132
+ return;
133
+ }
134
+ hydrateAttrs(context, node, elementVar, indent);
135
+ hydrateEvents(context, node, elementVar, indent);
136
+ const contentDirective = getContentDirectiveAttr(node);
137
+ const hydrateChildrenBeforeModel = node.tag === "select" && !contentDirective;
138
+ if (hydrateChildrenBeforeModel) {
139
+ hydrateChildren(context, node.children, elementVar, indent);
140
+ }
141
+ hydrateModelAndShow(context, node, elementVar, indent);
142
+ hydrateContentDirective(context, node, elementVar, indent);
143
+ hydrateTemplateRef(context, node, elementVar, indent);
144
+ if (!contentDirective && !hydrateChildrenBeforeModel) {
145
+ hydrateChildren(context, node.children, elementVar, indent);
146
+ }
147
+ }
148
+ function hydrateChildren(context, rawChildren, parentVar, indent) {
149
+ const children = rawChildren.filter(isHydratableNode);
150
+ const domIndexVar = nextName(context, "domIndex");
151
+ emit(context, indent, `let ${domIndexVar} = 0;`);
152
+ children.forEach((child) => {
153
+ if (child.type === "element" && child.tag === "Teleport") {
154
+ hydrateTeleportAtIndex(context, child, parentVar, domIndexVar, indent);
155
+ return;
156
+ }
157
+ if (child.type === "element" && child.tag === "component") {
158
+ hydrateDynamicComponentAtIndex(context, child, parentVar, domIndexVar, indent);
159
+ return;
160
+ }
161
+ if (child.type === "element" && child.tag === "KeepAlive") {
162
+ hydrateKeepAliveAtIndex(context, child, parentVar, domIndexVar, indent);
163
+ return;
164
+ }
165
+ if (child.type === "element" && child.tag === "AsyncBoundary") {
166
+ hydrateAsyncBoundaryAtIndex(context, child, parentVar, domIndexVar, indent);
167
+ return;
168
+ }
169
+ if (child.type === "element" && child.tag === "ErrorBoundary") {
170
+ hydrateErrorBoundaryAtIndex(context, child, parentVar, domIndexVar, indent);
171
+ return;
172
+ }
173
+ if (child.type === "element" && child.tag === "TransitionGroup") {
174
+ hydrateTransitionGroupAtIndex(context, child, parentVar, domIndexVar, indent);
175
+ return;
176
+ }
177
+ if (child.type === "element" && child.tag === "Transition") {
178
+ hydrateTransitionAtIndex(context, child, parentVar, domIndexVar, indent);
179
+ return;
180
+ }
181
+ if (child.type === "element" && getAttr(child, "v-if") && !getAttr(child, "v-pre")) {
182
+ hydrateIf(context, child, parentVar, domIndexVar, indent);
183
+ emit(context, indent, `${domIndexVar} += 1;`);
184
+ return;
185
+ }
186
+ if (child.type === "element" && getAttr(child, "v-for") && !getAttr(child, "v-pre")) {
187
+ hydrateFor(context, child, parentVar, domIndexVar, indent, domIndexVar);
188
+ return;
189
+ }
190
+ const childVar = nextName(context, "node");
191
+ emit(context, indent, `const ${childVar} = ${parentVar}.childNodes[${domIndexVar}];`);
192
+ if (child.type === "element") {
193
+ const elementCheck = isComponentTag(child.tag)
194
+ ? `!${childVar} || ${childVar}.nodeType !== 1`
195
+ : `!${childVar} || ${childVar}.nodeType !== 1 || ${childVar}.tagName?.toLowerCase() !== ${quote(child.tag.toLowerCase())}`;
196
+ emit(context, indent, `if (${elementCheck}) { __mikuru_recover(${quote(`Element mismatch: expected <${child.tag.toLowerCase()}>, got `)} + __mikuru_describeNode(${childVar})); } else {`);
197
+ hydrateNode(context, child, childVar, indent + 1);
198
+ emit(context, indent, "}");
199
+ }
200
+ else {
201
+ emit(context, indent, `if (!${childVar} || ${childVar}.nodeType !== 3) { __mikuru_recover("Text mismatch: expected text, got " + __mikuru_describeNode(${childVar})); } else {`);
202
+ hydrateNode(context, child, childVar, indent + 1);
203
+ emit(context, indent, "}");
204
+ }
205
+ emit(context, indent, `${domIndexVar} += 1;`);
206
+ });
207
+ emit(context, indent, `if (${parentVar}.childNodes.length > ${domIndexVar}) { __mikuru_warn("Extra DOM nodes after hydration: " + Array.from(${parentVar}.childNodes).slice(${domIndexVar}).map(__mikuru_describeNode).join(", ") + "."); }`);
208
+ }
209
+ function hydrateTeleportAtIndex(context, node, parentVar, domIndex, indent) {
210
+ const id = `t${context.teleportIndex}`;
211
+ context.teleportIndex += 1;
212
+ const startVar = nextName(context, "teleportStart");
213
+ const endVar = nextName(context, "teleportEnd");
214
+ const disabledVar = nextName(context, "teleportDisabled");
215
+ const targetVar = nextName(context, "teleportTarget");
216
+ const contentStartVar = nextName(context, "teleportContentStart");
217
+ const contentEndVar = nextName(context, "teleportContentEnd");
218
+ const nodesVar = nextName(context, "teleportNodes");
219
+ const cursorVar = nextName(context, "teleportCursor");
220
+ const parentProxyVar = nextName(context, "teleportParent");
221
+ const toExpression = getTeleportToExpression(context, node);
222
+ const disabledExpression = getTeleportDisabledExpression(context, node);
223
+ emit(context, indent, `const ${startVar} = ${parentVar}.childNodes[${domIndex}];`);
224
+ emit(context, indent, `const ${endVar} = ${startVar} ? __mikuru_findNextComment(${startVar}, ${quote(`/teleport:${id}`)}) : undefined;`);
225
+ emit(context, indent, `if (!${startVar} || ${startVar}.nodeType !== 8 || ${startVar}.nodeValue !== ${quote(`teleport:${id}`)} || !${endVar}) {`);
226
+ emit(context, indent + 1, "__mikuru_recover(\"Teleport marker mismatch\");");
227
+ emit(context, indent, "} else {");
228
+ emit(context, indent + 1, `const ${disabledVar} = Boolean(unwrap(${disabledExpression}));`);
229
+ emit(context, indent + 1, `const ${targetVar} = ${disabledVar} ? undefined : (typeof unwrap(${toExpression}) === "string" ? document.querySelector(unwrap(${toExpression})) : unwrap(${toExpression}));`);
230
+ emit(context, indent + 1, `if (!${disabledVar} && !${targetVar}) { __mikuru_warn("Teleport target was not found."); } else {`);
231
+ emit(context, indent + 2, `const ${contentStartVar} = ${disabledVar} ? ${startVar} : __mikuru_findComment(${targetVar}, ${quote(`teleport content:${id}`)});`);
232
+ emit(context, indent + 2, `const ${contentEndVar} = ${disabledVar} ? ${endVar} : __mikuru_findComment(${targetVar}, ${quote(`/teleport content:${id}`)});`);
233
+ emit(context, indent + 2, `if (!${contentStartVar} || !${contentEndVar}) { __mikuru_recover("Teleport content marker mismatch"); } else {`);
234
+ emit(context, indent + 3, `const ${nodesVar} = [];`);
235
+ emit(context, indent + 3, `let ${cursorVar} = ${contentStartVar}.nextSibling;`);
236
+ emit(context, indent + 3, `while (${cursorVar} && ${cursorVar} !== ${contentEndVar}) { ${nodesVar}.push(${cursorVar}); ${cursorVar} = ${cursorVar}.nextSibling; }`);
237
+ emit(context, indent + 3, `const ${parentProxyVar} = { childNodes: ${nodesVar} };`);
238
+ hydrateChildren(context, node.children, parentProxyVar, indent + 3);
239
+ emit(context, indent + 3, `if (!${disabledVar}) __mikuru_cleanup.push(() => { ${contentStartVar}.remove(); ${contentEndVar}.remove(); });`);
240
+ emit(context, indent + 2, "}");
241
+ emit(context, indent + 1, "}");
242
+ emit(context, indent + 1, `${domIndex} = Array.prototype.indexOf.call(${parentVar}.childNodes, ${endVar}) + 1;`);
243
+ emit(context, indent, "}");
244
+ }
245
+ function hydrateTeleport(context, node, elementVar, indent) {
246
+ const domIndexVar = nextName(context, "domIndex");
247
+ emit(context, indent, `let ${domIndexVar} = 0;`);
248
+ hydrateTeleportAtIndex(context, node, "({ childNodes: [undefined, undefined] })", domIndexVar, indent);
249
+ }
250
+ function hydrateIf(context, node, parentVar, domIndex, indent) {
251
+ const condition = getAttrValue(node, "v-if");
252
+ const childVar = nextName(context, "branch");
253
+ const elementCheck = isComponentTag(node.tag)
254
+ ? `!${childVar} || ${childVar}.nodeType !== 1`
255
+ : `!${childVar} || ${childVar}.nodeType !== 1 || ${childVar}.tagName?.toLowerCase() !== ${quote(node.tag.toLowerCase())}`;
256
+ emit(context, indent, `const ${childVar} = ${parentVar}.childNodes[${domIndex}];`);
257
+ emit(context, indent, `if (unwrap(${compileHydrationExpression(context, condition, "v-if")})) {`);
258
+ emit(context, indent + 1, `if (${elementCheck}) { __mikuru_recover("Branch mismatch: dynamic v-if expected " + __mikuru_describeNode(${childVar})); } else {`);
259
+ hydrateElement(context, withoutAttrs(node, ["v-if"]), childVar, indent + 2);
260
+ emit(context, indent + 1, "}");
261
+ emit(context, indent, `} else if (${childVar}) {`);
262
+ emit(context, indent + 1, "__mikuru_recover(\"Branch mismatch: expected no v-if DOM for initial state\");");
263
+ emit(context, indent, "}");
264
+ }
265
+ function hydrateFor(context, node, parentVar, domIndex, indent, advanceVar) {
266
+ const attr = getAttr(node, "v-for");
267
+ if (!attr || attr.value === true) {
268
+ return;
269
+ }
270
+ const forExpression = parseForExpression(String(attr.value));
271
+ const listVar = nextName(context, "list");
272
+ const itemVar = nextName(context, "item");
273
+ const childVar = nextName(context, "row");
274
+ const elementCheck = isComponentTag(node.tag)
275
+ ? `!${childVar} || ${childVar}.nodeType !== 1`
276
+ : `!${childVar} || ${childVar}.nodeType !== 1 || ${childVar}.tagName?.toLowerCase() !== ${quote(node.tag.toLowerCase())}`;
277
+ emit(context, indent, `const ${listVar} = Array.from(unwrap(${compileHydrationExpression(context, forExpression.source, "v-for source")}) ?? []);`);
278
+ emit(context, indent, `for (const [__mikuru_index, ${itemVar}] of ${listVar}.entries()) {`);
279
+ emit(context, indent + 1, `const ${forExpression.item} = ${itemVar};`);
280
+ if (forExpression.index) {
281
+ emit(context, indent + 1, `const ${forExpression.index} = __mikuru_index;`);
282
+ }
283
+ emit(context, indent + 1, `const ${childVar} = ${parentVar}.childNodes[${domIndex} + __mikuru_index];`);
284
+ emit(context, indent + 1, `if (${elementCheck}) { __mikuru_recover("List mismatch: dynamic v-for expected row, got " + __mikuru_describeNode(${childVar})); } else {`);
285
+ withTemplateRefMode(context, "array", () => {
286
+ hydrateElement(context, withoutAttrs(node, ["v-for"]), childVar, indent + 2);
287
+ });
288
+ emit(context, indent + 1, "}");
289
+ emit(context, indent, "}");
290
+ if (advanceVar) {
291
+ emit(context, indent, `${advanceVar} += ${listVar}.length;`);
292
+ }
293
+ }
294
+ function hydrateAttrs(context, node, elementVar, indent) {
295
+ const staticClass = getStaticAttrValue(node, "class");
296
+ const staticStyle = getStaticAttrValue(node, "style");
297
+ const hasObjectBind = node.attrs.some((attr) => Boolean(parseObjectBindDirective(attr.name)));
298
+ const hasDynamicClass = node.attrs.some((attr) => getDynamicAttrName(attr.name) === "class");
299
+ const hasDynamicStyle = node.attrs.some((attr) => getDynamicAttrName(attr.name) === "style");
300
+ for (const attr of node.attrs) {
301
+ if (attr.name === "v-cloak") {
302
+ emit(context, indent, `${elementVar}.removeAttribute("v-cloak");`);
303
+ continue;
304
+ }
305
+ if (shouldSkipAttr(attr)) {
306
+ continue;
307
+ }
308
+ const bindDirective = parseBindDirective(attr.name);
309
+ const dynamicArgument = bindDirective?.nameExpression ? bindDirective : undefined;
310
+ if (dynamicArgument) {
311
+ validateBindModifiers(dynamicArgument, attr);
312
+ const nameExpression = compileHydrationExpression(context, dynamicArgument.nameExpression ?? "", attr.name);
313
+ const valueExpression = compileHydrationExpression(context, String(attr.value), attr.name);
314
+ const previousNameVar = nextName(context, "attrName");
315
+ const nextNameVar = nextName(context, "attrName");
316
+ const valueVar = nextName(context, "attrValue");
317
+ emit(context, indent, `let ${previousNameVar};`);
318
+ emit(context, indent, `__mikuru_cleanup.push(effect(() => {`);
319
+ emit(context, indent + 1, `const ${nextNameVar} = ${bindNameExpression(`String(unwrap(${nameExpression}) ?? "")`, dynamicArgument)};`);
320
+ emit(context, indent + 1, `if (!${nextNameVar}) { if (${previousNameVar}) setAttribute(${elementVar}, ${previousNameVar}, null); ${previousNameVar} = undefined; return; }`);
321
+ emit(context, indent + 1, `if (${previousNameVar} && ${previousNameVar} !== ${nextNameVar}) setAttribute(${elementVar}, ${previousNameVar}, null);`);
322
+ emit(context, indent + 1, `const ${valueVar} = unwrap(${valueExpression});`);
323
+ emit(context, indent + 1, `setAttribute(${elementVar}, ${nextNameVar}, ${nextNameVar} === "class" && ${staticClass ? "true" : "false"} ? [${quote(staticClass ?? "")}, ${valueVar}] : ${nextNameVar} === "style" && ${staticStyle ? "true" : "false"} ? [${quote(staticStyle ?? "")}, ${valueVar}] : ${valueVar}${bindOptionsExpression(dynamicArgument)});`);
324
+ emit(context, indent + 1, `${previousNameVar} = ${nextNameVar};`);
325
+ emit(context, indent, `}));`);
326
+ continue;
327
+ }
328
+ const dynamicName = bindDirective?.name;
329
+ if (dynamicName) {
330
+ validateBindModifiers(bindDirective, attr);
331
+ const expression = compileHydrationExpression(context, String(attr.value), attr.name);
332
+ const valueExpression = dynamicName === "class" && staticClass
333
+ ? `[${quote(staticClass)}, unwrap(${expression})]`
334
+ : dynamicName === "style" && staticStyle
335
+ ? `[${quote(staticStyle)}, unwrap(${expression})]`
336
+ : `unwrap(${expression})`;
337
+ emit(context, indent, `__mikuru_cleanup.push(effect(() => setAttribute(${elementVar}, ${quote(dynamicName)}, ${valueExpression}${bindOptionsExpression(bindDirective)})));`);
338
+ continue;
339
+ }
340
+ const objectBindDirective = parseObjectBindDirective(attr.name);
341
+ if (objectBindDirective) {
342
+ validateObjectBindModifiers(objectBindDirective, attr);
343
+ const prevKeysVar = nextName(context, "attrsPrevKeys");
344
+ const nextKeysVar = nextName(context, "attrsNextKeys");
345
+ const attrsVar = nextName(context, "attrs");
346
+ const keyVar = nextName(context, "key");
347
+ const boundKeyVar = nextName(context, "key");
348
+ const valueVar = nextName(context, "value");
349
+ const staleKeyVar = nextName(context, "staleKey");
350
+ emit(context, indent, `const ${prevKeysVar} = new Set();`);
351
+ emit(context, indent, "__mikuru_cleanup.push(effect(() => {");
352
+ emit(context, indent + 1, `const ${attrsVar} = unwrap(${compileHydrationExpression(context, String(attr.value), attr.name)}) ?? {};`);
353
+ emit(context, indent + 1, `const ${nextKeysVar} = new Set();`);
354
+ emit(context, indent + 1, `if (${attrsVar} && typeof ${attrsVar} === "object") {`);
355
+ emit(context, indent + 2, `for (const [${keyVar}, ${valueVar}] of Object.entries(${attrsVar})) {`);
356
+ emit(context, indent + 3, `const ${boundKeyVar} = ${objectBindKeyExpression(keyVar, objectBindDirective)};`);
357
+ emit(context, indent + 3, `${nextKeysVar}.add(${boundKeyVar});`);
358
+ if (staticClass || staticStyle) {
359
+ emit(context, indent + 3, `setAttribute(${elementVar}, ${boundKeyVar}, ${boundKeyVar} === "class" && ${staticClass ? "true" : "false"} ? [${quote(staticClass ?? "")}, unwrap(${valueVar})] : ${boundKeyVar} === "style" && ${staticStyle ? "true" : "false"} ? [${quote(staticStyle ?? "")}, unwrap(${valueVar})] : unwrap(${valueVar})${bindOptionsExpression(objectBindDirective)});`);
360
+ }
361
+ else {
362
+ emit(context, indent + 3, `setAttribute(${elementVar}, ${boundKeyVar}, unwrap(${valueVar})${bindOptionsExpression(objectBindDirective)});`);
363
+ }
364
+ emit(context, indent + 2, "}");
365
+ emit(context, indent + 1, "}");
366
+ emit(context, indent + 1, `for (const ${staleKeyVar} of ${prevKeysVar}) {`);
367
+ emit(context, indent + 2, `if (!${nextKeysVar}.has(${staleKeyVar})) {`);
368
+ if (staticClass || staticStyle) {
369
+ emit(context, indent + 3, `setAttribute(${elementVar}, ${staleKeyVar}, ${staleKeyVar} === "class" && ${staticClass ? "true" : "false"} ? ${quote(staticClass ?? "")} : ${staleKeyVar} === "style" && ${staticStyle ? "true" : "false"} ? ${quote(staticStyle ?? "")} : null${bindOptionsExpression(objectBindDirective)});`);
370
+ }
371
+ else {
372
+ emit(context, indent + 3, `setAttribute(${elementVar}, ${staleKeyVar}, null${bindOptionsExpression(objectBindDirective)});`);
373
+ }
374
+ emit(context, indent + 2, "}");
375
+ emit(context, indent + 1, "}");
376
+ emit(context, indent + 1, `${prevKeysVar}.clear();`);
377
+ emit(context, indent + 1, `for (const ${keyVar} of ${nextKeysVar}) { ${prevKeysVar}.add(${keyVar}); }`);
378
+ emit(context, indent, "}));");
379
+ continue;
380
+ }
381
+ if (!isDirectiveAttr(attr) && !((attr.name === "class" && (hasDynamicClass || hasObjectBind)) || (attr.name === "style" && (hasDynamicStyle || hasObjectBind)))) {
382
+ emitStaticAttrMismatchWarning(context, elementVar, attr, indent);
383
+ }
384
+ emit(context, indent, `setAttribute(${elementVar}, ${quote(attr.name)}, ${attr.value === true ? "true" : quote(attr.value)});`);
385
+ }
386
+ }
387
+ function emitStaticAttrMismatchWarning(context, elementVar, attr, indent) {
388
+ const expected = attr.value === true ? expectedStaticAttributeValue(attr.name) : String(attr.value);
389
+ emit(context, indent, `if (${elementVar}.getAttribute(${quote(attr.name)}) !== ${quote(expected)}) { __mikuru_warn(${quote(`Attribute mismatch on ${attr.name}: expected `)} + ${quote(expected)} + ${quote(", got ")} + JSON.stringify(${elementVar}.getAttribute(${quote(attr.name)})) + "."); }`);
390
+ }
391
+ function hydratePreElement(context, node, elementVar, indent) {
392
+ for (const attr of node.attrs) {
393
+ if (attr.name === "v-pre") {
394
+ continue;
395
+ }
396
+ emit(context, indent, `setAttribute(${elementVar}, ${quote(attr.name)}, ${attr.value === true ? "true" : quote(attr.value)});`);
397
+ }
398
+ const children = node.children.filter(isHydratableNode);
399
+ const domIndexVar = nextName(context, "preIndex");
400
+ emit(context, indent, `let ${domIndexVar} = 0;`);
401
+ children.forEach((child) => {
402
+ const childVar = nextName(context, "preNode");
403
+ emit(context, indent, `const ${childVar} = ${elementVar}.childNodes[${domIndexVar}];`);
404
+ if (child.type === "element") {
405
+ emit(context, indent, `if (${childVar} && ${childVar}.nodeType === 1) {`);
406
+ hydratePreElement(context, child, childVar, indent + 1);
407
+ emit(context, indent, "}");
408
+ }
409
+ else {
410
+ const text = child.parts.map((part) => part.value).join("");
411
+ emit(context, indent, `if (${childVar} && ${childVar}.nodeType === 3 && ${childVar}.textContent !== ${quote(text)}) { ${childVar}.textContent = ${quote(text)}; }`);
412
+ }
413
+ emit(context, indent, `${domIndexVar} += 1;`);
414
+ });
415
+ }
416
+ function hydrateComponent(context, node, elementVar, indent) {
417
+ const propsVar = nextName(context, "props");
418
+ emit(context, indent, `const ${propsVar} = {};`);
419
+ hydrateComponentProps(context, node, propsVar, indent);
420
+ emit(context, indent, `${propsVar}.__mikuru_context = __mikuru_context;`);
421
+ emitHydrationComponentSlots(context, node, propsVar, indent);
422
+ emitRouterViewRouteSlot(context, node, propsVar, indent);
423
+ emit(context, indent, `if (${node.tag} && typeof ${node.tag}.hydrate === "function") {`);
424
+ emit(context, indent + 1, `const __mikuru_child = ${node.tag}.hydrate(${elementVar}, ${propsVar});`);
425
+ emit(context, indent + 1, `if (__mikuru_child?.unmount) __mikuru_cleanup.push(() => __mikuru_child.unmount());`);
426
+ hydrateTemplateRef(context, node, "__mikuru_child", indent + 1);
427
+ emit(context, indent, `} else if (${node.tag} && typeof ${node.tag}.mount === "function") {`);
428
+ emit(context, indent + 1, "__mikuru_warn(\"Component hydration fallback; child component does not expose hydrate().\");");
429
+ emit(context, indent + 1, `const __mikuru_parent = ${elementVar}.parentNode;`);
430
+ emit(context, indent + 1, "const __mikuru_anchor = document.createComment(\"mikuru-hydrate-component\");");
431
+ emit(context, indent + 1, `__mikuru_parent?.insertBefore(__mikuru_anchor, ${elementVar});`);
432
+ emit(context, indent + 1, `${elementVar}.remove();`);
433
+ emit(context, indent + 1, "const __mikuru_fragment = document.createDocumentFragment();");
434
+ emit(context, indent + 1, `const __mikuru_child = ${node.tag}.mount(__mikuru_fragment, ${propsVar});`);
435
+ emit(context, indent + 1, "__mikuru_parent?.insertBefore(__mikuru_fragment, __mikuru_anchor);");
436
+ emit(context, indent + 1, "__mikuru_anchor.remove();");
437
+ emit(context, indent + 1, `if (__mikuru_child?.unmount) __mikuru_cleanup.push(() => __mikuru_child.unmount());`);
438
+ hydrateTemplateRef(context, node, "__mikuru_child", indent + 1);
439
+ emit(context, indent, "} else {");
440
+ emit(context, indent + 1, `__mikuru_recover(${quote(`Component mismatch at <${node.tag}>`)});`);
441
+ emit(context, indent, "}");
442
+ }
443
+ function emitRouterViewRouteSlot(context, node, propsVar, indent) {
444
+ if (node.tag !== "RouterView")
445
+ return;
446
+ emit(context, indent, `if (typeof props.children === "function") { ${propsVar}.children = props.children; ${propsVar}.slots = { ...(${propsVar}.slots ?? {}), default: props.children }; }`);
447
+ }
448
+ function emitHydrationComponentSlots(context, node, propsVar, indent) {
449
+ const children = getDefaultHydrationSlotChildren(node);
450
+ if (!children || !hasMeaningfulHydrationChildren(children)) {
451
+ return;
452
+ }
453
+ const slotTargetVar = nextName(context, "slotTarget");
454
+ const slotPropsVar = nextName(context, "slotProps");
455
+ emit(context, indent, `${propsVar}.children = (${slotTargetVar}, ${slotPropsVar} = {}) => {`);
456
+ hydrateChildren(context, children, slotTargetVar, indent + 1);
457
+ emit(context, indent, "};");
458
+ emit(context, indent, `${propsVar}.slots = { ...(${propsVar}.slots ?? {}), default: ${propsVar}.children };`);
459
+ }
460
+ function getDefaultHydrationSlotChildren(node) {
461
+ const defaultChildren = [];
462
+ for (const child of node.children) {
463
+ if (child.type === "element" && child.tag === "template") {
464
+ const defaultSlotAttr = child.attrs.find(isDefaultSlotTemplateAttr);
465
+ if (defaultSlotAttr) {
466
+ return child.children;
467
+ }
468
+ if (child.attrs.some(isSlotTemplateAttr)) {
469
+ continue;
470
+ }
471
+ }
472
+ defaultChildren.push(child);
473
+ }
474
+ return defaultChildren;
475
+ }
476
+ function isDefaultSlotTemplateAttr(attr) {
477
+ return attr.name === "v-slot" || attr.name === "v-slot:default" || attr.name === "#default";
478
+ }
479
+ function isSlotTemplateAttr(attr) {
480
+ return attr.name === "v-slot" || attr.name.startsWith("v-slot:") || attr.name.startsWith("#");
481
+ }
482
+ function hasMeaningfulHydrationChildren(children) {
483
+ return children.some((child) => child.type === "element" || child.parts.some((part) => part.value.trim()));
484
+ }
485
+ function hydrateDynamicComponentAtIndex(context, node, parentVar, domIndex, indent) {
486
+ const isAttr = getDynamicComponentIsAttr(node);
487
+ if (!isAttr) {
488
+ throw new Error("Dynamic component requires :is to resolve to a component object");
489
+ }
490
+ const componentTypeVar = nextName(context, "dynamicComponent");
491
+ const childVar = nextName(context, "node");
492
+ emit(context, indent, `const ${componentTypeVar} = unwrap(${compileHydrationExpression(context, requireAttrValue(isAttr), isAttr.name)});`);
493
+ emit(context, indent, `if (${componentTypeVar}) {`);
494
+ emit(context, indent + 1, `const ${childVar} = ${parentVar}.childNodes[${domIndex}];`);
495
+ emit(context, indent + 1, `if (!${childVar} || ${childVar}.nodeType !== 1) { __mikuru_recover("Element mismatch: expected dynamic component root, got " + __mikuru_describeNode(${childVar})); } else {`);
496
+ hydrateDynamicComponent(context, node, childVar, componentTypeVar, indent + 2);
497
+ emit(context, indent + 1, "}");
498
+ emit(context, indent + 1, `${domIndex} += 1;`);
499
+ emit(context, indent, "}");
500
+ }
501
+ function hydrateDynamicComponent(context, node, elementVar, componentType, indent) {
502
+ const dynamicNode = withoutDynamicComponentIs(node);
503
+ const propsVar = nextName(context, "props");
504
+ emit(context, indent, `const ${propsVar} = {};`);
505
+ hydrateComponentProps(context, dynamicNode, propsVar, indent);
506
+ emit(context, indent, `${propsVar}.__mikuru_context = __mikuru_context;`);
507
+ emitHydrationComponentSlots(context, dynamicNode, propsVar, indent);
508
+ emitRouterViewRouteSlot(context, dynamicNode, propsVar, indent);
509
+ emit(context, indent, `if (${componentType} && typeof ${componentType}.hydrate === "function") {`);
510
+ emit(context, indent + 1, `const __mikuru_child = ${componentType}.hydrate(${elementVar}, ${propsVar});`);
511
+ emit(context, indent + 1, `if (__mikuru_child?.unmount) __mikuru_cleanup.push(() => __mikuru_child.unmount());`);
512
+ hydrateTemplateRef(context, dynamicNode, "__mikuru_child", indent + 1);
513
+ emit(context, indent, `} else if (${componentType} && typeof ${componentType}.mount === "function") {`);
514
+ emit(context, indent + 1, "__mikuru_warn(\"Dynamic component hydration fallback; child component does not expose hydrate().\");");
515
+ emit(context, indent + 1, `const __mikuru_parent = ${elementVar}.parentNode;`);
516
+ emit(context, indent + 1, "const __mikuru_anchor = document.createComment(\"mikuru-hydrate-dynamic-component\");");
517
+ emit(context, indent + 1, `__mikuru_parent?.insertBefore(__mikuru_anchor, ${elementVar});`);
518
+ emit(context, indent + 1, `${elementVar}.remove();`);
519
+ emit(context, indent + 1, "const __mikuru_fragment = document.createDocumentFragment();");
520
+ emit(context, indent + 1, `const __mikuru_child = ${componentType}.mount(__mikuru_fragment, ${propsVar});`);
521
+ emit(context, indent + 1, "__mikuru_parent?.insertBefore(__mikuru_fragment, __mikuru_anchor);");
522
+ emit(context, indent + 1, "__mikuru_anchor.remove();");
523
+ emit(context, indent + 1, `if (__mikuru_child?.unmount) __mikuru_cleanup.push(() => __mikuru_child.unmount());`);
524
+ hydrateTemplateRef(context, dynamicNode, "__mikuru_child", indent + 1);
525
+ emit(context, indent, "} else {");
526
+ emit(context, indent + 1, "__mikuru_recover(\"Dynamic component mismatch: :is did not resolve to hydrate() or mount()\");");
527
+ emit(context, indent, "}");
528
+ }
529
+ function hydrateKeepAliveAtIndex(context, node, parentVar, domIndex, indent) {
530
+ validateKeepAliveAttributes(node);
531
+ const child = getSingleElementChild(node, "<KeepAlive>");
532
+ if (child.tag !== "component") {
533
+ throw new Error("<KeepAlive> requires a single <component :is=\"...\" /> child in v1");
534
+ }
535
+ if (!getDynamicComponentIsAttr(child)) {
536
+ throw new Error("<KeepAlive> dynamic child requires :is to resolve to a component object");
537
+ }
538
+ hydrateDynamicComponentAtIndex(context, child, parentVar, domIndex, indent);
539
+ }
540
+ function hydrateKeepAliveElement(context, node, elementVar, indent) {
541
+ validateKeepAliveAttributes(node);
542
+ const child = getSingleElementChild(node, "<KeepAlive>");
543
+ const isAttr = getDynamicComponentIsAttr(child);
544
+ if (child.tag !== "component" || !isAttr) {
545
+ throw new Error("<KeepAlive> requires a single <component :is=\"...\" /> child in v1");
546
+ }
547
+ const componentTypeVar = nextName(context, "dynamicComponent");
548
+ emit(context, indent, `const ${componentTypeVar} = unwrap(${compileHydrationExpression(context, requireAttrValue(isAttr), isAttr.name)});`);
549
+ emit(context, indent, `if (${componentTypeVar}) {`);
550
+ hydrateDynamicComponent(context, child, elementVar, componentTypeVar, indent + 1);
551
+ emit(context, indent, "}");
552
+ }
553
+ function hydrateAsyncBoundaryAtIndex(context, node, parentVar, domIndex, indent) {
554
+ validateAsyncBoundaryAttributes(node);
555
+ hydrateFragmentChildrenAtIndex(context, getAsyncBoundaryChildren(node), parentVar, domIndex, indent);
556
+ }
557
+ function hydrateAsyncBoundaryElement(context, node, elementVar, indent) {
558
+ validateAsyncBoundaryAttributes(node);
559
+ const parentVar = nextName(context, "asyncBoundaryParent");
560
+ const indexVar = nextName(context, "asyncBoundaryIndex");
561
+ emit(context, indent, `const ${parentVar} = ${elementVar}.parentNode;`);
562
+ emit(context, indent, `let ${indexVar} = ${parentVar} ? Array.prototype.indexOf.call(${parentVar}.childNodes, ${elementVar}) : 0;`);
563
+ emit(context, indent, `if (${parentVar}) {`);
564
+ hydrateFragmentChildrenAtIndex(context, getAsyncBoundaryChildren(node), parentVar, indexVar, indent + 1);
565
+ emit(context, indent, "}");
566
+ }
567
+ function hydrateErrorBoundaryAtIndex(context, node, parentVar, domIndex, indent) {
568
+ validateErrorBoundaryAttributes(node);
569
+ getErrorBoundaryFallbackAttr(node);
570
+ hydrateFragmentChildrenAtIndex(context, [getSingleElementChild(node, "<ErrorBoundary>")], parentVar, domIndex, indent);
571
+ }
572
+ function hydrateErrorBoundaryElement(context, node, elementVar, indent) {
573
+ validateErrorBoundaryAttributes(node);
574
+ getErrorBoundaryFallbackAttr(node);
575
+ const parentVar = nextName(context, "errorBoundaryParent");
576
+ const indexVar = nextName(context, "errorBoundaryIndex");
577
+ emit(context, indent, `const ${parentVar} = ${elementVar}.parentNode;`);
578
+ emit(context, indent, `let ${indexVar} = ${parentVar} ? Array.prototype.indexOf.call(${parentVar}.childNodes, ${elementVar}) : 0;`);
579
+ emit(context, indent, `if (${parentVar}) {`);
580
+ hydrateFragmentChildrenAtIndex(context, [getSingleElementChild(node, "<ErrorBoundary>")], parentVar, indexVar, indent + 1);
581
+ emit(context, indent, "}");
582
+ }
583
+ function hydrateTransitionAtIndex(context, node, parentVar, domIndex, indent) {
584
+ validateTransitionAttributes(node);
585
+ const children = getTransitionChildren(node);
586
+ if (getAttr(children[0], "v-if")) {
587
+ hydrateTransitionIfChainAtIndex(context, children, parentVar, domIndex, indent);
588
+ return;
589
+ }
590
+ hydrateFragmentChildrenAtIndex(context, [children[0]], parentVar, domIndex, indent);
591
+ }
592
+ function hydrateTransitionElement(context, node, elementVar, indent) {
593
+ validateTransitionAttributes(node);
594
+ const parentVar = nextName(context, "transitionParent");
595
+ const indexVar = nextName(context, "transitionIndex");
596
+ emit(context, indent, `const ${parentVar} = ${elementVar}.parentNode;`);
597
+ emit(context, indent, `let ${indexVar} = ${parentVar} ? Array.prototype.indexOf.call(${parentVar}.childNodes, ${elementVar}) : 0;`);
598
+ emit(context, indent, `if (${parentVar}) {`);
599
+ hydrateTransitionAtIndex(context, node, parentVar, indexVar, indent + 1);
600
+ emit(context, indent, "}");
601
+ }
602
+ function hydrateTransitionIfChainAtIndex(context, children, parentVar, domIndex, indent) {
603
+ children.forEach((child, index) => {
604
+ if (index === 0) {
605
+ emit(context, indent, `if (unwrap(${compileHydrationExpression(context, getAttrValue(child, "v-if"), "v-if")})) {`);
606
+ }
607
+ else if (getAttr(child, "v-else-if")) {
608
+ emit(context, indent, `else if (unwrap(${compileHydrationExpression(context, getAttrValue(child, "v-else-if"), "v-else-if")})) {`);
609
+ }
610
+ else {
611
+ emit(context, indent, "else {");
612
+ }
613
+ hydrateFragmentChildrenAtIndex(context, [withoutAttrs(child, ["v-if", "v-else-if", "v-else"])], parentVar, domIndex, indent + 1);
614
+ emit(context, indent, "}");
615
+ });
616
+ }
617
+ function hydrateTransitionGroupAtIndex(context, node, parentVar, domIndex, indent) {
618
+ validateTransitionGroupAttributes(node);
619
+ const child = getTransitionGroupChild(node);
620
+ const groupVar = nextName(context, "transitionGroup");
621
+ const expectedTagVar = nextName(context, "transitionGroupTag");
622
+ const groupIndexVar = nextName(context, "transitionGroupIndex");
623
+ emit(context, indent, `const ${groupVar} = ${parentVar}.childNodes[${domIndex}];`);
624
+ emit(context, indent, `const ${expectedTagVar} = String(unwrap(${getTransitionGroupTagExpression(context, node)}) ?? "span").toLowerCase();`);
625
+ emit(context, indent, `if (!${groupVar} || ${groupVar}.nodeType !== 1 || ${groupVar}.tagName?.toLowerCase() !== ${expectedTagVar}) {`);
626
+ emit(context, indent + 1, `__mikuru_recover("TransitionGroup mismatch: expected <" + ${expectedTagVar} + ">, got " + __mikuru_describeNode(${groupVar}));`);
627
+ emit(context, indent, "} else {");
628
+ emit(context, indent + 1, `let ${groupIndexVar} = 0;`);
629
+ hydrateFor(context, withoutAttrs(child, [":key", "v-bind:key"]), groupVar, groupIndexVar, indent + 1, groupIndexVar);
630
+ emit(context, indent + 1, `if (${groupVar}.childNodes.length > ${groupIndexVar}) { __mikuru_warn("Extra DOM nodes after TransitionGroup hydration: " + Array.from(${groupVar}.childNodes).slice(${groupIndexVar}).map(__mikuru_describeNode).join(", ") + "."); }`);
631
+ emit(context, indent, "}");
632
+ emit(context, indent, `${domIndex} += 1;`);
633
+ }
634
+ function hydrateTransitionGroupElement(context, node, elementVar, indent) {
635
+ validateTransitionGroupAttributes(node);
636
+ const child = getTransitionGroupChild(node);
637
+ const expectedTagVar = nextName(context, "transitionGroupTag");
638
+ const groupIndexVar = nextName(context, "transitionGroupIndex");
639
+ emit(context, indent, `const ${expectedTagVar} = String(unwrap(${getTransitionGroupTagExpression(context, node)}) ?? "span").toLowerCase();`);
640
+ emit(context, indent, `if (${elementVar}.tagName?.toLowerCase() !== ${expectedTagVar}) { __mikuru_recover("TransitionGroup mismatch: expected <" + ${expectedTagVar} + ">, got " + __mikuru_describeNode(${elementVar})); }`);
641
+ emit(context, indent, `let ${groupIndexVar} = 0;`);
642
+ hydrateFor(context, withoutAttrs(child, [":key", "v-bind:key"]), elementVar, groupIndexVar, indent, groupIndexVar);
643
+ emit(context, indent, `if (${elementVar}.childNodes.length > ${groupIndexVar}) { __mikuru_warn("Extra DOM nodes after TransitionGroup hydration: " + Array.from(${elementVar}.childNodes).slice(${groupIndexVar}).map(__mikuru_describeNode).join(", ") + "."); }`);
644
+ }
645
+ function hydrateFragmentChildrenAtIndex(context, rawChildren, parentVar, domIndex, indent) {
646
+ const children = rawChildren.filter(isHydratableNode);
647
+ children.forEach((child) => {
648
+ if (child.type === "element" && child.tag === "Teleport") {
649
+ hydrateTeleportAtIndex(context, child, parentVar, domIndex, indent);
650
+ return;
651
+ }
652
+ if (child.type === "element" && child.tag === "component") {
653
+ hydrateDynamicComponentAtIndex(context, child, parentVar, domIndex, indent);
654
+ return;
655
+ }
656
+ if (child.type === "element" && child.tag === "KeepAlive") {
657
+ hydrateKeepAliveAtIndex(context, child, parentVar, domIndex, indent);
658
+ return;
659
+ }
660
+ if (child.type === "element" && child.tag === "AsyncBoundary") {
661
+ hydrateAsyncBoundaryAtIndex(context, child, parentVar, domIndex, indent);
662
+ return;
663
+ }
664
+ if (child.type === "element" && child.tag === "ErrorBoundary") {
665
+ hydrateErrorBoundaryAtIndex(context, child, parentVar, domIndex, indent);
666
+ return;
667
+ }
668
+ if (child.type === "element" && child.tag === "TransitionGroup") {
669
+ hydrateTransitionGroupAtIndex(context, child, parentVar, domIndex, indent);
670
+ return;
671
+ }
672
+ if (child.type === "element" && child.tag === "Transition") {
673
+ hydrateTransitionAtIndex(context, child, parentVar, domIndex, indent);
674
+ return;
675
+ }
676
+ if (child.type === "element" && getAttr(child, "v-if") && !getAttr(child, "v-pre")) {
677
+ hydrateIf(context, child, parentVar, domIndex, indent);
678
+ emit(context, indent, `${domIndex} += 1;`);
679
+ return;
680
+ }
681
+ if (child.type === "element" && getAttr(child, "v-for") && !getAttr(child, "v-pre")) {
682
+ hydrateFor(context, child, parentVar, domIndex, indent, domIndex);
683
+ return;
684
+ }
685
+ const childVar = nextName(context, "node");
686
+ emit(context, indent, `const ${childVar} = ${parentVar}.childNodes[${domIndex}];`);
687
+ if (child.type === "element") {
688
+ const elementCheck = isComponentTag(child.tag)
689
+ ? `!${childVar} || ${childVar}.nodeType !== 1`
690
+ : `!${childVar} || ${childVar}.nodeType !== 1 || ${childVar}.tagName?.toLowerCase() !== ${quote(child.tag.toLowerCase())}`;
691
+ emit(context, indent, `if (${elementCheck}) { __mikuru_recover(${quote(`Element mismatch: expected <${child.tag.toLowerCase()}>, got `)} + __mikuru_describeNode(${childVar})); } else {`);
692
+ hydrateNode(context, child, childVar, indent + 1);
693
+ emit(context, indent, "}");
694
+ }
695
+ else {
696
+ emit(context, indent, `if (!${childVar} || ${childVar}.nodeType !== 3) { __mikuru_recover("Text mismatch: expected text, got " + __mikuru_describeNode(${childVar})); } else {`);
697
+ hydrateNode(context, child, childVar, indent + 1);
698
+ emit(context, indent, "}");
699
+ }
700
+ emit(context, indent, `${domIndex} += 1;`);
701
+ });
702
+ }
703
+ function hydrateComponentProps(context, node, propsVar, indent) {
704
+ for (const attr of node.attrs) {
705
+ const modelDirective = parseModelDirective(attr.name);
706
+ if (modelDirective) {
707
+ const expression = validateAssignableExpression(getAttrValueFromDirective(attr), attr.name, {
708
+ source: context.source ?? String(attr.value),
709
+ offset: attr.valueLoc?.offset ?? attr.loc?.offset ?? 0,
710
+ filename: context.filename
711
+ });
712
+ const valueExpression = compileHydrationExpression(context, expression, attr.name);
713
+ const propName = modelDirective.argument ?? "modelValue";
714
+ const updatePropName = toComponentEventProp(`update:${propName}`);
715
+ const modifiersPropName = modelDirective.argument ? `${propName}Modifiers` : "modelModifiers";
716
+ emit(context, indent, `Object.defineProperty(${propsVar}, ${quote(propName)}, { enumerable: true, get() { return unwrap(${valueExpression}); } });`);
717
+ emit(context, indent, `${propsVar}[${quote(updatePropName)}] = ($value) => { ${expression}.value = $value; };`);
718
+ if (modelDirective.modifiers.length > 0) {
719
+ emit(context, indent, `${propsVar}[${quote(modifiersPropName)}] = { ${modelDirective.modifiers.map((modifier) => `${quote(modifier)}: true`).join(", ")} };`);
720
+ }
721
+ continue;
722
+ }
723
+ const objectEvent = parseObjectOnDirective(attr.name);
724
+ if (objectEvent && attr.value !== true) {
725
+ validateObjectOnModifiers(objectEvent, attr, "component");
726
+ const listenersVar = nextName(context, "listeners");
727
+ const eventNameVar = nextName(context, "eventName");
728
+ const handlerVar = nextName(context, "handler");
729
+ const propNameVar = nextName(context, "propName");
730
+ emit(context, indent, `{`);
731
+ emit(context, indent + 1, `const ${listenersVar} = unwrap(${compileHydrationExpression(context, String(attr.value), attr.name)}) ?? {};`);
732
+ emit(context, indent + 1, `if (${listenersVar} && typeof ${listenersVar} === "object") {`);
733
+ emit(context, indent + 2, `for (const [${eventNameVar}, ${handlerVar}] of Object.entries(${listenersVar})) {`);
734
+ emit(context, indent + 3, `const ${propNameVar} = ${componentEventPropRuntimeExpression(`String(${eventNameVar})`)};`);
735
+ emit(context, indent + 3, `if (typeof ${handlerVar} === "function") { ${propsVar}[${propNameVar}] = ${handlerVar}; }`);
736
+ emit(context, indent + 2, "}");
737
+ emit(context, indent + 1, "}");
738
+ emit(context, indent, `}`);
739
+ continue;
740
+ }
741
+ const event = parseEventDirective(attr.name);
742
+ if (event && attr.value !== true) {
743
+ validateComponentEventModifiers(event, attr);
744
+ const handlerExpression = `($value) => ${String(attr.value).trim()}($value)`;
745
+ const propName = event.nameExpression
746
+ ? componentEventPropRuntimeExpression(`String(unwrap(${compileHydrationExpression(context, event.nameExpression, attr.name)}) ?? "")`)
747
+ : quote(toComponentEventProp(event.name ?? ""));
748
+ emit(context, indent, `${propsVar}[${propName}] = ${componentEventHandlerExpression(event, handlerExpression, context)};`);
749
+ continue;
750
+ }
751
+ if (shouldSkipAttr(attr)) {
752
+ continue;
753
+ }
754
+ if (parseObjectBindDirective(attr.name) && attr.value !== true) {
755
+ emit(context, indent, `Object.assign(${propsVar}, unwrap(${compileHydrationExpression(context, String(attr.value), attr.name)}) ?? {});`);
756
+ continue;
757
+ }
758
+ const dynamicArgument = getDynamicAttrArgument(attr.name);
759
+ if (dynamicArgument && attr.value !== true) {
760
+ emit(context, indent, `${propsVar}[String(unwrap(${compileHydrationExpression(context, dynamicArgument.expression, attr.name)}) ?? "")] = unwrap(${compileHydrationExpression(context, String(attr.value), attr.name)});`);
761
+ continue;
762
+ }
763
+ const dynamicName = getDynamicAttrName(attr.name);
764
+ if (dynamicName && attr.value !== true) {
765
+ emit(context, indent, `${propsVar}[${quote(dynamicName)}] = unwrap(${compileHydrationExpression(context, String(attr.value), attr.name)});`);
766
+ continue;
767
+ }
768
+ emit(context, indent, `${propsVar}[${quote(attr.name)}] = ${attr.value === true ? "true" : quote(attr.value)};`);
769
+ }
770
+ }
771
+ function hydrateEvents(context, node, elementVar, indent) {
772
+ for (const attr of node.attrs) {
773
+ const objectEvent = parseObjectOnDirective(attr.name);
774
+ if (objectEvent && attr.value !== true) {
775
+ validateObjectOnModifiers(objectEvent, attr, "element");
776
+ const eventOptions = eventListenerOptions(objectEvent);
777
+ const expression = compileHydrationExpression(context, String(attr.value), attr.name);
778
+ const listenersVar = nextName(context, "listeners");
779
+ const stopVar = nextName(context, "stop");
780
+ const sourceVar = nextName(context, "listeners");
781
+ const eventVar = nextName(context, "event");
782
+ const handlerVar = nextName(context, "handler");
783
+ const wrappedHandlerVar = nextName(context, "handler");
784
+ emit(context, indent, `const ${listenersVar} = new Map();`);
785
+ emit(context, indent, `const ${stopVar} = effect(() => {`);
786
+ emit(context, indent + 1, `for (const [${eventVar}, ${handlerVar}] of ${listenersVar}) {`);
787
+ emit(context, indent + 2, `${elementVar}.removeEventListener(${eventVar}, ${handlerVar}${eventOptions ? `, ${eventOptions}` : ""});`);
788
+ emit(context, indent + 1, "}");
789
+ emit(context, indent + 1, `${listenersVar}.clear();`);
790
+ emit(context, indent + 1, `const ${sourceVar} = unwrap(${expression}) ?? {};`);
791
+ emit(context, indent + 1, `if (${sourceVar} && typeof ${sourceVar} === "object") {`);
792
+ emit(context, indent + 2, `for (const [${eventVar}, ${handlerVar}] of Object.entries(${sourceVar})) {`);
793
+ emit(context, indent + 3, `if (typeof ${handlerVar} === "function") {`);
794
+ emit(context, indent + 4, `const ${wrappedHandlerVar} = ($event) => ${handlerVar}($event);`);
795
+ emit(context, indent + 4, `${elementVar}.addEventListener(${eventVar}, ${wrappedHandlerVar}${eventOptions ? `, ${eventOptions}` : ""});`);
796
+ emit(context, indent + 4, `${listenersVar}.set(${eventVar}, ${wrappedHandlerVar});`);
797
+ emit(context, indent + 3, "}");
798
+ emit(context, indent + 2, "}");
799
+ emit(context, indent + 1, "}");
800
+ emit(context, indent, "});");
801
+ emit(context, indent, `__mikuru_cleanup.push(() => {`);
802
+ emit(context, indent + 1, `${stopVar}();`);
803
+ emit(context, indent + 1, `for (const [${eventVar}, ${handlerVar}] of ${listenersVar}) {`);
804
+ emit(context, indent + 2, `${elementVar}.removeEventListener(${eventVar}, ${handlerVar}${eventOptions ? `, ${eventOptions}` : ""});`);
805
+ emit(context, indent + 1, "}");
806
+ emit(context, indent + 1, `${listenersVar}.clear();`);
807
+ emit(context, indent, "});");
808
+ continue;
809
+ }
810
+ const event = parseEventDirective(attr.name);
811
+ const dynamicEvent = event?.nameExpression ? event : undefined;
812
+ if (dynamicEvent && attr.value !== true) {
813
+ validateEventModifiers(dynamicEvent, attr);
814
+ const expression = compileHydrationExpression(context, dynamicEvent.nameExpression ?? "", attr.name);
815
+ const eventOptions = eventListenerOptions(dynamicEvent);
816
+ const handlerVar = nextName(context, "handler");
817
+ const currentEventVar = nextName(context, "eventName");
818
+ const nextEventVar = nextName(context, "eventName");
819
+ emitHydrationEventHandler(context, indent, elementVar, handlerVar, String(attr.value).trim(), dynamicEvent);
820
+ emit(context, indent, `let ${currentEventVar};`);
821
+ emit(context, indent, "__mikuru_cleanup.push(effect(() => {");
822
+ emit(context, indent + 1, `const ${nextEventVar} = String(unwrap(${expression}) ?? "");`);
823
+ emit(context, indent + 1, `if (${nextEventVar} === ${currentEventVar}) return;`);
824
+ emit(context, indent + 1, `if (${currentEventVar}) ${elementVar}.removeEventListener(${currentEventVar}, ${handlerVar}${eventOptions ? `, ${eventOptions}` : ""});`);
825
+ emit(context, indent + 1, `${currentEventVar} = ${nextEventVar};`);
826
+ emit(context, indent + 1, `if (${currentEventVar}) ${elementVar}.addEventListener(${currentEventVar}, ${handlerVar}${eventOptions ? `, ${eventOptions}` : ""});`);
827
+ emit(context, indent, "}));");
828
+ emit(context, indent, `__mikuru_cleanup.push(() => { if (${currentEventVar}) ${elementVar}.removeEventListener(${currentEventVar}, ${handlerVar}${eventOptions ? `, ${eventOptions}` : ""}); });`);
829
+ continue;
830
+ }
831
+ if (!event?.name || attr.value === true) {
832
+ continue;
833
+ }
834
+ validateEventModifiers(event, attr);
835
+ const eventOptions = eventListenerOptions(event);
836
+ const handlerVar = nextName(context, "handler");
837
+ emitHydrationEventHandler(context, indent, elementVar, handlerVar, String(attr.value).trim(), event);
838
+ emit(context, indent, `${elementVar}.addEventListener(${quote(event.name)}, ${handlerVar}${eventOptions ? `, ${eventOptions}` : ""});`);
839
+ emit(context, indent, `__mikuru_cleanup.push(() => ${elementVar}.removeEventListener(${quote(event.name)}, ${handlerVar}${eventOptions ? `, ${eventOptions}` : ""}));`);
840
+ }
841
+ }
842
+ function emitHydrationEventHandler(context, indent, elementVar, handlerVar, handlerExpression, event) {
843
+ const guard = eventModifierGuardExpression(event);
844
+ const hasControl = event.modifiers.includes("prevent") || event.modifiers.includes("stop") || event.modifiers.includes("self") || guard;
845
+ if (!hasControl) {
846
+ emit(context, indent, `const ${handlerVar} = ($event) => ${handlerExpression}($event);`);
847
+ return;
848
+ }
849
+ emit(context, indent, `const ${handlerVar} = ($event) => {`);
850
+ if (event.modifiers.includes("self")) {
851
+ emit(context, indent + 1, `if ($event.target !== ${elementVar}) { return; }`);
852
+ }
853
+ if (guard) {
854
+ emit(context, indent + 1, `if (${guard}) { return; }`);
855
+ }
856
+ if (event.modifiers.includes("prevent")) {
857
+ emit(context, indent + 1, "$event.preventDefault();");
858
+ }
859
+ if (event.modifiers.includes("stop")) {
860
+ emit(context, indent + 1, "$event.stopPropagation();");
861
+ }
862
+ emit(context, indent + 1, `return ${handlerExpression}($event);`);
863
+ emit(context, indent, "};");
864
+ }
865
+ function hydrateModelAndShow(context, node, elementVar, indent) {
866
+ for (const attr of node.attrs) {
867
+ const modelDirective = parseModelDirective(attr.name);
868
+ if (modelDirective) {
869
+ if (modelDirective.argument) {
870
+ continue;
871
+ }
872
+ const expression = validateAssignableExpression(getAttrValueFromDirective(attr), attr.name, {
873
+ source: context.source ?? String(attr.value),
874
+ offset: attr.valueLoc?.offset ?? attr.loc?.offset ?? 0,
875
+ filename: context.filename
876
+ });
877
+ const handlerVar = nextName(context, "handler");
878
+ const inputType = getStaticAttrValue(node, "type")?.toLowerCase();
879
+ const multiple = node.tag === "select" && hasStaticBooleanAttr(node, "multiple");
880
+ const modelMode = node.tag === "input" && inputType === "checkbox"
881
+ ? "checkbox"
882
+ : node.tag === "input" && inputType === "radio"
883
+ ? "radio"
884
+ : node.tag === "select" && multiple
885
+ ? "select-multiple"
886
+ : node.tag === "select"
887
+ ? "select"
888
+ : "text";
889
+ const eventName = modelMode === "text" && !modelDirective.modifiers.includes("lazy") ? "input" : "change";
890
+ const propertyName = modelMode === "checkbox" || modelMode === "radio" ? "checked" : "value";
891
+ const renderedValue = modelMode === "checkbox"
892
+ ? `(() => { const value = unwrap(${expression}); const checkboxValue = ${modelElementValueExpression(`${elementVar}`, modelDirective.modifiers)}; return Array.isArray(value) ? value.some((item) => Object.is(item, checkboxValue)) : Boolean(value); })()`
893
+ : modelMode === "radio"
894
+ ? `Object.is(${modelElementValueExpression(`${elementVar}`, modelDirective.modifiers)}, unwrap(${expression}))`
895
+ : modelMode === "select-multiple"
896
+ ? `Array.from(${elementVar}.options).forEach((option) => { const optionValue = ${modelElementValueExpression("option", modelDirective.modifiers)}; option.selected = (unwrap(${expression}) ?? []).some((item) => Object.is(item, optionValue)); })`
897
+ : modelMode === "select"
898
+ ? `Array.from(${elementVar}.options).forEach((option) => { option.selected = Object.is(${modelElementValueExpression("option", modelDirective.modifiers)}, unwrap(${expression})); })`
899
+ : `String(unwrap(${expression}) ?? "")`;
900
+ const assignedValue = modelAssignedValue(modelMode, modelDirective.modifiers, expression);
901
+ const warnedVar = nextName(context, "modelMismatchWarned");
902
+ emit(context, indent, `let ${warnedVar} = false;`);
903
+ emit(context, indent, "__mikuru_cleanup.push(effect(() => {");
904
+ if (modelMode === "select-multiple") {
905
+ const expectedValuesVar = nextName(context, "expectedValues");
906
+ const actualValuesVar = nextName(context, "actualValues");
907
+ const optionValueVar = nextName(context, "optionValue");
908
+ emit(context, indent + 1, `const ${expectedValuesVar} = unwrap(${expression}) ?? [];`);
909
+ emit(context, indent + 1, `const ${actualValuesVar} = Array.from(${elementVar}.selectedOptions).map((option) => ${modelElementValueExpression("option", modelDirective.modifiers)});`);
910
+ emit(context, indent + 1, `if (${actualValuesVar}.length !== ${expectedValuesVar}.length || ${expectedValuesVar}.some((${optionValueVar}) => !${actualValuesVar}.some((actualValue) => Object.is(actualValue, ${optionValueVar}))) || ${actualValuesVar}.some((${optionValueVar}) => !${expectedValuesVar}.some((expectedValue) => Object.is(expectedValue, ${optionValueVar})))) {`);
911
+ emit(context, indent + 2, `if (!${warnedVar}) { __mikuru_warn("v-model selected mismatch: expected " + JSON.stringify(${expectedValuesVar}) + ", got " + JSON.stringify(${actualValuesVar}) + "."); ${warnedVar} = true; }`);
912
+ emit(context, indent + 1, "}");
913
+ emit(context, indent + 1, renderedValue);
914
+ }
915
+ else if (modelMode === "select") {
916
+ emit(context, indent + 1, `if (${elementVar}.selectedOptions.length === 0 || !Object.is(${modelElementValueExpression(`${elementVar}.selectedOptions[0]`, modelDirective.modifiers)}, unwrap(${expression}))) {`);
917
+ emit(context, indent + 2, `if (!${warnedVar}) { __mikuru_warn("v-model selected mismatch: expected " + JSON.stringify(unwrap(${expression})) + ", got " + JSON.stringify(${elementVar}.selectedOptions.length === 0 ? "" : ${modelElementValueExpression(`${elementVar}.selectedOptions[0]`, modelDirective.modifiers)}) + "."); ${warnedVar} = true; }`);
918
+ emit(context, indent + 2, renderedValue);
919
+ emit(context, indent + 1, "}");
920
+ }
921
+ else {
922
+ emit(context, indent + 1, `if (${elementVar}.${propertyName} !== ${renderedValue}) {`);
923
+ emit(context, indent + 2, `if (!${warnedVar}) { __mikuru_warn(${quote(`v-model ${propertyName} mismatch: expected `)} + JSON.stringify(${renderedValue}) + ", got " + JSON.stringify(${elementVar}.${propertyName}) + "."); ${warnedVar} = true; }`);
924
+ emit(context, indent + 2, `${elementVar}.${propertyName} = ${renderedValue};`);
925
+ emit(context, indent + 1, "}");
926
+ }
927
+ emit(context, indent, "}));");
928
+ emit(context, indent, `const ${handlerVar} = ($event) => { ${expression}.value = ${assignedValue}; };`);
929
+ emit(context, indent, `${elementVar}.addEventListener(${quote(eventName)}, ${handlerVar});`);
930
+ emit(context, indent, `__mikuru_cleanup.push(() => ${elementVar}.removeEventListener(${quote(eventName)}, ${handlerVar}));`);
931
+ continue;
932
+ }
933
+ if (attr.name === "v-show") {
934
+ emit(context, indent, `__mikuru_cleanup.push(effect(() => { ${elementVar}.style.display = unwrap(${compileHydrationExpression(context, getAttrValueFromDirective(attr), attr.name)}) ? "" : "none"; }));`);
935
+ }
936
+ }
937
+ }
938
+ function hydrateContentDirective(context, node, elementVar, indent) {
939
+ const attr = getContentDirectiveAttr(node);
940
+ if (!attr || attr.value === true) {
941
+ return;
942
+ }
943
+ const expression = compileHydrationExpression(context, String(attr.value), attr.name);
944
+ const property = attr.name === "v-html" ? "innerHTML" : "textContent";
945
+ const warnedVar = nextName(context, "contentMismatchWarned");
946
+ emit(context, indent, `let ${warnedVar} = false;`);
947
+ emit(context, indent, `__mikuru_cleanup.push(effect(() => { const __mikuru_content = String(unwrap(${expression}) ?? ""); if (${elementVar}.${property} !== __mikuru_content) { if (!${warnedVar}) { __mikuru_warn(${quote(`${attr.name} content mismatch: expected `)} + JSON.stringify(__mikuru_content) + ", got " + JSON.stringify(${elementVar}.${property} ?? "") + "."); ${warnedVar} = true; } ${elementVar}.${property} = __mikuru_content; } }));`);
948
+ }
949
+ function hydrateText(context, node, nodeVar, indent) {
950
+ const expression = node.parts.map((part) => {
951
+ if (part.type === "static") {
952
+ return quote(part.value);
953
+ }
954
+ return `String(unwrap(${compileHydrationExpression(context, part.value, "interpolation")}) ?? "")`;
955
+ }).join(" + ");
956
+ const warnedVar = nextName(context, "textMismatchWarned");
957
+ emit(context, indent, `let ${warnedVar} = false;`);
958
+ emit(context, indent, `__mikuru_cleanup.push(effect(() => { const __mikuru_text = ${expression || "\"\""}; if (${nodeVar}.textContent !== __mikuru_text) { if (!${warnedVar}) { __mikuru_warn("Text content mismatch: expected " + JSON.stringify(__mikuru_text) + ", got " + JSON.stringify(${nodeVar}.textContent ?? "") + "."); ${warnedVar} = true; } ${nodeVar}.textContent = __mikuru_text; } }));`);
959
+ }
960
+ function hydrateTemplateRef(context, node, valueExpression, indent) {
961
+ const refAttr = getTemplateRefAttr(node);
962
+ if (!refAttr) {
963
+ return;
964
+ }
965
+ const targetExpression = templateRefTargetExpression(context, refAttr);
966
+ const cleanupRefVar = nextName(context, "cleanupRef");
967
+ const multiple = context.templateRefMode === "array";
968
+ emit(context, indent, `const ${cleanupRefVar} = __mikuru_setRef(${targetExpression}, ${valueExpression}, ${multiple ? "true" : "false"});`);
969
+ emit(context, indent, `__mikuru_cleanup.push(${cleanupRefVar});`);
970
+ }
971
+ function getTemplateRefAttr(node) {
972
+ return node.attrs.find((attr) => attr.name === "ref" || getDynamicAttrName(attr.name) === "ref");
973
+ }
974
+ function templateRefTargetExpression(context, attr) {
975
+ if (getDynamicAttrName(attr.name) === "ref") {
976
+ return compileHydrationExpression(context, requireAttrValue(attr), attr.name);
977
+ }
978
+ if (attr.value === true || !attr.value.trim()) {
979
+ throw new Error("Template ref requires a ref object name, for example ref=\"inputEl\"");
980
+ }
981
+ const name = attr.value.trim();
982
+ if (!isIdentifier(name)) {
983
+ throw new Error("Template ref must be a simple identifier that points to a ref object");
984
+ }
985
+ return name;
986
+ }
987
+ function isHydratableNode(node) {
988
+ return node.type === "element" || node.parts.some((part) => part.type === "expression" || (part.type === "static" && part.value.length > 0));
989
+ }
990
+ function shouldSkipAttr(attr) {
991
+ return attr.name === "v-if"
992
+ || attr.name === "v-else-if"
993
+ || attr.name === "v-else"
994
+ || attr.name === "v-for"
995
+ || attr.name === "v-show"
996
+ || attr.name === "v-html"
997
+ || attr.name === "v-text"
998
+ || attr.name === "v-pre"
999
+ || attr.name === "v-cloak"
1000
+ || attr.name === "v-model"
1001
+ || attr.name.startsWith("v-model.")
1002
+ || attr.name.startsWith("v-model:")
1003
+ || attr.name === "ref"
1004
+ || getDynamicAttrName(attr.name) === "ref"
1005
+ || attr.name === "key"
1006
+ || Boolean(parseObjectOnDirective(attr.name))
1007
+ || attr.name.startsWith("@")
1008
+ || attr.name.startsWith("v-on:");
1009
+ }
1010
+ function isDirectiveAttr(attr) {
1011
+ return shouldSkipAttr(attr)
1012
+ || Boolean(parseBindDirective(attr.name))
1013
+ || Boolean(parseObjectBindDirective(attr.name));
1014
+ }
1015
+ function expectedStaticAttributeValue(name) {
1016
+ return booleanAttributes.has(name.toLowerCase()) ? "" : "true";
1017
+ }
1018
+ const booleanAttributes = new Set([
1019
+ "allowfullscreen",
1020
+ "async",
1021
+ "autofocus",
1022
+ "checked",
1023
+ "controls",
1024
+ "default",
1025
+ "defer",
1026
+ "disabled",
1027
+ "formnovalidate",
1028
+ "hidden",
1029
+ "inert",
1030
+ "ismap",
1031
+ "itemscope",
1032
+ "loop",
1033
+ "multiple",
1034
+ "muted",
1035
+ "nomodule",
1036
+ "novalidate",
1037
+ "open",
1038
+ "playsinline",
1039
+ "readonly",
1040
+ "required",
1041
+ "reversed",
1042
+ "selected"
1043
+ ]);
1044
+ function getAttr(node, name) {
1045
+ return node.attrs.find((attr) => attr.name === name);
1046
+ }
1047
+ function getAttrValue(node, name) {
1048
+ const attr = getAttr(node, name);
1049
+ return attr && attr.value !== true ? attr.value : "false";
1050
+ }
1051
+ function withoutAttrs(node, names) {
1052
+ return {
1053
+ ...node,
1054
+ attrs: node.attrs.filter((attr) => !names.includes(attr.name))
1055
+ };
1056
+ }
1057
+ function validateKeepAliveAttributes(node) {
1058
+ for (const attr of node.attrs) {
1059
+ const name = parseBindDirective(attr.name)?.name ?? attr.name;
1060
+ if (name === "include" || name === "exclude" || name === "max") {
1061
+ continue;
1062
+ }
1063
+ throw new Error(`Unsupported attribute "${attr.name}" on <KeepAlive>. Supported attributes: include, exclude, and max.`);
1064
+ }
1065
+ }
1066
+ function validateAsyncBoundaryAttributes(node) {
1067
+ for (const attr of node.attrs) {
1068
+ const name = parseBindDirective(attr.name)?.name ?? attr.name;
1069
+ if (name === "loading" || name === "fallback" || name === "delay" || name === "timeout") {
1070
+ continue;
1071
+ }
1072
+ throw new Error(`Unsupported attribute "${attr.name}" on <AsyncBoundary>. Supported attributes: loading, fallback, delay, and timeout.`);
1073
+ }
1074
+ }
1075
+ function validateErrorBoundaryAttributes(node) {
1076
+ for (const attr of node.attrs) {
1077
+ const name = parseBindDirective(attr.name)?.name ?? attr.name;
1078
+ if (name === "fallback" || name === "reset-key") {
1079
+ continue;
1080
+ }
1081
+ throw new Error(`Unsupported attribute "${attr.name}" on <ErrorBoundary>. Supported attributes: fallback and reset-key.`);
1082
+ }
1083
+ }
1084
+ function validateTransitionAttributes(node) {
1085
+ const supported = new Set([
1086
+ "name",
1087
+ "appear",
1088
+ "mode",
1089
+ "enter-from-class",
1090
+ "enter-active-class",
1091
+ "enter-to-class",
1092
+ "leave-from-class",
1093
+ "leave-active-class",
1094
+ "leave-to-class"
1095
+ ]);
1096
+ for (const attr of node.attrs) {
1097
+ const name = parseBindDirective(attr.name)?.name ?? attr.name;
1098
+ if (supported.has(name)) {
1099
+ continue;
1100
+ }
1101
+ throw new Error(`Unsupported attribute "${attr.name}" on <Transition>. Supported attributes: name, appear, mode, and CSS class override attributes.`);
1102
+ }
1103
+ }
1104
+ function validateTransitionGroupAttributes(node) {
1105
+ const supported = new Set([
1106
+ "name",
1107
+ "tag",
1108
+ "enter-from-class",
1109
+ "enter-active-class",
1110
+ "enter-to-class",
1111
+ "leave-from-class",
1112
+ "leave-active-class",
1113
+ "leave-to-class",
1114
+ "move-class"
1115
+ ]);
1116
+ for (const attr of node.attrs) {
1117
+ const name = parseBindDirective(attr.name)?.name ?? attr.name;
1118
+ if (supported.has(name)) {
1119
+ continue;
1120
+ }
1121
+ throw new Error(`Unsupported attribute "${attr.name}" on <TransitionGroup>. Supported attributes: name, tag, and CSS class override attributes.`);
1122
+ }
1123
+ }
1124
+ function getErrorBoundaryFallbackAttr(node) {
1125
+ const attr = node.attrs.find((candidate) => parseBindDirective(candidate.name)?.name === "fallback");
1126
+ if (!attr) {
1127
+ throw new Error("<ErrorBoundary> requires :fallback to resolve to a component object");
1128
+ }
1129
+ return attr;
1130
+ }
1131
+ function getAsyncBoundaryChildren(node) {
1132
+ const meaningful = node.children.filter((child) => child.type === "element" || child.parts.some((part) => part.value.trim()));
1133
+ if (meaningful.length === 0) {
1134
+ throw new Error("<AsyncBoundary> requires at least one child");
1135
+ }
1136
+ return node.children;
1137
+ }
1138
+ function getTransitionChildren(node) {
1139
+ const meaningful = node.children.filter((child) => child.type === "element" || child.parts.some((part) => part.value.trim()));
1140
+ if (meaningful.length === 0 || meaningful.some((child) => child.type !== "element")) {
1141
+ throw new Error("<Transition> requires exactly one element/component child or one v-if chain");
1142
+ }
1143
+ const children = meaningful;
1144
+ if (children.length === 1) {
1145
+ return children;
1146
+ }
1147
+ if (!getAttr(children[0], "v-if")) {
1148
+ throw new Error("<Transition> requires exactly one element/component child or one v-if chain");
1149
+ }
1150
+ for (const child of children.slice(1)) {
1151
+ if (!getAttr(child, "v-else-if") && !getAttr(child, "v-else")) {
1152
+ throw new Error("<Transition> only accepts multiple children when they form a v-if chain");
1153
+ }
1154
+ }
1155
+ return children;
1156
+ }
1157
+ function getTransitionGroupChild(node) {
1158
+ const child = getSingleElementChild(node, "<TransitionGroup>");
1159
+ if (!getAttr(child, "v-for") || !getKeyExpression(child)) {
1160
+ throw new Error("<TransitionGroup> requires a single keyed v-for child in v1");
1161
+ }
1162
+ return child;
1163
+ }
1164
+ function getTransitionGroupTagExpression(context, node) {
1165
+ const dynamicTag = node.attrs.find((attr) => parseBindDirective(attr.name)?.name === "tag");
1166
+ if (dynamicTag) {
1167
+ return compileHydrationExpression(context, requireAttrValue(dynamicTag), dynamicTag.name);
1168
+ }
1169
+ return quote(getStaticAttrValue(node, "tag") ?? "span");
1170
+ }
1171
+ function getKeyExpression(node) {
1172
+ return getStaticAttrValue(node, ":key") ?? getStaticAttrValue(node, "v-bind:key");
1173
+ }
1174
+ function getSingleElementChild(node, label) {
1175
+ const meaningful = node.children.filter((child) => child.type === "element" || child.parts.some((part) => part.value.trim()));
1176
+ if (meaningful.length !== 1 || meaningful[0]?.type !== "element") {
1177
+ throw new Error(`${label} requires exactly one element or component child`);
1178
+ }
1179
+ return meaningful[0];
1180
+ }
1181
+ function getDynamicComponentIsAttr(node) {
1182
+ return node.attrs.find((attr) => parseBindDirective(attr.name)?.name === "is");
1183
+ }
1184
+ function withoutDynamicComponentIs(node) {
1185
+ return {
1186
+ ...node,
1187
+ attrs: node.attrs.filter((attr) => parseBindDirective(attr.name)?.name !== "is")
1188
+ };
1189
+ }
1190
+ function isComponentTag(tag) {
1191
+ return /^[A-Z]/.test(tag);
1192
+ }
1193
+ function getDynamicAttrName(name) {
1194
+ const binding = parseBindDirective(name);
1195
+ return binding?.nameExpression ? undefined : binding?.name;
1196
+ }
1197
+ function getEventName(name) {
1198
+ if (name.startsWith("@[") || name.startsWith("v-on:["))
1199
+ return undefined;
1200
+ if (name.startsWith("@"))
1201
+ return name.slice(1).split(".")[0];
1202
+ if (name.startsWith("v-on:"))
1203
+ return name.slice("v-on:".length).split(".")[0];
1204
+ return undefined;
1205
+ }
1206
+ function parseEventDirective(name) {
1207
+ const dynamic = getDynamicEventArgument(name);
1208
+ if (dynamic) {
1209
+ return { nameExpression: dynamic.expression, modifiers: dynamic.modifiers };
1210
+ }
1211
+ const rawName = name.startsWith("@")
1212
+ ? name.slice(1)
1213
+ : name.startsWith("v-on:")
1214
+ ? name.slice("v-on:".length)
1215
+ : undefined;
1216
+ if (!rawName || rawName.startsWith("[")) {
1217
+ return undefined;
1218
+ }
1219
+ const [eventName, ...modifiers] = rawName.split(".");
1220
+ return { name: eventName, modifiers };
1221
+ }
1222
+ function getDynamicAttrArgument(name) {
1223
+ const binding = parseBindDirective(name);
1224
+ return binding?.nameExpression ? { expression: binding.nameExpression } : undefined;
1225
+ }
1226
+ function parseBindDirective(name) {
1227
+ const dynamic = parseDynamicArgument(name, [":", "v-bind:"]);
1228
+ if (dynamic) {
1229
+ return { nameExpression: dynamic.expression, modifiers: dynamic.modifiers };
1230
+ }
1231
+ const rawName = name.startsWith(":")
1232
+ ? name.slice(1)
1233
+ : name.startsWith("v-bind:")
1234
+ ? name.slice("v-bind:".length)
1235
+ : undefined;
1236
+ if (!rawName) {
1237
+ return undefined;
1238
+ }
1239
+ const [bindingName, ...modifiers] = rawName.split(".");
1240
+ if (!bindingName) {
1241
+ return undefined;
1242
+ }
1243
+ return { name: modifiers.includes("camel") ? camelize(bindingName) : bindingName, modifiers };
1244
+ }
1245
+ function validateBindModifiers(binding, attr) {
1246
+ const allowed = new Set(["camel", "prop", "attr"]);
1247
+ for (const modifier of binding.modifiers) {
1248
+ if (!allowed.has(modifier)) {
1249
+ throw new Error(`Unsupported v-bind modifier ".${modifier}" on ${attr.name}. Use .camel, .prop, or .attr.`);
1250
+ }
1251
+ }
1252
+ if (binding.modifiers.includes("prop") && binding.modifiers.includes("attr")) {
1253
+ throw new Error(`v-bind modifiers .prop and .attr cannot be used together on ${attr.name}`);
1254
+ }
1255
+ }
1256
+ function validateObjectBindModifiers(binding, attr) {
1257
+ const allowed = new Set(["camel", "prop", "attr"]);
1258
+ for (const modifier of binding.modifiers) {
1259
+ if (!allowed.has(modifier)) {
1260
+ throw new Error(`Unsupported object v-bind modifier ".${modifier}" on ${attr.name}. Use .camel, .prop, or .attr.`);
1261
+ }
1262
+ }
1263
+ if (binding.modifiers.includes("prop") && binding.modifiers.includes("attr")) {
1264
+ throw new Error(`Object v-bind modifiers .prop and .attr cannot be used together on ${attr.name}`);
1265
+ }
1266
+ }
1267
+ function bindOptionsExpression(binding) {
1268
+ if (binding.modifiers.includes("prop"))
1269
+ return ", { property: true }";
1270
+ if (binding.modifiers.includes("attr"))
1271
+ return ", { attribute: true }";
1272
+ return "";
1273
+ }
1274
+ function bindNameExpression(expression, binding) {
1275
+ return binding.modifiers.includes("camel") ? `(${expression}).replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase())` : expression;
1276
+ }
1277
+ function objectBindKeyExpression(keyExpression, binding) {
1278
+ return bindNameExpression(`String(${keyExpression})`, binding);
1279
+ }
1280
+ function camelize(value) {
1281
+ return value.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
1282
+ }
1283
+ function parseObjectBindDirective(name) {
1284
+ if (name === "v-bind") {
1285
+ return { modifiers: [] };
1286
+ }
1287
+ if (!name.startsWith("v-bind.")) {
1288
+ return undefined;
1289
+ }
1290
+ return { modifiers: name.slice("v-bind.".length).split(".").filter(Boolean) };
1291
+ }
1292
+ function parseObjectOnDirective(name) {
1293
+ if (name === "v-on") {
1294
+ return { modifiers: [] };
1295
+ }
1296
+ if (!name.startsWith("v-on.")) {
1297
+ return undefined;
1298
+ }
1299
+ return { modifiers: name.slice("v-on.".length).split(".").filter(Boolean) };
1300
+ }
1301
+ function validateEventModifiers(event, attr) {
1302
+ const supportedModifiers = [...eventControlModifiers, ...eventOptionModifiers, ...eventSystemModifiers, ...eventMouseModifiers, ...eventKeyModifiers, "exact"];
1303
+ for (const modifier of event.modifiers) {
1304
+ if (!supportedModifiers.includes(modifier)) {
1305
+ throw new Error(`Unsupported event modifier .${modifier} on ${attr.name}.`);
1306
+ }
1307
+ }
1308
+ if (event.modifiers.includes("passive") && event.modifiers.includes("prevent")) {
1309
+ throw new Error(`Event modifiers .passive and .prevent cannot be combined on ${attr.name}`);
1310
+ }
1311
+ }
1312
+ function validateObjectOnModifiers(event, attr, target) {
1313
+ if (target === "component" && event.modifiers.length > 0) {
1314
+ throw new Error(`Object v-on modifiers are only supported on native elements: ${attr.name}`);
1315
+ }
1316
+ for (const modifier of event.modifiers) {
1317
+ if (!eventOptionModifiers.includes(modifier)) {
1318
+ throw new Error(`Object v-on modifier .${modifier} is not supported on ${attr.name}. Use .once, .capture, or .passive.`);
1319
+ }
1320
+ }
1321
+ }
1322
+ function validateComponentEventModifiers(event, attr) {
1323
+ for (const modifier of event.modifiers) {
1324
+ if (modifier !== "once") {
1325
+ throw new Error(`Event modifier .${modifier} is only supported on DOM events: ${attr.name}`);
1326
+ }
1327
+ }
1328
+ }
1329
+ function eventListenerOptions(event) {
1330
+ const options = [
1331
+ event.modifiers.includes("capture") ? "capture: true" : undefined,
1332
+ event.modifiers.includes("once") ? "once: true" : undefined,
1333
+ event.modifiers.includes("passive") ? "passive: true" : undefined
1334
+ ].filter(Boolean);
1335
+ return options.length ? `{ ${options.join(", ")} }` : undefined;
1336
+ }
1337
+ const eventControlModifiers = ["prevent", "stop", "self"];
1338
+ const eventOptionModifiers = ["once", "capture", "passive"];
1339
+ const eventSystemModifiers = ["ctrl", "shift", "alt", "meta"];
1340
+ const eventMouseModifiers = ["left", "right", "middle"];
1341
+ const eventKeyModifiers = ["enter", "escape", "esc", "space", "tab", "delete", "backspace", "up", "down", "left", "right"];
1342
+ function eventModifierGuardExpression(event) {
1343
+ const checks = [];
1344
+ const mouseEvent = isMouseEventName(event.name);
1345
+ for (const modifier of event.modifiers) {
1346
+ if (eventSystemModifiers.includes(modifier)) {
1347
+ checks.push(`!$event.${modifier}Key`);
1348
+ continue;
1349
+ }
1350
+ const mouseExpression = mouseEvent ? eventMouseButtonExpression(modifier) : undefined;
1351
+ if (mouseExpression) {
1352
+ checks.push(`$event.button !== ${mouseExpression}`);
1353
+ continue;
1354
+ }
1355
+ const keyExpression = eventKeyExpression(modifier);
1356
+ if (keyExpression) {
1357
+ checks.push(`!${keyExpression}.includes($event.key)`);
1358
+ }
1359
+ }
1360
+ if (event.modifiers.includes("exact")) {
1361
+ for (const modifier of eventSystemModifiers) {
1362
+ if (!event.modifiers.includes(modifier)) {
1363
+ checks.push(`$event.${modifier}Key`);
1364
+ }
1365
+ }
1366
+ }
1367
+ return checks.length ? checks.join(" || ") : undefined;
1368
+ }
1369
+ function isMouseEventName(name) {
1370
+ return !!name && /^(?:click|dblclick|auxclick|contextmenu|mousedown|mouseup|mousemove|mouseover|mouseout|mouseenter|mouseleave|pointerdown|pointerup|pointermove|pointerover|pointerout|pointerenter|pointerleave)$/.test(name);
1371
+ }
1372
+ function eventMouseButtonExpression(modifier) {
1373
+ const mouseButtons = {
1374
+ left: "0",
1375
+ middle: "1",
1376
+ right: "2"
1377
+ };
1378
+ return mouseButtons[modifier];
1379
+ }
1380
+ function eventKeyExpression(modifier) {
1381
+ const keyAliases = {
1382
+ enter: ["Enter"],
1383
+ escape: ["Escape"],
1384
+ esc: ["Escape"],
1385
+ space: [" ", "Spacebar"],
1386
+ tab: ["Tab"],
1387
+ delete: ["Delete"],
1388
+ backspace: ["Backspace"],
1389
+ up: ["ArrowUp", "Up"],
1390
+ down: ["ArrowDown", "Down"],
1391
+ left: ["ArrowLeft", "Left"],
1392
+ right: ["ArrowRight", "Right"]
1393
+ };
1394
+ const keys = keyAliases[modifier];
1395
+ return keys ? JSON.stringify(keys) : undefined;
1396
+ }
1397
+ function componentEventHandlerExpression(event, handlerExpression, context) {
1398
+ if (!event.modifiers.includes("once")) {
1399
+ return handlerExpression;
1400
+ }
1401
+ const calledVar = nextName(context, "called");
1402
+ const handlerVar = nextName(context, "handler");
1403
+ return `(() => { let ${calledVar} = false; const ${handlerVar} = ${handlerExpression}; return (...$args) => { if (${calledVar}) { return; } ${calledVar} = true; return ${handlerVar}(...$args); }; })()`;
1404
+ }
1405
+ function componentEventPropRuntimeExpression(eventNameExpression) {
1406
+ return `"on" + ${eventNameExpression}.split(/[-:]/).filter(Boolean).map((part) => part[0]?.toUpperCase() + part.slice(1)).join("")`;
1407
+ }
1408
+ function getDynamicEventArgument(name) {
1409
+ const dynamic = parseDynamicArgument(name, ["@", "v-on:"]);
1410
+ if (!dynamic)
1411
+ return undefined;
1412
+ return { expression: dynamic.expression, modifiers: dynamic.modifiers };
1413
+ }
1414
+ function parseDynamicArgument(name, prefixes) {
1415
+ for (const prefix of prefixes) {
1416
+ if (!name.startsWith(`${prefix}[`))
1417
+ continue;
1418
+ const argumentStart = prefix.length + 1;
1419
+ const argumentEnd = name.indexOf("]", argumentStart);
1420
+ if (argumentEnd === -1)
1421
+ return undefined;
1422
+ const expression = name.slice(argumentStart, argumentEnd).trim();
1423
+ if (!expression)
1424
+ return undefined;
1425
+ const rest = name.slice(argumentEnd + 1);
1426
+ const modifiers = rest.startsWith(".") ? rest.slice(1).split(".").filter(Boolean) : [];
1427
+ return { expression, modifiers };
1428
+ }
1429
+ return undefined;
1430
+ }
1431
+ function parseModelDirective(name) {
1432
+ if (name === "v-model")
1433
+ return { modifiers: [] };
1434
+ if (name.startsWith("v-model."))
1435
+ return { modifiers: name.slice("v-model.".length).split(".").filter(Boolean) };
1436
+ if (!name.startsWith("v-model:"))
1437
+ return undefined;
1438
+ const [argument = "", ...modifiers] = name.slice("v-model:".length).split(".");
1439
+ return { argument, modifiers: modifiers.filter(Boolean) };
1440
+ }
1441
+ function toComponentEventProp(eventName) {
1442
+ return `on${eventName.split(":").map((part) => part ? part[0].toUpperCase() + part.slice(1) : "").join("")}`;
1443
+ }
1444
+ function getAttrValueFromDirective(attr) {
1445
+ return attr.value === true ? "" : String(attr.value);
1446
+ }
1447
+ function requireAttrValue(attr) {
1448
+ if (attr.value === true) {
1449
+ throw new Error(`Attribute ${attr.name} requires a value`);
1450
+ }
1451
+ return attr.value;
1452
+ }
1453
+ function getStaticAttrValue(node, name) {
1454
+ const attr = getAttr(node, name);
1455
+ return attr && attr.value !== true ? String(attr.value) : undefined;
1456
+ }
1457
+ function getContentDirectiveAttr(node) {
1458
+ return getAttr(node, "v-html") ?? getAttr(node, "v-text");
1459
+ }
1460
+ function hasStaticBooleanAttr(node, name) {
1461
+ const attr = getAttr(node, name);
1462
+ return !!attr && (attr.value === true || attr.value === "");
1463
+ }
1464
+ const modelValueProperty = "__mikuruModelValue";
1465
+ function modelElementValueExpression(targetExpression, modifiers) {
1466
+ const raw = `(${quote(modelValueProperty)} in ${targetExpression} ? ${targetExpression}[${quote(modelValueProperty)}] : ${targetExpression}.getAttribute("value") ?? (${targetExpression}.tagName === "OPTION" ? (${targetExpression}.textContent ?? "") : ${targetExpression}.value ?? ""))`;
1467
+ const trimmed = modifiers.includes("trim") ? `String(${raw}).trim()` : raw;
1468
+ return modifiers.includes("number") ? `Number(${trimmed})` : trimmed;
1469
+ }
1470
+ function modelAssignedValue(modelMode, modifiers, expression) {
1471
+ if (modelMode === "checkbox") {
1472
+ const valueExpression = modelElementValueExpression("$event.target", modifiers);
1473
+ return `(() => { const current = unwrap(${expression}); if (Array.isArray(current)) { return $event.target.checked ? [...current, ${valueExpression}] : current.filter((item) => !Object.is(item, ${valueExpression})); } return $event.target.checked; })()`;
1474
+ }
1475
+ if (modelMode === "radio") {
1476
+ return modelElementValueExpression("$event.target", modifiers);
1477
+ }
1478
+ if (modelMode === "select-multiple") {
1479
+ return `Array.from($event.target.selectedOptions).map((option) => ${modelElementValueExpression("option", modifiers)})`;
1480
+ }
1481
+ if (modelMode === "select") {
1482
+ return `(() => { const option = $event.target.selectedOptions[0]; return option ? ${modelElementValueExpression("option", modifiers)} : ""; })()`;
1483
+ }
1484
+ const raw = "$event.target.value";
1485
+ const trimmed = modifiers.includes("trim") ? `${raw}.trim()` : raw;
1486
+ return modifiers.includes("number") ? `Number(${trimmed})` : trimmed;
1487
+ }
1488
+ function getTeleportToExpression(context, node) {
1489
+ const dynamicTarget = getAttr(node, ":to") ?? getAttr(node, "v-bind:to");
1490
+ if (dynamicTarget && dynamicTarget.value !== true) {
1491
+ return compileHydrationExpression(context, String(dynamicTarget.value), "Teleport to");
1492
+ }
1493
+ const staticTarget = getAttr(node, "to");
1494
+ if (staticTarget && staticTarget.value !== true) {
1495
+ return quote(staticTarget.value);
1496
+ }
1497
+ return "\"\"";
1498
+ }
1499
+ function getTeleportDisabledExpression(context, node) {
1500
+ const dynamicDisabled = getAttr(node, ":disabled") ?? getAttr(node, "v-bind:disabled");
1501
+ if (dynamicDisabled && dynamicDisabled.value !== true) {
1502
+ return compileHydrationExpression(context, String(dynamicDisabled.value), "Teleport disabled");
1503
+ }
1504
+ return getAttr(node, "disabled") ? "true" : "false";
1505
+ }
1506
+ function compileHydrationExpression(context, expression, usage) {
1507
+ return compileTemplateExpression(expression, usage, {
1508
+ source: context.source ?? expression,
1509
+ offset: 0,
1510
+ filename: context.filename
1511
+ });
1512
+ }
1513
+ function isIdentifier(value) {
1514
+ return /^[A-Za-z_$][\w$]*$/.test(value);
1515
+ }
1516
+ function withTemplateRefMode(context, mode, callback) {
1517
+ const previousMode = context.templateRefMode;
1518
+ context.templateRefMode = mode;
1519
+ try {
1520
+ return callback();
1521
+ }
1522
+ finally {
1523
+ context.templateRefMode = previousMode;
1524
+ }
1525
+ }
1526
+ function splitScript(script) {
1527
+ const imports = [];
1528
+ const body = [];
1529
+ for (const line of script.split(/\r?\n/)) {
1530
+ if (/^\s*import\s/.test(line))
1531
+ imports.push(line.trim());
1532
+ else
1533
+ body.push(line);
1534
+ }
1535
+ return { imports, body: body.join("\n") };
1536
+ }
1537
+ function emit(context, indent, line) {
1538
+ context.lines.push(`${" ".repeat(indent)}${line}`);
1539
+ }
1540
+ function emitRaw(context, source, indent = 0) {
1541
+ for (const line of source.split(/\r?\n/)) {
1542
+ context.lines.push(`${" ".repeat(indent)}${line}`);
1543
+ }
1544
+ }
1545
+ function nextName(context, prefix) {
1546
+ const name = `__mikuru_${prefix}_${context.index}`;
1547
+ context.index += 1;
1548
+ return name;
1549
+ }
1550
+ function quote(value) {
1551
+ return JSON.stringify(String(value));
1552
+ }
1553
+ //# sourceMappingURL=generateHydration.js.map