@fluixi/compiler 1.0.0-alpha.83 → 1.0.0-alpha.85

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 (241) hide show
  1. package/dist/analyze/expr-shape.cjs +62 -1
  2. package/dist/analyze/expr-shape.d.cts +14 -0
  3. package/dist/analyze/expr-shape.d.ts +2 -2
  4. package/dist/analyze/expr-shape.js +1 -1
  5. package/dist/analyze/expr-shape.mjs +41 -1
  6. package/dist/analyze/intrinsics.cjs +80 -1
  7. package/dist/analyze/intrinsics.d.cts +66 -0
  8. package/dist/analyze/intrinsics.d.ts +7 -7
  9. package/dist/analyze/intrinsics.d.ts.map +1 -1
  10. package/dist/analyze/intrinsics.js +3 -3
  11. package/dist/analyze/intrinsics.mjs +59 -1
  12. package/dist/analyze/paren.cjs +134 -0
  13. package/dist/analyze/paren.d.cts +23 -0
  14. package/dist/analyze/paren.d.ts +24 -0
  15. package/dist/analyze/paren.d.ts.map +1 -0
  16. package/dist/analyze/paren.js +168 -0
  17. package/dist/analyze/paren.mjs +113 -0
  18. package/dist/analyze/props-destructure.cjs +226 -1
  19. package/dist/analyze/props-destructure.d.cts +83 -0
  20. package/dist/analyze/props-destructure.d.ts +3 -3
  21. package/dist/analyze/props-destructure.d.ts.map +1 -1
  22. package/dist/analyze/props-destructure.js +4 -4
  23. package/dist/analyze/props-destructure.mjs +205 -1
  24. package/dist/analyze/reactive-bindings.cjs +190 -1
  25. package/dist/analyze/reactive-bindings.d.cts +42 -0
  26. package/dist/analyze/reactive-bindings.d.ts +1 -1
  27. package/dist/analyze/reactive-bindings.js +2 -2
  28. package/dist/analyze/reactive-bindings.mjs +167 -1
  29. package/dist/analyze/reactive-expr.cjs +38 -1
  30. package/dist/analyze/reactive-expr.d.cts +38 -0
  31. package/dist/analyze/reactive-expr.d.ts +4 -4
  32. package/dist/analyze/reactive-expr.d.ts.map +1 -1
  33. package/dist/analyze/reactive-expr.js +2 -2
  34. package/dist/analyze/reactive-expr.mjs +17 -1
  35. package/dist/analyze/static-graph.cjs +811 -1
  36. package/dist/analyze/static-graph.d.cts +102 -0
  37. package/dist/analyze/static-graph.d.ts +1 -1
  38. package/dist/analyze/static-graph.d.ts.map +1 -1
  39. package/dist/analyze/static-graph.js +11 -11
  40. package/dist/analyze/static-graph.mjs +793 -1
  41. package/dist/babel-TGY76XJ7.mjs +636 -0
  42. package/dist/chunk-4PLHS2FP.mjs +158 -0
  43. package/dist/chunk-6DB5FXS4.mjs +1718 -0
  44. package/dist/chunk-F74GFKSL.mjs +16 -0
  45. package/dist/chunk-G6QC2WRJ.mjs +11 -0
  46. package/dist/chunk-RUDJDZAA.mjs +1078 -0
  47. package/dist/codegen/backend.cjs +18 -1
  48. package/dist/codegen/backend.d.cts +35 -0
  49. package/dist/codegen/backends/imperative.cjs +542 -1
  50. package/dist/codegen/backends/imperative.d.cts +11 -0
  51. package/dist/codegen/backends/imperative.d.ts +1 -1
  52. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  53. package/dist/codegen/backends/imperative.js +24 -20
  54. package/dist/codegen/backends/imperative.mjs +519 -1
  55. package/dist/codegen/contract.cjs +52 -1
  56. package/dist/codegen/contract.d.cts +24 -0
  57. package/dist/codegen/contract.d.ts +2 -2
  58. package/dist/codegen/contract.js +2 -2
  59. package/dist/codegen/contract.mjs +31 -1
  60. package/dist/codegen/partial-template.cjs +176 -1
  61. package/dist/codegen/partial-template.d.cts +61 -0
  62. package/dist/codegen/partial-template.d.ts +4 -4
  63. package/dist/codegen/partial-template.js +0 -0
  64. package/dist/codegen/partial-template.mjs +153 -1
  65. package/dist/codegen/serialize-static.cjs +125 -1
  66. package/dist/codegen/serialize-static.d.cts +38 -0
  67. package/dist/codegen/serialize-static.d.ts +3 -3
  68. package/dist/codegen/serialize-static.js +6 -6
  69. package/dist/codegen/serialize-static.mjs +104 -1
  70. package/dist/frontend/babel/build-ir-lit.cjs +1509 -1
  71. package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
  72. package/dist/frontend/babel/build-ir-lit.d.ts +2 -2
  73. package/dist/frontend/babel/build-ir-lit.mjs +1478 -1
  74. package/dist/frontend/babel/build-ir.cjs +1524 -1
  75. package/dist/frontend/babel/build-ir.d.cts +35 -0
  76. package/dist/frontend/babel/build-ir.d.ts +2 -2
  77. package/dist/frontend/babel/build-ir.js +2 -2
  78. package/dist/frontend/babel/build-ir.mjs +1495 -1
  79. package/dist/frontend/babel/index.cjs +2186 -1
  80. package/dist/frontend/babel/index.d.cts +33 -0
  81. package/dist/frontend/babel/index.d.ts +1 -1
  82. package/dist/frontend/babel/index.js +1 -1
  83. package/dist/frontend/babel/index.mjs +2156 -1
  84. package/dist/frontend/babel/lower-template.cjs +1507 -1
  85. package/dist/frontend/babel/lower-template.d.cts +23 -0
  86. package/dist/frontend/babel/lower-template.d.ts +1 -1
  87. package/dist/frontend/babel/lower-template.js +2 -2
  88. package/dist/frontend/babel/lower-template.mjs +1478 -1
  89. package/dist/frontend/babel/plugin.cjs +2132 -1
  90. package/dist/frontend/babel/plugin.d.cts +95 -0
  91. package/dist/frontend/babel/plugin.d.ts +5 -5
  92. package/dist/frontend/babel/plugin.d.ts.map +1 -1
  93. package/dist/frontend/babel/plugin.js +14 -14
  94. package/dist/frontend/babel/plugin.mjs +2103 -1
  95. package/dist/frontend/babel/server-functions.cjs +110 -1
  96. package/dist/frontend/babel/server-functions.d.cts +10 -0
  97. package/dist/frontend/babel/server-functions.mjs +89 -1
  98. package/dist/frontend/babel/types.cjs +18 -1
  99. package/dist/frontend/babel/types.d.cts +33 -0
  100. package/dist/frontend/types.cjs +18 -1
  101. package/dist/frontend/types.d.cts +25 -0
  102. package/dist/frontend/vocabulary.cjs +98 -0
  103. package/dist/frontend/vocabulary.d.cts +79 -0
  104. package/dist/frontend/vocabulary.d.ts +80 -0
  105. package/dist/frontend/vocabulary.d.ts.map +1 -0
  106. package/dist/frontend/vocabulary.js +124 -0
  107. package/dist/frontend/vocabulary.mjs +77 -0
  108. package/dist/index.cjs +1595 -14
  109. package/dist/index.d.cts +27 -0
  110. package/dist/index.d.ts +1 -1
  111. package/dist/index.js +4 -4
  112. package/dist/index.mjs +1575 -14
  113. package/dist/integrations.cjs +4312 -26
  114. package/dist/integrations.d.cts +215 -0
  115. package/dist/integrations.d.ts +9 -9
  116. package/dist/integrations.d.ts.map +1 -1
  117. package/dist/integrations.js +29 -8
  118. package/dist/integrations.mjs +536 -18
  119. package/dist/ir/nodes.cjs +18 -1
  120. package/dist/ir/nodes.d.cts +168 -0
  121. package/dist/ir/nodes.d.ts +6 -6
  122. package/dist/lower/compile-template.cjs +1356 -1
  123. package/dist/lower/compile-template.d.cts +69 -0
  124. package/dist/lower/compile-template.d.ts +3 -3
  125. package/dist/lower/compile-template.js +1 -1
  126. package/dist/lower/compile-template.mjs +1336 -1
  127. package/dist/lower/jsx.cjs +529 -1
  128. package/dist/lower/jsx.d.cts +25 -0
  129. package/dist/lower/jsx.d.ts +1 -1
  130. package/dist/lower/jsx.d.ts.map +1 -1
  131. package/dist/lower/jsx.js +6 -5
  132. package/dist/lower/jsx.mjs +506 -1
  133. package/dist/lower/template.cjs +1061 -1
  134. package/dist/lower/template.d.cts +53 -0
  135. package/dist/lower/template.d.ts +3 -3
  136. package/dist/lower/template.d.ts.map +1 -1
  137. package/dist/lower/template.js +12 -11
  138. package/dist/lower/template.mjs +1042 -1
  139. package/dist/lower/text.cjs +42 -1
  140. package/dist/lower/text.d.cts +10 -0
  141. package/dist/lower/text.d.ts +2 -2
  142. package/dist/lower/text.d.ts.map +1 -1
  143. package/dist/lower/text.js +2 -2
  144. package/dist/lower/text.mjs +21 -1
  145. package/dist/optimize/analyze-static.cjs +112 -1
  146. package/dist/optimize/analyze-static.d.cts +39 -0
  147. package/dist/optimize/analyze-static.d.ts +2 -2
  148. package/dist/optimize/analyze-static.js +2 -2
  149. package/dist/optimize/analyze-static.mjs +91 -1
  150. package/dist/optimize/collapse-strategies.cjs +90 -1
  151. package/dist/optimize/collapse-strategies.d.cts +30 -0
  152. package/dist/optimize/collapse-strategies.d.ts +3 -3
  153. package/dist/optimize/collapse-strategies.mjs +67 -1
  154. package/dist/options.cjs +33 -1
  155. package/dist/options.d.cts +39 -0
  156. package/dist/options.d.ts +2 -2
  157. package/dist/options.mjs +12 -1
  158. package/dist/resolve/builtins.cjs +73 -1
  159. package/dist/resolve/builtins.d.cts +68 -0
  160. package/dist/resolve/builtins.d.ts +8 -8
  161. package/dist/resolve/builtins.d.ts.map +1 -1
  162. package/dist/resolve/builtins.js +4 -4
  163. package/dist/resolve/builtins.mjs +53 -1
  164. package/dist/resolve/component-globals.cjs +234 -14
  165. package/dist/resolve/component-globals.d.cts +80 -0
  166. package/dist/resolve/component-globals.d.ts +5 -5
  167. package/dist/resolve/component-globals.js +10 -10
  168. package/dist/resolve/component-globals.mjs +211 -14
  169. package/dist/resolve/component-resolver.cjs +80 -1
  170. package/dist/resolve/component-resolver.d.cts +68 -0
  171. package/dist/resolve/component-resolver.d.ts +3 -3
  172. package/dist/resolve/component-resolver.d.ts.map +1 -1
  173. package/dist/resolve/component-resolver.js +3 -3
  174. package/dist/resolve/component-resolver.mjs +59 -1
  175. package/dist/resolve/load-directive.cjs +93 -1
  176. package/dist/resolve/load-directive.d.cts +53 -0
  177. package/dist/resolve/load-directive.d.ts +5 -5
  178. package/dist/resolve/load-directive.js +6 -6
  179. package/dist/resolve/load-directive.mjs +72 -1
  180. package/dist/resolve/resolve-ir.cjs +108 -1
  181. package/dist/resolve/resolve-ir.d.cts +53 -0
  182. package/dist/resolve/resolve-ir.d.ts +6 -6
  183. package/dist/resolve/resolve-ir.d.ts.map +1 -1
  184. package/dist/resolve/resolve-ir.js +1 -1
  185. package/dist/resolve/resolve-ir.mjs +85 -1
  186. package/dist/resolve/write-globals.cjs +319 -14
  187. package/dist/resolve/write-globals.d.cts +30 -0
  188. package/dist/resolve/write-globals.js +2 -2
  189. package/dist/resolve/write-globals.mjs +298 -14
  190. package/dist/server-fns-ZYWQTSZU.mjs +78 -0
  191. package/dist/server-functions-PCERFA7A.mjs +82 -0
  192. package/dist/transform/bindings.cjs +71 -1
  193. package/dist/transform/bindings.d.cts +16 -0
  194. package/dist/transform/bindings.d.ts +1 -1
  195. package/dist/transform/bindings.js +1 -1
  196. package/dist/transform/bindings.mjs +50 -1
  197. package/dist/transform/index.cjs +2732 -8
  198. package/dist/transform/index.d.cts +15 -0
  199. package/dist/transform/index.mjs +3773 -17
  200. package/dist/transform/intrinsics.cjs +216 -3
  201. package/dist/transform/intrinsics.d.cts +21 -0
  202. package/dist/transform/intrinsics.js +1 -1
  203. package/dist/transform/intrinsics.mjs +193 -3
  204. package/dist/transform/props.cjs +441 -3
  205. package/dist/transform/props.d.cts +45 -0
  206. package/dist/transform/props.d.ts +1 -1
  207. package/dist/transform/props.d.ts.map +1 -1
  208. package/dist/transform/props.js +4 -4
  209. package/dist/transform/props.mjs +1482 -12
  210. package/dist/transform/server-fn-id.cjs +35 -1
  211. package/dist/transform/server-fn-id.d.cts +9 -0
  212. package/dist/transform/server-fn-id.d.ts +1 -1
  213. package/dist/transform/server-fn-id.js +2 -2
  214. package/dist/transform/server-fn-id.mjs +14 -1
  215. package/dist/transform/server-fns.cjs +114 -2
  216. package/dist/transform/server-fns.d.cts +12 -0
  217. package/dist/transform/server-fns.js +3 -3
  218. package/dist/transform/server-fns.mjs +1155 -11
  219. package/dist/transform/source-locations.cjs +330 -1
  220. package/dist/transform/source-locations.d.cts +43 -0
  221. package/dist/transform/source-locations.d.ts +1 -1
  222. package/dist/transform/source-locations.js +5 -5
  223. package/dist/transform/source-locations.mjs +307 -1
  224. package/dist/transform/templates.cjs +2701 -7
  225. package/dist/transform/templates.d.cts +69 -0
  226. package/dist/transform/templates.d.ts +2 -2
  227. package/dist/transform/templates.d.ts.map +1 -1
  228. package/dist/transform/templates.js +7 -7
  229. package/dist/transform/templates.mjs +3743 -16
  230. package/dist/transform-RWDTQUF5.mjs +893 -0
  231. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  232. package/package.json +6 -5
  233. package/dist/babel-VXKH6MRQ.mjs +0 -1
  234. package/dist/chunk-3SAEGOMQ.mjs +0 -1
  235. package/dist/chunk-5KMMN5QP.mjs +0 -1
  236. package/dist/chunk-IBRM4W7I.mjs +0 -10
  237. package/dist/chunk-OHHZCYIQ.mjs +0 -1
  238. package/dist/chunk-YKZ54NVE.mjs +0 -1
  239. package/dist/server-fns-6QM243HC.mjs +0 -2
  240. package/dist/server-functions-E3LKCZ4R.mjs +0 -1
  241. package/dist/transform-C4ZXRVGP.mjs +0 -8
@@ -0,0 +1,893 @@
1
+ /*! @fluixi/compiler v1.0.0-alpha.85 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+ import {
3
+ analyzeStatic,
4
+ buildJsxIR,
5
+ collapseStrategies,
6
+ collectSourceEdits,
7
+ declaredNames,
8
+ imperativeBackend,
9
+ inlineTemplates,
10
+ isDeferred,
11
+ isReactiveShape,
12
+ lowerTemplate,
13
+ mayHaveReactiveCall,
14
+ resolveComponentSources,
15
+ resolveReactiveBindings,
16
+ shapeOf
17
+ } from "./chunk-6DB5FXS4.mjs";
18
+ import {
19
+ CORE_CONTROL_FLOW,
20
+ DOM_CONTROL_FLOW,
21
+ INTRINSICS,
22
+ ROUTER_COMPONENTS,
23
+ createComponentResolver,
24
+ isIntrinsicName,
25
+ mayHaveIntrinsic
26
+ } from "./chunk-4PLHS2FP.mjs";
27
+ import {
28
+ MagicString
29
+ } from "./chunk-RUDJDZAA.mjs";
30
+ import "./chunk-G6QC2WRJ.mjs";
31
+
32
+ // src/transform/templates.ts
33
+ import { parse as parse2 } from "@babel/parser";
34
+
35
+ // src/lower/compile-template.ts
36
+ function compilePieces(pieces, holes, options = {}) {
37
+ const used = /* @__PURE__ */ new Set();
38
+ const ir = lowerTemplate(pieces, [...holes], used, {
39
+ svg: options.svg,
40
+ ...options.sourceFile ? { sourceFile: options.sourceFile } : {},
41
+ ...options.positionAt ? { positionAt: options.positionAt } : {}
42
+ });
43
+ analyzeStatic(ir);
44
+ resolveComponentSources(ir, {
45
+ resolver: createComponentResolver(options.resolve ?? []),
46
+ modules: {
47
+ controlFlowModule: options.controlFlowModule ?? "@fluixi/dom",
48
+ coreModule: options.coreModule ?? "@fluixi/core",
49
+ routerModule: options.routerModule ?? "@fluixi/core/router"
50
+ },
51
+ strategyFor: (node) => node.load
52
+ });
53
+ collapseStrategies(ir);
54
+ const { code, imports, templates } = imperativeBackend.emit(ir, {
55
+ templateClone: options.templateClone,
56
+ partialTemplates: options.partialTemplates
57
+ });
58
+ for (const symbol of imports) used.add(symbol);
59
+ if (options.hoistTemplates) return { code, imports: [...used], ir, templates };
60
+ return { code: inlineTemplates(code, templates), imports: [...used], ir };
61
+ }
62
+
63
+ // src/transform/bindings.ts
64
+ function patternNames(node, out) {
65
+ if (!node) return;
66
+ switch (node.type) {
67
+ case "Identifier":
68
+ out.add(node.name);
69
+ return;
70
+ case "ObjectPattern":
71
+ for (const p of node.properties) {
72
+ if (p.type === "RestElement") patternNames(p.argument, out);
73
+ else patternNames(p.value, out);
74
+ }
75
+ return;
76
+ case "ArrayPattern":
77
+ for (const e of node.elements) patternNames(e, out);
78
+ return;
79
+ case "AssignmentPattern":
80
+ patternNames(node.left, out);
81
+ return;
82
+ case "RestElement":
83
+ patternNames(node.argument, out);
84
+ return;
85
+ }
86
+ }
87
+ function declared(node, out) {
88
+ switch (node.type) {
89
+ case "ImportDeclaration":
90
+ for (const s of node.specifiers) patternNames(s.local, out);
91
+ return;
92
+ case "VariableDeclaration":
93
+ for (const d of node.declarations) patternNames(d.id, out);
94
+ return;
95
+ case "FunctionDeclaration":
96
+ case "ClassDeclaration":
97
+ patternNames(node.id, out);
98
+ return;
99
+ case "ExportNamedDeclaration":
100
+ case "ExportDefaultDeclaration":
101
+ if (node.declaration) declared(node.declaration, out);
102
+ return;
103
+ }
104
+ }
105
+ function moduleBindings(program) {
106
+ const names = /* @__PURE__ */ new Set();
107
+ for (const statement of program.body) declared(statement, names);
108
+ return names;
109
+ }
110
+
111
+ // src/transform/props.ts
112
+ import { parse } from "@babel/parser";
113
+
114
+ // src/analyze/props-destructure.ts
115
+ function patternNames2(node, out) {
116
+ if (!node) return;
117
+ switch (node.type) {
118
+ case "Identifier":
119
+ out.add(node.name);
120
+ return;
121
+ case "ObjectPattern":
122
+ for (const p of node.properties) {
123
+ if (p.type === "RestElement") patternNames2(p.argument, out);
124
+ else patternNames2(p.value, out);
125
+ }
126
+ return;
127
+ case "ArrayPattern":
128
+ for (const e of node.elements) patternNames2(e, out);
129
+ return;
130
+ case "AssignmentPattern":
131
+ patternNames2(node.left, out);
132
+ return;
133
+ case "RestElement":
134
+ patternNames2(node.argument, out);
135
+ return;
136
+ }
137
+ }
138
+ function isSafeDefault(node) {
139
+ switch (node.type) {
140
+ case "StringLiteral":
141
+ case "NumericLiteral":
142
+ case "BooleanLiteral":
143
+ case "NullLiteral":
144
+ case "BigIntLiteral":
145
+ case "RegExpLiteral":
146
+ case "Identifier":
147
+ return true;
148
+ // ESTree spells every literal as `Literal`; both shapes reach this analysis.
149
+ case "Literal":
150
+ return true;
151
+ case "TemplateLiteral":
152
+ return node.expressions.every(isSafeDefault);
153
+ case "UnaryExpression":
154
+ return isSafeDefault(node.argument);
155
+ case "MemberExpression":
156
+ return false;
157
+ default:
158
+ return false;
159
+ }
160
+ }
161
+ function walk(root, visit) {
162
+ if (!root || typeof root !== "object") return;
163
+ visit(root);
164
+ for (const key of Object.keys(root)) {
165
+ if (key === "loc" || key === "range" || key === "leadingComments" || key === "trailingComments") continue;
166
+ const value = root[key];
167
+ if (Array.isArray(value)) {
168
+ for (const item of value) if (item && typeof item === "object") walk(item, visit);
169
+ } else if (value && typeof value === "object" && typeof value.type === "string") {
170
+ walk(value, visit);
171
+ }
172
+ }
173
+ }
174
+ function reassignedNames(body) {
175
+ const written = /* @__PURE__ */ new Set();
176
+ walk(body, (node) => {
177
+ if (node.type === "AssignmentExpression") patternNames2(node.left, written);
178
+ else if (node.type === "UpdateExpression") {
179
+ const arg = node.argument;
180
+ if (arg?.type === "Identifier") written.add(arg.name);
181
+ }
182
+ });
183
+ return written;
184
+ }
185
+ function shadowedNames(body, candidates) {
186
+ const shadowed = /* @__PURE__ */ new Set();
187
+ const note = (node) => {
188
+ const names = /* @__PURE__ */ new Set();
189
+ patternNames2(node, names);
190
+ for (const n of names) if (candidates.has(n)) shadowed.add(n);
191
+ };
192
+ walk(body, (node) => {
193
+ switch (node.type) {
194
+ case "VariableDeclarator":
195
+ note(node.id);
196
+ return;
197
+ case "FunctionDeclaration":
198
+ case "FunctionExpression":
199
+ case "ArrowFunctionExpression":
200
+ note(node.id);
201
+ for (const p of node.params ?? []) note(p);
202
+ return;
203
+ case "CatchClause":
204
+ note(node.param);
205
+ return;
206
+ case "ClassDeclaration":
207
+ case "ClassExpression":
208
+ note(node.id);
209
+ return;
210
+ }
211
+ });
212
+ return shadowed;
213
+ }
214
+ function collect(pattern, path, plan) {
215
+ for (const property of pattern.properties ?? []) {
216
+ if (property.type === "RestElement") {
217
+ const argument = property.argument;
218
+ if (argument?.type !== "Identifier" || path.length > 0) {
219
+ const names2 = /* @__PURE__ */ new Set();
220
+ patternNames2(argument, names2);
221
+ for (const name of names2) plan.bails.push({ name, reason: "rest" });
222
+ continue;
223
+ }
224
+ plan.rest = { name: argument.name, keys: [] };
225
+ continue;
226
+ }
227
+ if (property.computed) {
228
+ const names2 = /* @__PURE__ */ new Set();
229
+ patternNames2(property.value, names2);
230
+ for (const name of names2) plan.bails.push({ name, reason: "computed" });
231
+ continue;
232
+ }
233
+ const key = property.key;
234
+ const propertyName = key.type === "Identifier" ? key.name : key.value;
235
+ let value = property.value;
236
+ let fallback;
237
+ if (value.type === "AssignmentPattern") {
238
+ fallback = value.right;
239
+ value = value.left;
240
+ }
241
+ const here = [...path, propertyName];
242
+ if (value.type === "Identifier") {
243
+ if (fallback && !isSafeDefault(fallback)) {
244
+ plan.bails.push({ name: value.name, reason: "unsafe-default" });
245
+ continue;
246
+ }
247
+ plan.reads.push({ name: value.name, path: here, ...fallback ? { fallback } : {} });
248
+ continue;
249
+ }
250
+ if (value.type === "ObjectPattern") {
251
+ if (fallback) {
252
+ const names2 = /* @__PURE__ */ new Set();
253
+ patternNames2(value, names2);
254
+ for (const name of names2) plan.bails.push({ name, reason: "unsafe-default" });
255
+ continue;
256
+ }
257
+ collect(value, here, plan);
258
+ continue;
259
+ }
260
+ const names = /* @__PURE__ */ new Set();
261
+ patternNames2(value, names);
262
+ for (const name of names) plan.bails.push({ name, reason: "computed" });
263
+ }
264
+ }
265
+ function planPropsDestructure(pattern, body) {
266
+ const plan = { reads: [], bails: [] };
267
+ if (pattern?.type !== "ObjectPattern") return plan;
268
+ collect(pattern, [], plan);
269
+ if (plan.rest) {
270
+ if (body?.type !== "BlockStatement") {
271
+ plan.bails.push({ name: plan.rest.name, reason: "rest" });
272
+ delete plan.rest;
273
+ } else {
274
+ plan.rest.keys = (pattern.properties ?? []).filter((p) => p.type !== "RestElement" && !p.computed).map((p) => {
275
+ const key = p.key;
276
+ return key.type === "Identifier" ? key.name : key.value;
277
+ });
278
+ }
279
+ }
280
+ if (plan.reads.length === 0 && !plan.rest) return plan;
281
+ const candidates = new Set(plan.reads.map((r) => r.name));
282
+ if (plan.rest) candidates.add(plan.rest.name);
283
+ const written = reassignedNames(body);
284
+ const shadowed = shadowedNames(body, candidates);
285
+ const kept = [];
286
+ for (const read of plan.reads) {
287
+ if (written.has(read.name)) plan.bails.push({ name: read.name, reason: "reassigned" });
288
+ else if (shadowed.has(read.name)) plan.bails.push({ name: read.name, reason: "shadowed" });
289
+ else kept.push(read);
290
+ }
291
+ plan.reads = kept;
292
+ if (plan.rest && written.has(plan.rest.name)) {
293
+ plan.bails.push({ name: plan.rest.name, reason: "reassigned" });
294
+ delete plan.rest;
295
+ } else if (plan.rest && shadowed.has(plan.rest.name)) {
296
+ plan.bails.push({ name: plan.rest.name, reason: "shadowed" });
297
+ delete plan.rest;
298
+ }
299
+ return plan;
300
+ }
301
+ function explainBail(reason) {
302
+ switch (reason) {
303
+ case "rest":
304
+ return "this rest element cannot be served by splitProps, and copying the props into a plain object would lose the getters";
305
+ case "computed":
306
+ return "the property is not known until it runs";
307
+ case "reassigned":
308
+ return "the binding is assigned to, and props are read-only";
309
+ case "shadowed":
310
+ return "an inner scope binds the same name";
311
+ case "unsafe-default":
312
+ return "the default would have to run again on every read";
313
+ }
314
+ }
315
+
316
+ // src/transform/props.ts
317
+ function walk2(root, visit, parent = null) {
318
+ if (!root || typeof root !== "object" || typeof root.type !== "string") return;
319
+ if (root.type.startsWith("TS")) return;
320
+ if (visit(root, parent) === false) return;
321
+ for (const key of Object.keys(root)) {
322
+ if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
323
+ const value = root[key];
324
+ if (Array.isArray(value)) {
325
+ for (const item of value) walk2(item, visit, root);
326
+ } else if (value && typeof value === "object") {
327
+ walk2(value, visit, root);
328
+ }
329
+ }
330
+ }
331
+ function isComponentName(name) {
332
+ return !!name && name[0] >= "A" && name[0] <= "Z";
333
+ }
334
+ function componentFunctions(program) {
335
+ const found = [];
336
+ walk2(program, (node) => {
337
+ if (node.type === "FunctionDeclaration" && isComponentName(node.id?.name)) {
338
+ found.push(node);
339
+ return;
340
+ }
341
+ if (node.type === "VariableDeclarator" && isComponentName(node.id?.name)) {
342
+ const init = node.init;
343
+ if (init && (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression")) found.push(init);
344
+ }
345
+ });
346
+ return found;
347
+ }
348
+ function usedNames(fn) {
349
+ const names = /* @__PURE__ */ new Set();
350
+ walk2(fn, (node) => {
351
+ if (node.type === "Identifier") names.add(node.name);
352
+ });
353
+ return names;
354
+ }
355
+ function isReferencePosition(node, parent) {
356
+ if (!parent) return true;
357
+ switch (parent.type) {
358
+ case "MemberExpression":
359
+ case "OptionalMemberExpression":
360
+ return !(parent.property === node && !parent.computed);
361
+ case "ObjectProperty":
362
+ case "ObjectMethod":
363
+ case "ClassProperty":
364
+ case "ClassMethod":
365
+ return !(parent.key === node && !parent.computed);
366
+ case "LabeledStatement":
367
+ case "BreakStatement":
368
+ case "ContinueStatement":
369
+ return parent.label !== node;
370
+ case "ImportSpecifier":
371
+ case "ExportSpecifier":
372
+ return false;
373
+ default:
374
+ return true;
375
+ }
376
+ }
377
+ function collectPropsEdits(program, code, options = {}) {
378
+ const edits = [];
379
+ const diagnostics = [];
380
+ const used = /* @__PURE__ */ new Set();
381
+ for (const fn of componentFunctions(program)) {
382
+ const pattern = fn.params?.[0];
383
+ if (pattern?.type !== "ObjectPattern") continue;
384
+ const plan = planPropsDestructure(pattern, fn.body);
385
+ for (const b of plan.bails) {
386
+ diagnostics.push({ name: b.name, reason: b.reason, message: explainBail(b.reason), start: pattern.start });
387
+ }
388
+ if (plan.bails.length > 0) continue;
389
+ if (plan.reads.length === 0 && !plan.rest) continue;
390
+ const taken = usedNames(fn);
391
+ let parameter = options.parameterName ?? "props";
392
+ while (taken.has(parameter)) parameter = `_${parameter}`;
393
+ const replacement = /* @__PURE__ */ new Map();
394
+ for (const read of plan.reads) {
395
+ const access = `${parameter}.${read.path.join(".")}`;
396
+ const fallback = read.fallback;
397
+ replacement.set(
398
+ read.name,
399
+ fallback ? `(${access} === undefined ? ${code.slice(fallback.start, fallback.end)} : ${access})` : access
400
+ );
401
+ }
402
+ const annotation = pattern.typeAnnotation;
403
+ edits.push({ start: pattern.start, end: annotation?.start ?? pattern.end, code: parameter });
404
+ if (plan.rest) {
405
+ const keys = plan.rest.keys.map((k) => JSON.stringify(k)).join(", ");
406
+ const body = fn.body;
407
+ edits.push({
408
+ start: body.start + 1,
409
+ end: body.start + 1,
410
+ code: `
411
+ const [, ${plan.rest.name}] = splitProps(${parameter}, [${keys}]);`
412
+ });
413
+ used.add("splitProps");
414
+ }
415
+ const matches = [];
416
+ walk2(fn.body, (node, parent) => {
417
+ if (node.type !== "Identifier") return void 0;
418
+ const text = replacement.get(node.name);
419
+ if (!text) return void 0;
420
+ const shorthand = parent?.type === "ObjectProperty" && parent.shorthand && parent.value === node;
421
+ if (!shorthand && !isReferencePosition(node, parent)) return void 0;
422
+ const path = plan.reads.find((r) => r.name === node.name).path;
423
+ matches.push({ node, parent: shorthand ? parent : null, text, property: path[path.length - 1] });
424
+ return void 0;
425
+ });
426
+ for (const match of matches) {
427
+ if (match.parent) {
428
+ edits.push({ start: match.parent.start, end: match.parent.end, code: `${match.node.name}: ${match.text}` });
429
+ } else {
430
+ edits.push({ start: match.node.start, end: match.node.end, code: match.text });
431
+ }
432
+ asMemberRead(match.node, parameter, match.property);
433
+ }
434
+ }
435
+ return { edits, diagnostics, used };
436
+ }
437
+ function asMemberRead(node, parameter, property) {
438
+ node.type = "MemberExpression";
439
+ node.computed = false;
440
+ node.optional = false;
441
+ node.object = { type: "Identifier", name: parameter, start: node.start, end: node.start };
442
+ node.property = { type: "Identifier", name: property, start: node.end, end: node.end };
443
+ delete node["name"];
444
+ }
445
+ function transformProps(code, filename = "module.tsx", options = {}) {
446
+ const ast = parse(code, {
447
+ sourceType: "module",
448
+ plugins: ["typescript", "jsx"],
449
+ errorRecovery: true
450
+ });
451
+ const { edits, diagnostics, used } = collectPropsEdits(ast.program, code, options);
452
+ const source = new MagicString(code);
453
+ for (const e of edits) {
454
+ if (e.start === e.end) source.appendLeft(e.start, e.code);
455
+ else source.overwrite(e.start, e.end, e.code);
456
+ }
457
+ if (used.has("splitProps") && !moduleBindings(ast.program).has("splitProps")) {
458
+ source.prepend(`import { splitProps } from ${JSON.stringify(options.runtimeModule ?? "@fluixi/dom")};
459
+ `);
460
+ }
461
+ return {
462
+ code: source.toString(),
463
+ map: source.generateMap({ source: filename, includeContent: true, hires: true }),
464
+ diagnostics,
465
+ rewritten: edits.filter((e) => e.code !== (options.parameterName ?? "props")).length
466
+ };
467
+ }
468
+
469
+ // src/transform/intrinsics.ts
470
+ function walk3(root, visit) {
471
+ if (!root || typeof root !== "object" || typeof root.type !== "string") return;
472
+ visit(root);
473
+ for (const key of Object.keys(root)) {
474
+ if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
475
+ const value = root[key];
476
+ if (Array.isArray(value)) for (const item of value) walk3(item, visit);
477
+ else if (value && typeof value === "object") walk3(value, visit);
478
+ }
479
+ }
480
+ function collectIntrinsicEdits(program) {
481
+ const edits = [];
482
+ const diagnostics = [];
483
+ const imports = /* @__PURE__ */ new Map();
484
+ const reported = /* @__PURE__ */ new Set();
485
+ const { shadowed } = resolveReactiveBindings(program);
486
+ walk3(program, (node) => {
487
+ if (node.type !== "CallExpression") return;
488
+ const callee = node.callee;
489
+ if (callee?.type !== "Identifier") return;
490
+ const name = callee.name;
491
+ if (!isIntrinsicName(name)) return;
492
+ if (shadowed.has(name)) {
493
+ if (!reported.has(name)) {
494
+ reported.add(name);
495
+ diagnostics.push({
496
+ name,
497
+ message: `${name} is reserved for the compiler, and this module binds it. The call keeps your binding's meaning; rename it to use the intrinsic.`,
498
+ start: callee.start
499
+ });
500
+ }
501
+ return;
502
+ }
503
+ const intrinsic = INTRINSICS[name];
504
+ edits.push({ start: callee.start, end: callee.end, code: intrinsic.export });
505
+ const forModule = imports.get(intrinsic.module) ?? /* @__PURE__ */ new Set();
506
+ forModule.add(intrinsic.export);
507
+ imports.set(intrinsic.module, forModule);
508
+ });
509
+ return { edits, diagnostics, imports };
510
+ }
511
+ function intrinsicImports(result, bound) {
512
+ const lines = [];
513
+ for (const [module, names] of [...result.imports].sort(([a], [b]) => a.localeCompare(b))) {
514
+ const wanted = [...names].filter((name) => !bound.has(name)).sort();
515
+ if (wanted.length) lines.push(`import { ${wanted.join(", ")} } from ${JSON.stringify(module)};`);
516
+ }
517
+ return lines.length ? `${lines.join("\n")}
518
+ ` : "";
519
+ }
520
+
521
+ // src/transform/templates.ts
522
+ var CONTROL_FLOW = new Set(DOM_CONTROL_FLOW);
523
+ var CORE_ONLY = new Set(CORE_CONTROL_FLOW);
524
+ var ROUTER = new Set(ROUTER_COMPONENTS);
525
+ var REACTIVE = /* @__PURE__ */ new Set([
526
+ "createMemo",
527
+ "createEffect",
528
+ "createRenderEffect",
529
+ "createRoot",
530
+ "createSignal",
531
+ "onCleanup",
532
+ "batch",
533
+ "untrack"
534
+ ]);
535
+ function walk4(node, visit, parent = null, key = "") {
536
+ if (!node || typeof node !== "object") return;
537
+ if (Array.isArray(node)) {
538
+ for (const child of node) walk4(child, visit, parent, key);
539
+ return;
540
+ }
541
+ if (typeof node.type === "string") visit(node, parent, key);
542
+ for (const k of Object.keys(node)) {
543
+ if (k === "loc" || k === "leadingComments" || k === "trailingComments") continue;
544
+ walk4(node[k], visit, typeof node.type === "string" ? node : parent, k);
545
+ }
546
+ }
547
+ var isJsx = (node) => node.type === "JSXElement" || node.type === "JSXFragment";
548
+ function isJsxRoot(node, parent, key) {
549
+ if (!isJsx(node)) return false;
550
+ return !(parent && isJsx(parent) && key === "children");
551
+ }
552
+ function isTemplateTag(node, litTag) {
553
+ return node.type === "TaggedTemplateExpression" && node.tag?.type === "Identifier" && (node.tag.name === litTag || node.tag.name === "svg");
554
+ }
555
+ function outermost(list) {
556
+ return list.filter(
557
+ (e) => !list.some(
558
+ (o) => o !== e && o.start <= e.start && o.end >= e.end && o.end - o.start > e.end - e.start && // An insertion at either edge of the container sits beside it, not inside it, so
559
+ // it is not something the container's code already folded in. A statement can
560
+ // start where its callee starts (`$effect(…)`) and a declarator can end where its
561
+ // JSX ends (`const Row = () => <b/>`).
562
+ !(e.start === e.end && (e.start === o.start || e.start === o.end))
563
+ )
564
+ );
565
+ }
566
+ function slice(code, start, end, edits) {
567
+ const inside = outermost(edits.filter((e) => e.start >= start && e.end <= end)).sort((a, b) => b.start - a.start);
568
+ let out = code.slice(start, end);
569
+ for (const e of inside) out = out.slice(0, e.start - start) + e.code + out.slice(e.end - start);
570
+ return out;
571
+ }
572
+ function bindHole(code, expr, edits, keepPosition = false) {
573
+ const at = keepPosition ? expr.loc?.start : void 0;
574
+ const hole = {
575
+ code: slice(code, expr.start, expr.end, edits),
576
+ reactive: isReactiveShape(shapeOf(expr)),
577
+ // Where the `${…}` is, so a binding made from it can say so. The source map cannot:
578
+ // the whole template is one overwrite. Only when source locations were asked for.
579
+ ...at ? { at: { line: at.line, column: at.column } } : {}
580
+ };
581
+ if (expr.type === "ArrowFunctionExpression" && expr.body?.type !== "BlockStatement") {
582
+ hole.arrow = {
583
+ params: expr.params.map((p) => slice(code, p.start, p.end, edits)),
584
+ body: slice(code, expr.body.start, expr.body.end, edits),
585
+ bodyReactive: isReactiveShape(shapeOf(expr.body))
586
+ };
587
+ }
588
+ if (expr.type === "ObjectExpression") hole.object = true;
589
+ return hole;
590
+ }
591
+ function adoptTemplates(code, templates, hoisted) {
592
+ if (!templates || templates.length === 0) return code;
593
+ const rename = /* @__PURE__ */ new Map();
594
+ for (const tpl of templates) {
595
+ const key = `${tpl.svg ? "svg:" : ""}${tpl.html}`;
596
+ let name = hoisted.get(key);
597
+ if (!name) {
598
+ name = `_fxTmpl$${hoisted.size}`;
599
+ hoisted.set(key, name);
600
+ }
601
+ rename.set(tpl.id, name);
602
+ }
603
+ return code.replace(/_tmpl\$\d+/g, (id) => rename.get(id) ?? id);
604
+ }
605
+ function collectNeeds(node, out) {
606
+ if (node.kind === "component" && node.load && !node.source && isDeferred(node.load)) {
607
+ if (!out.ignoredLoad.has(node.name)) out.ignoredLoad.set(node.name, node.load);
608
+ }
609
+ if (node.kind === "component" && node.source) {
610
+ const src = node.source;
611
+ if (src.origin === "builtin") out.builtins.add(node.name);
612
+ else if (isDeferred(src.loading) && !out.resolved.has(node.name)) out.deferred.set(node.name, src);
613
+ else {
614
+ out.deferred.delete(node.name);
615
+ out.resolved.set(node.name, src);
616
+ }
617
+ }
618
+ if ("props" in node && node.props) {
619
+ for (const p of node.props) {
620
+ if (p.kind === "event" && p.event?.delegated) out.delegatedEvents.add(p.event.name);
621
+ }
622
+ }
623
+ if ("children" in node && node.children) for (const c of node.children) collectNeeds(c, out);
624
+ }
625
+ function deferrableImport(program, name) {
626
+ for (const statement of program.body ?? []) {
627
+ if (statement.type !== "ImportDeclaration") continue;
628
+ for (const specifier of statement.specifiers ?? []) {
629
+ if (specifier.local?.name !== name) continue;
630
+ if (specifier.type === "ImportNamespaceSpecifier") return void 0;
631
+ const exported = specifier.type === "ImportDefaultSpecifier" ? "default" : specifier.imported?.name ?? specifier.imported?.value;
632
+ return { module: statement.source.value, export: exported, declaration: statement, specifier };
633
+ }
634
+ }
635
+ return void 0;
636
+ }
637
+ function hasNamespaceImport(program, name) {
638
+ for (const statement of program.body ?? []) {
639
+ if (statement.type !== "ImportDeclaration") continue;
640
+ for (const specifier of statement.specifiers ?? []) {
641
+ if (specifier.type === "ImportNamespaceSpecifier" && specifier.local?.name === name) return true;
642
+ }
643
+ }
644
+ return false;
645
+ }
646
+ function usedAsValue(program, name, specifier) {
647
+ let seen = false;
648
+ walk4(program, (node) => {
649
+ if (seen || node.type !== "Identifier" || node.name !== name) return;
650
+ if (node.start === specifier.local?.start && node.end === specifier.local?.end) return;
651
+ seen = true;
652
+ });
653
+ return seen;
654
+ }
655
+ function strategyLiteral(s) {
656
+ const parts = [`kind: ${JSON.stringify(s.kind)}`];
657
+ if (s.kind === "visible" && s.rootMargin) parts.push(`rootMargin: ${JSON.stringify(s.rootMargin)}`);
658
+ if (s.kind === "interaction") parts.push(`events: ${JSON.stringify(s.events)}`);
659
+ if (s.kind === "media") parts.push(`query: ${JSON.stringify(s.query)}`);
660
+ return `{ ${parts.join(", ")} }`;
661
+ }
662
+ function positionsIn(code) {
663
+ const starts = [0];
664
+ for (let i = 0; i < code.length; i++) if (code.charCodeAt(i) === 10) starts.push(i + 1);
665
+ return (offset) => {
666
+ let low = 0;
667
+ let high = starts.length - 1;
668
+ while (low < high) {
669
+ const mid = low + high + 1 >> 1;
670
+ if (starts[mid] <= offset) low = mid;
671
+ else high = mid - 1;
672
+ }
673
+ return { line: low + 1, column: offset - starts[low] };
674
+ };
675
+ }
676
+ function toPieces(node) {
677
+ const pieces = [];
678
+ node.quasi.quasis.forEach((q, i) => {
679
+ pieces.push({ kind: "static", text: q.value.cooked ?? q.value.raw, start: q.start });
680
+ if (i < node.quasi.expressions.length) {
681
+ const e = node.quasi.expressions[i];
682
+ pieces.push({ kind: "hole", index: i, start: e.start, end: e.end });
683
+ }
684
+ });
685
+ return pieces;
686
+ }
687
+ function relativeToRoot(id, root) {
688
+ if (!root) return id;
689
+ const base = root.endsWith("/") ? root : `${root}/`;
690
+ return id.startsWith(base) ? id.slice(base.length) : id;
691
+ }
692
+ function transformTemplates(code, id, options = {}) {
693
+ const litTag = options.litTag ?? "html";
694
+ const format = options.format ?? "both";
695
+ const wantsLit = format !== "jsx";
696
+ const wantsJsx = format !== "lit";
697
+ const mayHaveTemplate = wantsLit && (code.includes(`${litTag}\``) || code.includes("svg`"));
698
+ const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
699
+ const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
700
+ const sourceName = relativeToRoot(id, options.sourceRoot);
701
+ if (!mayHaveTemplate && !(wantsJsx && code.includes("<")) && !wantsIntrinsics && !wantsSources) return null;
702
+ const ast = parse2(code, {
703
+ sourceType: "module",
704
+ plugins: ["jsx", "typescript"],
705
+ errorRecovery: true
706
+ });
707
+ const found = [];
708
+ walk4(ast.program, (n, parent, key) => {
709
+ if (wantsLit && isTemplateTag(n, litTag)) found.push(n);
710
+ else if (wantsJsx && isJsxRoot(n, parent, key)) found.push(n);
711
+ });
712
+ const props = options.propsDestructure === false ? { edits: [], diagnostics: [], used: /* @__PURE__ */ new Set() } : collectPropsEdits(ast.program, code, { runtimeModule: options.runtimeModule });
713
+ const intrinsics = options.intrinsics === false ? { edits: [], diagnostics: [], imports: /* @__PURE__ */ new Map() } : collectIntrinsicEdits(ast.program);
714
+ const sources = options.sourceLocations === true ? collectSourceEdits(ast.program, sourceName) : { edits: [], marked: 0 };
715
+ const silent = found.length === 0 && props.edits.length === 0 && sources.edits.length === 0 && intrinsics.edits.length === 0 && intrinsics.diagnostics.length === 0 && props.diagnostics.length === 0;
716
+ if (silent) return null;
717
+ found.sort((a, b) => b.start - a.start || a.end - b.end);
718
+ const used = new Set(props.used);
719
+ const needs = {
720
+ builtins: /* @__PURE__ */ new Set(),
721
+ resolved: /* @__PURE__ */ new Map(),
722
+ deferred: /* @__PURE__ */ new Map(),
723
+ delegatedEvents: /* @__PURE__ */ new Set(),
724
+ ignoredLoad: /* @__PURE__ */ new Map(),
725
+ unresolved: /* @__PURE__ */ new Set(),
726
+ declared: declaredNames(ast.program)
727
+ };
728
+ const hoisted = /* @__PURE__ */ new Map();
729
+ const edits = [...props.edits, ...intrinsics.edits, ...sources.edits];
730
+ for (const node of found) {
731
+ const nested = found.some(
732
+ (o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start
733
+ );
734
+ if (isJsx(node)) {
735
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName) });
736
+ continue;
737
+ }
738
+ const holes = node.quasi.expressions.map(
739
+ (e) => bindHole(code, e, edits, options.sourceLocations === true)
740
+ );
741
+ const result = compilePieces(toPieces(node), holes, {
742
+ ...options,
743
+ hoistTemplates: true,
744
+ // A tag inside a template gets the same mark a JSX tag does. Without one, the nodes it
745
+ // makes are the only ones in the module carrying no mark, and they take whichever was
746
+ // left behind by the last declaration that did.
747
+ ...options.sourceLocations === true ? { sourceFile: sourceName, positionAt: positionsIn(code) } : {},
748
+ // Same defaults as the plugin, so moving a build over is not a rendering change.
749
+ templateClone: options.templateClone ?? true,
750
+ partialTemplates: nested ? false : options.partialTemplates ?? true,
751
+ svg: node.tag.name === "svg"
752
+ });
753
+ for (const symbol of result.imports) used.add(symbol);
754
+ collectNeeds(result.ir, needs);
755
+ edits.push({ start: node.start, end: node.end, code: adoptTemplates(result.code, result.templates, hoisted) });
756
+ }
757
+ const out = new MagicString(code);
758
+ for (const e of outermost(edits)) {
759
+ if (e.start === e.end) out.appendLeft(e.start, e.code);
760
+ else out.overwrite(e.start, e.end, e.code);
761
+ }
762
+ const bound = moduleBindings(ast.program);
763
+ const why = /* @__PURE__ */ new Map();
764
+ for (const [name] of needs.ignoredLoad) {
765
+ if (!bound.has(name)) why.set(name, "unsupplied");
766
+ }
767
+ for (const [name, strategy] of [...needs.ignoredLoad]) {
768
+ if (!bound.has(name)) continue;
769
+ const found2 = deferrableImport(ast.program, name);
770
+ if (!found2) {
771
+ why.set(name, hasNamespaceImport(ast.program, name) ? "namespace" : "local");
772
+ continue;
773
+ }
774
+ if (usedAsValue(ast.program, name, found2.specifier)) {
775
+ why.set(name, "value");
776
+ continue;
777
+ }
778
+ const rest = found2.declaration.specifiers.filter((sp) => sp !== found2.specifier);
779
+ const end = rest.length === 0 && code[found2.declaration.end] === "\n" ? found2.declaration.end + 1 : found2.declaration.end;
780
+ out.overwrite(
781
+ found2.declaration.start,
782
+ end,
783
+ rest.length === 0 ? "" : `import { ${rest.map((sp) => code.slice(sp.start, sp.end)).join(", ")} } from ${JSON.stringify(found2.declaration.source.value)};`
784
+ );
785
+ needs.deferred.set(name, { module: found2.module, export: found2.export, origin: "rule", loading: strategy });
786
+ bound.delete(name);
787
+ needs.ignoredLoad.delete(name);
788
+ }
789
+ const prologue = buildPrologue(used, needs, hoisted, bound, options);
790
+ if (prologue) out.prepend(prologue);
791
+ const runtimeImports = intrinsicImports(intrinsics, bound);
792
+ if (runtimeImports) out.prepend(runtimeImports);
793
+ const reasons = {
794
+ value: (name) => `${name} is used as a value here, not only as a tag, so its import has to stay — deferring would hand those references a lazy wrapper instead of the component. Defer it at the point it is rendered, or keep it eager.`,
795
+ namespace: (name) => `${name} came in through a namespace import, which has no single export to defer. Import ${name} by name.`,
796
+ local: (name) => `${name} is declared in this file, so there is no module to load separately. Move it to its own file and import it.`,
797
+ unsupplied: (name) => `nothing supplies ${name}, so there is no import to defer. Import it, or add a \`resolve\` rule for it.`
798
+ };
799
+ const loadDiagnostics = [...needs.ignoredLoad].map(([name, strategy]) => ({
800
+ name,
801
+ strategy,
802
+ message: `load:${strategy.kind} has no effect on <${name}>: ${reasons[why.get(name) ?? "unsupplied"](name)}`
803
+ }));
804
+ const unresolvedDiagnostics = [...needs.unresolved].map((name) => ({
805
+ name,
806
+ message: `<${name}> is not defined: nothing imports it and no \`resolve\` rule supplies it. This compiles to a reference to a name that does not exist, so the component renders nothing. Import ${name}, or add a \`resolve\` rule for it.`
807
+ }));
808
+ return {
809
+ code: out.toString(),
810
+ map: out.generateMap({ source: id, includeContent: true, hires: true }),
811
+ ...loadDiagnostics.length ? { loadDiagnostics } : {},
812
+ ...unresolvedDiagnostics.length ? { unresolvedDiagnostics } : {},
813
+ ...props.diagnostics.length ? { propsDiagnostics: props.diagnostics } : {},
814
+ ...intrinsics.diagnostics.length ? { intrinsicDiagnostics: intrinsics.diagnostics } : {}
815
+ };
816
+ }
817
+ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile) {
818
+ const ir = buildJsxIR(node, {
819
+ code: (n) => slice(code, n.start, n.end, edits),
820
+ used,
821
+ ...options.sourceLocations === true && sourceFile ? { sourceFile } : {}
822
+ });
823
+ analyzeStatic(ir);
824
+ const report = resolveComponentSources(ir, {
825
+ resolver: createComponentResolver(options.resolve ?? []),
826
+ // Without this the pass calls every author-imported component unresolved, and the
827
+ // report is unusable for diagnostics.
828
+ isBound: (name) => needs.declared.has(name),
829
+ modules: {
830
+ controlFlowModule: options.controlFlowModule ?? options.runtimeModule ?? "@fluixi/dom",
831
+ coreModule: options.coreModule ?? "@fluixi/core",
832
+ routerModule: options.routerModule ?? "@fluixi/core/router"
833
+ },
834
+ strategyFor: (n) => n.load
835
+ });
836
+ for (const name of report.unresolved) needs.unresolved.add(name);
837
+ collapseStrategies(ir);
838
+ const emitted = imperativeBackend.emit(ir, {
839
+ templateClone: options.templateClone ?? true,
840
+ partialTemplates: nested ? false : options.partialTemplates ?? true
841
+ });
842
+ for (const symbol of emitted.imports) used.add(symbol);
843
+ collectNeeds(ir, needs);
844
+ return adoptTemplates(emitted.code, emitted.templates, hoisted);
845
+ }
846
+ function buildPrologue(used, needs, hoisted, bound, options) {
847
+ const runtime = options.runtimeModule ?? "@fluixi/dom";
848
+ const core = options.coreModule ?? "@fluixi/core";
849
+ const groups = /* @__PURE__ */ new Map();
850
+ const add = (mod, name) => groups.set(mod, [...groups.get(mod) ?? [], name]);
851
+ const wanted = new Set(used);
852
+ for (const name of needs.builtins) wanted.add(name);
853
+ if (needs.delegatedEvents.size > 0) wanted.add("delegateEvents");
854
+ for (const name of [...wanted].sort()) {
855
+ if (bound.has(name)) continue;
856
+ if (REACTIVE.has(name)) add(options.reactiveModule ?? "@fluixi/reactive/signal", name);
857
+ else if (ROUTER.has(name)) add(options.routerModule ?? "@fluixi/core/router", name);
858
+ else if (CORE_ONLY.has(name)) add(core, name);
859
+ else if (CONTROL_FLOW.has(name)) add(options.controlFlowModule ?? runtime, name);
860
+ else add(runtime, name);
861
+ }
862
+ for (const [name, src] of needs.resolved) {
863
+ if (!bound.has(name)) add(src.module, src.export === "default" ? `default as ${name}` : name === src.export ? name : `${src.export} as ${name}`);
864
+ }
865
+ const lines = [];
866
+ for (const [mod, names] of groups) {
867
+ lines.push(`import { ${names.join(", ")} } from ${JSON.stringify(mod)};`);
868
+ }
869
+ const lazy = [...needs.deferred].filter(([name]) => !bound.has(name));
870
+ if (lazy.length > 0) {
871
+ if (!bound.has("deferred")) lines.push(`import { deferred } from ${JSON.stringify(core)};`);
872
+ for (const [name, src] of lazy) {
873
+ lines.push(
874
+ `const ${name} = deferred(() => import(${JSON.stringify(src.module)}), { strategy: ${strategyLiteral(src.loading)}, export: ${JSON.stringify(src.export)} });`
875
+ );
876
+ }
877
+ }
878
+ for (const [key, name] of hoisted) {
879
+ lines.push(`const ${name} = ${JSON.stringify(key.startsWith("svg:") ? key.slice(4) : key)};`);
880
+ }
881
+ if (needs.delegatedEvents.size > 0) {
882
+ lines.push(`delegateEvents(${JSON.stringify([...needs.delegatedEvents])});`);
883
+ }
884
+ return lines.length > 0 ? lines.join("\n") + "\n" : null;
885
+ }
886
+ export {
887
+ explainBail,
888
+ moduleBindings,
889
+ planPropsDestructure,
890
+ shapeOf,
891
+ transformProps,
892
+ transformTemplates
893
+ };