@fluixi/compiler 1.0.0-alpha.82 → 1.0.0-alpha.84

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 (188) 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.mjs +41 -1
  4. package/dist/analyze/intrinsics.cjs +80 -1
  5. package/dist/analyze/intrinsics.d.cts +66 -0
  6. package/dist/analyze/intrinsics.mjs +59 -1
  7. package/dist/analyze/paren.cjs +134 -0
  8. package/dist/analyze/paren.d.cts +23 -0
  9. package/dist/analyze/paren.d.ts +24 -0
  10. package/dist/analyze/paren.d.ts.map +1 -0
  11. package/dist/analyze/paren.js +168 -0
  12. package/dist/analyze/paren.mjs +113 -0
  13. package/dist/analyze/props-destructure.cjs +226 -1
  14. package/dist/analyze/props-destructure.d.cts +83 -0
  15. package/dist/analyze/props-destructure.mjs +205 -1
  16. package/dist/analyze/reactive-bindings.cjs +190 -1
  17. package/dist/analyze/reactive-bindings.d.cts +42 -0
  18. package/dist/analyze/reactive-bindings.mjs +167 -1
  19. package/dist/analyze/reactive-expr.cjs +38 -1
  20. package/dist/analyze/reactive-expr.d.cts +38 -0
  21. package/dist/analyze/reactive-expr.mjs +17 -1
  22. package/dist/analyze/static-graph.cjs +811 -0
  23. package/dist/analyze/static-graph.d.cts +102 -0
  24. package/dist/analyze/static-graph.d.ts +103 -0
  25. package/dist/analyze/static-graph.d.ts.map +1 -0
  26. package/dist/analyze/static-graph.js +869 -0
  27. package/dist/analyze/static-graph.mjs +793 -0
  28. package/dist/babel-NRW4EFTG.mjs +636 -0
  29. package/dist/chunk-3YKZ4GNH.mjs +11 -0
  30. package/dist/chunk-EZR7NZOY.mjs +1718 -0
  31. package/dist/chunk-FSSWUXUR.mjs +16 -0
  32. package/dist/chunk-MJV3UXIL.mjs +158 -0
  33. package/dist/chunk-R2VHAZAX.mjs +1078 -0
  34. package/dist/codegen/backend.cjs +18 -1
  35. package/dist/codegen/backend.d.cts +35 -0
  36. package/dist/codegen/backends/imperative.cjs +542 -1
  37. package/dist/codegen/backends/imperative.d.cts +11 -0
  38. package/dist/codegen/backends/imperative.d.ts.map +1 -1
  39. package/dist/codegen/backends/imperative.js +68 -13
  40. package/dist/codegen/backends/imperative.mjs +519 -1
  41. package/dist/codegen/contract.cjs +52 -1
  42. package/dist/codegen/contract.d.cts +24 -0
  43. package/dist/codegen/contract.mjs +31 -1
  44. package/dist/codegen/partial-template.cjs +176 -1
  45. package/dist/codegen/partial-template.d.cts +61 -0
  46. package/dist/codegen/partial-template.mjs +153 -1
  47. package/dist/codegen/serialize-static.cjs +125 -1
  48. package/dist/codegen/serialize-static.d.cts +38 -0
  49. package/dist/codegen/serialize-static.d.ts +16 -0
  50. package/dist/codegen/serialize-static.d.ts.map +1 -1
  51. package/dist/codegen/serialize-static.js +25 -0
  52. package/dist/codegen/serialize-static.mjs +104 -1
  53. package/dist/frontend/babel/build-ir-lit.cjs +1509 -1
  54. package/dist/frontend/babel/build-ir-lit.d.cts +26 -0
  55. package/dist/frontend/babel/build-ir-lit.mjs +1478 -1
  56. package/dist/frontend/babel/build-ir.cjs +1524 -1
  57. package/dist/frontend/babel/build-ir.d.cts +35 -0
  58. package/dist/frontend/babel/build-ir.mjs +1495 -1
  59. package/dist/frontend/babel/index.cjs +2186 -1
  60. package/dist/frontend/babel/index.d.cts +33 -0
  61. package/dist/frontend/babel/index.mjs +2156 -1
  62. package/dist/frontend/babel/lower-template.cjs +1507 -1
  63. package/dist/frontend/babel/lower-template.d.cts +23 -0
  64. package/dist/frontend/babel/lower-template.mjs +1478 -1
  65. package/dist/frontend/babel/plugin.cjs +2132 -1
  66. package/dist/frontend/babel/plugin.d.cts +95 -0
  67. package/dist/frontend/babel/plugin.mjs +2103 -1
  68. package/dist/frontend/babel/server-functions.cjs +110 -1
  69. package/dist/frontend/babel/server-functions.d.cts +10 -0
  70. package/dist/frontend/babel/server-functions.mjs +89 -1
  71. package/dist/frontend/babel/types.cjs +18 -1
  72. package/dist/frontend/babel/types.d.cts +33 -0
  73. package/dist/frontend/types.cjs +18 -1
  74. package/dist/frontend/types.d.cts +25 -0
  75. package/dist/frontend/vocabulary.cjs +98 -0
  76. package/dist/frontend/vocabulary.d.cts +79 -0
  77. package/dist/frontend/vocabulary.d.ts +80 -0
  78. package/dist/frontend/vocabulary.d.ts.map +1 -0
  79. package/dist/frontend/vocabulary.js +124 -0
  80. package/dist/frontend/vocabulary.mjs +77 -0
  81. package/dist/index.cjs +1594 -13
  82. package/dist/index.d.cts +27 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +3 -0
  85. package/dist/index.mjs +1574 -13
  86. package/dist/integrations.cjs +4307 -25
  87. package/dist/integrations.d.cts +215 -0
  88. package/dist/integrations.d.ts +16 -0
  89. package/dist/integrations.d.ts.map +1 -1
  90. package/dist/integrations.js +21 -2
  91. package/dist/integrations.mjs +531 -17
  92. package/dist/ir/nodes.cjs +18 -1
  93. package/dist/ir/nodes.d.cts +168 -0
  94. package/dist/ir/nodes.d.ts +46 -0
  95. package/dist/ir/nodes.d.ts.map +1 -1
  96. package/dist/lower/compile-template.cjs +1356 -1
  97. package/dist/lower/compile-template.d.cts +69 -0
  98. package/dist/lower/compile-template.d.ts +12 -0
  99. package/dist/lower/compile-template.d.ts.map +1 -1
  100. package/dist/lower/compile-template.js +5 -1
  101. package/dist/lower/compile-template.mjs +1336 -1
  102. package/dist/lower/jsx.cjs +529 -1
  103. package/dist/lower/jsx.d.cts +25 -0
  104. package/dist/lower/jsx.d.ts +2 -0
  105. package/dist/lower/jsx.d.ts.map +1 -1
  106. package/dist/lower/jsx.js +27 -4
  107. package/dist/lower/jsx.mjs +506 -1
  108. package/dist/lower/template.cjs +1061 -1
  109. package/dist/lower/template.d.cts +53 -0
  110. package/dist/lower/template.d.ts +14 -1
  111. package/dist/lower/template.d.ts.map +1 -1
  112. package/dist/lower/template.js +106 -19
  113. package/dist/lower/template.mjs +1042 -1
  114. package/dist/lower/text.cjs +42 -1
  115. package/dist/lower/text.d.cts +10 -0
  116. package/dist/lower/text.mjs +21 -1
  117. package/dist/optimize/analyze-static.cjs +112 -1
  118. package/dist/optimize/analyze-static.d.cts +39 -0
  119. package/dist/optimize/analyze-static.mjs +91 -1
  120. package/dist/optimize/collapse-strategies.cjs +90 -1
  121. package/dist/optimize/collapse-strategies.d.cts +30 -0
  122. package/dist/optimize/collapse-strategies.mjs +67 -1
  123. package/dist/options.cjs +33 -1
  124. package/dist/options.d.cts +39 -0
  125. package/dist/options.mjs +12 -1
  126. package/dist/resolve/builtins.cjs +73 -1
  127. package/dist/resolve/builtins.d.cts +68 -0
  128. package/dist/resolve/builtins.mjs +53 -1
  129. package/dist/resolve/component-globals.cjs +233 -13
  130. package/dist/resolve/component-globals.d.cts +80 -0
  131. package/dist/resolve/component-globals.mjs +210 -13
  132. package/dist/resolve/component-resolver.cjs +80 -1
  133. package/dist/resolve/component-resolver.d.cts +68 -0
  134. package/dist/resolve/component-resolver.mjs +59 -1
  135. package/dist/resolve/load-directive.cjs +93 -1
  136. package/dist/resolve/load-directive.d.cts +53 -0
  137. package/dist/resolve/load-directive.mjs +72 -1
  138. package/dist/resolve/resolve-ir.cjs +108 -1
  139. package/dist/resolve/resolve-ir.d.cts +53 -0
  140. package/dist/resolve/resolve-ir.mjs +85 -1
  141. package/dist/resolve/write-globals.cjs +318 -13
  142. package/dist/resolve/write-globals.d.cts +30 -0
  143. package/dist/resolve/write-globals.mjs +297 -13
  144. package/dist/server-fns-4ZXN6DYU.mjs +78 -0
  145. package/dist/server-functions-V6D6DRIA.mjs +82 -0
  146. package/dist/transform/bindings.cjs +71 -1
  147. package/dist/transform/bindings.d.cts +16 -0
  148. package/dist/transform/bindings.mjs +50 -1
  149. package/dist/transform/index.cjs +2732 -8
  150. package/dist/transform/index.d.cts +15 -0
  151. package/dist/transform/index.mjs +3773 -17
  152. package/dist/transform/intrinsics.cjs +216 -3
  153. package/dist/transform/intrinsics.d.cts +21 -0
  154. package/dist/transform/intrinsics.mjs +193 -3
  155. package/dist/transform/props.cjs +441 -3
  156. package/dist/transform/props.d.cts +45 -0
  157. package/dist/transform/props.mjs +1482 -12
  158. package/dist/transform/server-fn-id.cjs +35 -1
  159. package/dist/transform/server-fn-id.d.cts +9 -0
  160. package/dist/transform/server-fn-id.mjs +14 -1
  161. package/dist/transform/server-fns.cjs +114 -2
  162. package/dist/transform/server-fns.d.cts +12 -0
  163. package/dist/transform/server-fns.mjs +1155 -11
  164. package/dist/transform/source-locations.cjs +330 -0
  165. package/dist/transform/source-locations.d.cts +43 -0
  166. package/dist/transform/source-locations.d.ts +44 -0
  167. package/dist/transform/source-locations.d.ts.map +1 -0
  168. package/dist/transform/source-locations.js +238 -0
  169. package/dist/transform/source-locations.mjs +307 -0
  170. package/dist/transform/templates.cjs +2701 -7
  171. package/dist/transform/templates.d.cts +69 -0
  172. package/dist/transform/templates.d.ts +12 -4
  173. package/dist/transform/templates.d.ts.map +1 -1
  174. package/dist/transform/templates.js +72 -7
  175. package/dist/transform/templates.mjs +3743 -16
  176. package/dist/transform-BT4MMASR.mjs +893 -0
  177. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  178. package/package.json +6 -5
  179. package/dist/babel-4JUDAR2G.mjs +0 -1
  180. package/dist/chunk-3SAEGOMQ.mjs +0 -1
  181. package/dist/chunk-IBRM4W7I.mjs +0 -10
  182. package/dist/chunk-OHHZCYIQ.mjs +0 -1
  183. package/dist/chunk-PVR2SN3B.mjs +0 -1
  184. package/dist/chunk-QUIYULS2.mjs +0 -1
  185. package/dist/chunk-YR3SAEO7.mjs +0 -1
  186. package/dist/server-fns-6QM243HC.mjs +0 -2
  187. package/dist/server-functions-E3LKCZ4R.mjs +0 -1
  188. package/dist/transform-5WC4FWJE.mjs +0 -8
@@ -0,0 +1,811 @@
1
+ /*! @fluixi/compiler v1.0.0-alpha.84 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/analyze/static-graph.ts
22
+ var static_graph_exports = {};
23
+ __export(static_graph_exports, {
24
+ analyzeReactiveGraph: () => analyzeReactiveGraph
25
+ });
26
+ module.exports = __toCommonJS(static_graph_exports);
27
+ var import_parser = require("@babel/parser");
28
+ var import_template_parser = require("@fluixi/template-parser");
29
+
30
+ // src/analyze/intrinsics.ts
31
+ var REACTIVE_MODULE = "@fluixi/reactive/signal";
32
+ var INTRINSICS = {
33
+ $signal: { export: "signal", module: REACTIVE_MODULE, returns: "signal-handle" },
34
+ $memo: { export: "memo", module: REACTIVE_MODULE, returns: "memo-handle" },
35
+ $effect: { export: "effect", module: REACTIVE_MODULE, returns: "effect" },
36
+ $store: { export: "store", module: "@fluixi/reactive/store", returns: "store-handle" },
37
+ $resource: { export: "resource", module: REACTIVE_MODULE, returns: "resource-handle" },
38
+ // No short runtime form for these yet, so the intrinsic stands for the `create*`
39
+ // name. Still worth having — no import to write — and when a shorter form is
40
+ // designed, the change is this line rather than a compiler pass.
41
+ $selector: { export: "createSelector", module: REACTIVE_MODULE, returns: "memo-accessor" },
42
+ $deferred: { export: "createDeferred", module: REACTIVE_MODULE, returns: "memo-accessor" },
43
+ // Not value constructors, but the compiler has to know them: they change what a read
44
+ // does. `untrack` suppresses dependency collection, which is exactly the kind of thing
45
+ // dependency analysis must not guess at.
46
+ $untrack: { export: "untrack", module: REACTIVE_MODULE, returns: "plain" },
47
+ $untrackStore: { export: "untrackStore", module: "@fluixi/reactive/store", returns: "plain" }
48
+ };
49
+ var RUNTIME_PRIMITIVES = {
50
+ signal: "signal-handle",
51
+ memo: "memo-handle",
52
+ effect: "effect",
53
+ store: "store-handle",
54
+ createSignal: ["signal-accessor", "signal-setter"],
55
+ createMemo: "memo-accessor",
56
+ createEffect: "effect",
57
+ createRenderEffect: "effect",
58
+ createStore: "reactive-object",
59
+ resource: "resource-handle",
60
+ createResource: "reactive-object",
61
+ createSelector: "memo-accessor",
62
+ createDeferred: "memo-accessor"
63
+ };
64
+ var PRIMITIVE_MODULES = [
65
+ "@fluixi/reactive",
66
+ "@fluixi/reactive/signal",
67
+ "@fluixi/reactive/store",
68
+ "@fluixi/core"
69
+ ];
70
+ var INTRINSIC_CALL = new RegExp(`\\$(?:${Object.keys(INTRINSICS).map((n) => n.slice(1)).join("|")})\\s*\\(`);
71
+ function isIntrinsicName(name) {
72
+ return Object.prototype.hasOwnProperty.call(INTRINSICS, name);
73
+ }
74
+ function isPrimitiveModule(source) {
75
+ return PRIMITIVE_MODULES.includes(source);
76
+ }
77
+
78
+ // src/analyze/reactive-bindings.ts
79
+ function patternNames(node, out) {
80
+ if (!node) return;
81
+ switch (node.type) {
82
+ case "Identifier":
83
+ out.add(node.name);
84
+ return;
85
+ case "ObjectPattern":
86
+ for (const p of node.properties ?? []) {
87
+ if (p.type === "RestElement") patternNames(p.argument, out);
88
+ else patternNames(p.value, out);
89
+ }
90
+ return;
91
+ case "ArrayPattern":
92
+ for (const e of node.elements ?? []) patternNames(e, out);
93
+ return;
94
+ case "AssignmentPattern":
95
+ patternNames(node.left, out);
96
+ return;
97
+ case "RestElement":
98
+ patternNames(node.argument, out);
99
+ return;
100
+ }
101
+ }
102
+ function walk(root, visit) {
103
+ if (!root || typeof root !== "object" || typeof root.type !== "string") return;
104
+ visit(root);
105
+ for (const key of Object.keys(root)) {
106
+ if (key === "loc" || key === "leadingComments" || key === "trailingComments") continue;
107
+ const value = root[key];
108
+ if (Array.isArray(value)) for (const item of value) walk(item, visit);
109
+ else if (value && typeof value === "object") walk(value, visit);
110
+ }
111
+ }
112
+ function calledPrimitive(node, bindings) {
113
+ if (node.type !== "CallExpression") return void 0;
114
+ const callee = node.callee;
115
+ if (callee?.type !== "Identifier") return void 0;
116
+ const name = callee.name;
117
+ const imported = bindings.primitives.get(name);
118
+ if (imported) return imported;
119
+ const intrinsic = INTRINSICS[name];
120
+ if (intrinsic && !bindings.shadowed.has(name)) return intrinsic.returns;
121
+ return void 0;
122
+ }
123
+ function classify(id, returns, kinds) {
124
+ if (Array.isArray(returns)) {
125
+ if (id.type === "ArrayPattern") {
126
+ id.elements.forEach((element, index) => {
127
+ const kind = returns[index];
128
+ if (element?.type === "Identifier" && kind) kinds.set(element.name, kind);
129
+ });
130
+ }
131
+ return;
132
+ }
133
+ if (id.type === "Identifier") kinds.set(id.name, returns);
134
+ }
135
+ function resolveReactiveBindings(program) {
136
+ const bindings = { kinds: /* @__PURE__ */ new Map(), primitives: /* @__PURE__ */ new Map(), shadowed: /* @__PURE__ */ new Set() };
137
+ const root = program;
138
+ walk(root, (node) => {
139
+ const names = /* @__PURE__ */ new Set();
140
+ if (node.type === "VariableDeclarator") patternNames(node.id, names);
141
+ else if (node.type === "FunctionDeclaration" || node.type === "ClassDeclaration") patternNames(node.id, names);
142
+ else if (node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier") patternNames(node.local, names);
143
+ else if (node.type === "ImportSpecifier") patternNames(node.local, names);
144
+ else if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration") {
145
+ for (const p of node.params ?? []) patternNames(p, names);
146
+ }
147
+ for (const name of names) if (INTRINSICS[name]) bindings.shadowed.add(name);
148
+ });
149
+ for (const statement of root.body ?? []) {
150
+ if (statement.type !== "ImportDeclaration") continue;
151
+ if (!isPrimitiveModule(statement.source?.value)) continue;
152
+ for (const specifier of statement.specifiers ?? []) {
153
+ if (specifier.type !== "ImportSpecifier") continue;
154
+ const importedNode = specifier.imported;
155
+ const imported = importedNode.type === "Identifier" ? importedNode.name : importedNode.value;
156
+ const returns = RUNTIME_PRIMITIVES[imported];
157
+ if (returns) bindings.primitives.set(specifier.local.name, returns);
158
+ }
159
+ }
160
+ walk(root, (node) => {
161
+ if (node.type !== "VariableDeclarator" || !node.init) return;
162
+ const returns = calledPrimitive(node.init, bindings);
163
+ if (returns) classify(node.id, returns, bindings.kinds);
164
+ });
165
+ return bindings;
166
+ }
167
+
168
+ // src/resolve/builtins.ts
169
+ var DOM_CONTROL_FLOW = [
170
+ "Show",
171
+ "For",
172
+ "Index",
173
+ "Switch",
174
+ "Match",
175
+ "Portal",
176
+ "Dynamic",
177
+ "ErrorBoundary"
178
+ ];
179
+ var CORE_CONTROL_FLOW = ["Suspense", "SuspenseList", "Await"];
180
+ var ROUTER_COMPONENTS = ["Router", "Outlet", "Redirect", "Link"];
181
+ var BUILTIN_COMPONENTS = [
182
+ ...DOM_CONTROL_FLOW,
183
+ ...CORE_CONTROL_FLOW,
184
+ ...ROUTER_COMPONENTS
185
+ ];
186
+ var RESERVED_COMPONENTS = /* @__PURE__ */ new Set([
187
+ ...DOM_CONTROL_FLOW,
188
+ ...CORE_CONTROL_FLOW
189
+ ]);
190
+
191
+ // src/analyze/static-graph.ts
192
+ var PRIMITIVE_KIND = {
193
+ signal: "state",
194
+ createSignal: "state",
195
+ memo: "memo",
196
+ createMemo: "memo",
197
+ effect: "effect",
198
+ createEffect: "effect",
199
+ store: "store",
200
+ createStore: "store",
201
+ resource: "resource",
202
+ createResource: "resource"
203
+ };
204
+ var READS = /* @__PURE__ */ new Set(["memo", "effect", "resource"]);
205
+ var DIRECTIVES = /* @__PURE__ */ new Set([
206
+ ...DOM_CONTROL_FLOW,
207
+ ...CORE_CONTROL_FLOW,
208
+ // The router is supplied without an import too. Without these, an app whose root renders
209
+ // `<Router>` has a root component connected to nothing at all.
210
+ ...ROUTER_COMPONENTS
211
+ ]);
212
+ var TRACKED_PROP = {
213
+ Router: "routes",
214
+ Link: "href",
215
+ Redirect: "to",
216
+ Show: "when",
217
+ Match: "when",
218
+ For: "each",
219
+ Index: "each",
220
+ Dynamic: "component",
221
+ Portal: "mount",
222
+ Await: "value"
223
+ };
224
+ var ROUTER = new Set(ROUTER_COMPONENTS);
225
+ var directiveKind = (tag) => ROUTER.has(tag) ? "router" : "control";
226
+ var HTTP_METHODS = /* @__PURE__ */ new Set([
227
+ "GET",
228
+ "POST",
229
+ "PUT",
230
+ "PATCH",
231
+ "DELETE",
232
+ "HEAD",
233
+ "OPTIONS"
234
+ ]);
235
+ function normalizePath(path) {
236
+ return path.replace(/\\/g, "/").replace(/^\.?\/+/, "");
237
+ }
238
+ function walk2(node, visit, stack = []) {
239
+ if (!node || typeof node.type !== "string") return;
240
+ visit(node, stack);
241
+ stack.push(node);
242
+ for (const key of Object.keys(node)) {
243
+ if (key === "loc" || key === "parent") continue;
244
+ const value = node[key];
245
+ if (Array.isArray(value)) for (const child of value) walk2(child, visit, stack);
246
+ else if (value && typeof value.type === "string") walk2(value, visit, stack);
247
+ }
248
+ stack.pop();
249
+ }
250
+ function declaredName(stack) {
251
+ const declarator = [...stack].reverse().find((n) => n.type === "VariableDeclarator");
252
+ const id = declarator?.id;
253
+ if (id?.type === "Identifier") return id.name;
254
+ if (id?.type === "ArrayPattern") {
255
+ const first = id.elements?.[0];
256
+ if (first?.type === "Identifier") return first.name;
257
+ }
258
+ return void 0;
259
+ }
260
+ function componentName(node) {
261
+ if (node.type === "FunctionDeclaration") {
262
+ const name = node.id?.name;
263
+ return name && name[0] === name[0]?.toUpperCase() ? name : void 0;
264
+ }
265
+ if (node.type === "VariableDeclarator") {
266
+ const id = node.id;
267
+ const init = node.init;
268
+ if (id?.type !== "Identifier" || !init) return void 0;
269
+ if (init.type !== "ArrowFunctionExpression" && init.type !== "FunctionExpression") return void 0;
270
+ const name = id.name;
271
+ return name[0] === name[0]?.toUpperCase() ? name : void 0;
272
+ }
273
+ return void 0;
274
+ }
275
+ function mentions(node) {
276
+ const names = /* @__PURE__ */ new Set();
277
+ walk2(node, (n, stack) => {
278
+ if (n.type !== "Identifier") return;
279
+ const parent = stack[stack.length - 1];
280
+ if (parent?.type === "MemberExpression" && parent.property === n && !parent.computed) return;
281
+ if (parent?.type === "ObjectProperty" && parent.key === n && !parent.computed) return;
282
+ names.add(n.name);
283
+ });
284
+ return names;
285
+ }
286
+ function templatePieces(quasi) {
287
+ const pieces = [];
288
+ const quasis = quasi.quasis ?? [];
289
+ const expressions = quasi.expressions ?? [];
290
+ quasis.forEach((q, i) => {
291
+ const value = q.value;
292
+ pieces.push({ kind: "static", text: value?.cooked ?? value?.raw ?? "", start: q.start ?? 0 });
293
+ if (i < expressions.length) {
294
+ const e = expressions[i];
295
+ pieces.push({ kind: "hole", index: i, start: e.start ?? 0, end: e.end ?? 0 });
296
+ }
297
+ });
298
+ return pieces;
299
+ }
300
+ function positionsIn(code) {
301
+ const starts = [0];
302
+ for (let i = 0; i < code.length; i++) if (code.charCodeAt(i) === 10) starts.push(i + 1);
303
+ return (offset) => {
304
+ let low = 0;
305
+ let high = starts.length - 1;
306
+ while (low < high) {
307
+ const mid = low + high + 1 >> 1;
308
+ if (starts[mid] <= offset) low = mid;
309
+ else high = mid - 1;
310
+ }
311
+ return { line: low + 1, column: offset - starts[low] };
312
+ };
313
+ }
314
+ function describeTemplateElement(el) {
315
+ let id = "";
316
+ const classes = [];
317
+ for (const attr of el.attributes) {
318
+ if (attr.kind !== "Attribute" || attr.value?.kind !== "static") continue;
319
+ if (attr.name === "id") id = `#${attr.value.value}`;
320
+ else if (attr.name === "class") {
321
+ classes.push(...String(attr.value.value).split(/\s+/).filter(Boolean).slice(0, 2));
322
+ }
323
+ }
324
+ return `${el.tag}${id}${classes.map((c) => `.${c}`).join("")}`;
325
+ }
326
+ function valueHoles(value) {
327
+ if (!value) return [];
328
+ if (value.kind === "hole") return [value.hole];
329
+ if (value.kind === "mixed") return value.parts.flatMap((p) => "hole" in p ? [p.hole] : []);
330
+ return [];
331
+ }
332
+ function describeJsx(opening) {
333
+ const tag = opening.name?.name ?? "element";
334
+ let id = "";
335
+ const classes = [];
336
+ for (const attr of opening.attributes ?? []) {
337
+ if (attr.type !== "JSXAttribute") continue;
338
+ const name = attr.name?.name;
339
+ const value = attr.value;
340
+ if (value?.type !== "StringLiteral") continue;
341
+ if (name === "id") id = `#${value.value}`;
342
+ else if (name === "class" || name === "className") {
343
+ classes.push(...String(value.value).split(/\s+/).filter(Boolean).slice(0, 2));
344
+ }
345
+ }
346
+ return `${tag}${id}${classes.map((c) => `.${c}`).join("")}`;
347
+ }
348
+ function trackedExpression(opening, prop) {
349
+ for (const attr of opening.attributes ?? []) {
350
+ if (attr.type !== "JSXAttribute" || attr.name?.name !== prop) continue;
351
+ const value = attr.value;
352
+ return value?.type === "JSXExpressionContainer" ? value.expression : void 0;
353
+ }
354
+ return void 0;
355
+ }
356
+ function analyzeReactiveGraph(files, options = {}) {
357
+ const routesDir = (options.routesDir ?? "src/routes").replace(/^\.?\/+|\/+$/g, "");
358
+ const apiDir = (options.apiDir ?? "src/api").replace(/^\.?\/+|\/+$/g, "");
359
+ const fileRoutes = [];
360
+ const pending = [];
361
+ const exported = /* @__PURE__ */ new Map();
362
+ const locals = /* @__PURE__ */ new Map();
363
+ const imports = /* @__PURE__ */ new Map();
364
+ const usages = [];
365
+ const routeRefs = [];
366
+ const holes = [];
367
+ const domFor = /* @__PURE__ */ new Map();
368
+ const unresolved = [];
369
+ const componentMentions = /* @__PURE__ */ new Map();
370
+ let seq = 0;
371
+ for (const file of files) {
372
+ if (!/\.(tsx?|jsx?)$/.test(file.path)) continue;
373
+ let program;
374
+ try {
375
+ program = (0, import_parser.parse)(file.code, {
376
+ sourceType: "module",
377
+ plugins: ["jsx", "typescript"],
378
+ errorRecovery: true
379
+ }).program;
380
+ } catch {
381
+ continue;
382
+ }
383
+ const { primitives, shadowed } = resolveReactiveBindings(program);
384
+ const here = /* @__PURE__ */ new Map();
385
+ const sold = /* @__PURE__ */ new Map();
386
+ const from = /* @__PURE__ */ new Map();
387
+ locals.set(file.path, here);
388
+ exported.set(file.path, sold);
389
+ imports.set(file.path, from);
390
+ const inRoutesDir = normalizePath(file.path).startsWith(`${routesDir}/`);
391
+ const components = /* @__PURE__ */ new Map();
392
+ let positionAt = null;
393
+ const positionOf = () => positionAt ??= positionsIn(file.code);
394
+ walk2(program, (node, stack) => {
395
+ const name = componentName(node);
396
+ const at = node.loc?.start;
397
+ if (!name || !at) return;
398
+ const id = seq++;
399
+ components.set(node, id);
400
+ here.set(name, id);
401
+ componentMentions.set(id, mentions(node));
402
+ if (inRoutesDir) fileRoutes.push(id);
403
+ pending.push({
404
+ node: {
405
+ id,
406
+ label: name,
407
+ kind: HTTP_METHODS.has(name) ? "handler" : "component",
408
+ deps: [],
409
+ writes: [],
410
+ runs: 0,
411
+ lastPulse: 0,
412
+ source: { file: file.path, line: at.line, column: at.column }
413
+ },
414
+ reads: /* @__PURE__ */ new Set(),
415
+ file: file.path
416
+ });
417
+ });
418
+ walk2(program, (node, stack) => {
419
+ if (node.type === "ImportDeclaration") {
420
+ const source = node.source?.value;
421
+ for (const spec of node.specifiers ?? []) {
422
+ const local = spec.local?.name;
423
+ if (local && source?.startsWith(".")) from.set(local, source);
424
+ }
425
+ return;
426
+ }
427
+ if (node.type !== "CallExpression") return;
428
+ const callee = node.callee;
429
+ if (callee?.type !== "Identifier") return;
430
+ const name = callee.name;
431
+ const intrinsic = name.startsWith("$") && isIntrinsicName(name) && !shadowed.has(name);
432
+ if (!intrinsic && !primitives.has(name)) return;
433
+ const kind = PRIMITIVE_KIND[intrinsic ? name.slice(1) : name];
434
+ const at = node.loc?.start;
435
+ if (!kind || !at) return;
436
+ const id = seq++;
437
+ const label = declaredName(stack) ?? `${kind}${id}`;
438
+ here.set(label, id);
439
+ let owner;
440
+ for (let i = stack.length - 1; i >= 0; i--) {
441
+ const found = components.get(stack[i]);
442
+ if (found !== void 0) {
443
+ owner = found;
444
+ break;
445
+ }
446
+ }
447
+ pending.push({
448
+ node: {
449
+ id,
450
+ label,
451
+ kind,
452
+ deps: [],
453
+ writes: [],
454
+ runs: 0,
455
+ lastPulse: 0,
456
+ source: { file: file.path, line: at.line, column: at.column },
457
+ ...owner !== void 0 ? { createdIn: owner } : {}
458
+ },
459
+ // Only what reads can read: a signal's initial value is not a dependency.
460
+ reads: READS.has(kind) ? mentions(node.arguments?.[0]) : /* @__PURE__ */ new Set(),
461
+ file: file.path
462
+ });
463
+ });
464
+ walk2(program, (node, stack) => {
465
+ if (node.type !== "JSXOpeningElement") return;
466
+ const tag = node.name?.name;
467
+ if (!tag || tag[0] !== tag[0]?.toUpperCase()) return;
468
+ let owner;
469
+ for (let i = stack.length - 1; i >= 0; i--) {
470
+ const found = components.get(stack[i]);
471
+ if (found !== void 0) {
472
+ owner = found;
473
+ break;
474
+ }
475
+ }
476
+ const own = here.has(tag) || from.has(tag);
477
+ if (!own && DIRECTIVES.has(tag)) {
478
+ const at = node.loc?.start;
479
+ if (!at) return;
480
+ const id = seq++;
481
+ const prop = TRACKED_PROP[tag];
482
+ const tracked = prop ? trackedExpression(node, prop) : void 0;
483
+ const element = stack[stack.length - 1];
484
+ if (element?.type === "JSXElement") components.set(element, id);
485
+ pending.push({
486
+ node: {
487
+ id,
488
+ label: tag,
489
+ kind: directiveKind(tag),
490
+ deps: [],
491
+ writes: [],
492
+ runs: 0,
493
+ lastPulse: 0,
494
+ source: { file: file.path, line: at.line, column: at.column },
495
+ ...owner !== void 0 ? { createdIn: owner } : {}
496
+ },
497
+ reads: tracked ? mentions(tracked) : /* @__PURE__ */ new Set(),
498
+ file: file.path
499
+ });
500
+ return;
501
+ }
502
+ if (owner !== void 0) usages.push({ tag, file: file.path, owner });
503
+ });
504
+ walk2(program, (node, stack) => {
505
+ if (node.type !== "JSXExpressionContainer") return;
506
+ const expr = node.expression;
507
+ if (!expr || expr.type === "JSXEmptyExpression") return;
508
+ const at = expr.loc?.start;
509
+ if (!at) return;
510
+ const parent = stack[stack.length - 1];
511
+ const attribute = parent?.type === "JSXAttribute" ? parent.name?.name : void 0;
512
+ const holder = [...stack].reverse().find((n) => n.type === "JSXElement" || n.type === "JSXOpeningElement");
513
+ const opening = holder?.type === "JSXOpeningElement" ? holder : holder?.openingElement;
514
+ if (!opening) return;
515
+ const target = {
516
+ kind: attribute ? "attribute" : "content",
517
+ ...attribute ? { name: attribute } : {},
518
+ element: describeJsx(opening),
519
+ source: { file: file.path, line: at.line, column: at.column }
520
+ };
521
+ for (const name of mentions(expr)) holes.push({ file: file.path, name, target });
522
+ });
523
+ const describeTree = (el) => {
524
+ const opening = el.openingElement ?? void 0;
525
+ const tag = opening?.name?.name;
526
+ if (!opening || !tag) return void 0;
527
+ const at = el.loc?.start;
528
+ const where = at ? { file: file.path, line: at.line, column: at.column } : void 0;
529
+ const children = [];
530
+ for (const child of el.children ?? []) {
531
+ if (child?.type !== "JSXElement") continue;
532
+ const sub = describeTree(child);
533
+ if (sub) children.push(sub);
534
+ }
535
+ if (tag[0] === tag[0]?.toUpperCase()) {
536
+ const node = { label: tag, children, ...where ? { at: where } : {} };
537
+ const id = components.get(el) ?? here.get(tag);
538
+ if (id !== void 0) node.owner = id;
539
+ else unresolved.push({ node, tag, file: file.path });
540
+ return node;
541
+ }
542
+ return { label: describeJsx(opening), children, ...where ? { at: where } : {} };
543
+ };
544
+ walk2(program, (node, stack) => {
545
+ if (node.type !== "JSXElement") return;
546
+ let owner;
547
+ for (let i = stack.length - 1; i >= 0; i--) {
548
+ const found = stack[i];
549
+ if (found.type === "JSXElement") return;
550
+ const id = components.get(found);
551
+ if (id !== void 0) {
552
+ owner = id;
553
+ break;
554
+ }
555
+ }
556
+ if (owner === void 0) return;
557
+ const tree = describeTree(node);
558
+ if (!tree) return;
559
+ const held = domFor.get(owner);
560
+ if (held) held.push(tree);
561
+ else domFor.set(owner, [tree]);
562
+ });
563
+ walk2(program, (node, stack) => {
564
+ if (node.type !== "TaggedTemplateExpression") return;
565
+ const tagName = node.tag?.name;
566
+ if (tagName !== "html" && tagName !== "svg") return;
567
+ const quasi = node.quasi;
568
+ const expressions = quasi?.expressions ?? [];
569
+ const positionAt2 = positionOf();
570
+ let children;
571
+ try {
572
+ children = (0, import_template_parser.parseTemplate)(templatePieces(quasi), { svg: tagName === "svg" }).root.children;
573
+ } catch {
574
+ return;
575
+ }
576
+ const holeExpr = (index) => index == null ? void 0 : expressions[index];
577
+ const readsOf = (index) => {
578
+ const expr = holeExpr(index);
579
+ return expr ? mentions(expr) : /* @__PURE__ */ new Set();
580
+ };
581
+ const addControl = (tag, offset, hole, owner2) => {
582
+ const at = offset !== void 0 ? positionAt2(offset) : holeExpr(hole)?.loc?.start ?? node.loc?.start;
583
+ if (!at) return void 0;
584
+ const id = seq++;
585
+ pending.push({
586
+ node: {
587
+ id,
588
+ label: tag,
589
+ kind: directiveKind(tag),
590
+ deps: [],
591
+ writes: [],
592
+ runs: 0,
593
+ lastPulse: 0,
594
+ source: { file: file.path, line: at.line, column: at.column },
595
+ ...owner2 !== void 0 ? { createdIn: owner2 } : {}
596
+ },
597
+ reads: readsOf(hole),
598
+ file: file.path
599
+ });
600
+ return id;
601
+ };
602
+ const addTarget = (index, element, attribute) => {
603
+ const expr = holeExpr(index);
604
+ const at = expr?.loc?.start;
605
+ if (!expr || !at) return;
606
+ const target = {
607
+ kind: attribute ? "attribute" : "content",
608
+ ...attribute ? { name: attribute } : {},
609
+ element,
610
+ source: { file: file.path, line: at.line, column: at.column }
611
+ };
612
+ for (const name of mentions(expr)) holes.push({ file: file.path, name, target });
613
+ };
614
+ const elementTargets = (el) => {
615
+ const element = describeTemplateElement(el);
616
+ for (const attr of el.attributes) {
617
+ switch (attr.kind) {
618
+ case "Attribute":
619
+ for (const hole of valueHoles(attr.value)) addTarget(hole, element, attr.name);
620
+ break;
621
+ case "PropertyBinding":
622
+ case "BindDirective":
623
+ addTarget(attr.hole, element, attr.name);
624
+ break;
625
+ case "ClassDirective":
626
+ addTarget(attr.hole, element, "class");
627
+ break;
628
+ case "StyleDirective":
629
+ addTarget(attr.hole, element, "style");
630
+ break;
631
+ // A handler is not a read, and neither is a ref, a spread or a use.
632
+ default:
633
+ break;
634
+ }
635
+ }
636
+ };
637
+ const visit = (nodes, owner2, holder) => {
638
+ for (const child of nodes) {
639
+ switch (child.kind) {
640
+ case "Element": {
641
+ const ifDir = child.attributes.find((a) => a.kind === "IfDirective");
642
+ const eachDir = child.attributes.find((a) => a.kind === "EachDirective");
643
+ let inner = owner2;
644
+ if (ifDir?.kind === "IfDirective") inner = addControl("Show", child.loc?.start, ifDir.hole, owner2) ?? owner2;
645
+ else if (eachDir?.kind === "EachDirective") inner = addControl("For", child.loc?.start, eachDir.hole, owner2) ?? owner2;
646
+ elementTargets(child);
647
+ visit(child.children, inner, describeTemplateElement(child));
648
+ break;
649
+ }
650
+ case "Component": {
651
+ const tag = child.tag;
652
+ const own = here.has(tag) || from.has(tag);
653
+ if (tag && !own && DIRECTIVES.has(tag)) {
654
+ const prop = TRACKED_PROP[tag];
655
+ const tracked = prop ? child.attributes.find(
656
+ (a) => "name" in a && a.name === prop
657
+ ) : void 0;
658
+ const hole = tracked && "hole" in tracked ? tracked.hole : tracked && "value" in tracked ? valueHoles(tracked.value)[0] : void 0;
659
+ const id = addControl(tag, child.loc?.start, hole, owner2);
660
+ visit(child.children, id ?? owner2, holder);
661
+ break;
662
+ }
663
+ if (tag && owner2 !== void 0) usages.push({ tag, file: file.path, owner: owner2 });
664
+ visit(child.children, owner2, holder);
665
+ break;
666
+ }
667
+ case "Fragment":
668
+ visit(child.children, owner2, holder);
669
+ break;
670
+ case "Expression":
671
+ addTarget(child.hole, holder, void 0);
672
+ break;
673
+ default:
674
+ break;
675
+ }
676
+ }
677
+ };
678
+ let owner;
679
+ for (let i = stack.length - 1; i >= 0; i--) {
680
+ const found = components.get(stack[i]);
681
+ if (found !== void 0) {
682
+ owner = found;
683
+ break;
684
+ }
685
+ }
686
+ visit(children, owner, "template");
687
+ });
688
+ walk2(program, (node, stack) => {
689
+ if (node.type !== "ObjectProperty" || node.computed) return;
690
+ const key = node.key?.name ?? node.key?.value;
691
+ if (key !== "component" && key !== "Component") return;
692
+ const value = node.value;
693
+ if (value?.type !== "Identifier") return;
694
+ const holder = [...stack].reverse().find((n) => n.type === "VariableDeclarator");
695
+ const via = holder?.id?.name;
696
+ if (via) routeRefs.push({ via, tag: value.name, file: file.path });
697
+ });
698
+ walk2(program, (node) => {
699
+ if (node.type !== "ExportNamedDeclaration" && node.type !== "ExportDefaultDeclaration") return;
700
+ for (const name of here.keys()) sold.set(name, here.get(name));
701
+ });
702
+ }
703
+ const resolve = (file, name) => {
704
+ const local = locals.get(file)?.get(name);
705
+ if (local !== void 0) return local;
706
+ const source = imports.get(file)?.get(name);
707
+ if (!source) return void 0;
708
+ for (const [path, names] of exported) {
709
+ if (!sameModule(file, source, path)) continue;
710
+ const id = names.get(name);
711
+ if (id !== void 0) return id;
712
+ }
713
+ return void 0;
714
+ };
715
+ for (const entry of pending) {
716
+ const deps = /* @__PURE__ */ new Set();
717
+ for (const name of entry.reads) {
718
+ const id = resolve(entry.file, name);
719
+ if (id !== void 0 && id !== entry.node.id) deps.add(id);
720
+ }
721
+ entry.node.deps = [...deps];
722
+ }
723
+ const unique = /* @__PURE__ */ new Map();
724
+ for (const names of exported.values()) {
725
+ for (const [name, id] of names) unique.set(name, unique.has(name) ? null : id);
726
+ }
727
+ const byId = new Map(pending.map((p) => [p.node.id, p.node]));
728
+ for (const entry of unresolved) {
729
+ const id = resolve(entry.file, entry.tag) ?? unique.get(entry.tag) ?? void 0;
730
+ if (id !== void 0 && byId.get(id)?.kind === "component") entry.node.owner = id;
731
+ }
732
+ for (const [id, dom] of domFor) {
733
+ const node = byId.get(id);
734
+ if (node && dom.length) node.dom = dom;
735
+ }
736
+ for (const hole of holes) {
737
+ const id = resolve(hole.file, hole.name);
738
+ const node = id !== void 0 ? byId.get(id) : void 0;
739
+ if (!node || node.kind === "component") continue;
740
+ (node.targets ??= []).push(hole.target);
741
+ }
742
+ for (const ref of routeRefs) {
743
+ const named = resolve(ref.file, ref.tag) ?? unique.get(ref.tag) ?? void 0;
744
+ if (named === void 0) continue;
745
+ const router = pending.find(
746
+ (p) => p.file === ref.file && p.node.kind === "router" && p.node.id !== named && p.reads.has(ref.via)
747
+ )?.node.id;
748
+ const mentions2 = pending.find(
749
+ (p) => p.file === ref.file && (p.node.kind === "component" || p.node.kind === "handler") && p.node.id !== named && componentMentions.get(p.node.id)?.has(ref.via)
750
+ )?.node.id;
751
+ const holder = router ?? mentions2;
752
+ const node = byId.get(named);
753
+ if (node && node.createdIn === void 0 && holder !== void 0) node.createdIn = holder;
754
+ }
755
+ for (const use of usages) {
756
+ const id = resolve(use.file, use.tag) ?? unique.get(use.tag) ?? void 0;
757
+ if (id === void 0 || id === use.owner) continue;
758
+ const node = byId.get(id);
759
+ if (node && node.kind === "component" && node.createdIn === void 0) node.createdIn = use.owner;
760
+ }
761
+ const only = (kind, label) => {
762
+ const found = pending.filter((p) => p.node.kind === kind && p.node.label === label);
763
+ return found.length === 1 ? found[0].node.id : void 0;
764
+ };
765
+ const routeOwner = only("router", "Outlet") ?? only("router", "Router");
766
+ if (routeOwner !== void 0) {
767
+ for (const id of fileRoutes) {
768
+ const node = byId.get(id);
769
+ if (node && node.kind === "component" && node.createdIn === void 0 && id !== routeOwner) {
770
+ node.createdIn = routeOwner;
771
+ }
772
+ }
773
+ }
774
+ const loose = pending.filter(
775
+ (p) => p.node.kind === "handler" && p.node.createdIn === void 0
776
+ );
777
+ if (loose.length > 0) {
778
+ const id = seq++;
779
+ pending.push({
780
+ node: {
781
+ id,
782
+ label: "api",
783
+ kind: "handler",
784
+ deps: [],
785
+ writes: [],
786
+ runs: 0,
787
+ lastPulse: 0,
788
+ // The directory, since there is no line of anyone's source to point at.
789
+ source: { file: apiDir, line: 1, column: 0 }
790
+ },
791
+ reads: /* @__PURE__ */ new Set(),
792
+ file: apiDir
793
+ });
794
+ for (const p of loose) p.node.createdIn = id;
795
+ }
796
+ return { t: Date.now(), nodes: pending.map((p) => p.node), static: true };
797
+ }
798
+ var withoutExtension = (path) => path.replace(/\.(tsx?|jsx?|mts|cts|mjs|cjs)$/, "");
799
+ function sameModule(importer, specifier, candidate) {
800
+ const base = importer.includes("/") ? importer.slice(0, importer.lastIndexOf("/")) : "";
801
+ const parts = (base ? base.split("/") : []).concat(specifier.split("/"));
802
+ const stack = [];
803
+ for (const part of parts) {
804
+ if (part === "." || part === "") continue;
805
+ if (part === "..") stack.pop();
806
+ else stack.push(part);
807
+ }
808
+ const resolved = withoutExtension(stack.join("/"));
809
+ const target = withoutExtension(candidate);
810
+ return target === resolved || target === `${resolved}/index`;
811
+ }