chrome-devtools-frontend 1.0.1006768 → 1.0.1007846
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/config/gni/devtools_grd_files.gni +5 -0
- package/config/gni/devtools_image_files.gni +2 -0
- package/extension-api/ExtensionAPI.d.ts +10 -0
- package/front_end/Images/src/ic_sources_authored.svg +5 -0
- package/front_end/Images/src/ic_sources_deployed.svg +5 -0
- package/front_end/core/i18n/locales/en-US.json +39 -3
- package/front_end/core/i18n/locales/en-XL.json +39 -3
- package/front_end/core/sdk/CSSFontFace.ts +8 -0
- package/front_end/core/sdk/DebuggerModel.ts +12 -3
- package/front_end/core/sdk/NetworkManager.ts +6 -2
- package/front_end/devtools_compatibility.js +1 -0
- package/front_end/entrypoints/formatter_worker/FormatterActions.ts +1 -0
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +12 -10
- package/front_end/entrypoints/formatter_worker/formatter_worker-entrypoint.ts +4 -0
- package/front_end/entrypoints/lighthouse_worker/LighthouseWorkerService.ts +1 -4
- package/front_end/legacy_test_runner/lighthouse_test_runner/lighthouse_test_runner.js +16 -0
- package/front_end/models/extensions/ExtensionAPI.ts +95 -12
- package/front_end/models/extensions/ExtensionEndpoint.ts +69 -0
- package/front_end/models/extensions/ExtensionServer.ts +21 -0
- package/front_end/models/extensions/LanguageExtensionEndpoint.ts +46 -78
- package/front_end/models/extensions/RecorderExtensionEndpoint.ts +43 -0
- package/front_end/models/extensions/RecorderPluginManager.ts +30 -0
- package/front_end/models/extensions/extensions.ts +2 -0
- package/front_end/models/formatter/FormatterWorkerPool.ts +6 -0
- package/front_end/models/javascript_metadata/JavaScriptMetadata.ts +13 -20
- package/front_end/models/javascript_metadata/NativeFunctions.js +1237 -3962
- package/front_end/models/source_map_scopes/NamesResolver.ts +206 -73
- package/front_end/models/workspace/UISourceCode.ts +7 -0
- package/front_end/panels/application/AppManifestView.ts +2 -1
- package/front_end/panels/application/components/BackForwardCacheView.ts +16 -0
- package/front_end/panels/browser_debugger/DOMBreakpointsSidebarPane.ts +15 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +25 -10
- package/front_end/panels/lighthouse/LighthouseStartView.ts +32 -6
- package/front_end/panels/lighthouse/LighthouseStartViewFR.ts +70 -49
- package/front_end/panels/network/components/RequestHeadersView.css +36 -3
- package/front_end/panels/network/components/RequestHeadersView.ts +176 -3
- package/front_end/panels/sources/NavigatorView.ts +141 -40
- package/front_end/panels/sources/SourcesPanel.ts +8 -0
- package/front_end/panels/sources/TabbedEditorContainer.ts +2 -2
- package/front_end/panels/sources/sources-meta.ts +6 -0
- package/front_end/ui/components/text_editor/javascript.ts +12 -14
- package/front_end/ui/legacy/Treeoutline.ts +5 -2
- package/package.json +1 -1
- package/scripts/hosted_mode/server.js +14 -1
- package/scripts/javascript_natives/helpers.js +26 -7
- package/scripts/javascript_natives/index.js +4 -3
- package/scripts/javascript_natives/tests.js +2 -2
@@ -86,6 +86,7 @@ export namespace PrivateAPI {
|
|
86
86
|
Unsubscribe = 'unsubscribe',
|
87
87
|
UpdateButton = 'updateButton',
|
88
88
|
RegisterLanguageExtensionPlugin = 'registerLanguageExtensionPlugin',
|
89
|
+
RegisterRecorderExtensionPlugin = 'registerRecorderExtensionPlugin',
|
89
90
|
}
|
90
91
|
|
91
92
|
export const enum LanguageExtensionPluginCommands {
|
@@ -108,6 +109,14 @@ export namespace PrivateAPI {
|
|
108
109
|
UnregisteredLanguageExtensionPlugin = 'unregisteredLanguageExtensionPlugin',
|
109
110
|
}
|
110
111
|
|
112
|
+
export const enum RecorderExtensionPluginCommands {
|
113
|
+
Stringify = 'stringify',
|
114
|
+
}
|
115
|
+
|
116
|
+
export const enum RecorderExtensionPluginEvents {
|
117
|
+
UnregisteredRecorderExtensionPlugin = 'unregisteredRecorderExtensionPlugin',
|
118
|
+
}
|
119
|
+
|
111
120
|
export interface EvaluateOptions {
|
112
121
|
frameURL?: string;
|
113
122
|
useContentScriptContext?: boolean;
|
@@ -120,6 +129,11 @@ export namespace PrivateAPI {
|
|
120
129
|
port: MessagePort,
|
121
130
|
supportedScriptTypes: PublicAPI.Chrome.DevTools.SupportedScriptTypes,
|
122
131
|
};
|
132
|
+
type RegisterRecorderExtensionPluginRequest = {
|
133
|
+
command: Commands.RegisterRecorderExtensionPlugin,
|
134
|
+
pluginName: string,
|
135
|
+
port: MessagePort,
|
136
|
+
};
|
123
137
|
type SubscribeRequest = {command: Commands.Subscribe, type: string};
|
124
138
|
type UnsubscribeRequest = {command: Commands.Unsubscribe, type: string};
|
125
139
|
type AddRequestHeadersRequest = {
|
@@ -182,13 +196,13 @@ export namespace PrivateAPI {
|
|
182
196
|
type GetHARRequest = {command: Commands.GetHAR};
|
183
197
|
type GetPageResourcesRequest = {command: Commands.GetPageResources};
|
184
198
|
|
185
|
-
export type ServerRequests = RegisterLanguageExtensionPluginRequest|
|
186
|
-
AddRequestHeadersRequest|ApplyStyleSheetRequest|CreatePanelRequest|
|
187
|
-
UpdateButtonRequest|CompleteTraceSessionRequest|
|
188
|
-
SetSidebarContentRequest|SetSidebarPageRequest|
|
189
|
-
SetThemeChangeHandlerRequest|ReloadRequest|
|
190
|
-
GetResourceContentRequest|SetResourceContentRequest|
|
191
|
-
GetHARRequest|GetPageResourcesRequest;
|
199
|
+
export type ServerRequests = RegisterRecorderExtensionPluginRequest|RegisterLanguageExtensionPluginRequest|
|
200
|
+
SubscribeRequest|UnsubscribeRequest|AddRequestHeadersRequest|ApplyStyleSheetRequest|CreatePanelRequest|
|
201
|
+
ShowPanelRequest|CreateToolbarButtonRequest|UpdateButtonRequest|CompleteTraceSessionRequest|
|
202
|
+
CreateSidebarPaneRequest|SetSidebarHeightRequest|SetSidebarContentRequest|SetSidebarPageRequest|
|
203
|
+
OpenResourceRequest|SetOpenResourceHandlerRequest|SetThemeChangeHandlerRequest|ReloadRequest|
|
204
|
+
EvaluateOnInspectedPageRequest|GetRequestContentRequest|GetResourceContentRequest|SetResourceContentRequest|
|
205
|
+
AddTraceProviderRequest|ForwardKeyboardEventRequest|GetHARRequest|GetPageResourcesRequest;
|
192
206
|
export type ExtensionServerRequestMessage = PrivateAPI.ServerRequests&{requestId?: number};
|
193
207
|
|
194
208
|
type AddRawModuleRequest = {
|
@@ -256,6 +270,13 @@ export namespace PrivateAPI {
|
|
256
270
|
RawLocationToSourceLocationRequest|GetScopeInfoRequest|ListVariablesInScopeRequest|RemoveRawModuleRequest|
|
257
271
|
GetTypeInfoRequest|GetFormatterRequest|GetInspectableAddressRequest|GetFunctionInfoRequest|
|
258
272
|
GetInlinedFunctionRangesRequest|GetInlinedCalleesRangesRequest|GetMappedLinesRequest;
|
273
|
+
|
274
|
+
type StringifyRequest = {
|
275
|
+
method: RecorderExtensionPluginCommands.Stringify,
|
276
|
+
parameters: {recording: Record<string, unknown>},
|
277
|
+
};
|
278
|
+
|
279
|
+
export type RecorderExtensionRequests = StringifyRequest;
|
259
280
|
}
|
260
281
|
|
261
282
|
declare global {
|
@@ -264,7 +285,7 @@ declare global {
|
|
264
285
|
(extensionInfo: ExtensionDescriptor, inspectedTabId: string, themeName: string, keysToForward: number[],
|
265
286
|
testHook:
|
266
287
|
(extensionServer: APIImpl.ExtensionServerClient, extensionAPI: APIImpl.InspectorExtensionAPI) => unknown,
|
267
|
-
injectedScriptId: number) => void;
|
288
|
+
injectedScriptId: number, targetWindow?: Window) => void;
|
268
289
|
buildExtensionAPIInjectedScript(
|
269
290
|
extensionInfo: ExtensionDescriptor, inspectedTabId: string, themeName: string, keysToForward: number[],
|
270
291
|
testHook: undefined|((extensionServer: unknown, extensionAPI: unknown) => unknown)): string;
|
@@ -283,6 +304,7 @@ export type ExtensionDescriptor = {
|
|
283
304
|
namespace APIImpl {
|
284
305
|
export interface InspectorExtensionAPI {
|
285
306
|
languageServices: PublicAPI.Chrome.DevTools.LanguageExtensions;
|
307
|
+
recorder: PublicAPI.Chrome.DevTools.RecorderExtensions;
|
286
308
|
timeline: Timeline;
|
287
309
|
network: PublicAPI.Chrome.DevTools.Network;
|
288
310
|
panels: PublicAPI.Chrome.DevTools.Panels;
|
@@ -357,6 +379,10 @@ namespace APIImpl {
|
|
357
379
|
_plugins: Map<PublicAPI.Chrome.DevTools.LanguageExtensionPlugin, MessagePort>;
|
358
380
|
}
|
359
381
|
|
382
|
+
export interface RecorderExtensions extends PublicAPI.Chrome.DevTools.RecorderExtensions {
|
383
|
+
_plugins: Map<PublicAPI.Chrome.DevTools.RecorderExtensionPlugin, MessagePort>;
|
384
|
+
}
|
385
|
+
|
360
386
|
export interface ExtensionPanel extends ExtensionView, PublicAPI.Chrome.DevTools.ExtensionPanel {
|
361
387
|
show(): void;
|
362
388
|
}
|
@@ -392,7 +418,7 @@ namespace APIImpl {
|
|
392
418
|
self.injectedExtensionAPI = function(
|
393
419
|
extensionInfo: ExtensionDescriptor, inspectedTabId: string, themeName: string, keysToForward: number[],
|
394
420
|
testHook: (extensionServer: APIImpl.ExtensionServerClient, extensionAPI: APIImpl.InspectorExtensionAPI) => unknown,
|
395
|
-
injectedScriptId: number): void {
|
421
|
+
injectedScriptId: number, targetWindowForTest?: Window): void {
|
396
422
|
const keysToForwardSet = new Set<number>(keysToForward);
|
397
423
|
const chrome = window.chrome || {};
|
398
424
|
|
@@ -473,6 +499,7 @@ self.injectedExtensionAPI = function(
|
|
473
499
|
this.network = new (Constructor(Network))();
|
474
500
|
this.timeline = new (Constructor(Timeline))();
|
475
501
|
this.languageServices = new (Constructor(LanguageServicesAPI))();
|
502
|
+
this.recorder = new (Constructor(RecorderServicesAPI))();
|
476
503
|
defineDeprecatedProperty(this, 'webInspector', 'resources', 'network');
|
477
504
|
}
|
478
505
|
|
@@ -671,6 +698,60 @@ self.injectedExtensionAPI = function(
|
|
671
698
|
__proto__: ExtensionViewImpl.prototype,
|
672
699
|
};
|
673
700
|
|
701
|
+
function RecorderServicesAPIImpl(this: APIImpl.RecorderExtensions): void {
|
702
|
+
this._plugins = new Map();
|
703
|
+
}
|
704
|
+
|
705
|
+
(RecorderServicesAPIImpl.prototype as
|
706
|
+
Pick<APIImpl.RecorderExtensions, 'registerRecorderExtensionPlugin'|'unregisterRecorderExtensionPlugin'>) = {
|
707
|
+
registerRecorderExtensionPlugin: async function(
|
708
|
+
this: APIImpl.RecorderExtensions, plugin: PublicAPI.Chrome.DevTools.RecorderExtensionPlugin,
|
709
|
+
pluginName: string): Promise<void> {
|
710
|
+
if (this._plugins.has(plugin)) {
|
711
|
+
throw new Error(`Tried to register plugin '${pluginName}' twice`);
|
712
|
+
}
|
713
|
+
const channel = new MessageChannel();
|
714
|
+
const port = channel.port1;
|
715
|
+
this._plugins.set(plugin, port);
|
716
|
+
port.onmessage = ({data}: MessageEvent<{requestId: number}&PrivateAPI.RecorderExtensionRequests>): void => {
|
717
|
+
const {requestId} = data;
|
718
|
+
dispatchMethodCall(data)
|
719
|
+
.then(result => port.postMessage({requestId, result}))
|
720
|
+
.catch(error => port.postMessage({requestId, error: {message: error.message}}));
|
721
|
+
};
|
722
|
+
|
723
|
+
function dispatchMethodCall(request: PrivateAPI.RecorderExtensionRequests): Promise<unknown> {
|
724
|
+
switch (request.method) {
|
725
|
+
case PrivateAPI.RecorderExtensionPluginCommands.Stringify:
|
726
|
+
return plugin.stringify(request.parameters.recording);
|
727
|
+
default:
|
728
|
+
throw new Error(`'${request.method}' is not recognized`);
|
729
|
+
}
|
730
|
+
}
|
731
|
+
|
732
|
+
await new Promise<void>(resolve => {
|
733
|
+
extensionServer.sendRequest(
|
734
|
+
{
|
735
|
+
command: PrivateAPI.Commands.RegisterRecorderExtensionPlugin,
|
736
|
+
pluginName,
|
737
|
+
port: channel.port2,
|
738
|
+
},
|
739
|
+
() => resolve(), [channel.port2]);
|
740
|
+
});
|
741
|
+
},
|
742
|
+
|
743
|
+
unregisterRecorderExtensionPlugin: async function(
|
744
|
+
this: APIImpl.RecorderExtensions, plugin: PublicAPI.Chrome.DevTools.RecorderExtensionPlugin): Promise<void> {
|
745
|
+
const port = this._plugins.get(plugin);
|
746
|
+
if (!port) {
|
747
|
+
throw new Error('Tried to unregister a plugin that was not previously registered');
|
748
|
+
}
|
749
|
+
this._plugins.delete(plugin);
|
750
|
+
port.postMessage({event: PrivateAPI.RecorderExtensionPluginEvents.UnregisteredRecorderExtensionPlugin});
|
751
|
+
port.close();
|
752
|
+
},
|
753
|
+
};
|
754
|
+
|
674
755
|
function LanguageServicesAPIImpl(this: APIImpl.LanguageExtensions): void {
|
675
756
|
this._plugins = new Map();
|
676
757
|
}
|
@@ -787,6 +868,7 @@ self.injectedExtensionAPI = function(
|
|
787
868
|
}
|
788
869
|
|
789
870
|
const LanguageServicesAPI = declareInterfaceClass(LanguageServicesAPIImpl);
|
871
|
+
const RecorderServicesAPI = declareInterfaceClass(RecorderServicesAPIImpl);
|
790
872
|
const Button = declareInterfaceClass(ButtonImpl);
|
791
873
|
const EventSink = declareInterfaceClass(EventSinkImpl);
|
792
874
|
const ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
|
@@ -1128,7 +1210,7 @@ self.injectedExtensionAPI = function(
|
|
1128
1210
|
|
1129
1211
|
document.addEventListener('keydown', forwardKeyboardEvent, false);
|
1130
1212
|
|
1131
|
-
function ExtensionServerClient(this: APIImpl.ExtensionServerClient): void {
|
1213
|
+
function ExtensionServerClient(this: APIImpl.ExtensionServerClient, targetWindow: Window): void {
|
1132
1214
|
this._callbacks = {};
|
1133
1215
|
this._handlers = {};
|
1134
1216
|
this._lastRequestId = 0;
|
@@ -1141,7 +1223,7 @@ self.injectedExtensionAPI = function(
|
|
1141
1223
|
this._port.addEventListener('message', this._onMessage.bind(this), false);
|
1142
1224
|
this._port.start();
|
1143
1225
|
|
1144
|
-
|
1226
|
+
targetWindow.postMessage('registerExtension', '*', [channel.port2]);
|
1145
1227
|
}
|
1146
1228
|
|
1147
1229
|
(ExtensionServerClient.prototype as Pick<
|
@@ -1225,7 +1307,7 @@ self.injectedExtensionAPI = function(
|
|
1225
1307
|
}
|
1226
1308
|
}
|
1227
1309
|
|
1228
|
-
const extensionServer = new (Constructor(ExtensionServerClient))();
|
1310
|
+
const extensionServer = new (Constructor(ExtensionServerClient))(targetWindowForTest || window.parent);
|
1229
1311
|
|
1230
1312
|
const coreAPI = new (Constructor(InspectorExtensionAPI))();
|
1231
1313
|
|
@@ -1241,6 +1323,7 @@ self.injectedExtensionAPI = function(
|
|
1241
1323
|
chrome.devtools!.panels = coreAPI.panels;
|
1242
1324
|
chrome.devtools!.panels.themeName = themeName;
|
1243
1325
|
chrome.devtools!.languageServices = coreAPI.languageServices;
|
1326
|
+
chrome.devtools!.recorder = coreAPI.recorder;
|
1244
1327
|
|
1245
1328
|
// default to expose experimental APIs for now.
|
1246
1329
|
if (extensionInfo.exposeExperimentalAPIs !== false) {
|
@@ -0,0 +1,69 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
type Response = {
|
6
|
+
requestId: number,
|
7
|
+
result: unknown,
|
8
|
+
error: Error|null,
|
9
|
+
};
|
10
|
+
|
11
|
+
type Event = {
|
12
|
+
event: string,
|
13
|
+
};
|
14
|
+
|
15
|
+
type Message = MessageEvent<Response|Event>;
|
16
|
+
|
17
|
+
export class ExtensionEndpoint {
|
18
|
+
private readonly port: MessagePort;
|
19
|
+
private nextRequestId: number = 0;
|
20
|
+
private pendingRequests: Map<number, {
|
21
|
+
resolve: (arg: unknown) => void,
|
22
|
+
reject: (error: Error) => void,
|
23
|
+
}>;
|
24
|
+
|
25
|
+
constructor(port: MessagePort) {
|
26
|
+
this.port = port;
|
27
|
+
this.port.onmessage = this.onResponse.bind(this);
|
28
|
+
this.pendingRequests = new Map();
|
29
|
+
}
|
30
|
+
|
31
|
+
sendRequest<ReturnType>(method: string, parameters: unknown): Promise<ReturnType> {
|
32
|
+
return new Promise((resolve, reject) => {
|
33
|
+
const requestId = this.nextRequestId++;
|
34
|
+
this.pendingRequests.set(requestId, {resolve: resolve as (arg: unknown) => void, reject});
|
35
|
+
this.port.postMessage({requestId, method, parameters});
|
36
|
+
});
|
37
|
+
}
|
38
|
+
|
39
|
+
protected disconnect(): void {
|
40
|
+
for (const {reject} of this.pendingRequests.values()) {
|
41
|
+
reject(new Error('Extension endpoint disconnected'));
|
42
|
+
}
|
43
|
+
this.pendingRequests.clear();
|
44
|
+
this.port.close();
|
45
|
+
}
|
46
|
+
|
47
|
+
private onResponse({data}: Message): void {
|
48
|
+
if ('event' in data) {
|
49
|
+
this.handleEvent(data);
|
50
|
+
return;
|
51
|
+
}
|
52
|
+
const {requestId, result, error} = data;
|
53
|
+
const pendingRequest = this.pendingRequests.get(requestId);
|
54
|
+
if (!pendingRequest) {
|
55
|
+
console.error(`No pending request ${requestId}`);
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
this.pendingRequests.delete(requestId);
|
59
|
+
if (error) {
|
60
|
+
pendingRequest.reject(new Error(error.message));
|
61
|
+
} else {
|
62
|
+
pendingRequest.resolve(result);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
protected handleEvent(_event: Event): void {
|
67
|
+
throw new Error('handleEvent is not implemented');
|
68
|
+
}
|
69
|
+
}
|
@@ -52,7 +52,9 @@ import {ExtensionButton, ExtensionPanel, ExtensionSidebarPane} from './Extension
|
|
52
52
|
import type {TracingSession} from './ExtensionTraceProvider.js';
|
53
53
|
import {ExtensionTraceProvider} from './ExtensionTraceProvider.js';
|
54
54
|
import {LanguageExtensionEndpoint} from './LanguageExtensionEndpoint.js';
|
55
|
+
import {RecorderExtensionEndpoint} from './RecorderExtensionEndpoint.js';
|
55
56
|
import {PrivateAPI} from './ExtensionAPI.js';
|
57
|
+
import {RecorderPluginManager} from './RecorderPluginManager.js';
|
56
58
|
|
57
59
|
const extensionOrigins: WeakMap<MessagePort, Platform.DevToolsPath.UrlString> = new WeakMap();
|
58
60
|
|
@@ -138,6 +140,8 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
138
140
|
this.registerHandler(PrivateAPI.Commands.UpdateButton, this.onUpdateButton.bind(this));
|
139
141
|
this.registerHandler(
|
140
142
|
PrivateAPI.Commands.RegisterLanguageExtensionPlugin, this.registerLanguageExtensionEndpoint.bind(this));
|
143
|
+
this.registerHandler(
|
144
|
+
PrivateAPI.Commands.RegisterRecorderExtensionPlugin, this.registerRecorderExtensionEndpoint.bind(this));
|
141
145
|
window.addEventListener('message', this.onWindowMessage.bind(this), false); // Only for main window.
|
142
146
|
|
143
147
|
const existingTabId =
|
@@ -215,6 +219,16 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
215
219
|
return this.status.OK();
|
216
220
|
}
|
217
221
|
|
222
|
+
private registerRecorderExtensionEndpoint(
|
223
|
+
message: PrivateAPI.ExtensionServerRequestMessage, _shared_port: MessagePort): Record {
|
224
|
+
if (message.command !== PrivateAPI.Commands.RegisterRecorderExtensionPlugin) {
|
225
|
+
return this.status.E_BADARG('command', `expected ${PrivateAPI.Commands.Subscribe}`);
|
226
|
+
}
|
227
|
+
const {pluginName, port} = message;
|
228
|
+
RecorderPluginManager.instance().addPlugin(new RecorderExtensionEndpoint(pluginName, port));
|
229
|
+
return this.status.OK();
|
230
|
+
}
|
231
|
+
|
218
232
|
private inspectedURLChanged(event: Common.EventTarget.EventTargetEvent<SDK.Target.Target>): void {
|
219
233
|
if (!this.canInspectURL(event.data.inspectedURL())) {
|
220
234
|
this.disableExtensions();
|
@@ -856,6 +870,13 @@ export class ExtensionServer extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
856
870
|
}
|
857
871
|
}
|
858
872
|
|
873
|
+
addExtensionForTest(extensionInfo: Host.InspectorFrontendHostAPI.ExtensionDescriptor, origin: string): boolean
|
874
|
+
|undefined {
|
875
|
+
const name = extensionInfo.name || `Extension ${origin}`;
|
876
|
+
this.registeredExtensions.set(origin, {name});
|
877
|
+
return true;
|
878
|
+
}
|
879
|
+
|
859
880
|
private addExtension(extensionInfo: Host.InspectorFrontendHostAPI.ExtensionDescriptor): boolean|undefined {
|
860
881
|
const startPage = extensionInfo.startPage;
|
861
882
|
|
@@ -5,9 +5,30 @@
|
|
5
5
|
import type * as SDK from '../../core/sdk/sdk.js';
|
6
6
|
import * as Bindings from '../bindings/bindings.js';
|
7
7
|
import type {Chrome} from '../../../extension-api/ExtensionAPI.js'; // eslint-disable-line rulesdir/es_modules_import
|
8
|
+
import {ExtensionEndpoint} from './ExtensionEndpoint.js';
|
8
9
|
|
9
10
|
import {PrivateAPI} from './ExtensionAPI.js';
|
10
11
|
|
12
|
+
class LanguageExtensionEndpointImpl extends ExtensionEndpoint {
|
13
|
+
private plugin: LanguageExtensionEndpoint;
|
14
|
+
constructor(plugin: LanguageExtensionEndpoint, port: MessagePort) {
|
15
|
+
super(port);
|
16
|
+
this.plugin = plugin;
|
17
|
+
}
|
18
|
+
protected handleEvent({event}: {event: string}): void {
|
19
|
+
switch (event) {
|
20
|
+
case PrivateAPI.LanguageExtensionPluginEvents.UnregisteredLanguageExtensionPlugin: {
|
21
|
+
this.disconnect();
|
22
|
+
const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
23
|
+
if (pluginManager) {
|
24
|
+
pluginManager.removePlugin(this.plugin);
|
25
|
+
}
|
26
|
+
break;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
11
32
|
export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.DebuggerLanguagePlugin {
|
12
33
|
private readonly supportedScriptTypes: {
|
13
34
|
language: string,
|
@@ -15,13 +36,7 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
15
36
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
16
37
|
symbol_types: Array<string>,
|
17
38
|
};
|
18
|
-
private
|
19
|
-
private nextRequestId: number;
|
20
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
21
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
22
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
23
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
24
|
-
private pendingRequests: Map<any, any>;
|
39
|
+
private endpoint: LanguageExtensionEndpointImpl;
|
25
40
|
constructor(
|
26
41
|
name: string, supportedScriptTypes: {
|
27
42
|
language: string,
|
@@ -32,63 +47,7 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
32
47
|
port: MessagePort) {
|
33
48
|
super(name);
|
34
49
|
this.supportedScriptTypes = supportedScriptTypes;
|
35
|
-
this.
|
36
|
-
this.port.onmessage = this.onResponse.bind(this);
|
37
|
-
this.nextRequestId = 0;
|
38
|
-
this.pendingRequests = new Map();
|
39
|
-
}
|
40
|
-
|
41
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
42
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
43
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
44
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
45
|
-
private sendRequest(method: string, parameters: any): Promise<any> {
|
46
|
-
return new Promise((resolve, reject) => {
|
47
|
-
const requestId = this.nextRequestId++;
|
48
|
-
this.pendingRequests.set(requestId, {resolve, reject});
|
49
|
-
this.port.postMessage({requestId, method, parameters});
|
50
|
-
});
|
51
|
-
}
|
52
|
-
|
53
|
-
private onResponse({data}: MessageEvent<{
|
54
|
-
requestId: number,
|
55
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
57
|
-
result: any,
|
58
|
-
error: Error|null,
|
59
|
-
}|{
|
60
|
-
event: string,
|
61
|
-
}>): void {
|
62
|
-
if ('event' in data) {
|
63
|
-
const {event} = data;
|
64
|
-
switch (event) {
|
65
|
-
case PrivateAPI.LanguageExtensionPluginEvents.UnregisteredLanguageExtensionPlugin: {
|
66
|
-
for (const {reject} of this.pendingRequests.values()) {
|
67
|
-
reject(new Error('Language extension endpoint disconnected'));
|
68
|
-
}
|
69
|
-
this.pendingRequests.clear();
|
70
|
-
this.port.close();
|
71
|
-
const {pluginManager} = Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance();
|
72
|
-
if (pluginManager) {
|
73
|
-
pluginManager.removePlugin(this);
|
74
|
-
}
|
75
|
-
break;
|
76
|
-
}
|
77
|
-
}
|
78
|
-
return;
|
79
|
-
}
|
80
|
-
const {requestId, result, error} = data;
|
81
|
-
if (!this.pendingRequests.has(requestId)) {
|
82
|
-
console.error(`No pending request ${requestId}`);
|
83
|
-
return;
|
84
|
-
}
|
85
|
-
const {resolve, reject} = this.pendingRequests.get(requestId);
|
86
|
-
this.pendingRequests.delete(requestId);
|
87
|
-
if (error) {
|
88
|
-
reject(new Error(error.message));
|
89
|
-
} else {
|
90
|
-
resolve(result);
|
91
|
-
}
|
50
|
+
this.endpoint = new LanguageExtensionEndpointImpl(this, port);
|
92
51
|
}
|
93
52
|
|
94
53
|
handleScript(script: SDK.Script.Script): boolean {
|
@@ -100,7 +59,7 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
100
59
|
/** Notify the plugin about a new script
|
101
60
|
*/
|
102
61
|
addRawModule(rawModuleId: string, symbolsURL: string, rawModule: Chrome.DevTools.RawModule): Promise<string[]> {
|
103
|
-
return this.sendRequest(
|
62
|
+
return this.endpoint.sendRequest(
|
104
63
|
PrivateAPI.LanguageExtensionPluginCommands.AddRawModule, {rawModuleId, symbolsURL, rawModule}) as
|
105
64
|
Promise<string[]>;
|
106
65
|
}
|
@@ -109,33 +68,36 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
109
68
|
* Notifies the plugin that a script is removed.
|
110
69
|
*/
|
111
70
|
removeRawModule(rawModuleId: string): Promise<void> {
|
112
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.RemoveRawModule, {rawModuleId}) as
|
71
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.RemoveRawModule, {rawModuleId}) as
|
72
|
+
Promise<void>;
|
113
73
|
}
|
114
74
|
|
115
75
|
/** Find locations in raw modules from a location in a source file
|
116
76
|
*/
|
117
77
|
sourceLocationToRawLocation(sourceLocation: Chrome.DevTools.SourceLocation):
|
118
78
|
Promise<Chrome.DevTools.RawLocationRange[]> {
|
119
|
-
return this.sendRequest(
|
79
|
+
return this.endpoint.sendRequest(
|
80
|
+
PrivateAPI.LanguageExtensionPluginCommands.SourceLocationToRawLocation, {sourceLocation}) as
|
120
81
|
Promise<Chrome.DevTools.RawLocationRange[]>;
|
121
82
|
}
|
122
83
|
|
123
84
|
/** Find locations in source files from a location in a raw module
|
124
85
|
*/
|
125
86
|
rawLocationToSourceLocation(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.SourceLocation[]> {
|
126
|
-
return this.sendRequest(
|
87
|
+
return this.endpoint.sendRequest(
|
88
|
+
PrivateAPI.LanguageExtensionPluginCommands.RawLocationToSourceLocation, {rawLocation}) as
|
127
89
|
Promise<Chrome.DevTools.SourceLocation[]>;
|
128
90
|
}
|
129
91
|
|
130
92
|
getScopeInfo(type: string): Promise<Chrome.DevTools.ScopeInfo> {
|
131
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetScopeInfo, {type}) as
|
93
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetScopeInfo, {type}) as
|
132
94
|
Promise<Chrome.DevTools.ScopeInfo>;
|
133
95
|
}
|
134
96
|
|
135
97
|
/** List all variables in lexical scope at a given location in a raw module
|
136
98
|
*/
|
137
99
|
listVariablesInScope(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.Variable[]> {
|
138
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.ListVariablesInScope, {rawLocation}) as
|
100
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.ListVariablesInScope, {rawLocation}) as
|
139
101
|
Promise<Chrome.DevTools.Variable[]>;
|
140
102
|
}
|
141
103
|
|
@@ -144,7 +106,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
144
106
|
getFunctionInfo(rawLocation: Chrome.DevTools.RawLocation): Promise<{
|
145
107
|
frames: Array<Chrome.DevTools.FunctionInfo>,
|
146
108
|
}> {
|
147
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetFunctionInfo, {rawLocation}) as
|
109
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetFunctionInfo, {rawLocation}) as
|
110
|
+
Promise<{
|
148
111
|
frames: Array<Chrome.DevTools.FunctionInfo>,
|
149
112
|
}>;
|
150
113
|
}
|
@@ -153,7 +116,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
153
116
|
* that rawLocation is in.
|
154
117
|
*/
|
155
118
|
getInlinedFunctionRanges(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.RawLocationRange[]> {
|
156
|
-
return this.sendRequest(
|
119
|
+
return this.endpoint.sendRequest(
|
120
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetInlinedFunctionRanges, {rawLocation}) as
|
157
121
|
Promise<Chrome.DevTools.RawLocationRange[]>;
|
158
122
|
}
|
159
123
|
|
@@ -161,7 +125,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
161
125
|
* called by the function or inline frame that rawLocation is in.
|
162
126
|
*/
|
163
127
|
getInlinedCalleesRanges(rawLocation: Chrome.DevTools.RawLocation): Promise<Chrome.DevTools.RawLocationRange[]> {
|
164
|
-
return this.sendRequest(
|
128
|
+
return this.endpoint.sendRequest(
|
129
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetInlinedCalleesRanges, {rawLocation}) as
|
165
130
|
Promise<Chrome.DevTools.RawLocationRange[]>;
|
166
131
|
}
|
167
132
|
|
@@ -169,7 +134,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
169
134
|
typeInfos: Array<Chrome.DevTools.TypeInfo>,
|
170
135
|
base: Chrome.DevTools.EvalBase,
|
171
136
|
}|null> {
|
172
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetTypeInfo, {expression, context}) as
|
137
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetTypeInfo, {expression, context}) as
|
138
|
+
Promise<{
|
173
139
|
typeInfos: Array<Chrome.DevTools.TypeInfo>,
|
174
140
|
base: Chrome.DevTools.EvalBase,
|
175
141
|
}|null>;
|
@@ -183,8 +149,8 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
183
149
|
context: Chrome.DevTools.RawLocation): Promise<{
|
184
150
|
js: string,
|
185
151
|
}> {
|
186
|
-
return this.sendRequest(
|
187
|
-
|
152
|
+
return this.endpoint.sendRequest(
|
153
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetFormatter, {expressionOrField, context}) as Promise<{
|
188
154
|
js: string,
|
189
155
|
}>;
|
190
156
|
}
|
@@ -195,13 +161,15 @@ export class LanguageExtensionEndpoint extends Bindings.DebuggerLanguagePlugins.
|
|
195
161
|
}): Promise<{
|
196
162
|
js: string,
|
197
163
|
}> {
|
198
|
-
return this.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetInspectableAddress, {field}) as
|
164
|
+
return this.endpoint.sendRequest(PrivateAPI.LanguageExtensionPluginCommands.GetInspectableAddress, {field}) as
|
165
|
+
Promise<{
|
199
166
|
js: string,
|
200
167
|
}>;
|
201
168
|
}
|
202
169
|
|
203
170
|
async getMappedLines(rawModuleId: string, sourceFileURL: string): Promise<number[]|undefined> {
|
204
|
-
return this.sendRequest(
|
171
|
+
return this.endpoint.sendRequest(
|
172
|
+
PrivateAPI.LanguageExtensionPluginCommands.GetMappedLines, {rawModuleId, sourceFileURL});
|
205
173
|
}
|
206
174
|
|
207
175
|
dispose(): void {
|
@@ -0,0 +1,43 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
import {PrivateAPI} from './ExtensionAPI.js';
|
6
|
+
import {ExtensionEndpoint} from './ExtensionEndpoint.js';
|
7
|
+
import {RecorderPluginManager} from './RecorderPluginManager.js';
|
8
|
+
|
9
|
+
export class RecorderExtensionEndpoint extends ExtensionEndpoint {
|
10
|
+
private readonly name: string;
|
11
|
+
|
12
|
+
constructor(name: string, port: MessagePort) {
|
13
|
+
super(port);
|
14
|
+
this.name = name;
|
15
|
+
}
|
16
|
+
|
17
|
+
getName(): string {
|
18
|
+
return this.name;
|
19
|
+
}
|
20
|
+
|
21
|
+
protected handleEvent({event}: {event: string}): void {
|
22
|
+
switch (event) {
|
23
|
+
case PrivateAPI.RecorderExtensionPluginEvents.UnregisteredRecorderExtensionPlugin: {
|
24
|
+
this.disconnect();
|
25
|
+
RecorderPluginManager.instance().removePlugin(this);
|
26
|
+
break;
|
27
|
+
}
|
28
|
+
default:
|
29
|
+
throw new Error(`Unrecognized Recorder extension endpoint event: ${event}`);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* In practice, `recording` is a UserFlow[1], but we avoid defining this type on the
|
35
|
+
* API in order to prevent dependencies between Chrome and puppeteer. Extensions
|
36
|
+
* are responsible for working out potential compatibility issues.
|
37
|
+
*
|
38
|
+
* [1]: https://github.com/puppeteer/replay/blob/main/src/Schema.ts#L245
|
39
|
+
*/
|
40
|
+
stringify(recording: Object): Promise<string> {
|
41
|
+
return this.sendRequest(PrivateAPI.RecorderExtensionPluginCommands.Stringify, {recording});
|
42
|
+
}
|
43
|
+
}
|
@@ -0,0 +1,30 @@
|
|
1
|
+
// Copyright 2022 The Chromium Authors. All rights reserved.
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
3
|
+
// found in the LICENSE file.
|
4
|
+
|
5
|
+
import type {RecorderExtensionEndpoint} from './RecorderExtensionEndpoint.js';
|
6
|
+
|
7
|
+
let instance: RecorderPluginManager|null = null;
|
8
|
+
|
9
|
+
export class RecorderPluginManager {
|
10
|
+
#plugins: Set<RecorderExtensionEndpoint> = new Set();
|
11
|
+
|
12
|
+
static instance(): RecorderPluginManager {
|
13
|
+
if (!instance) {
|
14
|
+
instance = new RecorderPluginManager();
|
15
|
+
}
|
16
|
+
return instance;
|
17
|
+
}
|
18
|
+
|
19
|
+
addPlugin(plugin: RecorderExtensionEndpoint): void {
|
20
|
+
this.#plugins.add(plugin);
|
21
|
+
}
|
22
|
+
|
23
|
+
removePlugin(plugin: RecorderExtensionEndpoint): void {
|
24
|
+
this.#plugins.delete(plugin);
|
25
|
+
}
|
26
|
+
|
27
|
+
plugins(): RecorderExtensionEndpoint[] {
|
28
|
+
return Array.from(this.#plugins.values());
|
29
|
+
}
|
30
|
+
}
|
@@ -7,6 +7,7 @@ import * as ExtensionPanel from './ExtensionPanel.js';
|
|
7
7
|
import * as ExtensionServer from './ExtensionServer.js';
|
8
8
|
import * as ExtensionTraceProvider from './ExtensionTraceProvider.js';
|
9
9
|
import * as ExtensionView from './ExtensionView.js';
|
10
|
+
import * as RecorderPluginManager from './RecorderPluginManager.js';
|
10
11
|
|
11
12
|
export {
|
12
13
|
ExtensionAPI,
|
@@ -14,4 +15,5 @@ export {
|
|
14
15
|
ExtensionServer,
|
15
16
|
ExtensionTraceProvider,
|
16
17
|
ExtensionView,
|
18
|
+
RecorderPluginManager,
|
17
19
|
};
|
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
6
6
|
import * as FormatterActions from '../../entrypoints/formatter_worker/FormatterActions.js'; // eslint-disable-line rulesdir/es_modules_import
|
7
|
+
export {DefinitionKind, type ScopeTreeNode} from '../../entrypoints/formatter_worker/FormatterActions.js';
|
7
8
|
|
8
9
|
const MAX_WORKERS = Math.min(2, navigator.hardwareConcurrency - 1);
|
9
10
|
|
@@ -140,6 +141,11 @@ export class FormatterWorkerPool {
|
|
140
141
|
.then(result => result || '');
|
141
142
|
}
|
142
143
|
|
144
|
+
javaScriptScopeTree(expression: string): Promise<FormatterActions.ScopeTreeNode|null> {
|
145
|
+
return this.runTask(FormatterActions.FormatterActions.JAVASCRIPT_SCOPE_TREE, {content: expression})
|
146
|
+
.then(result => result || null);
|
147
|
+
}
|
148
|
+
|
143
149
|
evaluatableJavaScriptSubstring(content: string): Promise<string> {
|
144
150
|
return this.runTask(FormatterActions.FormatterActions.EVALUATE_JAVASCRIPT_SUBSTRING, {content: content})
|
145
151
|
.then(text => text || '');
|