chrome-devtools-frontend 1.0.968254 → 1.0.968818
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/front_end/core/sdk/CSSMatchedStyles.ts +1 -1
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +31 -0
- package/front_end/panels/sources/SourceMapNamesResolver.ts +15 -9
- package/package.json +1 -1
- package/scripts/build/devtools_plugin.js +32 -1
- package/scripts/build/esbuild.js +1 -24
- package/scripts/build/tests/plugins_test.js +60 -1
@@ -273,7 +273,7 @@ export class CSSMatchedStyles {
|
|
273
273
|
async recomputeMatchingSelectors(rule: CSSStyleRule): Promise<void> {
|
274
274
|
const node = this.nodeForStyle(rule.style);
|
275
275
|
if (!node) {
|
276
|
-
return
|
276
|
+
return;
|
277
277
|
}
|
278
278
|
const promises = [];
|
279
279
|
for (const selector of rule.selectors) {
|
@@ -90,6 +90,8 @@ export class ScopeChainSidebarPane extends UI.Widget.VBox implements UI.ContextF
|
|
90
90
|
private readonly expandController: ObjectUI.ObjectPropertiesSection.ObjectPropertiesSectionsTreeExpandController;
|
91
91
|
private readonly linkifier: Components.Linkifier.Linkifier;
|
92
92
|
private infoElement: HTMLDivElement;
|
93
|
+
#scopesScript: SDK.Script.Script|null = null;
|
94
|
+
|
93
95
|
private constructor() {
|
94
96
|
super(true);
|
95
97
|
|
@@ -126,6 +128,34 @@ export class ScopeChainSidebarPane extends UI.Widget.VBox implements UI.ContextF
|
|
126
128
|
}
|
127
129
|
}
|
128
130
|
|
131
|
+
private sourceMapAttached(
|
132
|
+
event: Common.EventTarget.EventTargetEvent<{client: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap}>):
|
133
|
+
void {
|
134
|
+
if (event.data.client === this.#scopesScript) {
|
135
|
+
void this.update();
|
136
|
+
}
|
137
|
+
}
|
138
|
+
|
139
|
+
private setScopeSourceMapSubscription(callFrame: SDK.DebuggerModel.CallFrame|null): void {
|
140
|
+
const oldScript = this.#scopesScript;
|
141
|
+
this.#scopesScript = callFrame?.script ?? null;
|
142
|
+
|
143
|
+
// Shortcut for the case when we are listening to the same model.
|
144
|
+
if (oldScript?.debuggerModel === this.#scopesScript?.debuggerModel) {
|
145
|
+
return;
|
146
|
+
}
|
147
|
+
|
148
|
+
if (oldScript) {
|
149
|
+
oldScript.debuggerModel.sourceMapManager().removeEventListener(
|
150
|
+
SDK.SourceMapManager.Events.SourceMapAttached, this.sourceMapAttached, this);
|
151
|
+
}
|
152
|
+
|
153
|
+
if (this.#scopesScript) {
|
154
|
+
this.#scopesScript.debuggerModel.sourceMapManager().addEventListener(
|
155
|
+
SDK.SourceMapManager.Events.SourceMapAttached, this.sourceMapAttached, this);
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
129
159
|
private async update(): Promise<void> {
|
130
160
|
// The `resolveThisObject(callFrame)` and `resolveScopeChain(callFrame)` calls
|
131
161
|
// below may take a while to complete, so indicate to the user that something
|
@@ -137,6 +167,7 @@ export class ScopeChainSidebarPane extends UI.Widget.VBox implements UI.ContextF
|
|
137
167
|
this.linkifier.reset();
|
138
168
|
|
139
169
|
const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame);
|
170
|
+
this.setScopeSourceMapSubscription(callFrame);
|
140
171
|
const [thisObject, scopeChain] = await Promise.all([resolveThisObject(callFrame), resolveScopeChain(callFrame)]);
|
141
172
|
// By now the developer might have moved on, and we don't want to show stale
|
142
173
|
// scope information, so check again that we're still on the same CallFrame.
|
@@ -10,9 +10,14 @@ import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
10
10
|
import type * as Workspace from '../../models/workspace/workspace.js';
|
11
11
|
import * as Protocol from '../../generated/protocol.js';
|
12
12
|
|
13
|
-
|
13
|
+
interface CachedScopeMap {
|
14
|
+
sourceMap: SDK.SourceMap.SourceMap|null;
|
15
|
+
identifiersPromise: Promise<Map<string, string>>;
|
16
|
+
}
|
14
17
|
|
18
|
+
const scopeToCachedIdentifiersMap = new WeakMap<SDK.DebuggerModel.ScopeChainEntry, CachedScopeMap>();
|
15
19
|
const cachedMapByCallFrame = new WeakMap<SDK.DebuggerModel.CallFrame, Map<string, string>>();
|
20
|
+
|
16
21
|
export class Identifier {
|
17
22
|
name: string;
|
18
23
|
lineNumber: number;
|
@@ -79,17 +84,17 @@ export const resolveScopeChain =
|
|
79
84
|
};
|
80
85
|
|
81
86
|
export const resolveScope = async(scope: SDK.DebuggerModel.ScopeChainEntry): Promise<Map<string, string>> => {
|
82
|
-
let
|
83
|
-
|
87
|
+
let cachedScopeMap = scopeToCachedIdentifiersMap.get(scope);
|
88
|
+
const script = scope.callFrame().script;
|
89
|
+
const sourceMap = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().sourceMapForScript(script);
|
90
|
+
|
91
|
+
if (!cachedScopeMap || cachedScopeMap.sourceMap !== sourceMap) {
|
84
92
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
85
93
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
86
94
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
87
95
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
88
|
-
identifiersPromise = (async(): Promise<Map<any, any>> => {
|
96
|
+
const identifiersPromise = (async(): Promise<Map<any, any>> => {
|
89
97
|
const namesMapping = new Map<string, string>();
|
90
|
-
const script = scope.callFrame().script;
|
91
|
-
const sourceMap =
|
92
|
-
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().sourceMapForScript(script);
|
93
98
|
if (sourceMap) {
|
94
99
|
const textCache = new Map<string, TextUtils.Text.Text>();
|
95
100
|
// Extract as much as possible from SourceMap and resolve
|
@@ -111,9 +116,10 @@ export const resolveScope = async(scope: SDK.DebuggerModel.ScopeChainEntry): Pro
|
|
111
116
|
}
|
112
117
|
return namesMapping;
|
113
118
|
})();
|
114
|
-
|
119
|
+
cachedScopeMap = {sourceMap, identifiersPromise};
|
120
|
+
scopeToCachedIdentifiersMap.set(scope, {sourceMap, identifiersPromise});
|
115
121
|
}
|
116
|
-
return await identifiersPromise;
|
122
|
+
return await cachedScopeMap.identifiersPromise;
|
117
123
|
|
118
124
|
async function resolveSourceName(
|
119
125
|
script: SDK.Script.Script, sourceMap: SDK.SourceMap.SourceMap, id: Identifier,
|
package/package.json
CHANGED
@@ -111,4 +111,35 @@ function devtoolsPlugin(source, importer) {
|
|
111
111
|
};
|
112
112
|
}
|
113
113
|
|
114
|
-
|
114
|
+
function esbuildPlugin(outdir) {
|
115
|
+
return args => {
|
116
|
+
// args.importer is absolute path in esbuild.
|
117
|
+
const res = devtoolsPlugin(args.path, args.importer);
|
118
|
+
if (!res) {
|
119
|
+
return null;
|
120
|
+
}
|
121
|
+
|
122
|
+
if (res.external) {
|
123
|
+
// res.id can be both of absolutized local JavaScript path or node's
|
124
|
+
// builtin module (e.g. 'fs', 'path'), and only relativize the path in
|
125
|
+
// former case.
|
126
|
+
if (path.isAbsolute(res.id)) {
|
127
|
+
res.id = './' + path.relative(outdir, res.id);
|
128
|
+
}
|
129
|
+
|
130
|
+
return {
|
131
|
+
external: res.external,
|
132
|
+
path: res.id,
|
133
|
+
};
|
134
|
+
}
|
135
|
+
|
136
|
+
return {
|
137
|
+
path: res.id,
|
138
|
+
};
|
139
|
+
};
|
140
|
+
}
|
141
|
+
|
142
|
+
module.exports = {
|
143
|
+
devtoolsPlugin,
|
144
|
+
esbuildPlugin
|
145
|
+
};
|
package/scripts/build/esbuild.js
CHANGED
@@ -21,30 +21,7 @@ const plugin = {
|
|
21
21
|
name: 'devtools-plugin',
|
22
22
|
setup(build) {
|
23
23
|
// https://esbuild.github.io/plugins/#on-resolve
|
24
|
-
build.onResolve({filter: /.*/},
|
25
|
-
const res = devtools_plugin.devtoolsPlugin(args.path, args.importer);
|
26
|
-
if (!res) {
|
27
|
-
return null;
|
28
|
-
}
|
29
|
-
|
30
|
-
if (res.external) {
|
31
|
-
// res.id can be both of absolutized local JavaScript path or node's
|
32
|
-
// builtin module (e.g. 'fs', 'path'), and only relativize the path in
|
33
|
-
// former case.
|
34
|
-
if (path.isAbsolute(res.id)) {
|
35
|
-
res.id = './' + path.relative(outdir, res.id);
|
36
|
-
}
|
37
|
-
|
38
|
-
return {
|
39
|
-
external: res.external,
|
40
|
-
path: res.id,
|
41
|
-
};
|
42
|
-
}
|
43
|
-
|
44
|
-
return {
|
45
|
-
path: res.id,
|
46
|
-
};
|
47
|
-
});
|
24
|
+
build.onResolve({filter: /.*/}, devtools_plugin.esbuildPlugin(outdir));
|
48
25
|
},
|
49
26
|
};
|
50
27
|
|
@@ -5,7 +5,7 @@
|
|
5
5
|
const {assert} = require('chai');
|
6
6
|
const path = require('path');
|
7
7
|
|
8
|
-
const {devtoolsPlugin} = require('../devtools_plugin.js');
|
8
|
+
const {devtoolsPlugin, esbuildPlugin} = require('../devtools_plugin.js');
|
9
9
|
|
10
10
|
describe('devtools_plugin can compute paths with', () => {
|
11
11
|
it('same directory import', () => {
|
@@ -27,4 +27,63 @@ describe('devtools_plugin can compute paths with', () => {
|
|
27
27
|
it('importing generated files', () => {
|
28
28
|
assert.strictEqual(devtoolsPlugin('../../generated/Protocol.js', 'front_end/core/sdk/FirstFile.js'), null);
|
29
29
|
});
|
30
|
+
|
31
|
+
it('importing lighthouse files', () => {
|
32
|
+
assert.deepEqual(
|
33
|
+
devtoolsPlugin('./front_end/third_party/lighthouse/lighthouse-dt-bundle.js', 'front_end/core/sdk/FirstFile.js'),
|
34
|
+
{
|
35
|
+
id: path.join(
|
36
|
+
'front_end', 'core', 'sdk', 'front_end', 'third_party', 'lighthouse', 'lighthouse-dt-bundle.js'),
|
37
|
+
external: true,
|
38
|
+
});
|
39
|
+
});
|
40
|
+
});
|
41
|
+
|
42
|
+
describe('esbuild_plugin can compute paths with', () => {
|
43
|
+
const srcdir = __dirname;
|
44
|
+
const outdir = path.join(srcdir, 'out');
|
45
|
+
const plugin = esbuildPlugin(outdir);
|
46
|
+
it('same directory import', () => {
|
47
|
+
assert.deepEqual(
|
48
|
+
plugin({path: './AnotherFile.js', importer: path.join(srcdir, 'front_end/core/sdk/FirstFile.js')}),
|
49
|
+
{path: path.join(srcdir, 'front_end', 'core', 'sdk', 'AnotherFile.js')});
|
50
|
+
});
|
51
|
+
|
52
|
+
it('different directory import', () => {
|
53
|
+
assert.deepEqual(
|
54
|
+
plugin({path: '../common/common.js', importer: path.join(srcdir, 'front_end/core/sdk/FirstFile.js')}),
|
55
|
+
{path: './' + path.join('..', 'front_end', 'core', 'common', 'common.js'), external: true});
|
56
|
+
});
|
57
|
+
|
58
|
+
it('node built-in modules', () => {
|
59
|
+
assert.deepEqual(
|
60
|
+
plugin({path: 'fs', importer: path.join(srcdir, 'scripts/some-script.js')}), {path: 'fs', external: true});
|
61
|
+
});
|
62
|
+
|
63
|
+
it('codemirror modules', () => {
|
64
|
+
assert.deepEqual(
|
65
|
+
plugin({path: '../../lib/codemirror', importer: path.join(srcdir, 'scripts/some-script.js')}),
|
66
|
+
{path: '../../lib/codemirror', external: true});
|
67
|
+
});
|
68
|
+
|
69
|
+
it('importing generated files', () => {
|
70
|
+
assert.strictEqual(
|
71
|
+
plugin({path: '../../generated/Protocol.js', importer: path.join(srcdir, 'front_end/core/sdk/FirstFile.js')}),
|
72
|
+
null);
|
73
|
+
});
|
74
|
+
|
75
|
+
it('importing lighthouse files', () => {
|
76
|
+
assert.deepEqual(
|
77
|
+
plugin({
|
78
|
+
path: './front_end/third_party/lighthouse/lighthouse-dt-bundle.js',
|
79
|
+
importer: path.join(srcdir, 'front_end/core/sdk/FirstFile.js')
|
80
|
+
}),
|
81
|
+
{
|
82
|
+
path: './' +
|
83
|
+
path.join(
|
84
|
+
'..', 'front_end', 'core', 'sdk', 'front_end', 'third_party', 'lighthouse',
|
85
|
+
'lighthouse-dt-bundle.js'),
|
86
|
+
external: true,
|
87
|
+
});
|
88
|
+
});
|
30
89
|
});
|