@oddsquad/vite-plugin-lit 0.2.2 → 0.3.0

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 (210) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/LICENSE +28 -0
  3. package/README.md +153 -0
  4. package/bin.mjs +154 -0
  5. package/client.d.ts +61 -0
  6. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js +69 -0
  7. package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js.map +1 -0
  8. package/dist/client/assets/index-CFrVgNfS.js +9740 -0
  9. package/dist/client/assets/index-CFrVgNfS.js.map +1 -0
  10. package/{panel → dist/client}/index.html +1 -0
  11. package/index.d.ts.map +1 -1
  12. package/index.js +2 -2
  13. package/index.js.map +1 -1
  14. package/lib/color-scheme.d.ts.map +1 -1
  15. package/lib/color-scheme.js +17 -21
  16. package/lib/color-scheme.js.map +1 -1
  17. package/lib/devframe/definition.d.ts +45 -0
  18. package/lib/devframe/definition.d.ts.map +1 -0
  19. package/lib/devframe/definition.js +547 -0
  20. package/lib/devframe/definition.js.map +1 -0
  21. package/lib/devframe/icon.d.ts +8 -0
  22. package/lib/devframe/icon.d.ts.map +1 -0
  23. package/lib/devframe/icon.js +21 -0
  24. package/lib/devframe/icon.js.map +1 -0
  25. package/lib/devframe/paths.d.ts +12 -0
  26. package/lib/devframe/paths.d.ts.map +1 -0
  27. package/lib/devframe/paths.js +38 -0
  28. package/lib/devframe/paths.js.map +1 -0
  29. package/lib/devframe/protocol.d.ts +218 -0
  30. package/lib/devframe/protocol.d.ts.map +1 -0
  31. package/lib/devframe/protocol.js +76 -0
  32. package/lib/devframe/protocol.js.map +1 -0
  33. package/lib/devframe/source.d.ts +49 -0
  34. package/lib/devframe/source.d.ts.map +1 -0
  35. package/lib/devframe/source.js +23 -0
  36. package/lib/devframe/source.js.map +1 -0
  37. package/lib/devframe/vite.d.ts +116 -0
  38. package/lib/devframe/vite.d.ts.map +1 -0
  39. package/lib/devframe/vite.js +291 -0
  40. package/lib/devframe/vite.js.map +1 -0
  41. package/lib/http.d.ts +29 -0
  42. package/lib/http.d.ts.map +1 -0
  43. package/lib/http.js +35 -0
  44. package/lib/http.js.map +1 -0
  45. package/lib/icons.d.ts +2 -0
  46. package/lib/icons.d.ts.map +1 -1
  47. package/lib/icons.js +10 -4
  48. package/lib/icons.js.map +1 -1
  49. package/lib/plugin.d.ts +15 -4
  50. package/lib/plugin.d.ts.map +1 -1
  51. package/lib/plugin.js +640 -574
  52. package/lib/plugin.js.map +1 -1
  53. package/lib/runtime/css.d.ts +2 -16
  54. package/lib/runtime/css.d.ts.map +1 -1
  55. package/lib/runtime/css.js +43 -36
  56. package/lib/runtime/css.js.map +1 -1
  57. package/lib/runtime/edge-panel.d.ts.map +1 -1
  58. package/lib/runtime/edge-panel.js +82 -91
  59. package/lib/runtime/edge-panel.js.map +1 -1
  60. package/lib/runtime/fonts.d.ts.map +1 -1
  61. package/lib/runtime/fonts.js +1 -1
  62. package/lib/runtime/fonts.js.map +1 -1
  63. package/lib/runtime/indicator.d.ts.map +1 -1
  64. package/lib/runtime/indicator.js +71 -74
  65. package/lib/runtime/indicator.js.map +1 -1
  66. package/lib/runtime/inspector/collect.d.ts.map +1 -1
  67. package/lib/runtime/inspector/collect.js +83 -90
  68. package/lib/runtime/inspector/collect.js.map +1 -1
  69. package/lib/runtime/inspector/highlight.d.ts +16 -0
  70. package/lib/runtime/inspector/highlight.d.ts.map +1 -0
  71. package/lib/runtime/inspector/highlight.js +66 -0
  72. package/lib/runtime/inspector/highlight.js.map +1 -0
  73. package/lib/runtime/inspector/install.d.ts.map +1 -1
  74. package/lib/runtime/inspector/install.js +180 -205
  75. package/lib/runtime/inspector/install.js.map +1 -1
  76. package/lib/runtime/inspector/serialize.d.ts.map +1 -1
  77. package/lib/runtime/inspector/serialize.js +86 -107
  78. package/lib/runtime/inspector/serialize.js.map +1 -1
  79. package/lib/runtime/intern.d.ts.map +1 -1
  80. package/lib/runtime/intern.js +31 -29
  81. package/lib/runtime/intern.js.map +1 -1
  82. package/lib/runtime/overrides.d.ts.map +1 -1
  83. package/lib/runtime/overrides.js +14 -13
  84. package/lib/runtime/overrides.js.map +1 -1
  85. package/lib/runtime/patch.d.ts +8 -0
  86. package/lib/runtime/patch.d.ts.map +1 -1
  87. package/lib/runtime/patch.js +321 -282
  88. package/lib/runtime/patch.js.map +1 -1
  89. package/lib/runtime/source-meta.d.ts.map +1 -1
  90. package/lib/runtime/source-meta.js +1 -1
  91. package/lib/runtime/source-meta.js.map +1 -1
  92. package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
  93. package/lib/runtime/source-overlay/editors.js +27 -27
  94. package/lib/runtime/source-overlay/editors.js.map +1 -1
  95. package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -1
  96. package/lib/runtime/source-overlay/mask-path.js +15 -15
  97. package/lib/runtime/source-overlay/mask-path.js.map +1 -1
  98. package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
  99. package/lib/runtime/source-overlay/overlay-element.js +347 -356
  100. package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
  101. package/lib/runtime/source-overlay/source-host.d.ts.map +1 -1
  102. package/lib/runtime/source-overlay/source-host.js +64 -71
  103. package/lib/runtime/source-overlay/source-host.js.map +1 -1
  104. package/lib/runtime/source-overlay/template.d.ts.map +1 -1
  105. package/lib/runtime/source-overlay/template.js +3 -3
  106. package/lib/runtime/source-overlay/template.js.map +1 -1
  107. package/lib/runtime/source-overlay.d.ts.map +1 -1
  108. package/lib/runtime/source-overlay.js +5 -2
  109. package/lib/runtime/source-overlay.js.map +1 -1
  110. package/lib/runtime/timeline/clock.d.ts.map +1 -1
  111. package/lib/runtime/timeline/clock.js +2 -2
  112. package/lib/runtime/timeline/clock.js.map +1 -1
  113. package/lib/runtime/timeline/flash.d.ts +39 -0
  114. package/lib/runtime/timeline/flash.d.ts.map +1 -0
  115. package/lib/runtime/timeline/flash.js +169 -0
  116. package/lib/runtime/timeline/flash.js.map +1 -0
  117. package/lib/runtime/timeline/identity.d.ts.map +1 -1
  118. package/lib/runtime/timeline/identity.js +27 -27
  119. package/lib/runtime/timeline/identity.js.map +1 -1
  120. package/lib/runtime/timeline/input.d.ts.map +1 -1
  121. package/lib/runtime/timeline/input.js +54 -67
  122. package/lib/runtime/timeline/input.js.map +1 -1
  123. package/lib/runtime/timeline/install.d.ts.map +1 -1
  124. package/lib/runtime/timeline/install.js +38 -29
  125. package/lib/runtime/timeline/install.js.map +1 -1
  126. package/lib/runtime/timeline/lifecycle.d.ts +8 -0
  127. package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
  128. package/lib/runtime/timeline/lifecycle.js +149 -133
  129. package/lib/runtime/timeline/lifecycle.js.map +1 -1
  130. package/lib/runtime/timeline/public-api.d.ts.map +1 -1
  131. package/lib/runtime/timeline/public-api.js +9 -9
  132. package/lib/runtime/timeline/public-api.js.map +1 -1
  133. package/lib/runtime/timeline/render.d.ts.map +1 -1
  134. package/lib/runtime/timeline/render.js +70 -75
  135. package/lib/runtime/timeline/render.js.map +1 -1
  136. package/lib/runtime/timeline/transport.d.ts.map +1 -1
  137. package/lib/runtime/timeline/transport.js +39 -43
  138. package/lib/runtime/timeline/transport.js.map +1 -1
  139. package/lib/segmented-tabs.d.ts +3 -1
  140. package/lib/segmented-tabs.d.ts.map +1 -1
  141. package/lib/segmented-tabs.js +136 -107
  142. package/lib/segmented-tabs.js.map +1 -1
  143. package/lib/snapshot.d.ts +28 -0
  144. package/lib/snapshot.d.ts.map +1 -0
  145. package/lib/snapshot.js +57 -0
  146. package/lib/snapshot.js.map +1 -0
  147. package/lib/source-meta.d.ts.map +1 -1
  148. package/lib/source-meta.js +176 -162
  149. package/lib/source-meta.js.map +1 -1
  150. package/lib/timeline/derive.d.ts +152 -0
  151. package/lib/timeline/derive.d.ts.map +1 -0
  152. package/lib/timeline/derive.js +242 -0
  153. package/lib/timeline/derive.js.map +1 -0
  154. package/lib/timeline-plugin.d.ts.map +1 -1
  155. package/lib/timeline-plugin.js +304 -321
  156. package/lib/timeline-plugin.js.map +1 -1
  157. package/lib/tokens.d.ts.map +1 -1
  158. package/lib/tokens.js +17 -18
  159. package/lib/tokens.js.map +1 -1
  160. package/lib/transform.d.ts.map +1 -1
  161. package/lib/transform.js +62 -57
  162. package/lib/transform.js.map +1 -1
  163. package/lib/types.d.ts.map +1 -1
  164. package/lib/types.js +1 -1
  165. package/lib/types.js.map +1 -1
  166. package/lib/wrap-table.d.ts.map +1 -1
  167. package/lib/wrap-table.js +19 -17
  168. package/lib/wrap-table.js.map +1 -1
  169. package/package.json +77 -13
  170. package/types/hmr-incompatibility.d.ts +59 -0
  171. package/types/hmr-incompatibility.d.ts.map +1 -0
  172. package/types/hmr-incompatibility.js +30 -0
  173. package/types/hmr-incompatibility.js.map +1 -0
  174. package/types/in-page.d.ts +49 -0
  175. package/types/in-page.d.ts.map +1 -0
  176. package/types/in-page.js +33 -0
  177. package/types/in-page.js.map +1 -0
  178. package/types/inspector.d.ts.map +1 -1
  179. package/types/inspector.js.map +1 -1
  180. package/types/snapshot.d.ts +44 -0
  181. package/types/snapshot.d.ts.map +1 -0
  182. package/types/snapshot.js +7 -0
  183. package/types/snapshot.js.map +1 -0
  184. package/types/timeline.d.ts +11 -0
  185. package/types/timeline.d.ts.map +1 -1
  186. package/types/timeline.js.map +1 -1
  187. package/panel/components-view.d.ts +0 -60
  188. package/panel/components-view.d.ts.map +0 -1
  189. package/panel/components-view.js +0 -587
  190. package/panel/components-view.js.map +0 -1
  191. package/panel/devtools-settings.d.ts +0 -41
  192. package/panel/devtools-settings.d.ts.map +0 -1
  193. package/panel/devtools-settings.js +0 -463
  194. package/panel/devtools-settings.js.map +0 -1
  195. package/panel/lit-devtools-panel.d.ts +0 -37
  196. package/panel/lit-devtools-panel.d.ts.map +0 -1
  197. package/panel/lit-devtools-panel.js +0 -185
  198. package/panel/lit-devtools-panel.js.map +0 -1
  199. package/panel/timeline-event-list.d.ts +0 -43
  200. package/panel/timeline-event-list.d.ts.map +0 -1
  201. package/panel/timeline-event-list.js +0 -416
  202. package/panel/timeline-event-list.js.map +0 -1
  203. package/panel/timeline-layers.d.ts +0 -25
  204. package/panel/timeline-layers.d.ts.map +0 -1
  205. package/panel/timeline-layers.js +0 -96
  206. package/panel/timeline-layers.js.map +0 -1
  207. package/panel/timeline-view.d.ts +0 -38
  208. package/panel/timeline-view.d.ts.map +0 -1
  209. package/panel/timeline-view.js +0 -234
  210. package/panel/timeline-view.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"segmented-tabs.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/segmented-tabs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;;;;;;AAEH,OAAO,EAAC,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAC,MAAM,KAAK,CAAC;AACnD,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAUnC;;;;;GAKG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;aAC3B,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoDF;KACF,AAvDqB,CAuDpB;IAQF;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAEO,OAAO,CAAC,EAAU;QACxB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,QAAQ,EAAE;YACxB,MAAM,EAAE,EAAC,KAAK,EAAE,EAAE,EAAC;YACnB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,KAAK,CAAC,GAAG,CACd,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAA;;;4BAGM,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK;oBAC9B,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;qBACrC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;;cAElC,IAAI,CAAC,IAAI;YACT,CAAC,CAAC,IAAI,CAAA;;;;;4BAKQ,IAAI,CAAC,IAAI;uBACd;YACT,CAAC,CAAC,OAAO;cACT,IAAI,CAAC,KAAK;;SAEf,CACF;KACF,CAAC;IACJ,CAAC;;AAhDgC;IAAhC,QAAQ,CAAC,EAAC,IAAI,EAAE,KAAK,EAAC,CAAC;4CAA0B;AAE9B;IAAnB,QAAQ,EAAE;4CAAuB;AAEd;IAAnB,QAAQ,EAAE;2CAA0B;AA9D1B,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CA2GzB","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {LitElement, html, css, nothing} from 'lit';\nimport {customElement, property} from 'lit/decorators.js';\nimport {tokens} from './tokens.js';\n\nexport interface TabItem {\n id: string;\n label: string;\n icon?: string;\n}\n\nexport type SegTabSize = 'sm' | 'md';\n\n/**\n * Inline segmented tab control. Renders a horizontal row of text-only tabs\n * with the active one highlighted by the accent color.\n *\n * Matches the SegmentedTabs spec from the Lit Design System devtools kit.\n */\n@customElement('segmented-tabs')\nexport class SegmentedTabs extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: flex;\n gap: var(--lit-devtools-space-1);\n align-self: stretch;\n }\n button {\n appearance: none;\n display: flex;\n align-items: center;\n gap: var(--lit-devtools-space-2);\n border: 0;\n background: none;\n font: inherit;\n color: var(--lit-devtools-text-muted);\n padding: 0 var(--lit-devtools-space-5);\n cursor: pointer;\n border-bottom: 2px solid transparent;\n white-space: nowrap;\n transition:\n color var(--lit-devtools-dur-fast) var(--lit-devtools-ease-standard),\n border-color var(--lit-devtools-dur-fast)\n var(--lit-devtools-ease-standard),\n background var(--lit-devtools-dur-fast)\n var(--lit-devtools-ease-standard);\n }\n button:hover {\n color: var(--lit-devtools-text);\n background: var(--lit-devtools-surface-hover);\n }\n button.active {\n color: var(--lit-devtools-accent);\n border-bottom-color: var(--lit-devtools-accent);\n }\n button:focus-visible {\n outline: 2px solid var(--lit-devtools-accent-ring);\n outline-offset: -2px;\n }\n button svg {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n }\n :host([size='sm']) button {\n font-size: var(--lit-devtools-text-xs);\n padding: 0 var(--lit-devtools-space-4);\n }\n :host([size='md']) button,\n :host(:not([size])) button {\n font-size: var(--lit-devtools-text-sm);\n padding: 0 var(--lit-devtools-space-5);\n }\n `,\n ];\n\n @property({type: Array}) declare items: TabItem[];\n\n @property() declare value: string;\n\n @property() declare size: SegTabSize;\n\n constructor() {\n super();\n this.items = [];\n this.value = '';\n this.size = 'md';\n }\n\n private _select(id: string): void {\n this.value = id;\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: id},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n return html`\n ${this.items.map(\n (item) => html`\n <button\n role=\"tab\"\n aria-selected=${item.id === this.value}\n class=${item.id === this.value ? 'active' : ''}\n @click=${() => this._select(item.id)}\n >\n ${item.icon\n ? html`<svg\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=${item.icon} />\n </svg>`\n : nothing}\n ${item.label}\n </button>\n `\n )}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'segmented-tabs': SegmentedTabs;\n }\n}\n"]}
1
+ {"version":3,"file":"segmented-tabs.js","sourceRoot":"","sources":["../src/lib/segmented-tabs.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;;;;;;AAEH,OAAO,EAAC,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAC,MAAM,KAAK,CAAC;AACnD,OAAO,EAAC,aAAa,EAAE,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAC,MAAM,EAAC,MAAM,aAAa,CAAC;AAYnC;;;;;GAKG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;aAC3B,WAAM,GAAG;QACvB,MAAM;QACN,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+DF;KACF,AAlEqB,CAkEpB;IAQF;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAEO,OAAO,CAAC,EAAU;QACxB,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,QAAQ,EAAE;YACxB,MAAM,EAAE,EAAC,KAAK,EAAE,EAAE,EAAC;YACnB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;SACf,CAAC,CACH,CAAC;IACJ,CAAC;IAEQ,MAAM;QACb,OAAO,IAAI,CAAA;QACP,IAAI,CAAC,KAAK,CAAC,GAAG,CACd,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAA;;;4BAGM,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK;oBAC9B,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;qBACrC,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;;cAGlC,IAAI,CAAC,IAAI;YACP,CAAC,CAAC,IAAI,CAAA;;;;;8BAKQ,IAAI,CAAC,IAAI;yBACd;YACT,CAAC,CAAC,OACN;cACE,IAAI,CAAC,KAAK;cAEV,IAAI,CAAC,KAAK;YACR,CAAC,CAAC,IAAI,CAAA,uBAAuB,IAAI,CAAC,KAAK,SAAS;YAChD,CAAC,CAAC,OACN;;SAEH,CACF;KACF,CAAC;IACJ,CAAC;CACF,CAAA;AAxDkC;IAAhC,QAAQ,CAAC,EAAC,IAAI,EAAE,KAAK,EAAC,CAAC;4CAA0B;AAE9B;IAAnB,QAAQ,EAAE;4CAAuB;AAEd;IAAnB,QAAQ,EAAE;2CAA0B;AAzE1B,aAAa;IADzB,aAAa,CAAC,gBAAgB,CAAC;GACnB,aAAa,CA6HzB","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport {LitElement, html, css, nothing} from 'lit';\nimport {customElement, property} from 'lit/decorators.js';\nimport {tokens} from './tokens.js';\n\nexport interface TabItem {\n id: string;\n label: string;\n icon?: string;\n /** Optional count pill trailing the label. Hidden when absent or zero. */\n badge?: number;\n}\n\nexport type SegTabSize = 'sm' | 'md';\n\n/**\n * Inline segmented tab control. Renders a horizontal row of text-only tabs\n * with the active one highlighted by the accent color.\n *\n * Matches the SegmentedTabs spec from the Lit Design System devtools kit.\n */\n@customElement('segmented-tabs')\nexport class SegmentedTabs extends LitElement {\n static override styles = [\n tokens,\n css`\n :host {\n display: flex;\n gap: var(--lit-devtools-space-1);\n align-self: stretch;\n }\n button {\n appearance: none;\n display: flex;\n align-items: center;\n gap: var(--lit-devtools-space-2);\n border: 0;\n background: none;\n font: inherit;\n color: var(--lit-devtools-text-muted);\n padding: 0 var(--lit-devtools-space-5);\n cursor: pointer;\n border-bottom: 2px solid transparent;\n white-space: nowrap;\n transition:\n color var(--lit-devtools-dur-fast) var(--lit-devtools-ease-standard),\n border-color var(--lit-devtools-dur-fast)\n var(--lit-devtools-ease-standard),\n background var(--lit-devtools-dur-fast)\n var(--lit-devtools-ease-standard);\n }\n button:hover {\n color: var(--lit-devtools-text);\n background: var(--lit-devtools-surface-hover);\n }\n button.active {\n color: var(--lit-devtools-accent);\n border-bottom-color: var(--lit-devtools-accent);\n }\n button:focus-visible {\n outline: 2px solid var(--lit-devtools-accent-ring);\n outline-offset: -2px;\n }\n button svg {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n }\n .badge {\n flex-shrink: 0;\n min-width: 16px;\n padding: 0 var(--lit-devtools-space-1);\n border-radius: var(--lit-devtools-radius-pill);\n background: var(--lit-devtools-error-soft);\n color: var(--lit-devtools-error);\n font-size: var(--lit-devtools-text-xs);\n line-height: 16px;\n text-align: center;\n }\n :host([size='sm']) button {\n font-size: var(--lit-devtools-text-xs);\n padding: 0 var(--lit-devtools-space-4);\n }\n :host([size='md']) button,\n :host(:not([size])) button {\n font-size: var(--lit-devtools-text-sm);\n padding: 0 var(--lit-devtools-space-5);\n }\n `,\n ];\n\n @property({type: Array}) declare items: TabItem[];\n\n @property() declare value: string;\n\n @property() declare size: SegTabSize;\n\n constructor() {\n super();\n this.items = [];\n this.value = '';\n this.size = 'md';\n }\n\n private _select(id: string): void {\n this.value = id;\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: id},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n override render() {\n return html`\n ${this.items.map(\n (item) => html`\n <button\n role=\"tab\"\n aria-selected=${item.id === this.value}\n class=${item.id === this.value ? 'active' : ''}\n @click=${() => this._select(item.id)}\n >\n ${\n item.icon\n ? html`<svg\n viewBox=\"0 0 256 256\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path d=${item.icon} />\n </svg>`\n : nothing\n }\n ${item.label}\n ${\n item.badge\n ? html`<span class=\"badge\">${item.badge}</span>`\n : nothing\n }\n </button>\n `\n )}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'segmented-tabs': SegmentedTabs;\n }\n}\n"]}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ import type { FeatureSettings } from '../types/timeline.js';
7
+ import type { SessionSnapshot } from '../types/snapshot.js';
8
+ /** What {@link buildSnapshot} reports back to whoever asked for the export. */
9
+ export interface SnapshotBuildResult {
10
+ outDir: string;
11
+ events: number;
12
+ components: number;
13
+ details: number;
14
+ }
15
+ /**
16
+ * Write `snapshot` to `outDir` as a self-contained static panel.
17
+ *
18
+ * The build adapter is imported dynamically: it reaches for `node:fs`, and
19
+ * `definition.ts` is deliberately framework- and environment-neutral, so a
20
+ * static import would drag filesystem code into every context that merely
21
+ * builds the definition.
22
+ */
23
+ export declare const buildSnapshot: (snapshot: SessionSnapshot, options: {
24
+ outDir: string;
25
+ features: FeatureSettings | null;
26
+ clientAssets?: string;
27
+ }) => Promise<SnapshotBuildResult>;
28
+ //# sourceMappingURL=snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../src/lib/snapshot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,sBAAsB,CAAC;AAE1D,+EAA+E;AAC/E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;;;;;GAOG;AACH,eAAO,MAAM,aAAa,aACd,eAAe,WAChB;IACP,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,KACA,OAAO,CAAC,mBAAmB,CA0B7B,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ */
6
+ /**
7
+ * Freezing a live session into a static panel someone else can open.
8
+ *
9
+ * Capture needs no transport: by the time a developer wants to export, the
10
+ * node side is already holding the timeline buffer, the component tree, the
11
+ * details of everything that was inspected, and the HMR incompatibility list.
12
+ * The export reads its own state and hands it to devframe's build adapter as
13
+ * a second, replaying definition.
14
+ *
15
+ * The output is a plain directory: the panel SPA, a `__connection.json` that
16
+ * says `backend: 'static'`, and the baked RPC dump. It is mount-path agnostic,
17
+ * so it works opened from a file server at any base — zip it onto an issue.
18
+ */
19
+ import {createLitDevframe} from './devframe/definition.js';
20
+ import {createNullSource} from './devframe/source.js';
21
+ /** Count the nodes of a tree, so the caller can say what it exported. */
22
+ const countNodes = (nodes) =>
23
+ nodes.reduce((total, node) => total + 1 + countNodes(node.children), 0);
24
+ /**
25
+ * Write `snapshot` to `outDir` as a self-contained static panel.
26
+ *
27
+ * The build adapter is imported dynamically: it reaches for `node:fs`, and
28
+ * `definition.ts` is deliberately framework- and environment-neutral, so a
29
+ * static import would drag filesystem code into every context that merely
30
+ * builds the definition.
31
+ */
32
+ export const buildSnapshot = async (snapshot, options) => {
33
+ const {createBuild} = await import('devframe/adapters/build');
34
+ const definition = createLitDevframe({
35
+ // Nothing to attach to: the page this session describes is gone, and
36
+ // every answer the frozen panel needs is already in `replay`.
37
+ source: createNullSource(),
38
+ version: snapshot.version,
39
+ features: () => options.features,
40
+ clientAssets: options.clientAssets,
41
+ replay: snapshot,
42
+ });
43
+ await createBuild(definition, {
44
+ outDir: options.outDir,
45
+ // The Vite plugin declares `capabilities.build: false` because there is
46
+ // nothing to render during `vite build` — a *recorded* session is the one
47
+ // case where a build does make sense.
48
+ force: true,
49
+ });
50
+ return {
51
+ outDir: options.outDir,
52
+ events: snapshot.events.length,
53
+ components: countNodes(snapshot.roots),
54
+ details: snapshot.details.length,
55
+ };
56
+ };
57
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/lib/snapshot.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAC,gBAAgB,EAAC,MAAM,sBAAsB,CAAC;AAYtD,yEAAyE;AACzE,MAAM,UAAU,GAAG,CAAC,KAA+B,EAAU,EAAE,CAC7D,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AAE1E;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,EAChC,QAAyB,EACzB,OAIC,EAC6B,EAAE;IAChC,MAAM,EAAC,WAAW,EAAC,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,iBAAiB,CAAC;QACnC,qEAAqE;QACrE,8DAA8D;QAC9D,MAAM,EAAE,gBAAgB,EAAE;QAC1B,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,QAAQ,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,QAAQ;QAChC,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,MAAM,EAAE,QAAQ;KACjB,CAAC,CAAC;IAEH,MAAM,WAAW,CAAC,UAAU,EAAE;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,wEAAwE;QACxE,0EAA0E;QAC1E,sCAAsC;QACtC,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM;QAC9B,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC;QACtC,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM;KACjC,CAAC;AACJ,CAAC,CAAC","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\n/**\n * Freezing a live session into a static panel someone else can open.\n *\n * Capture needs no transport: by the time a developer wants to export, the\n * node side is already holding the timeline buffer, the component tree, the\n * details of everything that was inspected, and the HMR incompatibility list.\n * The export reads its own state and hands it to devframe's build adapter as\n * a second, replaying definition.\n *\n * The output is a plain directory: the panel SPA, a `__connection.json` that\n * says `backend: 'static'`, and the baked RPC dump. It is mount-path agnostic,\n * so it works opened from a file server at any base — zip it onto an issue.\n */\n\nimport {createLitDevframe} from './devframe/definition.js';\nimport {createNullSource} from './devframe/source.js';\nimport type {FeatureSettings} from '../types/timeline.js';\nimport type {SessionSnapshot} from '../types/snapshot.js';\n\n/** What {@link buildSnapshot} reports back to whoever asked for the export. */\nexport interface SnapshotBuildResult {\n outDir: string;\n events: number;\n components: number;\n details: number;\n}\n\n/** Count the nodes of a tree, so the caller can say what it exported. */\nconst countNodes = (nodes: SessionSnapshot['roots']): number =>\n nodes.reduce((total, node) => total + 1 + countNodes(node.children), 0);\n\n/**\n * Write `snapshot` to `outDir` as a self-contained static panel.\n *\n * The build adapter is imported dynamically: it reaches for `node:fs`, and\n * `definition.ts` is deliberately framework- and environment-neutral, so a\n * static import would drag filesystem code into every context that merely\n * builds the definition.\n */\nexport const buildSnapshot = async (\n snapshot: SessionSnapshot,\n options: {\n outDir: string;\n features: FeatureSettings | null;\n clientAssets?: string;\n }\n): Promise<SnapshotBuildResult> => {\n const {createBuild} = await import('devframe/adapters/build');\n const definition = createLitDevframe({\n // Nothing to attach to: the page this session describes is gone, and\n // every answer the frozen panel needs is already in `replay`.\n source: createNullSource(),\n version: snapshot.version,\n features: () => options.features,\n clientAssets: options.clientAssets,\n replay: snapshot,\n });\n\n await createBuild(definition, {\n outDir: options.outDir,\n // The Vite plugin declares `capabilities.build: false` because there is\n // nothing to render during `vite build` — a *recorded* session is the one\n // case where a build does make sense.\n force: true,\n });\n\n return {\n outDir: options.outDir,\n events: snapshot.events.length,\n components: countNodes(snapshot.roots),\n details: snapshot.details.length,\n };\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"source-meta.d.ts","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/source-meta.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,WAAW,MAAM,cAAc,CAAC;AAE5C,yEAAyE;AACzE,eAAO,MAAM,eAAe,qCAAqC,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,eAAe,mDAAqC,CAAC;AAElE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uDAAuD;AACvD,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,EAAE,OAAO,MAAM,KAAG,MAClB,CAAC;AAqI1C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAM,MAAM,EACZ,UAAU,MAAM,EAChB,IAAI,WAAW,KACd,OA8DF,CAAC"}
1
+ {"version":3,"file":"source-meta.d.ts","sourceRoot":"","sources":["../src/lib/source-meta.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,WAAW,MAAM,cAAc,CAAC;AAE5C,yEAAyE;AACzE,eAAO,MAAM,eAAe,qCAAqC,CAAC;AAElE;;;GAGG;AACH,eAAO,MAAM,eAAe,mDAAqC,CAAC;AAElE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,uDAAuD;AACvD,eAAO,MAAM,YAAY,SAAU,MAAM,SAAS,MAAM,KAAG,MAClB,CAAC;AA8I1C;;;GAGG;AACH,eAAO,MAAM,gBAAgB,SACrB,MAAM,YACF,MAAM,MACZ,WAAW,KACd,OAiEF,CAAC"}
@@ -11,7 +11,8 @@ export const SOURCE_META_KEY = '@lit-labs/vite-plugin-lit#source';
11
11
  */
12
12
  export const SOURCE_META_SYM = `Symbol.for('${SOURCE_META_KEY}')`;
13
13
  /** 1-based line number for an index in source text. */
14
- export const lineNumberAt = (code, index) => code.slice(0, index).split('\n').length;
14
+ export const lineNumberAt = (code, index) =>
15
+ code.slice(0, index).split('\n').length;
15
16
  /**
16
17
  * Finds the index after the closing `}` of a class body starting at
17
18
  * `classStart`. Skips braces inside strings, comments, regex literals, and
@@ -19,176 +20,189 @@ export const lineNumberAt = (code, index) => code.slice(0, index).split('\n').le
19
20
  * templates (Lit's `html\`…\`` inside `.map()` etc.) recurse arbitrarily.
20
21
  */
21
22
  const findClassBodyEnd = (code, classStart) => {
22
- const open = code.indexOf('{', classStart);
23
- if (open === -1)
24
- return -1;
25
- // Brace depth of the code scope currently being scanned. Entering a `${…}`
26
- // interpolation pushes the enclosing scope's depth and restarts at 1 (the
27
- // `${` counts as the open brace); balancing it pops back into the template.
28
- let depth = 1;
29
- const interpolationStack = [];
30
- let inTemplate = false;
31
- let i = open + 1;
32
- while (i < code.length) {
33
- const ch = code[i];
34
- if (inTemplate) {
35
- if (ch === '\\') {
36
- i += 2;
37
- continue;
38
- }
39
- if (ch === '`') {
40
- inTemplate = false;
41
- i++;
42
- continue;
43
- }
44
- if (ch === '$' && code[i + 1] === '{') {
45
- interpolationStack.push(depth);
46
- depth = 1;
47
- inTemplate = false;
48
- i += 2;
49
- continue;
50
- }
51
- i++;
52
- continue;
53
- }
54
- if (ch === '"' || ch === "'") {
55
- const quote = ch;
56
- i++;
57
- while (i < code.length && code[i] !== quote) {
58
- if (code[i] === '\\')
59
- i++;
60
- i++;
61
- }
62
- i++;
63
- continue;
64
- }
65
- if (ch === '`') {
66
- inTemplate = true;
67
- i++;
68
- continue;
69
- }
70
- if (ch === '/') {
71
- const next = code[i + 1];
72
- if (next === '/') {
73
- i = code.indexOf('\n', i);
74
- if (i === -1)
75
- return -1;
76
- continue;
77
- }
78
- if (next === '*') {
79
- i = code.indexOf('*/', i + 2);
80
- if (i === -1)
81
- return -1;
82
- i += 2;
83
- continue;
84
- }
85
- // Regex literal vs division: scan back over whitespace to the last
86
- // significant char — a regex can only follow an operator, opening
87
- // punctuation, or a keyword like `return`. `a / b` has an identifier
88
- // there, so it's division and scans on as plain code.
89
- let j = i - 1;
90
- while (j >= 0 && /\s/.test(code[j]))
91
- j--;
92
- const prev = j >= 0 ? code[j] : '';
93
- const regexPossible = j < 0 ||
94
- /[=:(,+\-!&|?{}[;]/.test(prev) ||
95
- /(?:^|[^\w$])(?:return|typeof|case|instanceof|in|of|new|delete|void|throw|do|else|yield|await)$/.test(code.slice(Math.max(0, j - 11), j + 1));
96
- if (regexPossible) {
97
- let k = i + 1;
98
- let inCharClass = false;
99
- while (k < code.length &&
100
- code[k] !== '\n' &&
101
- (inCharClass || code[k] !== '/')) {
102
- if (code[k] === '\\')
103
- k++;
104
- else if (code[k] === '[')
105
- inCharClass = true;
106
- else if (code[k] === ']')
107
- inCharClass = false;
108
- k++;
109
- }
110
- if (code[k] === '/') {
111
- i = k + 1;
112
- continue;
113
- }
114
- // No closing `/` before the line ends — not a regex after all.
115
- }
23
+ const open = code.indexOf('{', classStart);
24
+ if (open === -1) return -1;
25
+ // Brace depth of the code scope currently being scanned. Entering a `${…}`
26
+ // interpolation pushes the enclosing scope's depth and restarts at 1 (the
27
+ // `${` counts as the open brace); balancing it pops back into the template.
28
+ let depth = 1;
29
+ const interpolationStack = [];
30
+ let inTemplate = false;
31
+ let i = open + 1;
32
+ while (i < code.length) {
33
+ const ch = code[i];
34
+ if (inTemplate) {
35
+ if (ch === '\\') {
36
+ i += 2;
37
+ continue;
38
+ }
39
+ if (ch === '`') {
40
+ inTemplate = false;
41
+ i++;
42
+ continue;
43
+ }
44
+ if (ch === '$' && code[i + 1] === '{') {
45
+ interpolationStack.push(depth);
46
+ depth = 1;
47
+ inTemplate = false;
48
+ i += 2;
49
+ continue;
50
+ }
51
+ i++;
52
+ continue;
53
+ }
54
+ if (ch === '"' || ch === "'") {
55
+ const quote = ch;
56
+ i++;
57
+ while (i < code.length && code[i] !== quote) {
58
+ if (code[i] === '\\') i++;
59
+ i++;
60
+ }
61
+ i++;
62
+ continue;
63
+ }
64
+ if (ch === '`') {
65
+ inTemplate = true;
66
+ i++;
67
+ continue;
68
+ }
69
+ if (ch === '/') {
70
+ const next = code[i + 1];
71
+ if (next === '/') {
72
+ i = code.indexOf('\n', i);
73
+ if (i === -1) return -1;
74
+ continue;
75
+ }
76
+ if (next === '*') {
77
+ i = code.indexOf('*/', i + 2);
78
+ if (i === -1) return -1;
79
+ i += 2;
80
+ continue;
81
+ }
82
+ // Regex literal vs division: scan back over whitespace to the last
83
+ // significant char — a regex can only follow an operator, opening
84
+ // punctuation, or a keyword like `return`. `a / b` has an identifier
85
+ // there, so it's division and scans on as plain code.
86
+ let j = i - 1;
87
+ while (j >= 0 && /\s/.test(code[j])) j--;
88
+ const prev = j >= 0 ? code[j] : '';
89
+ const regexPossible =
90
+ j < 0 ||
91
+ /[=:(,+\-!&|?{}[;]/.test(prev) ||
92
+ /(?:^|[^\w$])(?:return|typeof|case|instanceof|in|of|new|delete|void|throw|do|else|yield|await)$/.test(
93
+ code.slice(Math.max(0, j - 11), j + 1)
94
+ );
95
+ if (regexPossible) {
96
+ let k = i + 1;
97
+ let inCharClass = false;
98
+ while (
99
+ k < code.length &&
100
+ code[k] !== '\n' &&
101
+ (inCharClass || code[k] !== '/')
102
+ ) {
103
+ if (code[k] === '\\') k++;
104
+ else if (code[k] === '[') inCharClass = true;
105
+ else if (code[k] === ']') inCharClass = false;
106
+ k++;
116
107
  }
117
- if (ch === '{') {
118
- depth++;
108
+ if (code[k] === '/') {
109
+ i = k + 1;
110
+ continue;
119
111
  }
120
- else if (ch === '}') {
121
- depth--;
122
- if (depth === 0) {
123
- const enclosing = interpolationStack.pop();
124
- if (enclosing === undefined) {
125
- return i + 1;
126
- }
127
- depth = enclosing;
128
- inTemplate = true;
129
- }
112
+ // No closing `/` before the line ends — not a regex after all.
113
+ }
114
+ }
115
+ if (ch === '{') {
116
+ depth++;
117
+ } else if (ch === '}') {
118
+ depth--;
119
+ if (depth === 0) {
120
+ const enclosing = interpolationStack.pop();
121
+ if (enclosing === undefined) {
122
+ return i + 1;
130
123
  }
131
- i++;
124
+ depth = enclosing;
125
+ inTemplate = true;
126
+ }
132
127
  }
133
- return -1;
128
+ i++;
129
+ }
130
+ return -1;
134
131
  };
135
- const makeAssignment = (className, filePath, lineNumber) => `${className}[${SOURCE_META_SYM}]={filePath:${JSON.stringify(filePath)},lineNumber:${lineNumber},componentName:${JSON.stringify(className)}};`;
136
- /** True when `className` is declared as a class/let/const in module code. */
137
- const isClassDeclaredInModule = (code, className) => new RegExp(`^\\s*(?:export\\s+)?(?:class|let|const|var)\\s+${className}\\b`, 'm').test(code);
132
+ const makeAssignment = (className, filePath, lineNumber) =>
133
+ `${className}[${SOURCE_META_SYM}]={filePath:${JSON.stringify(filePath)},lineNumber:${lineNumber},componentName:${JSON.stringify(className)}};`;
134
+ /**
135
+ * True when `className` is declared at module top level (column 0). Nested
136
+ * declarations are skipped deliberately: the metadata assignment for this path
137
+ * is appended at the end of the module, where a function/block-scoped binding
138
+ * would not be in scope (a `ReferenceError` at module evaluation).
139
+ */
140
+ const isClassDeclaredInModule = (code, className) =>
141
+ new RegExp(
142
+ `^(?:export\\s+)?(?:class|let|const|var)\\s+${className}\\b`,
143
+ 'm'
144
+ ).test(code);
145
+ /** True when `index` starts a line (module top level in emitted output). */
146
+ const isAtLineStart = (code, index) => index === 0 || code[index - 1] === '\n';
138
147
  /**
139
148
  * Injects component source metadata onto custom element class constructors.
140
149
  * Returns whether any injection was made.
141
150
  */
142
151
  export const injectSourceMeta = (code, filePath, ms) => {
143
- if (code.includes(SOURCE_META_SYM)) {
144
- return false;
145
- }
146
- let changed = false;
147
- const injected = new Set();
148
- const injectAtClassEnd = (className, matchIndex, match) => {
149
- if (injected.has(className))
150
- return;
151
- const classOffset = match.indexOf('class');
152
- if (classOffset === -1)
153
- return;
154
- const classStart = matchIndex + classOffset;
155
- const end = findClassBodyEnd(code, classStart);
156
- if (end === -1)
157
- return;
158
- // Report the match start (the `@customElement` decorator) rather than the
159
- // `class` keyword, so the overlay points at the top of the component.
160
- const line = lineNumberAt(code, matchIndex);
161
- ms.append('\n' + makeAssignment(className, filePath, line));
162
- injected.add(className);
163
- changed = true;
164
- };
165
- // @customElement(...) class Foo (any whitespace between them)
166
- for (const m of code.matchAll(/@customElement\s*\([^)]*\)\s+(?:export\s+)?class\s+(\w+)/g)) {
167
- injectAtClassEnd(m[1], m.index, m[0]);
168
- }
169
- // customElements.define('tag', ClassName)
170
- for (const m of code.matchAll(/customElements\.define\s*\(\s*['"][^'"]+['"]\s*,\s*(\w+)/g)) {
171
- const className = m[1];
172
- if (injected.has(className) || !isClassDeclaredInModule(code, className)) {
173
- continue;
174
- }
175
- const line = lineNumberAt(code, m.index);
176
- ms.append('\n' + makeAssignment(className, filePath, line));
177
- injected.add(className);
178
- changed = true;
179
- }
180
- // TypeScript experimental-decorators / esbuild output
181
- // e.g. `Foo = __decorateClass([customElement(...)], Foo)`
182
- // `Foo = _decorate([customElement(...)], Foo)`
183
- for (const m of code.matchAll(/(\w+)\s*=\s*__decorate\w*\(\s*\[[\s\S]*?customElement\s*\([^)]*\)[\s\S]*?\],\s*\1\)/g)) {
184
- const className = m[1];
185
- if (injected.has(className))
186
- continue;
187
- const line = lineNumberAt(code, m.index);
188
- ms.append('\n' + makeAssignment(className, filePath, line));
189
- injected.add(className);
190
- changed = true;
152
+ if (code.includes(SOURCE_META_SYM)) {
153
+ return false;
154
+ }
155
+ let changed = false;
156
+ const injected = new Set();
157
+ const injectAtClassEnd = (className, matchIndex, match) => {
158
+ if (injected.has(className)) return;
159
+ const classOffset = match.indexOf('class');
160
+ if (classOffset === -1) return;
161
+ const classStart = matchIndex + classOffset;
162
+ const end = findClassBodyEnd(code, classStart);
163
+ if (end === -1) return;
164
+ // Report the match start (the `@customElement` decorator) rather than the
165
+ // `class` keyword, so the overlay points at the top of the component.
166
+ const line = lineNumberAt(code, matchIndex);
167
+ // Insert right after the class body so the assignment lives in the same
168
+ // scope as the declaration — appending at module end breaks for a class
169
+ // declared inside a function or block.
170
+ ms.appendLeft(end, '\n' + makeAssignment(className, filePath, line));
171
+ injected.add(className);
172
+ changed = true;
173
+ };
174
+ // @customElement(...) class Foo (any whitespace between them)
175
+ for (const m of code.matchAll(
176
+ /@customElement\s*\([^)]*\)\s+(?:export\s+)?class\s+(\w+)/g
177
+ )) {
178
+ injectAtClassEnd(m[1], m.index, m[0]);
179
+ }
180
+ // customElements.define('tag', ClassName)
181
+ for (const m of code.matchAll(
182
+ /customElements\.define\s*\(\s*['"][^'"]+['"]\s*,\s*(\w+)/g
183
+ )) {
184
+ const className = m[1];
185
+ if (injected.has(className) || !isClassDeclaredInModule(code, className)) {
186
+ continue;
191
187
  }
192
- return changed;
188
+ const line = lineNumberAt(code, m.index);
189
+ ms.append('\n' + makeAssignment(className, filePath, line));
190
+ injected.add(className);
191
+ changed = true;
192
+ }
193
+ // TypeScript experimental-decorators / esbuild output
194
+ // e.g. `Foo = __decorateClass([customElement(...)], Foo)`
195
+ // `Foo = _decorate([customElement(...)], Foo)`
196
+ for (const m of code.matchAll(
197
+ /(\w+)\s*=\s*__decorate\w*\(\s*\[[\s\S]*?customElement\s*\([^)]*\)[\s\S]*?\],\s*\1\)/g
198
+ )) {
199
+ const className = m[1];
200
+ if (injected.has(className) || !isAtLineStart(code, m.index)) continue;
201
+ const line = lineNumberAt(code, m.index);
202
+ ms.append('\n' + makeAssignment(className, filePath, line));
203
+ injected.add(className);
204
+ changed = true;
205
+ }
206
+ return changed;
193
207
  };
194
- //# sourceMappingURL=source-meta.js.map
208
+ //# sourceMappingURL=source-meta.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"source-meta.js","sourceRoot":"","sources":["../../../packages/labs/vite-plugin-lit/src/lib/source-meta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport type MagicString from 'magic-string';\n\n/** Stable key shared between transform output and runtime resolution. */\nexport const SOURCE_META_KEY = '@lit-labs/vite-plugin-lit#source';\n\n/**\n * The expression string used in generated code to reference the shared\n * symbol at runtime.\n */\nexport const SOURCE_META_SYM = `Symbol.for('${SOURCE_META_KEY}')`;\n\nexport interface InjectedSourceMeta {\n filePath: string;\n lineNumber: number;\n componentName?: string;\n}\n\n/** 1-based line number for an index in source text. */\nexport const lineNumberAt = (code: string, index: number): number =>\n code.slice(0, index).split('\\n').length;\n\n/**\n * Finds the index after the closing `}` of a class body starting at\n * `classStart`. Skips braces inside strings, comments, regex literals, and\n * template literals — including code in `${…}` interpolations, where nested\n * templates (Lit's `html\\`…\\`` inside `.map()` etc.) recurse arbitrarily.\n */\nconst findClassBodyEnd = (code: string, classStart: number): number => {\n const open = code.indexOf('{', classStart);\n if (open === -1) return -1;\n // Brace depth of the code scope currently being scanned. Entering a `${…}`\n // interpolation pushes the enclosing scope's depth and restarts at 1 (the\n // `${` counts as the open brace); balancing it pops back into the template.\n let depth = 1;\n const interpolationStack: number[] = [];\n let inTemplate = false;\n let i = open + 1;\n while (i < code.length) {\n const ch = code[i];\n if (inTemplate) {\n if (ch === '\\\\') {\n i += 2;\n continue;\n }\n if (ch === '`') {\n inTemplate = false;\n i++;\n continue;\n }\n if (ch === '$' && code[i + 1] === '{') {\n interpolationStack.push(depth);\n depth = 1;\n inTemplate = false;\n i += 2;\n continue;\n }\n i++;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n const quote = ch;\n i++;\n while (i < code.length && code[i] !== quote) {\n if (code[i] === '\\\\') i++;\n i++;\n }\n i++;\n continue;\n }\n if (ch === '`') {\n inTemplate = true;\n i++;\n continue;\n }\n if (ch === '/') {\n const next = code[i + 1];\n if (next === '/') {\n i = code.indexOf('\\n', i);\n if (i === -1) return -1;\n continue;\n }\n if (next === '*') {\n i = code.indexOf('*/', i + 2);\n if (i === -1) return -1;\n i += 2;\n continue;\n }\n // Regex literal vs division: scan back over whitespace to the last\n // significant char — a regex can only follow an operator, opening\n // punctuation, or a keyword like `return`. `a / b` has an identifier\n // there, so it's division and scans on as plain code.\n let j = i - 1;\n while (j >= 0 && /\\s/.test(code[j])) j--;\n const prev = j >= 0 ? code[j] : '';\n const regexPossible =\n j < 0 ||\n /[=:(,+\\-!&|?{}[;]/.test(prev) ||\n /(?:^|[^\\w$])(?:return|typeof|case|instanceof|in|of|new|delete|void|throw|do|else|yield|await)$/.test(\n code.slice(Math.max(0, j - 11), j + 1)\n );\n if (regexPossible) {\n let k = i + 1;\n let inCharClass = false;\n while (\n k < code.length &&\n code[k] !== '\\n' &&\n (inCharClass || code[k] !== '/')\n ) {\n if (code[k] === '\\\\') k++;\n else if (code[k] === '[') inCharClass = true;\n else if (code[k] === ']') inCharClass = false;\n k++;\n }\n if (code[k] === '/') {\n i = k + 1;\n continue;\n }\n // No closing `/` before the line ends — not a regex after all.\n }\n }\n if (ch === '{') {\n depth++;\n } else if (ch === '}') {\n depth--;\n if (depth === 0) {\n const enclosing = interpolationStack.pop();\n if (enclosing === undefined) {\n return i + 1;\n }\n depth = enclosing;\n inTemplate = true;\n }\n }\n i++;\n }\n return -1;\n};\n\nconst makeAssignment = (\n className: string,\n filePath: string,\n lineNumber: number\n) =>\n `${className}[${SOURCE_META_SYM}]={filePath:${JSON.stringify(filePath)},lineNumber:${lineNumber},componentName:${JSON.stringify(className)}};`;\n\n/** True when `className` is declared as a class/let/const in module code. */\nconst isClassDeclaredInModule = (code: string, className: string): boolean =>\n new RegExp(\n `^\\\\s*(?:export\\\\s+)?(?:class|let|const|var)\\\\s+${className}\\\\b`,\n 'm'\n ).test(code);\n\n/**\n * Injects component source metadata onto custom element class constructors.\n * Returns whether any injection was made.\n */\nexport const injectSourceMeta = (\n code: string,\n filePath: string,\n ms: MagicString\n): boolean => {\n if (code.includes(SOURCE_META_SYM)) {\n return false;\n }\n let changed = false;\n const injected = new Set<string>();\n\n const injectAtClassEnd = (\n className: string,\n matchIndex: number,\n match: string\n ) => {\n if (injected.has(className)) return;\n const classOffset = match.indexOf('class');\n if (classOffset === -1) return;\n const classStart = matchIndex + classOffset;\n const end = findClassBodyEnd(code, classStart);\n if (end === -1) return;\n // Report the match start (the `@customElement` decorator) rather than the\n // `class` keyword, so the overlay points at the top of the component.\n const line = lineNumberAt(code, matchIndex);\n ms.append('\\n' + makeAssignment(className, filePath, line));\n injected.add(className);\n changed = true;\n };\n\n // @customElement(...) class Foo (any whitespace between them)\n for (const m of code.matchAll(\n /@customElement\\s*\\([^)]*\\)\\s+(?:export\\s+)?class\\s+(\\w+)/g\n )) {\n injectAtClassEnd(m[1], m.index, m[0]);\n }\n\n // customElements.define('tag', ClassName)\n for (const m of code.matchAll(\n /customElements\\.define\\s*\\(\\s*['\"][^'\"]+['\"]\\s*,\\s*(\\w+)/g\n )) {\n const className = m[1];\n if (injected.has(className) || !isClassDeclaredInModule(code, className)) {\n continue;\n }\n const line = lineNumberAt(code, m.index);\n ms.append('\\n' + makeAssignment(className, filePath, line));\n injected.add(className);\n changed = true;\n }\n\n // TypeScript experimental-decorators / esbuild output\n // e.g. `Foo = __decorateClass([customElement(...)], Foo)`\n // `Foo = _decorate([customElement(...)], Foo)`\n for (const m of code.matchAll(\n /(\\w+)\\s*=\\s*__decorate\\w*\\(\\s*\\[[\\s\\S]*?customElement\\s*\\([^)]*\\)[\\s\\S]*?\\],\\s*\\1\\)/g\n )) {\n const className = m[1];\n if (injected.has(className)) continue;\n const line = lineNumberAt(code, m.index);\n ms.append('\\n' + makeAssignment(className, filePath, line));\n injected.add(className);\n changed = true;\n }\n\n return changed;\n};\n"]}
1
+ {"version":3,"file":"source-meta.js","sourceRoot":"","sources":["../src/lib/source-meta.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @license\n * Copyright 2026 Google LLC\n * SPDX-License-Identifier: BSD-3-Clause\n */\n\nimport type MagicString from 'magic-string';\n\n/** Stable key shared between transform output and runtime resolution. */\nexport const SOURCE_META_KEY = '@lit-labs/vite-plugin-lit#source';\n\n/**\n * The expression string used in generated code to reference the shared\n * symbol at runtime.\n */\nexport const SOURCE_META_SYM = `Symbol.for('${SOURCE_META_KEY}')`;\n\nexport interface InjectedSourceMeta {\n filePath: string;\n lineNumber: number;\n componentName?: string;\n}\n\n/** 1-based line number for an index in source text. */\nexport const lineNumberAt = (code: string, index: number): number =>\n code.slice(0, index).split('\\n').length;\n\n/**\n * Finds the index after the closing `}` of a class body starting at\n * `classStart`. Skips braces inside strings, comments, regex literals, and\n * template literals — including code in `${…}` interpolations, where nested\n * templates (Lit's `html\\`…\\`` inside `.map()` etc.) recurse arbitrarily.\n */\nconst findClassBodyEnd = (code: string, classStart: number): number => {\n const open = code.indexOf('{', classStart);\n if (open === -1) return -1;\n // Brace depth of the code scope currently being scanned. Entering a `${…}`\n // interpolation pushes the enclosing scope's depth and restarts at 1 (the\n // `${` counts as the open brace); balancing it pops back into the template.\n let depth = 1;\n const interpolationStack: number[] = [];\n let inTemplate = false;\n let i = open + 1;\n while (i < code.length) {\n const ch = code[i];\n if (inTemplate) {\n if (ch === '\\\\') {\n i += 2;\n continue;\n }\n if (ch === '`') {\n inTemplate = false;\n i++;\n continue;\n }\n if (ch === '$' && code[i + 1] === '{') {\n interpolationStack.push(depth);\n depth = 1;\n inTemplate = false;\n i += 2;\n continue;\n }\n i++;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n const quote = ch;\n i++;\n while (i < code.length && code[i] !== quote) {\n if (code[i] === '\\\\') i++;\n i++;\n }\n i++;\n continue;\n }\n if (ch === '`') {\n inTemplate = true;\n i++;\n continue;\n }\n if (ch === '/') {\n const next = code[i + 1];\n if (next === '/') {\n i = code.indexOf('\\n', i);\n if (i === -1) return -1;\n continue;\n }\n if (next === '*') {\n i = code.indexOf('*/', i + 2);\n if (i === -1) return -1;\n i += 2;\n continue;\n }\n // Regex literal vs division: scan back over whitespace to the last\n // significant char — a regex can only follow an operator, opening\n // punctuation, or a keyword like `return`. `a / b` has an identifier\n // there, so it's division and scans on as plain code.\n let j = i - 1;\n while (j >= 0 && /\\s/.test(code[j])) j--;\n const prev = j >= 0 ? code[j] : '';\n const regexPossible =\n j < 0 ||\n /[=:(,+\\-!&|?{}[;]/.test(prev) ||\n /(?:^|[^\\w$])(?:return|typeof|case|instanceof|in|of|new|delete|void|throw|do|else|yield|await)$/.test(\n code.slice(Math.max(0, j - 11), j + 1)\n );\n if (regexPossible) {\n let k = i + 1;\n let inCharClass = false;\n while (\n k < code.length &&\n code[k] !== '\\n' &&\n (inCharClass || code[k] !== '/')\n ) {\n if (code[k] === '\\\\') k++;\n else if (code[k] === '[') inCharClass = true;\n else if (code[k] === ']') inCharClass = false;\n k++;\n }\n if (code[k] === '/') {\n i = k + 1;\n continue;\n }\n // No closing `/` before the line ends — not a regex after all.\n }\n }\n if (ch === '{') {\n depth++;\n } else if (ch === '}') {\n depth--;\n if (depth === 0) {\n const enclosing = interpolationStack.pop();\n if (enclosing === undefined) {\n return i + 1;\n }\n depth = enclosing;\n inTemplate = true;\n }\n }\n i++;\n }\n return -1;\n};\n\nconst makeAssignment = (\n className: string,\n filePath: string,\n lineNumber: number\n) =>\n `${className}[${SOURCE_META_SYM}]={filePath:${JSON.stringify(filePath)},lineNumber:${lineNumber},componentName:${JSON.stringify(className)}};`;\n\n/**\n * True when `className` is declared at module top level (column 0). Nested\n * declarations are skipped deliberately: the metadata assignment for this path\n * is appended at the end of the module, where a function/block-scoped binding\n * would not be in scope (a `ReferenceError` at module evaluation).\n */\nconst isClassDeclaredInModule = (code: string, className: string): boolean =>\n new RegExp(\n `^(?:export\\\\s+)?(?:class|let|const|var)\\\\s+${className}\\\\b`,\n 'm'\n ).test(code);\n\n/** True when `index` starts a line (module top level in emitted output). */\nconst isAtLineStart = (code: string, index: number): boolean =>\n index === 0 || code[index - 1] === '\\n';\n\n/**\n * Injects component source metadata onto custom element class constructors.\n * Returns whether any injection was made.\n */\nexport const injectSourceMeta = (\n code: string,\n filePath: string,\n ms: MagicString\n): boolean => {\n if (code.includes(SOURCE_META_SYM)) {\n return false;\n }\n let changed = false;\n const injected = new Set<string>();\n\n const injectAtClassEnd = (\n className: string,\n matchIndex: number,\n match: string\n ) => {\n if (injected.has(className)) return;\n const classOffset = match.indexOf('class');\n if (classOffset === -1) return;\n const classStart = matchIndex + classOffset;\n const end = findClassBodyEnd(code, classStart);\n if (end === -1) return;\n // Report the match start (the `@customElement` decorator) rather than the\n // `class` keyword, so the overlay points at the top of the component.\n const line = lineNumberAt(code, matchIndex);\n // Insert right after the class body so the assignment lives in the same\n // scope as the declaration — appending at module end breaks for a class\n // declared inside a function or block.\n ms.appendLeft(end, '\\n' + makeAssignment(className, filePath, line));\n injected.add(className);\n changed = true;\n };\n\n // @customElement(...) class Foo (any whitespace between them)\n for (const m of code.matchAll(\n /@customElement\\s*\\([^)]*\\)\\s+(?:export\\s+)?class\\s+(\\w+)/g\n )) {\n injectAtClassEnd(m[1], m.index, m[0]);\n }\n\n // customElements.define('tag', ClassName)\n for (const m of code.matchAll(\n /customElements\\.define\\s*\\(\\s*['\"][^'\"]+['\"]\\s*,\\s*(\\w+)/g\n )) {\n const className = m[1];\n if (injected.has(className) || !isClassDeclaredInModule(code, className)) {\n continue;\n }\n const line = lineNumberAt(code, m.index);\n ms.append('\\n' + makeAssignment(className, filePath, line));\n injected.add(className);\n changed = true;\n }\n\n // TypeScript experimental-decorators / esbuild output\n // e.g. `Foo = __decorateClass([customElement(...)], Foo)`\n // `Foo = _decorate([customElement(...)], Foo)`\n for (const m of code.matchAll(\n /(\\w+)\\s*=\\s*__decorate\\w*\\(\\s*\\[[\\s\\S]*?customElement\\s*\\([^)]*\\)[\\s\\S]*?\\],\\s*\\1\\)/g\n )) {\n const className = m[1];\n if (injected.has(className) || !isAtLineStart(code, m.index)) continue;\n const line = lineNumberAt(code, m.index);\n ms.append('\\n' + makeAssignment(className, filePath, line));\n injected.add(className);\n changed = true;\n }\n\n return changed;\n};\n"]}