@presto1314w/vite-devtools-browser 0.1.2 → 0.1.4
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/README.md +86 -69
- package/dist/browser.d.ts +37 -1
- package/dist/browser.js +291 -15
- package/dist/cli.d.ts +13 -1
- package/dist/cli.js +183 -124
- package/dist/client.d.ts +24 -0
- package/dist/client.js +37 -22
- package/dist/daemon.d.ts +57 -1
- package/dist/daemon.js +147 -118
- package/dist/react/devtools.d.ts +13 -0
- package/dist/react/devtools.js +130 -128
- package/dist/sourcemap.d.ts +14 -0
- package/dist/sourcemap.js +74 -0
- package/dist/svelte/devtools.d.ts +9 -0
- package/dist/svelte/devtools.js +110 -167
- package/dist/vue/devtools.d.ts +4 -0
- package/dist/vue/devtools.js +218 -236
- package/package.json +7 -2
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { SourceMapConsumer } from "source-map-js";
|
|
2
|
+
const consumers = new Map();
|
|
3
|
+
export async function resolveViaSourceMap(origin, fileUrl, line, column, includeSnippet = false, fetchImpl = fetch) {
|
|
4
|
+
const consumer = await loadConsumer(origin, fileUrl, fetchImpl);
|
|
5
|
+
if (!consumer)
|
|
6
|
+
return null;
|
|
7
|
+
const position = consumer.originalPositionFor({
|
|
8
|
+
line,
|
|
9
|
+
column: Math.max(0, column - 1),
|
|
10
|
+
});
|
|
11
|
+
if (!position.source || position.line == null || position.column == null)
|
|
12
|
+
return null;
|
|
13
|
+
const mapped = {
|
|
14
|
+
file: cleanSource(position.source),
|
|
15
|
+
line: position.line,
|
|
16
|
+
column: position.column + 1,
|
|
17
|
+
};
|
|
18
|
+
if (includeSnippet) {
|
|
19
|
+
mapped.snippet = snippetFor(consumer, position.source, position.line);
|
|
20
|
+
}
|
|
21
|
+
return mapped;
|
|
22
|
+
}
|
|
23
|
+
export function clearSourceMapCache() {
|
|
24
|
+
consumers.clear();
|
|
25
|
+
}
|
|
26
|
+
async function loadConsumer(origin, fileUrl, fetchImpl) {
|
|
27
|
+
const candidates = buildMapCandidates(origin, fileUrl);
|
|
28
|
+
for (const url of candidates) {
|
|
29
|
+
if (consumers.has(url)) {
|
|
30
|
+
const cached = consumers.get(url);
|
|
31
|
+
if (cached)
|
|
32
|
+
return cached;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
const response = await fetchImpl(url, { signal: AbortSignal.timeout(5000) }).catch(() => null);
|
|
36
|
+
if (!response?.ok) {
|
|
37
|
+
consumers.set(url, null);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const map = await response.json().catch(() => null);
|
|
41
|
+
if (!map) {
|
|
42
|
+
consumers.set(url, null);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const consumer = new SourceMapConsumer(map);
|
|
46
|
+
consumers.set(url, consumer);
|
|
47
|
+
return consumer;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
export function buildMapCandidates(origin, fileUrl) {
|
|
52
|
+
const url = new URL(fileUrl, origin);
|
|
53
|
+
const basePath = `${url.pathname}.map`;
|
|
54
|
+
const withSearch = url.search ? `${basePath}${url.search}` : basePath;
|
|
55
|
+
// Try preserving query first (Vite often keeps cache-busting query params).
|
|
56
|
+
return [`${origin}${withSearch}`, `${origin}${basePath}`];
|
|
57
|
+
}
|
|
58
|
+
export function cleanSource(source) {
|
|
59
|
+
const decoded = decodeURIComponent(source.replace(/^file:\/\//, ""));
|
|
60
|
+
const nodeModulesIndex = decoded.lastIndexOf("/node_modules/");
|
|
61
|
+
if (nodeModulesIndex >= 0)
|
|
62
|
+
return decoded.slice(nodeModulesIndex + 1);
|
|
63
|
+
return decoded;
|
|
64
|
+
}
|
|
65
|
+
export function snippetFor(consumer, source, line) {
|
|
66
|
+
const content = consumer.sourceContentFor(source, true);
|
|
67
|
+
if (!content)
|
|
68
|
+
return undefined;
|
|
69
|
+
const lines = content.split(/\r?\n/);
|
|
70
|
+
const sourceLine = lines[line - 1];
|
|
71
|
+
if (!sourceLine)
|
|
72
|
+
return undefined;
|
|
73
|
+
return `${line} | ${sourceLine.trim()}`;
|
|
74
|
+
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
import type { Page } from "playwright";
|
|
2
|
+
export type SvelteNode = {
|
|
3
|
+
id: number;
|
|
4
|
+
parent: number;
|
|
5
|
+
name: string;
|
|
6
|
+
props?: unknown;
|
|
7
|
+
file?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function formatComponentTree(nodes: SvelteNode[]): string;
|
|
10
|
+
export declare function formatComponentDetails(nodes: SvelteNode[], id: string): string;
|
|
2
11
|
export declare function getComponentTree(page: Page): Promise<string>;
|
|
3
12
|
export declare function getComponentDetails(page: Page, id: string): Promise<string>;
|
package/dist/svelte/devtools.js
CHANGED
|
@@ -1,177 +1,120 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
output.push("Svelte app detected, but no DevTools component graph is available.");
|
|
11
|
-
output.push("Tip: install/enable Svelte DevTools, then run `svelte tree` again.");
|
|
12
|
-
return output.join("\n");
|
|
13
|
-
}
|
|
14
|
-
const children = new Map();
|
|
15
|
-
for (const n of nodes) {
|
|
16
|
-
const list = children.get(n.parent) ?? [];
|
|
17
|
-
list.push(n);
|
|
18
|
-
children.set(n.parent, list);
|
|
19
|
-
}
|
|
20
|
-
for (const root of children.get(0) ?? [])
|
|
21
|
-
walk(root, 0);
|
|
1
|
+
export function formatComponentTree(nodes) {
|
|
2
|
+
const output = [
|
|
3
|
+
"# Svelte component tree",
|
|
4
|
+
"# Use `svelte tree <id>` to inspect component details.",
|
|
5
|
+
"",
|
|
6
|
+
];
|
|
7
|
+
if (nodes.length === 0) {
|
|
8
|
+
output.push("Svelte app detected, but no DevTools component graph is available.");
|
|
9
|
+
output.push("Tip: install/enable Svelte DevTools, then run `svelte tree` again.");
|
|
22
10
|
return output.join("\n");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
visit(candidate, 0, 0);
|
|
40
|
-
}
|
|
41
|
-
return out;
|
|
42
|
-
function visit(value, parent, depth) {
|
|
43
|
-
if (!value || typeof value !== "object")
|
|
44
|
-
return;
|
|
45
|
-
if (seen.has(value))
|
|
46
|
-
return;
|
|
47
|
-
if (depth > 6)
|
|
48
|
-
return;
|
|
49
|
-
seen.add(value);
|
|
50
|
-
const maybeComponent = !!value.$$ ||
|
|
51
|
-
typeof value.$set === "function" ||
|
|
52
|
-
typeof value.$destroy === "function" ||
|
|
53
|
-
value.type === "component";
|
|
54
|
-
let currentParent = parent;
|
|
55
|
-
if (maybeComponent) {
|
|
56
|
-
const id = Number.isFinite(Number(value.id)) ? Number(value.id) : seq++;
|
|
57
|
-
const name = value.name ||
|
|
58
|
-
value.$$?.component?.name ||
|
|
59
|
-
value.constructor?.name ||
|
|
60
|
-
value.$$?.tag ||
|
|
61
|
-
"AnonymousSvelteComponent";
|
|
62
|
-
const props = value.$capture_state?.() ?? value.props ?? value.$$?.props;
|
|
63
|
-
out.push({ id, parent, name: String(name), props });
|
|
64
|
-
currentParent = id;
|
|
65
|
-
}
|
|
66
|
-
const children = [
|
|
67
|
-
value.children,
|
|
68
|
-
value.$$?.children,
|
|
69
|
-
value.$$.fragment?.children,
|
|
70
|
-
value.components,
|
|
71
|
-
value.apps,
|
|
72
|
-
value.instances,
|
|
73
|
-
value.roots,
|
|
74
|
-
].filter(Boolean);
|
|
75
|
-
for (const child of children) {
|
|
76
|
-
if (Array.isArray(child)) {
|
|
77
|
-
for (const c of child)
|
|
78
|
-
visit(c, currentParent, depth + 1);
|
|
79
|
-
}
|
|
80
|
-
else if (typeof child === "object") {
|
|
81
|
-
for (const c of Object.values(child))
|
|
82
|
-
visit(c, currentParent, depth + 1);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
});
|
|
11
|
+
}
|
|
12
|
+
const children = new Map();
|
|
13
|
+
for (const n of nodes) {
|
|
14
|
+
const list = children.get(n.parent) ?? [];
|
|
15
|
+
list.push(n);
|
|
16
|
+
children.set(n.parent, list);
|
|
17
|
+
}
|
|
18
|
+
for (const root of children.get(0) ?? [])
|
|
19
|
+
walk(root, 0);
|
|
20
|
+
return output.join("\n");
|
|
21
|
+
function walk(node, depth) {
|
|
22
|
+
const indent = " ".repeat(depth);
|
|
23
|
+
output.push(`${indent}[${node.id}] ${node.name}`);
|
|
24
|
+
for (const c of children.get(node.id) ?? [])
|
|
25
|
+
walk(c, depth + 1);
|
|
26
|
+
}
|
|
88
27
|
}
|
|
89
|
-
export
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
28
|
+
export function formatComponentDetails(nodes, id) {
|
|
29
|
+
const match = nodes.find((n) => String(n.id) === id);
|
|
30
|
+
if (!match)
|
|
31
|
+
return `Component ${id} not found. Run 'svelte tree' to get fresh IDs.`;
|
|
32
|
+
const output = [`# Svelte component`, `# ID: ${match.id}`, `# Name: ${match.name}`, ""];
|
|
33
|
+
if (match.props && typeof match.props === "object") {
|
|
34
|
+
output.push("## Props/State");
|
|
35
|
+
for (const [k, v] of Object.entries(match.props)) {
|
|
36
|
+
output.push(` ${k}: ${safe(v)}`);
|
|
95
37
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
38
|
+
output.push("");
|
|
39
|
+
}
|
|
40
|
+
if (match.file) {
|
|
41
|
+
output.push("## Source");
|
|
42
|
+
output.push(` ${match.file}`);
|
|
43
|
+
}
|
|
44
|
+
return output.join("\n");
|
|
45
|
+
function safe(v) {
|
|
46
|
+
try {
|
|
47
|
+
return JSON.stringify(v);
|
|
103
48
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
output.push(` ${match.file}`);
|
|
49
|
+
catch {
|
|
50
|
+
return String(v);
|
|
107
51
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function getComponentTree(page) {
|
|
55
|
+
const nodes = await page.evaluate(collectSvelteNodes);
|
|
56
|
+
return formatComponentTree(nodes);
|
|
57
|
+
}
|
|
58
|
+
export async function getComponentDetails(page, id) {
|
|
59
|
+
const nodes = await page.evaluate(collectSvelteNodes);
|
|
60
|
+
return formatComponentDetails(nodes, id);
|
|
61
|
+
}
|
|
62
|
+
function collectSvelteNodes() {
|
|
63
|
+
const out = [];
|
|
64
|
+
const seen = new WeakSet();
|
|
65
|
+
let seq = 1;
|
|
66
|
+
const globalCandidates = [
|
|
67
|
+
window.__SVELTE_DEVTOOLS_GLOBAL_HOOK__,
|
|
68
|
+
window.__SVELTE_DEVTOOLS__,
|
|
69
|
+
window.__svelte,
|
|
70
|
+
].filter(Boolean);
|
|
71
|
+
for (const candidate of globalCandidates) {
|
|
72
|
+
visit(candidate, 0, 0);
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
function visit(value, parent, depth) {
|
|
76
|
+
if (!value || typeof value !== "object")
|
|
77
|
+
return;
|
|
78
|
+
if (seen.has(value))
|
|
79
|
+
return;
|
|
80
|
+
if (depth > 6)
|
|
81
|
+
return;
|
|
82
|
+
seen.add(value);
|
|
83
|
+
const maybeComponent = !!value.$$ ||
|
|
84
|
+
typeof value.$set === "function" ||
|
|
85
|
+
typeof value.$destroy === "function" ||
|
|
86
|
+
value.type === "component";
|
|
87
|
+
let currentParent = parent;
|
|
88
|
+
if (maybeComponent) {
|
|
89
|
+
const id = Number.isFinite(Number(value.id)) ? Number(value.id) : seq++;
|
|
90
|
+
const name = value.name ||
|
|
91
|
+
value.$$?.component?.name ||
|
|
92
|
+
value.constructor?.name ||
|
|
93
|
+
value.$$?.tag ||
|
|
94
|
+
"AnonymousSvelteComponent";
|
|
95
|
+
const props = value.$capture_state?.() ?? value.props ?? value.$$?.props;
|
|
96
|
+
const file = value.$$?.component?.__file || value.file;
|
|
97
|
+
out.push({ id, parent, name: String(name), props, file });
|
|
98
|
+
currentParent = id;
|
|
116
99
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
100
|
+
const children = [
|
|
101
|
+
value.children,
|
|
102
|
+
value.$$?.children,
|
|
103
|
+
value.$$.fragment?.children,
|
|
104
|
+
value.components,
|
|
105
|
+
value.apps,
|
|
106
|
+
value.instances,
|
|
107
|
+
value.roots,
|
|
108
|
+
].filter(Boolean);
|
|
109
|
+
for (const child of children) {
|
|
110
|
+
if (Array.isArray(child)) {
|
|
111
|
+
for (const c of child)
|
|
112
|
+
visit(c, currentParent, depth + 1);
|
|
128
113
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return;
|
|
133
|
-
if (seen.has(value))
|
|
134
|
-
return;
|
|
135
|
-
if (depth > 6)
|
|
136
|
-
return;
|
|
137
|
-
seen.add(value);
|
|
138
|
-
const maybeComponent = !!value.$$ ||
|
|
139
|
-
typeof value.$set === "function" ||
|
|
140
|
-
typeof value.$destroy === "function" ||
|
|
141
|
-
value.type === "component";
|
|
142
|
-
let currentParent = parent;
|
|
143
|
-
if (maybeComponent) {
|
|
144
|
-
const id = Number.isFinite(Number(value.id)) ? Number(value.id) : seq++;
|
|
145
|
-
const name = value.name ||
|
|
146
|
-
value.$$?.component?.name ||
|
|
147
|
-
value.constructor?.name ||
|
|
148
|
-
value.$$?.tag ||
|
|
149
|
-
"AnonymousSvelteComponent";
|
|
150
|
-
const props = value.$capture_state?.() ?? value.props ?? value.$$?.props;
|
|
151
|
-
const file = value.$$?.component?.__file || value.file;
|
|
152
|
-
out.push({ id, parent, name: String(name), props, file });
|
|
153
|
-
currentParent = id;
|
|
154
|
-
}
|
|
155
|
-
const children = [
|
|
156
|
-
value.children,
|
|
157
|
-
value.$$?.children,
|
|
158
|
-
value.$$.fragment?.children,
|
|
159
|
-
value.components,
|
|
160
|
-
value.apps,
|
|
161
|
-
value.instances,
|
|
162
|
-
value.roots,
|
|
163
|
-
].filter(Boolean);
|
|
164
|
-
for (const child of children) {
|
|
165
|
-
if (Array.isArray(child)) {
|
|
166
|
-
for (const c of child)
|
|
167
|
-
visit(c, currentParent, depth + 1);
|
|
168
|
-
}
|
|
169
|
-
else if (typeof child === "object") {
|
|
170
|
-
for (const c of Object.values(child))
|
|
171
|
-
visit(c, currentParent, depth + 1);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
114
|
+
else if (typeof child === "object") {
|
|
115
|
+
for (const c of Object.values(child))
|
|
116
|
+
visit(c, currentParent, depth + 1);
|
|
174
117
|
}
|
|
175
118
|
}
|
|
176
|
-
}
|
|
119
|
+
}
|
|
177
120
|
}
|
package/dist/vue/devtools.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ export interface VueComponent {
|
|
|
11
11
|
file?: string;
|
|
12
12
|
line?: number;
|
|
13
13
|
}
|
|
14
|
+
export declare function formatComponentTree(apps: any[]): string;
|
|
15
|
+
export declare function formatComponentDetails(targetInstance: any, componentId: string): string;
|
|
16
|
+
export declare function formatPiniaStores(pinia: any, storeName?: string, piniaFromWindow?: boolean): string;
|
|
17
|
+
export declare function formatRouterInfo(actualRouter: any): string;
|
|
14
18
|
/**
|
|
15
19
|
* Get Vue component tree from the page
|
|
16
20
|
*/
|