@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,69 @@
1
+ import MagicString from 'magic-string';
2
+ import { type CompileTemplateOptions } from '../lower/compile-template.cjs';
3
+ import type { IRLoadStrategy } from '../ir/nodes.cjs';
4
+ import { type PropsDiagnostic } from './props.cjs';
5
+ import { type IntrinsicDiagnostic } from './intrinsics.cjs';
6
+ export interface TransformOptions extends CompileTemplateOptions {
7
+ /**
8
+ * Which authoring syntaxes to compile. Both lower to the same IR, so this is
9
+ * about which source forms are touched, not about output.
10
+ * @default 'both'
11
+ */
12
+ format?: 'jsx' | 'lit' | 'both';
13
+ /** Tag marking a template for compilation. @default 'html' */
14
+ litTag?: string;
15
+ /** Module the emitted runtime symbols are imported from. @default '@fluixi/dom' */
16
+ runtimeModule?: string;
17
+ /** Where reactive primitives come from. @default '@fluixi/reactive/signal' */
18
+ reactiveModule?: string;
19
+ /**
20
+ * Rewrite a component's destructured props into property reads, so
21
+ * `function Card({ title })` keeps updating instead of reading `title` once.
22
+ * The edits go into the same string as the template edits, so the map still points
23
+ * at what the author wrote.
24
+ * @default true
25
+ */
26
+ propsDestructure?: boolean;
27
+ /**
28
+ * Record where each reactive primitive was created, so the devtools graph can say where a
29
+ * node comes from. Development tooling: leave it off for production, which then carries
30
+ * none of it.
31
+ * @default false
32
+ */
33
+ sourceLocations?: boolean;
34
+ /**
35
+ * Trim this prefix off the file name a source mark records, so a location reads
36
+ * `src/app.tsx:5:16` rather than an absolute path that means nothing to whoever opens it.
37
+ */
38
+ sourceRoot?: string;
39
+ /**
40
+ * Compile the `$` reactive intrinsics — `$signal`, `$memo`, `$effect`, `$store` — into
41
+ * the runtime calls they stand for, importing what they need.
42
+ * @default true
43
+ */
44
+ intrinsics?: boolean;
45
+ }
46
+ export interface UnresolvedDiagnostic {
47
+ /** The tag nothing supplies. */
48
+ name: string;
49
+ message: string;
50
+ }
51
+ export interface LoadDiagnostic {
52
+ /** The component the directive was written on. */
53
+ name: string;
54
+ strategy: IRLoadStrategy;
55
+ message: string;
56
+ }
57
+ export interface TransformResult {
58
+ code: string;
59
+ map: ReturnType<MagicString['generateMap']>;
60
+ /** Props patterns the rewrite refused, when `propsDestructure` is on. */
61
+ propsDiagnostics?: PropsDiagnostic[];
62
+ /** `$` names the module bound itself, so the intrinsic did not fire. */
63
+ intrinsicDiagnostics?: IntrinsicDiagnostic[];
64
+ /** `load:` directives that could not take effect, and why. */
65
+ loadDiagnostics?: LoadDiagnostic[];
66
+ /** Capitalised tags nothing supplies — they compile to an undefined reference. */
67
+ unresolvedDiagnostics?: UnresolvedDiagnostic[];
68
+ }
69
+ export declare function transformTemplates(code: string, id: string, options?: TransformOptions): TransformResult | null;
@@ -24,6 +24,18 @@ export interface TransformOptions extends CompileTemplateOptions {
24
24
  * @default true
25
25
  */
26
26
  propsDestructure?: boolean;
27
+ /**
28
+ * Record where each reactive primitive was created, so the devtools graph can say where a
29
+ * node comes from. Development tooling: leave it off for production, which then carries
30
+ * none of it.
31
+ * @default false
32
+ */
33
+ sourceLocations?: boolean;
34
+ /**
35
+ * Trim this prefix off the file name a source mark records, so a location reads
36
+ * `src/app.tsx:5:16` rather than an absolute path that means nothing to whoever opens it.
37
+ */
38
+ sourceRoot?: string;
27
39
  /**
28
40
  * Compile the `$` reactive intrinsics — `$signal`, `$memo`, `$effect`, `$store` — into
29
41
  * the runtime calls they stand for, importing what they need.
@@ -54,9 +66,5 @@ export interface TransformResult {
54
66
  /** Capitalised tags nothing supplies — they compile to an undefined reference. */
55
67
  unresolvedDiagnostics?: UnresolvedDiagnostic[];
56
68
  }
57
- /**
58
- * Compile every template in `code`. Returns null when the module has none, so a
59
- * bundler can skip the file untouched.
60
- */
61
69
  export declare function transformTemplates(code: string, id: string, options?: TransformOptions): TransformResult | null;
62
70
  //# sourceMappingURL=templates.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/transform/templates.ts"],"names":[],"mappings":"AASA,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAiB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAG1F,OAAO,KAAK,EAAqB,cAAc,EAAU,MAAM,gBAAgB,CAAC;AAWhF,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAA2C,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAmBpG,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D;;;;OAIG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAChC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5C,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7C,8DAA8D;IAC9D,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,kFAAkF;IAClF,qBAAqB,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAChD;AAwQD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,eAAe,GAAG,IAAI,CAyLxB"}
1
+ {"version":3,"file":"templates.d.ts","sourceRoot":"","sources":["../../src/transform/templates.ts"],"names":[],"mappings":"AASA,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAiB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAG1F,OAAO,KAAK,EAAqB,cAAc,EAAU,MAAM,gBAAgB,CAAC;AAWhF,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAA2C,KAAK,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAoBpG,MAAM,WAAW,gBAAiB,SAAQ,sBAAsB;IAC9D;;;;OAIG;IACH,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAChC,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B;;;;;OAKG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC;IAC5C,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,wEAAwE;IACxE,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7C,8DAA8D;IAC9D,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,kFAAkF;IAClF,qBAAqB,CAAC,EAAE,oBAAoB,EAAE,CAAC;CAChD;AAwTD,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,gBAAqB,GAC7B,eAAe,GAAG,IAAI,CAiNxB"}
@@ -21,6 +21,7 @@ import { imperativeBackend } from '../codegen/backends/imperative.js';
21
21
  import { moduleBindings } from './bindings.js';
22
22
  import { collectPropsEdits } from './props.js';
23
23
  import { collectIntrinsicEdits, intrinsicImports } from './intrinsics.js';
24
+ import { collectSourceEdits, mayHaveReactiveCall } from './source-locations.js';
24
25
  import { mayHaveIntrinsic } from '../analyze/intrinsics.js';
25
26
  import { declaredNames } from '../analyze/reactive-bindings.js';
26
27
  import { DOM_CONTROL_FLOW, CORE_CONTROL_FLOW, ROUTER_COMPONENTS } from '../resolve/builtins.js';
@@ -73,7 +74,15 @@ function isTemplateTag(node, litTag) {
73
74
  }
74
75
  /** The edits in `list` that no other edit in `list` contains. */
75
76
  function outermost(list) {
76
- return list.filter((e) => !list.some((o) => o !== e && o.start <= e.start && o.end >= e.end && o.end - o.start > e.end - e.start));
77
+ return list.filter((e) => !list.some((o) => o !== e &&
78
+ o.start <= e.start &&
79
+ o.end >= e.end &&
80
+ o.end - o.start > e.end - e.start &&
81
+ // An insertion at either edge of the container sits beside it, not inside it, so
82
+ // it is not something the container's code already folded in. A statement can
83
+ // start where its callee starts (`$effect(…)`) and a declarator can end where its
84
+ // JSX ends (`const Row = () => <b/>`).
85
+ !(e.start === e.end && (e.start === o.start || e.start === o.end))));
77
86
  }
78
87
  /**
79
88
  * Apply edits to a slice of the source.
@@ -91,10 +100,14 @@ function slice(code, start, end, edits) {
91
100
  return out;
92
101
  }
93
102
  /** Describe one `${…}` for the lowering, substituting any template already compiled inside it. */
94
- function bindHole(code, expr, edits) {
103
+ function bindHole(code, expr, edits, keepPosition = false) {
104
+ const at = keepPosition ? expr.loc?.start : undefined;
95
105
  const hole = {
96
106
  code: slice(code, expr.start, expr.end, edits),
97
107
  reactive: isReactiveShape(shapeOf(expr)),
108
+ // Where the `${…}` is, so a binding made from it can say so. The source map cannot:
109
+ // the whole template is one overwrite. Only when source locations were asked for.
110
+ ...(at ? { at: { line: at.line, column: at.column } } : {}),
98
111
  };
99
112
  if (expr.type === 'ArrowFunctionExpression' && expr.body?.type !== 'BlockStatement') {
100
113
  hole.arrow = {
@@ -232,6 +245,30 @@ function strategyLiteral(s) {
232
245
  parts.push(`query: ${JSON.stringify(s.query)}`);
233
246
  return `{ ${parts.join(', ')} }`;
234
247
  }
248
+ /**
249
+ * Offset → line and column, built once per module.
250
+ *
251
+ * The parser reports offsets into this file, since the pieces it is given carry the
252
+ * positions Babel recorded for the quasis.
253
+ */
254
+ function positionsIn(code) {
255
+ const starts = [0];
256
+ for (let i = 0; i < code.length; i++)
257
+ if (code.charCodeAt(i) === 10)
258
+ starts.push(i + 1);
259
+ return (offset) => {
260
+ let low = 0;
261
+ let high = starts.length - 1;
262
+ while (low < high) {
263
+ const mid = (low + high + 1) >> 1;
264
+ if (starts[mid] <= offset)
265
+ low = mid;
266
+ else
267
+ high = mid - 1;
268
+ }
269
+ return { line: low + 1, column: offset - starts[low] };
270
+ };
271
+ }
235
272
  /** Quasis and holes as position-carrying parser pieces. */
236
273
  function toPieces(node) {
237
274
  const pieces = [];
@@ -248,6 +285,13 @@ function toPieces(node) {
248
285
  * Compile every template in `code`. Returns null when the module has none, so a
249
286
  * bundler can skip the file untouched.
250
287
  */
288
+ /** No path module here: this runs in the browser as well as in a bundler. */
289
+ function relativeToRoot(id, root) {
290
+ if (!root)
291
+ return id;
292
+ const base = root.endsWith('/') ? root : `${root}/`;
293
+ return id.startsWith(base) ? id.slice(base.length) : id;
294
+ }
251
295
  export function transformTemplates(code, id, options = {}) {
252
296
  const litTag = options.litTag ?? 'html';
253
297
  const format = options.format ?? 'both';
@@ -257,7 +301,13 @@ export function transformTemplates(code, id, options = {}) {
257
301
  // A module can be nothing but `$signal` calls, so the skip check has to look for those
258
302
  // too or the file is never parsed.
259
303
  const wantsIntrinsics = options.intrinsics !== false && mayHaveIntrinsic(code);
260
- if (!mayHaveTemplate && !(wantsJsx && code.includes('<')) && !wantsIntrinsics)
304
+ // A module can be nothing but reactive calls and still need marking, so the skip check
305
+ // has to look for those too when source locations are wanted.
306
+ const wantsSources = options.sourceLocations === true && mayHaveReactiveCall(code);
307
+ // What a mark calls this file. The declaration marks and the usage marks are read back by
308
+ // name, so both passes have to spell it the same way.
309
+ const sourceName = relativeToRoot(id, options.sourceRoot);
310
+ if (!mayHaveTemplate && !(wantsJsx && code.includes('<')) && !wantsIntrinsics && !wantsSources)
261
311
  return null;
262
312
  const ast = parse(code, {
263
313
  sourceType: 'module',
@@ -281,10 +331,18 @@ export function transformTemplates(code, id, options = {}) {
281
331
  const intrinsics = options.intrinsics === false
282
332
  ? { edits: [], diagnostics: [], imports: new Map() }
283
333
  : collectIntrinsicEdits(ast.program);
334
+ // Where each reactive primitive was created, for the devtools graph. Off unless asked
335
+ // for: it is development tooling, and production should carry none of it.
336
+ // `wantsSources` only decides whether a module with nothing else in it is worth parsing.
337
+ // Past that point the ast exists, and a component declaration is worth marking too.
338
+ const sources = options.sourceLocations === true
339
+ ? collectSourceEdits(ast.program, sourceName)
340
+ : { edits: [], marked: 0 };
284
341
  // Nothing to emit still returns a result when there's something to say — a shadowed
285
342
  // intrinsic is a diagnostic even though the code comes back untouched.
286
343
  const silent = found.length === 0 &&
287
344
  props.edits.length === 0 &&
345
+ sources.edits.length === 0 &&
288
346
  intrinsics.edits.length === 0 &&
289
347
  intrinsics.diagnostics.length === 0 &&
290
348
  props.diagnostics.length === 0;
@@ -302,20 +360,26 @@ export function transformTemplates(code, id, options = {}) {
302
360
  declared: declaredNames(ast.program),
303
361
  };
304
362
  const hoisted = new Map();
305
- const edits = [...props.edits, ...intrinsics.edits];
363
+ const edits = [...props.edits, ...intrinsics.edits, ...sources.edits];
306
364
  for (const node of found) {
307
365
  // A root inside another root's hole is emitted without partial templates,
308
366
  // matching what the plugin does for nested emits. Marker layout has to agree
309
367
  // between server and client, so this is not the place to change it.
310
368
  const nested = found.some((o) => o !== node && o.start <= node.start && o.end >= node.end && o.end - o.start > node.end - node.start);
311
369
  if (isJsx(node)) {
312
- edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options) });
370
+ edits.push({ start: node.start, end: node.end, code: compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceName) });
313
371
  continue;
314
372
  }
315
- const holes = node.quasi.expressions.map((e) => bindHole(code, e, edits));
373
+ const holes = node.quasi.expressions.map((e) => bindHole(code, e, edits, options.sourceLocations === true));
316
374
  const result = compilePieces(toPieces(node), holes, {
317
375
  ...options,
318
376
  hoistTemplates: true,
377
+ // A tag inside a template gets the same mark a JSX tag does. Without one, the nodes it
378
+ // makes are the only ones in the module carrying no mark, and they take whichever was
379
+ // left behind by the last declaration that did.
380
+ ...(options.sourceLocations === true
381
+ ? { sourceFile: sourceName, positionAt: positionsIn(code) }
382
+ : {}),
319
383
  // Same defaults as the plugin, so moving a build over is not a rendering change.
320
384
  templateClone: options.templateClone ?? true,
321
385
  partialTemplates: nested ? false : options.partialTemplates ?? true,
@@ -417,10 +481,11 @@ export function transformTemplates(code, id, options = {}) {
417
481
  * with anything already compiled inside them folded in, so nested JSX and nested
418
482
  * `` html`` `` both come along for free.
419
483
  */
420
- function compileJsx(code, node, edits, nested, used, needs, hoisted, options) {
484
+ function compileJsx(code, node, edits, nested, used, needs, hoisted, options, sourceFile) {
421
485
  const ir = buildJsxIR(node, {
422
486
  code: (n) => slice(code, n.start, n.end, edits),
423
487
  used,
488
+ ...(options.sourceLocations === true && sourceFile ? { sourceFile } : {}),
424
489
  });
425
490
  analyzeStatic(ir);
426
491
  const report = resolveComponentSources(ir, {