@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.
- package/CHANGELOG.md +64 -0
- package/LICENSE +28 -0
- package/README.md +153 -0
- package/bin.mjs +154 -0
- package/client.d.ts +61 -0
- package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js +69 -0
- package/dist/client/assets/browser-agent-rpc-BXhoSh1z-BvWe4sTJ.js.map +1 -0
- package/dist/client/assets/index-CFrVgNfS.js +9740 -0
- package/dist/client/assets/index-CFrVgNfS.js.map +1 -0
- package/{panel → dist/client}/index.html +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +2 -2
- package/index.js.map +1 -1
- package/lib/color-scheme.d.ts.map +1 -1
- package/lib/color-scheme.js +17 -21
- package/lib/color-scheme.js.map +1 -1
- package/lib/devframe/definition.d.ts +45 -0
- package/lib/devframe/definition.d.ts.map +1 -0
- package/lib/devframe/definition.js +547 -0
- package/lib/devframe/definition.js.map +1 -0
- package/lib/devframe/icon.d.ts +8 -0
- package/lib/devframe/icon.d.ts.map +1 -0
- package/lib/devframe/icon.js +21 -0
- package/lib/devframe/icon.js.map +1 -0
- package/lib/devframe/paths.d.ts +12 -0
- package/lib/devframe/paths.d.ts.map +1 -0
- package/lib/devframe/paths.js +38 -0
- package/lib/devframe/paths.js.map +1 -0
- package/lib/devframe/protocol.d.ts +218 -0
- package/lib/devframe/protocol.d.ts.map +1 -0
- package/lib/devframe/protocol.js +76 -0
- package/lib/devframe/protocol.js.map +1 -0
- package/lib/devframe/source.d.ts +49 -0
- package/lib/devframe/source.d.ts.map +1 -0
- package/lib/devframe/source.js +23 -0
- package/lib/devframe/source.js.map +1 -0
- package/lib/devframe/vite.d.ts +116 -0
- package/lib/devframe/vite.d.ts.map +1 -0
- package/lib/devframe/vite.js +291 -0
- package/lib/devframe/vite.js.map +1 -0
- package/lib/http.d.ts +29 -0
- package/lib/http.d.ts.map +1 -0
- package/lib/http.js +35 -0
- package/lib/http.js.map +1 -0
- package/lib/icons.d.ts +2 -0
- package/lib/icons.d.ts.map +1 -1
- package/lib/icons.js +10 -4
- package/lib/icons.js.map +1 -1
- package/lib/plugin.d.ts +15 -4
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +640 -574
- package/lib/plugin.js.map +1 -1
- package/lib/runtime/css.d.ts +2 -16
- package/lib/runtime/css.d.ts.map +1 -1
- package/lib/runtime/css.js +43 -36
- package/lib/runtime/css.js.map +1 -1
- package/lib/runtime/edge-panel.d.ts.map +1 -1
- package/lib/runtime/edge-panel.js +82 -91
- package/lib/runtime/edge-panel.js.map +1 -1
- package/lib/runtime/fonts.d.ts.map +1 -1
- package/lib/runtime/fonts.js +1 -1
- package/lib/runtime/fonts.js.map +1 -1
- package/lib/runtime/indicator.d.ts.map +1 -1
- package/lib/runtime/indicator.js +71 -74
- package/lib/runtime/indicator.js.map +1 -1
- package/lib/runtime/inspector/collect.d.ts.map +1 -1
- package/lib/runtime/inspector/collect.js +83 -90
- package/lib/runtime/inspector/collect.js.map +1 -1
- package/lib/runtime/inspector/highlight.d.ts +16 -0
- package/lib/runtime/inspector/highlight.d.ts.map +1 -0
- package/lib/runtime/inspector/highlight.js +66 -0
- package/lib/runtime/inspector/highlight.js.map +1 -0
- package/lib/runtime/inspector/install.d.ts.map +1 -1
- package/lib/runtime/inspector/install.js +180 -205
- package/lib/runtime/inspector/install.js.map +1 -1
- package/lib/runtime/inspector/serialize.d.ts.map +1 -1
- package/lib/runtime/inspector/serialize.js +86 -107
- package/lib/runtime/inspector/serialize.js.map +1 -1
- package/lib/runtime/intern.d.ts.map +1 -1
- package/lib/runtime/intern.js +31 -29
- package/lib/runtime/intern.js.map +1 -1
- package/lib/runtime/overrides.d.ts.map +1 -1
- package/lib/runtime/overrides.js +14 -13
- package/lib/runtime/overrides.js.map +1 -1
- package/lib/runtime/patch.d.ts +8 -0
- package/lib/runtime/patch.d.ts.map +1 -1
- package/lib/runtime/patch.js +321 -282
- package/lib/runtime/patch.js.map +1 -1
- package/lib/runtime/source-meta.d.ts.map +1 -1
- package/lib/runtime/source-meta.js +1 -1
- package/lib/runtime/source-meta.js.map +1 -1
- package/lib/runtime/source-overlay/editors.d.ts.map +1 -1
- package/lib/runtime/source-overlay/editors.js +27 -27
- package/lib/runtime/source-overlay/editors.js.map +1 -1
- package/lib/runtime/source-overlay/mask-path.d.ts.map +1 -1
- package/lib/runtime/source-overlay/mask-path.js +15 -15
- package/lib/runtime/source-overlay/mask-path.js.map +1 -1
- package/lib/runtime/source-overlay/overlay-element.d.ts.map +1 -1
- package/lib/runtime/source-overlay/overlay-element.js +347 -356
- package/lib/runtime/source-overlay/overlay-element.js.map +1 -1
- package/lib/runtime/source-overlay/source-host.d.ts.map +1 -1
- package/lib/runtime/source-overlay/source-host.js +64 -71
- package/lib/runtime/source-overlay/source-host.js.map +1 -1
- package/lib/runtime/source-overlay/template.d.ts.map +1 -1
- package/lib/runtime/source-overlay/template.js +3 -3
- package/lib/runtime/source-overlay/template.js.map +1 -1
- package/lib/runtime/source-overlay.d.ts.map +1 -1
- package/lib/runtime/source-overlay.js +5 -2
- package/lib/runtime/source-overlay.js.map +1 -1
- package/lib/runtime/timeline/clock.d.ts.map +1 -1
- package/lib/runtime/timeline/clock.js +2 -2
- package/lib/runtime/timeline/clock.js.map +1 -1
- package/lib/runtime/timeline/flash.d.ts +39 -0
- package/lib/runtime/timeline/flash.d.ts.map +1 -0
- package/lib/runtime/timeline/flash.js +169 -0
- package/lib/runtime/timeline/flash.js.map +1 -0
- package/lib/runtime/timeline/identity.d.ts.map +1 -1
- package/lib/runtime/timeline/identity.js +27 -27
- package/lib/runtime/timeline/identity.js.map +1 -1
- package/lib/runtime/timeline/input.d.ts.map +1 -1
- package/lib/runtime/timeline/input.js +54 -67
- package/lib/runtime/timeline/input.js.map +1 -1
- package/lib/runtime/timeline/install.d.ts.map +1 -1
- package/lib/runtime/timeline/install.js +38 -29
- package/lib/runtime/timeline/install.js.map +1 -1
- package/lib/runtime/timeline/lifecycle.d.ts +8 -0
- package/lib/runtime/timeline/lifecycle.d.ts.map +1 -1
- package/lib/runtime/timeline/lifecycle.js +149 -133
- package/lib/runtime/timeline/lifecycle.js.map +1 -1
- package/lib/runtime/timeline/public-api.d.ts.map +1 -1
- package/lib/runtime/timeline/public-api.js +9 -9
- package/lib/runtime/timeline/public-api.js.map +1 -1
- package/lib/runtime/timeline/render.d.ts.map +1 -1
- package/lib/runtime/timeline/render.js +70 -75
- package/lib/runtime/timeline/render.js.map +1 -1
- package/lib/runtime/timeline/transport.d.ts.map +1 -1
- package/lib/runtime/timeline/transport.js +39 -43
- package/lib/runtime/timeline/transport.js.map +1 -1
- package/lib/segmented-tabs.d.ts +3 -1
- package/lib/segmented-tabs.d.ts.map +1 -1
- package/lib/segmented-tabs.js +136 -107
- package/lib/segmented-tabs.js.map +1 -1
- package/lib/snapshot.d.ts +28 -0
- package/lib/snapshot.d.ts.map +1 -0
- package/lib/snapshot.js +57 -0
- package/lib/snapshot.js.map +1 -0
- package/lib/source-meta.d.ts.map +1 -1
- package/lib/source-meta.js +176 -162
- package/lib/source-meta.js.map +1 -1
- package/lib/timeline/derive.d.ts +152 -0
- package/lib/timeline/derive.d.ts.map +1 -0
- package/lib/timeline/derive.js +242 -0
- package/lib/timeline/derive.js.map +1 -0
- package/lib/timeline-plugin.d.ts.map +1 -1
- package/lib/timeline-plugin.js +304 -321
- package/lib/timeline-plugin.js.map +1 -1
- package/lib/tokens.d.ts.map +1 -1
- package/lib/tokens.js +17 -18
- package/lib/tokens.js.map +1 -1
- package/lib/transform.d.ts.map +1 -1
- package/lib/transform.js +62 -57
- package/lib/transform.js.map +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +1 -1
- package/lib/types.js.map +1 -1
- package/lib/wrap-table.d.ts.map +1 -1
- package/lib/wrap-table.js +19 -17
- package/lib/wrap-table.js.map +1 -1
- package/package.json +77 -13
- package/types/hmr-incompatibility.d.ts +59 -0
- package/types/hmr-incompatibility.d.ts.map +1 -0
- package/types/hmr-incompatibility.js +30 -0
- package/types/hmr-incompatibility.js.map +1 -0
- package/types/in-page.d.ts +49 -0
- package/types/in-page.d.ts.map +1 -0
- package/types/in-page.js +33 -0
- package/types/in-page.js.map +1 -0
- package/types/inspector.d.ts.map +1 -1
- package/types/inspector.js.map +1 -1
- package/types/snapshot.d.ts +44 -0
- package/types/snapshot.d.ts.map +1 -0
- package/types/snapshot.js +7 -0
- package/types/snapshot.js.map +1 -0
- package/types/timeline.d.ts +11 -0
- package/types/timeline.d.ts.map +1 -1
- package/types/timeline.js.map +1 -1
- package/panel/components-view.d.ts +0 -60
- package/panel/components-view.d.ts.map +0 -1
- package/panel/components-view.js +0 -587
- package/panel/components-view.js.map +0 -1
- package/panel/devtools-settings.d.ts +0 -41
- package/panel/devtools-settings.d.ts.map +0 -1
- package/panel/devtools-settings.js +0 -463
- package/panel/devtools-settings.js.map +0 -1
- package/panel/lit-devtools-panel.d.ts +0 -37
- package/panel/lit-devtools-panel.d.ts.map +0 -1
- package/panel/lit-devtools-panel.js +0 -185
- package/panel/lit-devtools-panel.js.map +0 -1
- package/panel/timeline-event-list.d.ts +0 -43
- package/panel/timeline-event-list.d.ts.map +0 -1
- package/panel/timeline-event-list.js +0 -416
- package/panel/timeline-event-list.js.map +0 -1
- package/panel/timeline-layers.d.ts +0 -25
- package/panel/timeline-layers.d.ts.map +0 -1
- package/panel/timeline-layers.js +0 -96
- package/panel/timeline-layers.js.map +0 -1
- package/panel/timeline-view.d.ts +0 -38
- package/panel/timeline-view.d.ts.map +0 -1
- package/panel/timeline-view.js +0 -234
- package/panel/timeline-view.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"segmented-tabs.js","sourceRoot":"","sources":["
|
|
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"}
|
package/lib/snapshot.js
ADDED
|
@@ -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"]}
|
package/lib/source-meta.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-meta.d.ts","sourceRoot":"","sources":["
|
|
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"}
|
package/lib/source-meta.js
CHANGED
|
@@ -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) =>
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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 (
|
|
118
|
-
|
|
108
|
+
if (code[k] === '/') {
|
|
109
|
+
i = k + 1;
|
|
110
|
+
continue;
|
|
119
111
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
124
|
+
depth = enclosing;
|
|
125
|
+
inTemplate = true;
|
|
126
|
+
}
|
|
132
127
|
}
|
|
133
|
-
|
|
128
|
+
i++;
|
|
129
|
+
}
|
|
130
|
+
return -1;
|
|
134
131
|
};
|
|
135
|
-
const makeAssignment = (className, filePath, lineNumber) =>
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
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
|
package/lib/source-meta.js.map
CHANGED
|
@@ -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"]}
|