@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,362 @@
1
+ import { planPartialTemplate } from '../partial-template.js';
2
+ import { isSerializable, serializeStatic, templatePositions, isPlainLiteralAttr, htmlAttrName, } from '../serialize-static.js';
3
+ import { RUNTIME_CONTRACT_V1 } from '../contract.js';
4
+ import { markHole, markProps, SOURCE_MARKER } from '../../transform/source-locations.js';
5
+ import { paren } from '../../analyze/paren.js';
6
+ /**
7
+ * Imperative fine-grained backend: emits createNativeElement/insert/spread/
8
+ * createComponent (RUNTIME_CONTRACT_V1), the runtime proven by the @fluixi/dom
9
+ * contract tests.
10
+ *
11
+ * emit() consumes the host-agnostic IR and returns a code string, so any
12
+ * front-end (babel now, swc later) that can produce IR reuses this exact codegen.
13
+ * The output mirrors what the babel front-end emits inline today:
14
+ *
15
+ * element -> (() => { const _el$ = createNativeElement(tag);
16
+ * spread({ element: _el$, props });
17
+ * insert(_el$, children); return _el$; })()
18
+ * component -> createMemo(() => createComponent(Name, props))
19
+ * fragment -> [ ...children ]
20
+ */
21
+ const CONTROL_COMPONENT = {
22
+ show: 'Show',
23
+ for: 'For',
24
+ index: 'Index',
25
+ switch: 'Switch',
26
+ match: 'Match',
27
+ dynamic: 'Dynamic',
28
+ errorBoundary: 'ErrorBoundary',
29
+ suspense: 'Suspense',
30
+ };
31
+ function isIdent(name) {
32
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name);
33
+ }
34
+ function propKey(name) {
35
+ return isIdent(name) ? name : JSON.stringify(name);
36
+ }
37
+ function propValue(p) {
38
+ if (p.expr !== undefined) {
39
+ // A ref is not reactive, but which variable ends up holding the element is worth
40
+ // saying, so it carries its own text and position.
41
+ if (p.name === 'ref' && p.at)
42
+ return markHole(paren(p.expr, 'value'), p.at.line, p.at.column, p.expr);
43
+ // Events and non-reactive expressions pass through; reactive ones become thunks
44
+ // so the runtime (spread/insert) can wire a render effect.
45
+ if (!p.reactive)
46
+ return paren(p.expr, 'value');
47
+ const accessor = `() => ${paren(p.expr, 'arrowBody')}`;
48
+ // `at` is the gate: a production build carries no marker.
49
+ return p.at ? markHole(accessor, p.at.line, p.at.column, p.directive) : accessor;
50
+ }
51
+ return JSON.stringify(p.literal ?? true);
52
+ }
53
+ /**
54
+ * Component props are passed as VALUES, not thunks (unlike native-element attrs).
55
+ * The whole `createComponent(...)` call sits inside a `createMemo`, so reading a
56
+ * signal in a prop re-evaluates when the memo re-runs, no per-prop thunk needed.
57
+ * This matches the inline codegen; wrapping a prop like
58
+ * `history={createMemoryHistory()}` in `() => …` would hand the component a
59
+ * function instead of the value (e.g. `history.get is not a function`).
60
+ */
61
+ function componentPropValue(p) {
62
+ // Sits in a `return`, where a top-level comma would read as a sequence.
63
+ if (p.expr !== undefined)
64
+ return paren(p.expr, 'value');
65
+ return JSON.stringify(p.literal ?? true);
66
+ }
67
+ /** Build a props object literal (or mergeProps(...) when spreads are present). */
68
+ function emitProps(props, childrenExpr, used) {
69
+ const spreads = props.filter((p) => p.kind === 'spread');
70
+ const normal = props.filter((p) => p.kind !== 'spread');
71
+ const entries = normal.map((p) => `${propKey(p.name)}: ${propValue(p)}`);
72
+ if (childrenExpr != null)
73
+ entries.push(`children: ${childrenExpr}`);
74
+ const obj = `{ ${entries.join(', ')} }`;
75
+ if (spreads.length > 0) {
76
+ used.add('mergeProps');
77
+ return `mergeProps(${spreads.map((s) => s.expr).join(', ')}, ${obj})`;
78
+ }
79
+ return obj;
80
+ }
81
+ /**
82
+ * The memo a component lowers to is an accessor, so it takes the same hole mark as any
83
+ * other reactive binding. Without it, the insert that places the subtree reports whatever
84
+ * the runtime stack says: a position in the compiled file.
85
+ */
86
+ function markBind(code, at) {
87
+ return at ? markHole(code, at.line, at.column) : code;
88
+ }
89
+ function emitChildren(children, used, templates) {
90
+ if (children.length === 1)
91
+ return emitNode(children[0], used, templates);
92
+ // An element is built, and while hydrating claims its server node, when the array literal
93
+ // runs; a component, control flow or reactive expression is read later, when the array is
94
+ // placed. An element after one of those would claim first and take the server node that
95
+ // belongs to it, so from the first one on elements are deferred too (`deferElement`: built in
96
+ // order when the array is placed, once, in the owner the array was written in).
97
+ let deferred = false;
98
+ const items = children.map((child) => {
99
+ const code = emitNode(child, used, templates);
100
+ if (child.kind === 'element' && deferred) {
101
+ used.add('deferElement');
102
+ return `deferElement(() => ${paren(code, 'arrowBody')})`;
103
+ }
104
+ if (child.kind === 'component' || child.kind === 'control' || (child.kind === 'expr' && child.reactive))
105
+ deferred = true;
106
+ return code;
107
+ });
108
+ return `[${items.join(', ')}]`;
109
+ }
110
+ function emitComponent(name, props, children, used, templates, at) {
111
+ used.add('createMemo');
112
+ used.add('createComponent');
113
+ const spreads = props.filter((p) => p.kind === 'spread');
114
+ const normal = props.filter((p) => p.kind !== 'spread');
115
+ // ALL component props are emitted as getters (Solid model): reading a signal in a prop
116
+ // eagerly inside `createMemo(() => createComponent(...))` would re-create the whole component
117
+ // on every change (a <Portal> then piles up). As getters the component is built ONCE and
118
+ // reactivity flows through the getter into its own effects. Static props as getters are
119
+ // harmless (they return the same value). Matches lazyProps() in the inline codegen.
120
+ // Each body emitted once: emitting children registers their templates.
121
+ const bodies = normal.map((p) => [p.name, componentPropValue(p)]);
122
+ if (children.length > 0) {
123
+ // Children are a LAZY getter: evaluated inside the component's execution, so
124
+ // child components are created in the component's owner scope (preserves owner
125
+ // nesting for context/Suspense), after the component runs (correct provider
126
+ // ordering), and lazily (ErrorBoundary can still catch a throwing child).
127
+ bodies.push(['children', emitChildren(children, used, templates)]);
128
+ }
129
+ let obj = `{ ${bodies.map(([name, body]) => `get ${propKey(name)}() { return ${body}; }`).join(', ')} }`;
130
+ // A getter is a method: `this` inside it is the props object. Written in a class method
131
+ // (a custom element's render), `title={() => this.name}` then read the props, not the
132
+ // element. Arrows keep the enclosing `this`, so those props go out as arrow thunks and the
133
+ // getters call them. Only when some prop mentions `this`; everything else is unchanged.
134
+ if (bodies.some(([, body]) => /\bthis\b/.test(body))) {
135
+ // Parenthesised: an object literal body would otherwise parse as a block.
136
+ const thunks = bodies.map(([name, body]) => `${JSON.stringify(name)}: () => (${body})`);
137
+ const getters = bodies.map(([name]) => `get ${propKey(name)}() { return _$t[${JSON.stringify(name)}](); }`);
138
+ obj = `((_$t) => ({ ${getters.join(', ')} }))({ ${thunks.join(', ')} })`;
139
+ }
140
+ if (spreads.length > 0) {
141
+ used.add('mergeProps');
142
+ obj = `mergeProps(${spreads.map((s) => s.expr).join(', ')}, ${obj})`;
143
+ }
144
+ // Every prop is a getter, so none of them can carry a position. The map rides alongside,
145
+ // and a build that recorded no locations emits nothing.
146
+ const propAt = {};
147
+ for (const p of normal)
148
+ if (p.at)
149
+ propAt[p.name] = [p.at.line, p.at.column];
150
+ if (Object.keys(propAt).length)
151
+ obj = markProps(obj, propAt);
152
+ // The memo never recomputes: every prop is a getter, so this callback reads nothing
153
+ // reactive. It is here for what it makes `insert` do, and it cannot be elided.
154
+ //
155
+ // A component whose return value is *itself* bare control flow (`return <Show …/>`)
156
+ // produces a memo, which `createComponent` deliberately does not stamp as a component.
157
+ // Without this wrapper `insert` stops re-reading it, and the subtree goes stale when a
158
+ // sibling updates the context it depends on: see `show-context-insert.spec.ts`.
159
+ //
160
+ // Static props are not a sufficient condition for dropping it either: safety depends on
161
+ // what the callee *returns*, which lives in another module and is not visible here.
162
+ //
163
+ // Nor can it be a plain `() => createComponent(...)` thunk. The memo also provides
164
+ // *identity*: it runs once and caches. A thunk is re-invoked by insert's render effect
165
+ // on every run, rebuilding the component with a fresh owner, which loses context,
166
+ // duplicates the tree on hydration and piles up Portals. Measured: dropping the wrapper
167
+ // fails 3 tests, replacing it with a thunk fails 14.
168
+ //
169
+ // Control flow does use a bare arrow, and that is not a counter-example: control flow
170
+ // is the reactive boundary and is *meant* to re-run. A user component is meant to run
171
+ // once.
172
+ // The mark goes inside the call, where it runs before createMemo makes the node and so
173
+ // is the one the node takes. Devtools installs the global; without it this is a no-op.
174
+ const mark = at
175
+ ? `globalThis.${SOURCE_MARKER}?.(${JSON.stringify(at.file)},${at.line},${at.column},${JSON.stringify(name)}), `
176
+ : '';
177
+ // The mark makes this a sequence, which has to stay wrapped to pass as one argument.
178
+ // Without one there is nothing to wrap, and a production build never has one.
179
+ return `createMemo(${paren(`${mark}() => createComponent(${name}, ${obj})`, 'value')})`;
180
+ }
181
+ /** `el.setAttribute("class", "card")` for a compile-time constant. */
182
+ function staticAttrAssignment(el, prop) {
183
+ const name = htmlAttrName(prop.name);
184
+ const value = prop.literal;
185
+ // A valueless attribute is `true` in the IR and the empty string in the DOM.
186
+ if (value === true || value === undefined)
187
+ return `${el}.setAttribute(${JSON.stringify(name)}, "");`;
188
+ if (value === false || value === null)
189
+ return '';
190
+ return `${el}.setAttribute(${JSON.stringify(name)}, ${JSON.stringify(String(value))});`;
191
+ }
192
+ let partial = false;
193
+ function emitNode(node, used, templates) {
194
+ switch (node.kind) {
195
+ case 'text':
196
+ return JSON.stringify(node.value);
197
+ case 'expr': {
198
+ if (!node.reactive)
199
+ return paren(node.code, 'value');
200
+ const accessor = `() => ${paren(node.code, 'arrowBody')}`;
201
+ return node.at ? markHole(accessor, node.at.line, node.at.column) : accessor;
202
+ }
203
+ case 'fragment':
204
+ if (node.children.length === 0)
205
+ return 'null';
206
+ return emitChildren(node.children, used, templates);
207
+ case 'component':
208
+ // No reactive prop means no `bindAt`, which is most tags. The insert that places the
209
+ // subtree still has to report somewhere, and the tag itself is where it was written ,
210
+ // without this it reports whatever the runtime stack says, a line in the compiled file.
211
+ return markBind(emitComponent(node.name, node.props, node.children, used, templates, node.at), node.bindAt ?? node.at);
212
+ case 'control': {
213
+ const name = CONTROL_COMPONENT[node.control] ?? node.control;
214
+ used.add(name);
215
+ return markBind(emitComponent(name, node.props, node.children, used, templates), node.bindAt);
216
+ }
217
+ case 'element': {
218
+ // A static subtree is parsed once into a <template> and cloned per instance:
219
+ // one cloneNode instead of an createNativeElement + spread per element.
220
+ // SVG is excluded: the runtime wraps SVG template HTML in an <svg> host and
221
+ // `cloneTemplate(t, true)` returns that wrapper, not the serialized element, so
222
+ // cloning would hand back the wrong node. Correctness first, SVG keeps the
223
+ // imperative path until the runtime grows an unwrapping clone.
224
+ if (templates && node.static && !node.svg && isSerializable(node)) {
225
+ used.add('templateNode');
226
+ const id = `_tmpl$${templates.length}`;
227
+ templates.push({ id, html: serializeStatic(node), tag: node.tag, svg: false });
228
+ // The positions ride along so devtools can name the line each element was written
229
+ // on; the template string itself maps back to the root and nothing finer.
230
+ const at = templatePositions(node);
231
+ return at
232
+ ? `templateNode(${id}, ${JSON.stringify(node.tag)}, false, false, ${JSON.stringify(at)})`
233
+ : `templateNode(${id}, ${JSON.stringify(node.tag)})`;
234
+ }
235
+ // Structure static, contents dynamic: the common shape. One template for the
236
+ // structure, then each hole filled through a reference into the clone. Every
237
+ // reference is read before any insertion, since inserting shifts later positions.
238
+ if (templates && partial) {
239
+ const plan = planPartialTemplate(node);
240
+ if (plan) {
241
+ used.add('templateNode');
242
+ used.add('insert');
243
+ used.add('holeEnd');
244
+ used.add('holeContent');
245
+ used.add('holeScope');
246
+ const id = `_tmpl$${templates.length}`;
247
+ templates.push({ id, html: plan.html, tag: plan.tag, svg: false });
248
+ const at = templatePositions(node);
249
+ const lines = [
250
+ `const _el$ = templateNode(${id}, ${JSON.stringify(plan.tag)}, true${at ? `, false, ${JSON.stringify(at)}` : ''});`,
251
+ ];
252
+ // Every reference first: inserting shifts what follows, so the walk has to be
253
+ // complete before any content goes in.
254
+ for (const step of plan.steps)
255
+ lines.push(`const ${step.ref} = ${step.expr};`);
256
+ for (const hole of plan.holes) {
257
+ // The fourth argument is what the hole already holds, nothing on a fresh
258
+ // clone, the server's content when hydrating. `insert` reconciles against it,
259
+ // so hydration reuses those nodes rather than building new ones.
260
+ // `holeScope` places the hydration cursor at what the server rendered for
261
+ // this hole, so anything the content builds internally adopts too.
262
+ lines.push(`insert(${hole.parentRef}, holeScope(${hole.startRef}, () => ` +
263
+ `${paren(emitNode(hole.node, used, templates), 'arrowBody')}), ` +
264
+ `${hole.endRef}, holeContent(${hole.startRef}, ${hole.endRef}));`);
265
+ }
266
+ lines.push('return _el$;');
267
+ return `(() => { ${lines.join(' ')} })()`;
268
+ }
269
+ }
270
+ used.add('createNativeElement');
271
+ const tag = JSON.stringify(node.tag);
272
+ const el = '_el$';
273
+ const parts = [];
274
+ // The third argument is where the tag was written. An element built this way is not
275
+ // in a template, so nothing else records it.
276
+ const createArgs = node.at
277
+ ? `${tag}, ${node.svg}, ${JSON.stringify(node.at)}`
278
+ : node.svg
279
+ ? `${tag}, true`
280
+ : tag;
281
+ parts.push(`const ${el} = createNativeElement(${createArgs});`);
282
+ if (node.props.length > 0) {
283
+ // Literal attributes are written straight on. `spread` is a generic helper that
284
+ // walks every prop checking for reactivity, events, refs, class/style objects and
285
+ // namespaces: none of which a compile-time constant needs. Same predicate the
286
+ // template serializer uses, so the two agree on what a plain attribute is.
287
+ if (!node.svg && node.props.every(isPlainLiteralAttr)) {
288
+ for (const p of node.props)
289
+ parts.push(staticAttrAssignment(el, p));
290
+ }
291
+ else {
292
+ used.add('spread');
293
+ const svgFlag = node.svg ? ', isSVG: true' : '';
294
+ // A dash in the tag is what makes it a custom element, and the tag is known
295
+ // here, so the runtime does not have to read it back off the node. It falls
296
+ // back to that check when the flag is absent, which is how a hand-written
297
+ // `spread` call still behaves.
298
+ // For a custom element it also names the props wrapped as accessors: any other
299
+ // function is a property value (an action, a callback) and must not be called.
300
+ const accessors = node.props
301
+ .filter((p) => p.kind !== 'spread' && p.expr !== undefined && p.reactive && p.name !== 'ref')
302
+ .map((p) => p.name);
303
+ const customFlag = node.tag.includes('-') ? `, isCustomElement: true, accessors: ${JSON.stringify(accessors)}` : '';
304
+ parts.push(`spread({ element: ${el}, props: ${emitProps(node.props, null, used)}${svgFlag}${customFlag} });`);
305
+ }
306
+ }
307
+ // Insert each child individually (like the jsx runtime's applyProps), so a
308
+ // reactive/component child that isn't the only child still gets its own
309
+ // reactive binding. A single insert(el, [array]) does NOT bind function
310
+ // elements sitting inside the array.
311
+ for (const child of node.children) {
312
+ used.add('insert');
313
+ const childCode = emitNode(child, used, templates);
314
+ // `null` asks insert for an anchor of its own, which holds the child's place among
315
+ // its siblings. Every child whose content can change needs one: an expression the
316
+ // classifier calls opaque (an arrow, a function passed by name) may still be one.
317
+ // Only a literal never changes, and it goes straight in.
318
+ const anchored = (child.kind === 'expr' && (child.reactive || !isLiteralCode(child.code))) ||
319
+ child.kind === 'component' ||
320
+ child.kind === 'control';
321
+ parts.push(anchored ? `insert(${el}, ${childCode}, null);` : `insert(${el}, ${childCode});`);
322
+ }
323
+ parts.push(`return ${el};`);
324
+ return `(() => { ${parts.join(' ')} })()`;
325
+ }
326
+ }
327
+ }
328
+ /** A string, number, boolean or nullish literal: an expression that never renders anything else. */
329
+ const LITERAL = /^\s*(?:'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`[^`$]*`|-?\d[\d_.eE+-]*|true|false|null|undefined)\s*$/;
330
+ const isLiteralCode = (code) => LITERAL.test(code);
331
+ /**
332
+ * Substitute template declarations into the code as inline `createTemplate` calls.
333
+ *
334
+ * For hosts that cannot hoist: nested JSX lowered inside an expression, where there is
335
+ * no module scope to reach. `createTemplate` caches by HTML string, so this costs a Map
336
+ * lookup per instantiation rather than a re-parse, and is still far cheaper than
337
+ * building the subtree element by element.
338
+ */
339
+ export function inlineTemplates(code, templates) {
340
+ if (!templates || templates.length === 0)
341
+ return code;
342
+ const byId = new Map(templates.map((t) => [t.id, JSON.stringify(t.html)]));
343
+ // Single pass, for the same reason `adoptTemplates` needs one.
344
+ return code.replace(/_tmpl\$\d+/g, (id) => byId.get(id) ?? id);
345
+ }
346
+ export const imperativeBackend = {
347
+ name: 'imperative',
348
+ contract: RUNTIME_CONTRACT_V1,
349
+ emit(node, options) {
350
+ const used = new Set();
351
+ // Off by default: `createTemplate` builds real DOM nodes, so on the server they
352
+ // land in a ServerElement tree and clash, and during hydration a clone creates a
353
+ // fresh node where the existing one must be adopted. Both need runtime support
354
+ // that does not exist yet, so the client-only win stays opt-in until it does.
355
+ const templates = options?.templateClone !== false
356
+ ? []
357
+ : undefined;
358
+ partial = options?.partialTemplates === true;
359
+ const code = emitNode(node, used, templates);
360
+ return { code, imports: Array.from(used), templates };
361
+ },
362
+ };