@fluixi/compiler 1.0.0-alpha.100

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 (303) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +131 -0
  3. package/dist/analyze/expr-shape.cjs +62 -0
  4. package/dist/analyze/expr-shape.d.cts +14 -0
  5. package/dist/analyze/expr-shape.d.ts +15 -0
  6. package/dist/analyze/expr-shape.d.ts.map +1 -0
  7. package/dist/analyze/expr-shape.js +37 -0
  8. package/dist/analyze/expr-shape.mjs +41 -0
  9. package/dist/analyze/intrinsics.cjs +112 -0
  10. package/dist/analyze/intrinsics.d.cts +80 -0
  11. package/dist/analyze/intrinsics.d.ts +81 -0
  12. package/dist/analyze/intrinsics.d.ts.map +1 -0
  13. package/dist/analyze/intrinsics.js +126 -0
  14. package/dist/analyze/intrinsics.mjs +91 -0
  15. package/dist/analyze/paren.cjs +134 -0
  16. package/dist/analyze/paren.d.cts +23 -0
  17. package/dist/analyze/paren.d.ts +24 -0
  18. package/dist/analyze/paren.d.ts.map +1 -0
  19. package/dist/analyze/paren.js +168 -0
  20. package/dist/analyze/paren.mjs +113 -0
  21. package/dist/analyze/props-destructure.cjs +226 -0
  22. package/dist/analyze/props-destructure.d.cts +83 -0
  23. package/dist/analyze/props-destructure.d.ts +84 -0
  24. package/dist/analyze/props-destructure.d.ts.map +1 -0
  25. package/dist/analyze/props-destructure.js +272 -0
  26. package/dist/analyze/props-destructure.mjs +205 -0
  27. package/dist/analyze/reactive-bindings.cjs +210 -0
  28. package/dist/analyze/reactive-bindings.d.cts +42 -0
  29. package/dist/analyze/reactive-bindings.d.ts +43 -0
  30. package/dist/analyze/reactive-bindings.d.ts.map +1 -0
  31. package/dist/analyze/reactive-bindings.js +191 -0
  32. package/dist/analyze/reactive-bindings.mjs +187 -0
  33. package/dist/analyze/reactive-expr.cjs +38 -0
  34. package/dist/analyze/reactive-expr.d.cts +38 -0
  35. package/dist/analyze/reactive-expr.d.ts +39 -0
  36. package/dist/analyze/reactive-expr.d.ts.map +1 -0
  37. package/dist/analyze/reactive-expr.js +31 -0
  38. package/dist/analyze/reactive-expr.mjs +17 -0
  39. package/dist/analyze/static-graph.cjs +831 -0
  40. package/dist/analyze/static-graph.d.cts +102 -0
  41. package/dist/analyze/static-graph.d.ts +103 -0
  42. package/dist/analyze/static-graph.d.ts.map +1 -0
  43. package/dist/analyze/static-graph.js +871 -0
  44. package/dist/analyze/static-graph.mjs +813 -0
  45. package/dist/babel-I6BUWUCU.mjs +636 -0
  46. package/dist/chunk-3AICWNF7.mjs +92 -0
  47. package/dist/chunk-6CWJWGE2.mjs +2170 -0
  48. package/dist/chunk-C3XPDB4Y.mjs +16 -0
  49. package/dist/chunk-GX5XV6Z7.mjs +190 -0
  50. package/dist/chunk-HXEXPWJ2.mjs +999 -0
  51. package/dist/chunk-NU3W67UZ.mjs +584 -0
  52. package/dist/chunk-SKAVY75W.mjs +11 -0
  53. package/dist/codegen/backend.cjs +18 -0
  54. package/dist/codegen/backend.d.cts +35 -0
  55. package/dist/codegen/backend.d.ts +36 -0
  56. package/dist/codegen/backend.d.ts.map +1 -0
  57. package/dist/codegen/backend.js +1 -0
  58. package/dist/codegen/backend.mjs +0 -0
  59. package/dist/codegen/backends/imperative.cjs +577 -0
  60. package/dist/codegen/backends/imperative.d.cts +11 -0
  61. package/dist/codegen/backends/imperative.d.ts +12 -0
  62. package/dist/codegen/backends/imperative.d.ts.map +1 -0
  63. package/dist/codegen/backends/imperative.js +362 -0
  64. package/dist/codegen/backends/imperative.mjs +554 -0
  65. package/dist/codegen/contract.cjs +52 -0
  66. package/dist/codegen/contract.d.cts +24 -0
  67. package/dist/codegen/contract.d.ts +25 -0
  68. package/dist/codegen/contract.d.ts.map +1 -0
  69. package/dist/codegen/contract.js +30 -0
  70. package/dist/codegen/contract.mjs +31 -0
  71. package/dist/codegen/partial-template.cjs +176 -0
  72. package/dist/codegen/partial-template.d.cts +61 -0
  73. package/dist/codegen/partial-template.d.ts +62 -0
  74. package/dist/codegen/partial-template.d.ts.map +1 -0
  75. package/dist/codegen/partial-template.js +0 -0
  76. package/dist/codegen/partial-template.mjs +153 -0
  77. package/dist/codegen/serialize-static.cjs +125 -0
  78. package/dist/codegen/serialize-static.d.cts +38 -0
  79. package/dist/codegen/serialize-static.d.ts +39 -0
  80. package/dist/codegen/serialize-static.d.ts.map +1 -0
  81. package/dist/codegen/serialize-static.js +165 -0
  82. package/dist/codegen/serialize-static.mjs +104 -0
  83. package/dist/frontend/babel/build-ir-lit.cjs +1933 -0
  84. package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
  85. package/dist/frontend/babel/build-ir-lit.d.ts +27 -0
  86. package/dist/frontend/babel/build-ir-lit.d.ts.map +1 -0
  87. package/dist/frontend/babel/build-ir-lit.js +13 -0
  88. package/dist/frontend/babel/build-ir-lit.mjs +1902 -0
  89. package/dist/frontend/babel/build-ir.cjs +1948 -0
  90. package/dist/frontend/babel/build-ir.d.cts +35 -0
  91. package/dist/frontend/babel/build-ir.d.ts +36 -0
  92. package/dist/frontend/babel/build-ir.d.ts.map +1 -0
  93. package/dist/frontend/babel/build-ir.js +124 -0
  94. package/dist/frontend/babel/build-ir.mjs +1919 -0
  95. package/dist/frontend/babel/index.cjs +2610 -0
  96. package/dist/frontend/babel/index.d.cts +33 -0
  97. package/dist/frontend/babel/index.d.ts +34 -0
  98. package/dist/frontend/babel/index.d.ts.map +1 -0
  99. package/dist/frontend/babel/index.js +65 -0
  100. package/dist/frontend/babel/index.mjs +2580 -0
  101. package/dist/frontend/babel/lower-template.cjs +1931 -0
  102. package/dist/frontend/babel/lower-template.d.cts +23 -0
  103. package/dist/frontend/babel/lower-template.d.ts +24 -0
  104. package/dist/frontend/babel/lower-template.d.ts.map +1 -0
  105. package/dist/frontend/babel/lower-template.js +64 -0
  106. package/dist/frontend/babel/lower-template.mjs +1902 -0
  107. package/dist/frontend/babel/plugin.cjs +2556 -0
  108. package/dist/frontend/babel/plugin.d.cts +95 -0
  109. package/dist/frontend/babel/plugin.d.ts +96 -0
  110. package/dist/frontend/babel/plugin.d.ts.map +1 -0
  111. package/dist/frontend/babel/plugin.js +523 -0
  112. package/dist/frontend/babel/plugin.mjs +2527 -0
  113. package/dist/frontend/babel/server-functions.cjs +110 -0
  114. package/dist/frontend/babel/server-functions.d.cts +10 -0
  115. package/dist/frontend/babel/server-functions.d.ts +11 -0
  116. package/dist/frontend/babel/server-functions.d.ts.map +1 -0
  117. package/dist/frontend/babel/server-functions.js +81 -0
  118. package/dist/frontend/babel/server-functions.mjs +89 -0
  119. package/dist/frontend/babel/types.cjs +18 -0
  120. package/dist/frontend/babel/types.d.cts +33 -0
  121. package/dist/frontend/babel/types.d.ts +34 -0
  122. package/dist/frontend/babel/types.d.ts.map +1 -0
  123. package/dist/frontend/babel/types.js +1 -0
  124. package/dist/frontend/babel/types.mjs +0 -0
  125. package/dist/frontend/types.cjs +18 -0
  126. package/dist/frontend/types.d.cts +25 -0
  127. package/dist/frontend/types.d.ts +26 -0
  128. package/dist/frontend/types.d.ts.map +1 -0
  129. package/dist/frontend/types.js +1 -0
  130. package/dist/frontend/types.mjs +0 -0
  131. package/dist/frontend/vocabulary.cjs +98 -0
  132. package/dist/frontend/vocabulary.d.cts +79 -0
  133. package/dist/frontend/vocabulary.d.ts +80 -0
  134. package/dist/frontend/vocabulary.d.ts.map +1 -0
  135. package/dist/frontend/vocabulary.js +124 -0
  136. package/dist/frontend/vocabulary.mjs +77 -0
  137. package/dist/index.cjs +1957 -0
  138. package/dist/index.d.cts +27 -0
  139. package/dist/index.d.ts +28 -0
  140. package/dist/index.d.ts.map +1 -0
  141. package/dist/index.js +38 -0
  142. package/dist/index.mjs +1949 -0
  143. package/dist/integrations.cjs +5705 -0
  144. package/dist/integrations.d.cts +215 -0
  145. package/dist/integrations.d.ts +216 -0
  146. package/dist/integrations.d.ts.map +1 -0
  147. package/dist/integrations.js +566 -0
  148. package/dist/integrations.mjs +810 -0
  149. package/dist/ir/nodes.cjs +18 -0
  150. package/dist/ir/nodes.d.cts +168 -0
  151. package/dist/ir/nodes.d.ts +169 -0
  152. package/dist/ir/nodes.d.ts.map +1 -0
  153. package/dist/ir/nodes.js +1 -0
  154. package/dist/ir/nodes.mjs +0 -0
  155. package/dist/lower/compile-template.cjs +1670 -0
  156. package/dist/lower/compile-template.d.cts +82 -0
  157. package/dist/lower/compile-template.d.ts +83 -0
  158. package/dist/lower/compile-template.d.ts.map +1 -0
  159. package/dist/lower/compile-template.js +79 -0
  160. package/dist/lower/compile-template.mjs +1662 -0
  161. package/dist/lower/entities.cjs +288 -0
  162. package/dist/lower/entities.d.cts +1 -0
  163. package/dist/lower/entities.d.ts +2 -0
  164. package/dist/lower/entities.d.ts.map +1 -0
  165. package/dist/lower/entities.js +54 -0
  166. package/dist/lower/entities.mjs +267 -0
  167. package/dist/lower/jsx.cjs +1101 -0
  168. package/dist/lower/jsx.d.cts +33 -0
  169. package/dist/lower/jsx.d.ts +34 -0
  170. package/dist/lower/jsx.d.ts.map +1 -0
  171. package/dist/lower/jsx.js +414 -0
  172. package/dist/lower/jsx.mjs +1078 -0
  173. package/dist/lower/template.cjs +1354 -0
  174. package/dist/lower/template.d.cts +53 -0
  175. package/dist/lower/template.d.ts +54 -0
  176. package/dist/lower/template.d.ts.map +1 -0
  177. package/dist/lower/template.js +542 -0
  178. package/dist/lower/template.mjs +1335 -0
  179. package/dist/lower/text.cjs +42 -0
  180. package/dist/lower/text.d.cts +10 -0
  181. package/dist/lower/text.d.ts +11 -0
  182. package/dist/lower/text.d.ts.map +1 -0
  183. package/dist/lower/text.js +31 -0
  184. package/dist/lower/text.mjs +21 -0
  185. package/dist/optimize/analyze-static.cjs +112 -0
  186. package/dist/optimize/analyze-static.d.cts +39 -0
  187. package/dist/optimize/analyze-static.d.ts +40 -0
  188. package/dist/optimize/analyze-static.d.ts.map +1 -0
  189. package/dist/optimize/analyze-static.js +131 -0
  190. package/dist/optimize/analyze-static.mjs +91 -0
  191. package/dist/optimize/collapse-strategies.cjs +90 -0
  192. package/dist/optimize/collapse-strategies.d.cts +30 -0
  193. package/dist/optimize/collapse-strategies.d.ts +31 -0
  194. package/dist/optimize/collapse-strategies.d.ts.map +1 -0
  195. package/dist/optimize/collapse-strategies.js +33 -0
  196. package/dist/optimize/collapse-strategies.mjs +67 -0
  197. package/dist/options.cjs +33 -0
  198. package/dist/options.d.cts +39 -0
  199. package/dist/options.d.ts +40 -0
  200. package/dist/options.d.ts.map +1 -0
  201. package/dist/options.js +8 -0
  202. package/dist/options.mjs +12 -0
  203. package/dist/resolve/builtins.cjs +73 -0
  204. package/dist/resolve/builtins.d.cts +68 -0
  205. package/dist/resolve/builtins.d.ts +69 -0
  206. package/dist/resolve/builtins.d.ts.map +1 -0
  207. package/dist/resolve/builtins.js +64 -0
  208. package/dist/resolve/builtins.mjs +53 -0
  209. package/dist/resolve/component-globals.cjs +272 -0
  210. package/dist/resolve/component-globals.d.cts +88 -0
  211. package/dist/resolve/component-globals.d.ts +89 -0
  212. package/dist/resolve/component-globals.d.ts.map +1 -0
  213. package/dist/resolve/component-globals.js +160 -0
  214. package/dist/resolve/component-globals.mjs +249 -0
  215. package/dist/resolve/component-resolver.cjs +80 -0
  216. package/dist/resolve/component-resolver.d.cts +68 -0
  217. package/dist/resolve/component-resolver.d.ts +69 -0
  218. package/dist/resolve/component-resolver.d.ts.map +1 -0
  219. package/dist/resolve/component-resolver.js +95 -0
  220. package/dist/resolve/component-resolver.mjs +59 -0
  221. package/dist/resolve/load-directive.cjs +93 -0
  222. package/dist/resolve/load-directive.d.cts +53 -0
  223. package/dist/resolve/load-directive.d.ts +54 -0
  224. package/dist/resolve/load-directive.d.ts.map +1 -0
  225. package/dist/resolve/load-directive.js +93 -0
  226. package/dist/resolve/load-directive.mjs +72 -0
  227. package/dist/resolve/resolve-ir.cjs +108 -0
  228. package/dist/resolve/resolve-ir.d.cts +53 -0
  229. package/dist/resolve/resolve-ir.d.ts +54 -0
  230. package/dist/resolve/resolve-ir.d.ts.map +1 -0
  231. package/dist/resolve/resolve-ir.js +58 -0
  232. package/dist/resolve/resolve-ir.mjs +85 -0
  233. package/dist/resolve/write-globals.cjs +383 -0
  234. package/dist/resolve/write-globals.d.cts +36 -0
  235. package/dist/resolve/write-globals.d.ts +37 -0
  236. package/dist/resolve/write-globals.d.ts.map +1 -0
  237. package/dist/resolve/write-globals.js +169 -0
  238. package/dist/resolve/write-globals.mjs +362 -0
  239. package/dist/server-fns-VZLHMQTC.mjs +79 -0
  240. package/dist/server-functions-UAZKOLZW.mjs +82 -0
  241. package/dist/transform/bindings.cjs +71 -0
  242. package/dist/transform/bindings.d.cts +16 -0
  243. package/dist/transform/bindings.d.ts +17 -0
  244. package/dist/transform/bindings.d.ts.map +1 -0
  245. package/dist/transform/bindings.js +69 -0
  246. package/dist/transform/bindings.mjs +50 -0
  247. package/dist/transform/index.cjs +3837 -0
  248. package/dist/transform/index.d.cts +15 -0
  249. package/dist/transform/index.d.ts +16 -0
  250. package/dist/transform/index.d.ts.map +1 -0
  251. package/dist/transform/index.js +12 -0
  252. package/dist/transform/index.mjs +4882 -0
  253. package/dist/transform/intrinsics.cjs +261 -0
  254. package/dist/transform/intrinsics.d.cts +33 -0
  255. package/dist/transform/intrinsics.d.ts +34 -0
  256. package/dist/transform/intrinsics.d.ts.map +1 -0
  257. package/dist/transform/intrinsics.js +120 -0
  258. package/dist/transform/intrinsics.mjs +238 -0
  259. package/dist/transform/props.cjs +441 -0
  260. package/dist/transform/props.d.cts +45 -0
  261. package/dist/transform/props.d.ts +46 -0
  262. package/dist/transform/props.d.ts.map +1 -0
  263. package/dist/transform/props.js +221 -0
  264. package/dist/transform/props.mjs +1487 -0
  265. package/dist/transform/server-fn-id.cjs +35 -0
  266. package/dist/transform/server-fn-id.d.cts +9 -0
  267. package/dist/transform/server-fn-id.d.ts +10 -0
  268. package/dist/transform/server-fn-id.d.ts.map +1 -0
  269. package/dist/transform/server-fn-id.js +18 -0
  270. package/dist/transform/server-fn-id.mjs +14 -0
  271. package/dist/transform/server-fns.cjs +114 -0
  272. package/dist/transform/server-fns.d.cts +12 -0
  273. package/dist/transform/server-fns.d.ts +13 -0
  274. package/dist/transform/server-fns.d.ts.map +1 -0
  275. package/dist/transform/server-fns.js +94 -0
  276. package/dist/transform/server-fns.mjs +1160 -0
  277. package/dist/transform/source-locations.cjs +393 -0
  278. package/dist/transform/source-locations.d.cts +48 -0
  279. package/dist/transform/source-locations.d.ts +49 -0
  280. package/dist/transform/source-locations.d.ts.map +1 -0
  281. package/dist/transform/source-locations.js +303 -0
  282. package/dist/transform/source-locations.mjs +370 -0
  283. package/dist/transform/styles.cjs +606 -0
  284. package/dist/transform/styles.d.cts +237 -0
  285. package/dist/transform/styles.d.ts +238 -0
  286. package/dist/transform/styles.d.ts.map +1 -0
  287. package/dist/transform/styles.js +743 -0
  288. package/dist/transform/styles.mjs +671 -0
  289. package/dist/transform/templates.cjs +3806 -0
  290. package/dist/transform/templates.d.cts +82 -0
  291. package/dist/transform/templates.d.ts +83 -0
  292. package/dist/transform/templates.d.ts.map +1 -0
  293. package/dist/transform/templates.js +613 -0
  294. package/dist/transform/templates.mjs +4852 -0
  295. package/dist/transform-3W45L3EA.mjs +951 -0
  296. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  297. package/dist/vite-styles.cjs +223 -0
  298. package/dist/vite-styles.d.cts +68 -0
  299. package/dist/vite-styles.d.ts +69 -0
  300. package/dist/vite-styles.d.ts.map +1 -0
  301. package/dist/vite-styles.js +241 -0
  302. package/dist/vite-styles.mjs +214 -0
  303. package/package.json +141 -0
@@ -0,0 +1,566 @@
1
+ /**
2
+ * @fileoverview Bundler integrations for the Fluixi compiler.
3
+ * @module @fluixi/compiler/integrations
4
+ *
5
+ * vite, webpack, rollup and esbuild adapters. Each is a few lines around
6
+ * `compileModule`, which rewrites the source in place, JSX and `` html`` `` both
7
+ * lower to the shared IR and the imperative backend. fluixi re-exports
8
+ * createVitePlugin from here.
9
+ *
10
+ * `babel: true` routes through the babel front-end instead, for a project whose
11
+ * own babel plugins have to see the output. It is the only thing that needs
12
+ * @babel/core, and it says so rather than degrading: source that was not compiled
13
+ * is source whose templates never became DOM calls, and a build that ships it
14
+ * looks successful until the page is opened.
15
+ */
16
+ // ============================================================================
17
+ // Babel Plugin Helpers
18
+ // ============================================================================
19
+ /**
20
+ * Helper for creating a Babel plugin
21
+ */
22
+ export async function createBabelPlugin(options = {}) {
23
+ // Import the actual Babel plugin using dynamic import for ESM
24
+ let pluginModule = null;
25
+ try {
26
+ // The babel front-end lives in this same package now.
27
+ pluginModule = await import('./frontend/babel/index.js');
28
+ }
29
+ catch (e) {
30
+ console.warn('Could not load the babel front-end:', e);
31
+ }
32
+ return {
33
+ name: 'babel-fluixi-jsx',
34
+ plugin: pluginModule ? pluginModule.default || pluginModule : null,
35
+ // Provide options mapping
36
+ getOptions() {
37
+ return {
38
+ importSource: options.importSource || '@fluixi/jsx',
39
+ development: options.development || false,
40
+ delegateEvents: options.delegateEvents !== false,
41
+ ...(options.format ? { format: options.format } : {}),
42
+ // Forwarded explicitly: getOptions() is an allowlist, so an option missing
43
+ // here is silently dropped rather than rejected.
44
+ ...(options.resolve ? { resolve: options.resolve } : {}),
45
+ ...(options.templateClone !== undefined
46
+ ? { templateClone: options.templateClone }
47
+ : {}),
48
+ ...(options.partialTemplates !== undefined
49
+ ? { partialTemplates: options.partialTemplates }
50
+ : {}),
51
+ ...(options.litTag ? { litTag: options.litTag } : {}),
52
+ ...(options.signalModule ? { signalModule: options.signalModule } : {}),
53
+ ...(options.controlFlowModule
54
+ ? { controlFlowModule: options.controlFlowModule }
55
+ : {}),
56
+ ...(options.routerModule ? { routerModule: options.routerModule } : {}),
57
+ ...(options.reactiveModule ? { reactiveModule: options.reactiveModule } : {}),
58
+ };
59
+ },
60
+ };
61
+ }
62
+ // ============================================================================
63
+ // TypeScript Transformer Helpers
64
+ // ============================================================================
65
+ /**
66
+ * Helper for creating a TypeScript transformer
67
+ */
68
+ export function createTypeScriptTransformer(options = {}) {
69
+ const ts = tryRequire('typescript');
70
+ if (!ts) {
71
+ console.warn('TypeScript not found, transformer unavailable');
72
+ return (context) => (sourceFile) => sourceFile;
73
+ }
74
+ return (context) => {
75
+ const visitor = (node) => {
76
+ // Transform JSX elements
77
+ if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
78
+ // Use the same transformation logic as Babel
79
+ return transformTSJSXNode(node, options, ts);
80
+ }
81
+ return ts.visitEachChild(node, visitor, context);
82
+ };
83
+ return (sourceFile) => {
84
+ return ts.visitNode(sourceFile, visitor);
85
+ };
86
+ };
87
+ }
88
+ /**
89
+ * Transform TypeScript JSX node
90
+ */
91
+ function transformTSJSXNode(node, options, ts) {
92
+ // This is a placeholder - full implementation would mirror Babel transformation
93
+ // For now, return the node unchanged
94
+ return node;
95
+ }
96
+ /**
97
+ * Try to require a module, return null if not available
98
+ */
99
+ function tryRequire(moduleName) {
100
+ try {
101
+ return require(moduleName);
102
+ }
103
+ catch (e) {
104
+ return null;
105
+ }
106
+ }
107
+ // ============================================================================
108
+ // Vite Plugin
109
+ // ============================================================================
110
+ /**
111
+ * Subpaths that used to exist, and what to write instead. A rename is cheap to
112
+ * follow once you know it happened; the cost is finding out.
113
+ */
114
+ const RETIRED_SUBPATHS = {
115
+ '@fluixi/core/router-next': 'is now @fluixi/core/router',
116
+ '@fluixi/core/rx': 'is gone — import signals and effects from @fluixi/reactive, or the server ' +
117
+ 'primitives it resolved to under node from @fluixi/core/server',
118
+ };
119
+ /**
120
+ * Create a Vite plugin for JSX transformation
121
+ */
122
+ export function createVitePlugin(options = {}) {
123
+ // Component `<style>` blocks, when @fluixi-css/vite is in the build to process them.
124
+ let transformTemplates;
125
+ let projectRoot = process.cwd();
126
+ const componentStyles = createComponentStyles((code, id, styles) => {
127
+ // Scope ids hash the path from the project root, marks or not: the same on every machine
128
+ // and for every id a module is reached by.
129
+ // Reported by `transform`, from the module's last pass: a first pass, or a compile of
130
+ // another module whose values this one uses, would report what the next pass resolves.
131
+ return transformTemplates(code, id, { ...transformOptions(options, id), sourceRoot: projectRoot, styles });
132
+ });
133
+ return {
134
+ name: 'vite-fluixi-jsx',
135
+ enforce: 'pre',
136
+ // JSX the compiler leaves alone goes to Vite's own transform: Oxc in Vite 8 (Rolldown),
137
+ // esbuild before, which Vite 8 warns about.
138
+ // In dev, CSS maps are on unless the app says otherwise, so devtools show the line a
139
+ // component's rule was written on. Vite leaves them off by default; a build never has them.
140
+ config(user) {
141
+ const importSource = options.importSource || '@fluixi/jsx';
142
+ const jsx = this && this.meta?.rolldownVersion
143
+ ? { oxc: { jsx: { runtime: 'automatic', importSource } } }
144
+ : { esbuild: { jsx: 'automatic', jsxImportSource: importSource } };
145
+ return user?.css?.devSourcemap === undefined ? { ...jsx, css: { devSourcemap: true } } : jsx;
146
+ },
147
+ // Written once per build, and on dev-server start, rather than per transform: the
148
+ // set of resolvable names comes from config, so nothing a file does can change it.
149
+ async configResolved(config) {
150
+ const outcome = writeComponentGlobals(options, config?.root ?? process.cwd());
151
+ if (outcome.warning)
152
+ console.warn(outcome.warning);
153
+ if (options.babel)
154
+ return;
155
+ projectRoot = config?.root ?? projectRoot;
156
+ componentStyles.connect(config?.plugins, config?.root);
157
+ const entry = config?.command === 'build' && config.build?.lib ? config.build.lib.entry : undefined;
158
+ const first = typeof entry === 'string' ? entry : Array.isArray(entry) ? entry[0] : entry && typeof entry === 'object' ? Object.values(entry)[0] : undefined;
159
+ if (typeof first === 'string')
160
+ componentStyles.setLibrary(dirname(resolvePath(config.root ?? process.cwd(), first)));
161
+ if (componentStyles.active)
162
+ ({ transformTemplates } = await import('./transform/index.js'));
163
+ },
164
+ generateBundle() {
165
+ for (const [fileName, source] of componentStyles.libraryFiles())
166
+ this.emitFile({ type: 'asset', fileName, source });
167
+ },
168
+ // An edited component's style modules go out with its update: their ids end in `.css`, so
169
+ // Vite does not connect them to the file.
170
+ handleHotUpdate(ctx) {
171
+ if (!componentStyles.active)
172
+ return undefined;
173
+ const styles = componentStyles.hotModules(ctx.file, ctx.server.moduleGraph);
174
+ return styles.length ? [...ctx.modules, ...styles] : undefined;
175
+ },
176
+ configureServer(server) {
177
+ componentStyles.setServer(server);
178
+ },
179
+ load(id) {
180
+ return componentStyles.isStyle(id) ? componentStyles.load(id, this) : null;
181
+ },
182
+ // A subpath we retired resolves to nothing, and the bundler reports that as
183
+ // `Missing "./x" specifier`, which names neither the replacement nor the file
184
+ // that asked. Answer it here, where the rename is known.
185
+ resolveId(id, importer) {
186
+ if (componentStyles.isStyle(id))
187
+ return componentStyles.resolveId(id, importer, this);
188
+ if (componentStyles.isLibraryImport(id, importer))
189
+ return { id, external: true };
190
+ const moved = RETIRED_SUBPATHS[id];
191
+ if (!moved)
192
+ return null;
193
+ throw new Error(`[fluixi] ${id} ${moved}` + (importer ? `\n imported by ${importer}` : ''));
194
+ },
195
+ async transform(code, id) {
196
+ // Only process JSX/TSX files
197
+ if (!/\.(jsx|tsx|ts)$/i.test(id)) {
198
+ return null;
199
+ }
200
+ if (!options.babel && componentStyles.active) {
201
+ const result = await componentStyles.compile(code, id, this);
202
+ reportDiagnostics(result, id);
203
+ return result;
204
+ }
205
+ if (!options.babel)
206
+ return compileModule(code, id, options);
207
+ const babelPlugin = await createBabelPlugin(options);
208
+ try {
209
+ // Use dynamic import instead of require for ESM compatibility
210
+ const babel = await import('@babel/core').catch(() => null);
211
+ if (!babel) {
212
+ // No silent fallback. This front-end compiles through babel; without it
213
+ // there is no transform, and emitting the source unchanged would ship a
214
+ // build whose JSX and html`` templates were never compiled, a failure
215
+ // that looks exactly like success until the page is opened.
216
+ throw new Error(`[fluixi] @babel/core is required to compile ${id} but could not be loaded. ` +
217
+ `Install it alongside @fluixi/compiler.`);
218
+ }
219
+ const isTSX = /\.tsx$/.test(id);
220
+ const isTS = /\.ts$/.test(id);
221
+ const presets = [];
222
+ const plugins = [];
223
+ // Add TypeScript preset if needed (but with JSX preservation)
224
+ if (isTSX || isTS) {
225
+ const tsPreset = await import('@babel/preset-typescript')
226
+ .then((m) => m.default || m)
227
+ .catch(() => null);
228
+ if (tsPreset) {
229
+ presets.push([
230
+ tsPreset,
231
+ {
232
+ isTSX: isTSX,
233
+ allExtensions: true,
234
+ // Important: preserve JSX so our plugin can transform it
235
+ jsxPragma: 'jsx',
236
+ jsxPragmaFrag: 'Fragment',
237
+ onlyRemoveTypeImports: true,
238
+ },
239
+ ]);
240
+ }
241
+ }
242
+ // Only our custom babel plugin handles JSX, never @babel/preset-react, which
243
+ // rewrites spreads with Object.assign and breaks store-proxy reactivity.
244
+ if (babelPlugin && babelPlugin.plugin) {
245
+ plugins.push([babelPlugin.plugin, babelPlugin.getOptions()]);
246
+ }
247
+ else {
248
+ console.warn('[createVitePlugin] custom babel plugin not found');
249
+ }
250
+ const result = await babel.transformAsync(code, {
251
+ filename: id,
252
+ configFile: false,
253
+ babelrc: false,
254
+ presets: presets,
255
+ plugins: plugins,
256
+ sourceMaps: options.sourceMaps !== false,
257
+ });
258
+ // console.log('[createVitePlugin] Transformation complete for:', id);
259
+ // console.log(
260
+ // '[createVitePlugin] Has mergeProps in output:',
261
+ // result?.code?.includes('mergeProps')
262
+ // );
263
+ return {
264
+ code: result?.code || code,
265
+ map: result?.map,
266
+ };
267
+ }
268
+ catch (e) {
269
+ // Let it through to Vite. Swallowing a compile error here and returning
270
+ // half-transformed source turns a diagnosable failure into a mystery at
271
+ // runtime; the build should stop where the problem is.
272
+ throw e;
273
+ }
274
+ },
275
+ };
276
+ }
277
+ /** CompilerOptions as the transform wants them. Shared by every adapter. */
278
+ /**
279
+ * A dependency's own signals are not the author's, and marking them costs a call per node in
280
+ * code nobody is going to open. Source marks stop at the project boundary.
281
+ */
282
+ function marks(options, id) {
283
+ if (options.sourceLocations !== true)
284
+ return false;
285
+ if (options.sourceLocationsExternal)
286
+ return true;
287
+ if (!id || id.includes('/node_modules/'))
288
+ return false;
289
+ const root = options.sourceRoot;
290
+ if (!root)
291
+ return true;
292
+ const base = root.endsWith('/') ? root : `${root}/`;
293
+ return id.startsWith(base);
294
+ }
295
+ function transformOptions(options, id) {
296
+ return {
297
+ resolve: options.resolve,
298
+ litTag: options.litTag,
299
+ sourceLocations: marks(options, id),
300
+ sourceRoot: options.sourceRoot,
301
+ templateClone: options.templateClone,
302
+ partialTemplates: options.partialTemplates,
303
+ runtimeModule: options.signalModule,
304
+ controlFlowModule: options.controlFlowModule,
305
+ routerModule: options.routerModule,
306
+ reactiveModule: options.reactiveModule,
307
+ propsDestructure: options.propsDestructure,
308
+ };
309
+ }
310
+ /**
311
+ * The babel path compiles through a host AST, so the rewrite runs as its own pass there
312
+ * and pays for a second parse. The built-in path folds the same edits into the template
313
+ * transform instead, which is why only this branch needs it.
314
+ */
315
+ async function rewriteProps(code, id, options) {
316
+ if (options.propsDestructure === false)
317
+ return code;
318
+ const { transformProps } = await import('./transform/index.js');
319
+ const result = transformProps(code, id);
320
+ reportDiagnostics({ propsDiagnostics: result.diagnostics }, id);
321
+ // Untouched source comes back identical, so nothing pays for the option being on.
322
+ return result.rewritten > 0 ? result.code : code;
323
+ }
324
+ /**
325
+ * Warnings already printed, so a watch rebuild doesn't repeat them.
326
+ *
327
+ * A module is transformed again on every edit to it or its importers, and the same
328
+ * warning ten times reads as ten problems. Cleared when the message changes, which is
329
+ * the only thing worth re-printing.
330
+ */
331
+ const reported = new Set();
332
+ /**
333
+ * Say what the compiler refused to do.
334
+ *
335
+ * All of these build cleanly and fail at runtime, which is why they are worth printing: an
336
+ * unresolved tag renders nothing, a `load:` it cannot act on ships the chunk eagerly, and a
337
+ * props pattern the rewrite refused reads its value once instead of tracking it. None leaves
338
+ * a trace anywhere else: the last one is a stale value on screen and nothing in the build.
339
+ *
340
+ * `console.warn`, deliberately, not a plugin's `this.warn`: that only exists in the
341
+ * rollup/vite context, and this runs for the esbuild and webpack adapters too. A
342
+ * diagnostic that only some bundlers get is worse than one that is plainly ours.
343
+ */
344
+ function reportDiagnostics(result, id) {
345
+ const r = result;
346
+ const say = (message) => {
347
+ const key = `${id}\u0000${message}`;
348
+ if (reported.has(key))
349
+ return;
350
+ reported.add(key);
351
+ console.warn(`[fluixi] ${id}: ${message}`);
352
+ };
353
+ for (const d of r?.unresolvedDiagnostics ?? [])
354
+ say(d.message);
355
+ for (const d of r?.loadDiagnostics ?? [])
356
+ say(d.message);
357
+ for (const d of r?.intrinsicDiagnostics ?? [])
358
+ say(d.message);
359
+ for (const d of r?.styleDiagnostics ?? [])
360
+ say(`${d.line}:${d.column + 1} ${d.message}`);
361
+ for (const d of r?.propsDiagnostics ?? []) {
362
+ say(`\`${d.name}\` was left destructured: ${d.message}. It reads once instead of tracking.`);
363
+ }
364
+ }
365
+ /** Compile one module, through babel only when asked for it. */
366
+ async function compileModule(code, id, options) {
367
+ if (!options.babel) {
368
+ const { transformTemplates } = await import('./transform/index.js');
369
+ const result = transformTemplates(code, id, transformOptions(options, id));
370
+ reportDiagnostics(result, id);
371
+ return result;
372
+ }
373
+ const source = await rewriteProps(code, id, options);
374
+ const babel = await import('@babel/core').catch(() => null);
375
+ const plugin = await createBabelPlugin(options);
376
+ if (!babel || !plugin.plugin) {
377
+ throw new Error(`[fluixi] babel: true needs @babel/core, which could not be loaded for ${id}. ` +
378
+ `Install it, or drop the option to use the built-in compiler.`);
379
+ }
380
+ const result = await babel.transformAsync(source, {
381
+ filename: id,
382
+ configFile: false,
383
+ babelrc: false,
384
+ plugins: [[plugin.plugin, plugin.getOptions()]],
385
+ sourceMaps: options.sourceMaps !== false,
386
+ });
387
+ return result?.code ? { code: result.code, map: result.map } : null;
388
+ }
389
+ // ============================================================================
390
+ // Webpack Loader
391
+ // ============================================================================
392
+ /**
393
+ * Create a Webpack loader for JSX transformation
394
+ */
395
+ export function createWebpackLoader(options = {}) {
396
+ return async function (source) {
397
+ const callback = this.async();
398
+ compileModule(source, this.resourcePath, options)
399
+ .then((result) => {
400
+ callback(null, result?.code, result?.map);
401
+ })
402
+ .catch((err) => {
403
+ callback(err);
404
+ });
405
+ };
406
+ }
407
+ // ============================================================================
408
+ // Rollup Plugin
409
+ // ============================================================================
410
+ /**
411
+ * Create a Rollup plugin for JSX transformation
412
+ */
413
+ export function createRollupPlugin(options = {}) {
414
+ return {
415
+ name: 'rollup-fluixi-jsx',
416
+ async transform(code, id) {
417
+ if (!/\.[jt]sx?$/.test(id))
418
+ return null;
419
+ return compileModule(code, id, options);
420
+ },
421
+ };
422
+ }
423
+ // ============================================================================
424
+ // ESBuild Plugin
425
+ // ============================================================================
426
+ /**
427
+ * Create an ESBuild plugin for JSX transformation
428
+ */
429
+ export function createESBuildPlugin(options = {}) {
430
+ return {
431
+ name: 'esbuild-fluixi-jsx',
432
+ setup(build) {
433
+ build.onLoad({ filter: /\.[jt]sx?$/ }, async (args) => {
434
+ const { readFileSync } = await import('node:fs');
435
+ const source = readFileSync(args.path, 'utf8');
436
+ try {
437
+ const result = await compileModule(source, args.path, options);
438
+ // esbuild still has to strip the types the transform leaves in place.
439
+ return {
440
+ contents: result?.code ?? source,
441
+ loader: args.path.endsWith('x') ? 'tsx' : 'ts',
442
+ };
443
+ }
444
+ catch (e) {
445
+ return {
446
+ errors: [
447
+ {
448
+ text: `Transform error: ${e}`,
449
+ },
450
+ ],
451
+ };
452
+ }
453
+ });
454
+ },
455
+ };
456
+ }
457
+ import { writeComponentGlobals } from './resolve/write-globals.js';
458
+ import { createComponentStyles } from './vite-styles.js';
459
+ import { readdirSync, readFileSync } from 'node:fs';
460
+ import { dirname, join as _join, resolve as resolvePath } from 'node:path';
461
+ const SERVER_FNS_VMOD = 'virtual:fluixi-server-fns';
462
+ /** Recursively find source files containing the `"use server"` directive under `dir`. */
463
+ /**
464
+ * Whether a file actually carries a `"use server"` directive.
465
+ *
466
+ * Every module this matches is side-effect imported into the server bundle, so a false
467
+ * positive does more than waste a line: it runs that file on the server. A plain
468
+ * `includes('use server')` matched the words wherever they appeared, and a client entry
469
+ * that merely *mentioned* the directive in a comment was imported into the SSR graph and
470
+ * called `startClient` there, which fails with `document is not defined` from a line
471
+ * nobody wrote.
472
+ *
473
+ * Comments are stripped before the test rather than parsed around, because the answer
474
+ * only has to be good enough to decide whether the real transform should look at the
475
+ * file. A directive inside a string literal still matches, which costs an extra import
476
+ * and nothing else.
477
+ */
478
+ function hasServerDirective(source) {
479
+ const withoutComments = source
480
+ .replace(/\/\*[\s\S]*?\*\//g, ' ')
481
+ .replace(/(^|[^:])\/\/[^\n]*/g, '$1');
482
+ return /(^|[\s;{(,])['"]use server['"]/.test(withoutComments);
483
+ }
484
+ function findServerFnModules(dir, out = []) {
485
+ let entries;
486
+ try {
487
+ entries = readdirSync(dir, { withFileTypes: true });
488
+ }
489
+ catch {
490
+ return out;
491
+ }
492
+ for (const e of entries) {
493
+ if (e.name === 'node_modules' || e.name === 'dist' || e.name.startsWith('.'))
494
+ continue;
495
+ const full = _join(dir, e.name);
496
+ if (e.isDirectory())
497
+ findServerFnModules(full, out);
498
+ else if (/\.[jt]sx?$/.test(e.name)) {
499
+ try {
500
+ if (hasServerDirective(readFileSync(full, 'utf8')))
501
+ out.push(full);
502
+ }
503
+ catch {
504
+ /* unreadable: skip */
505
+ }
506
+ }
507
+ }
508
+ return out;
509
+ }
510
+ /**
511
+ * Vite plugin for `"use server"`: applies the transform (client→RPC stub, server→register
512
+ * the body), and provides `virtual:fluixi-server-fns`, side-effect imports of every
513
+ * module that defines a server function. The server entry imports it so ALL server
514
+ * functions register at startup (including those in lazy routes, which would otherwise
515
+ * register only when their chunk loads → an RPC registry miss). The client never imports
516
+ * it. `enforce:'pre'` so it runs on the raw source before other transforms.
517
+ */
518
+ export function serverFunctionsVitePlugin(options = {}) {
519
+ let root = process.cwd();
520
+ return {
521
+ name: 'fluixi-server-functions',
522
+ enforce: 'pre',
523
+ configResolved(config) {
524
+ root = config.root || root;
525
+ },
526
+ resolveId(id) {
527
+ return id === SERVER_FNS_VMOD || id === '@fluixi/start/server-fns'
528
+ ? '\0' + SERVER_FNS_VMOD
529
+ : null;
530
+ },
531
+ load(id) {
532
+ if (id !== '\0' + SERVER_FNS_VMOD)
533
+ return null;
534
+ const mods = findServerFnModules(_join(root, 'src'));
535
+ // First wire the request-context bridge (server-only), then side-effect import each
536
+ // server-fn module so its top-level $$registerServerFn(...) runs, then re-export the
537
+ // dispatcher so the host can route /_server through THIS module graph (sharing the
538
+ // registry the imports populated), apps don't need to re-export it from entry-server.
539
+ const setup = `import '@fluixi/start/server-fn-setup';\n`;
540
+ const imports = mods.map((m) => `import ${JSON.stringify(m)};`).join('\n');
541
+ const dispatcher = `\nexport { isServerFnRequest, handleServerFn } from '@fluixi/start/server-fn';\n`;
542
+ return setup + imports + dispatcher;
543
+ },
544
+ async transform(code, id, opts) {
545
+ if (!/\.[jt]sx?$/.test(id))
546
+ return null;
547
+ if (!code.includes('use server'))
548
+ return null;
549
+ const args = { ssr: !!opts?.ssr, filename: id, root };
550
+ if (options.babel) {
551
+ const { transformServerFunctions } = await import('./frontend/babel/server-functions.js');
552
+ return transformServerFunctions(code, args);
553
+ }
554
+ const { transformServerFns } = await import('./transform/server-fns.js');
555
+ return transformServerFns(code, args);
556
+ },
557
+ };
558
+ }
559
+ export default {
560
+ createBabelPlugin,
561
+ createTypeScriptTransformer,
562
+ createVitePlugin,
563
+ createWebpackLoader,
564
+ createRollupPlugin,
565
+ createESBuildPlugin,
566
+ };