blob: d0a9e1ab5e8d809dcf7a0893253387886f462cab [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
Philip Pfaffe7523faf2021-06-28 14:23:1431import type * as PublicAPI from '../../../extension-api/ExtensionAPI'; // eslint-disable-line rulesdir/es_modules_import
Philip Pfaffe4b88c662021-06-25 12:30:4732import type * as HAR from '../har/har.js';
Philip Pfaffe7523faf2021-06-28 14:23:1433
34/* eslint-disable @typescript-eslint/no-explicit-any,@typescript-eslint/naming-convention,@typescript-eslint/no-non-null-assertion */
Philip Pfaffe939605d2021-06-25 12:20:0435export namespace PrivateAPI {
36 export namespace Panels {
37 export const enum SearchAction {
38 CancelSearch = 'cancelSearch',
39 PerformSearch = 'performSearch',
40 NextSearchResult = 'nextSearchResult',
41 PreviousSearchResult = 'previousSearchResult',
42 }
Tim van der Lippe1d6e57a2019-09-30 11:55:3443 }
Blink Reformat4c46d092018-04-07 15:32:3744
Philip Pfaffe939605d2021-06-25 12:20:0445 export const enum Events {
46 ButtonClicked = 'button-clicked-',
47 PanelObjectSelected = 'panel-objectSelected-',
48 InspectedURLChanged = 'inspected-url-changed',
49 NetworkRequestFinished = 'network-request-finished',
50 OpenResource = 'open-resource',
51 PanelSearch = 'panel-search-',
52 RecordingStarted = 'trace-recording-started-',
53 RecordingStopped = 'trace-recording-stopped-',
54 ResourceAdded = 'resource-added',
55 ResourceContentCommitted = 'resource-content-committed',
56 ViewShown = 'view-shown-',
57 ViewHidden = 'view-hidden,',
58 }
Blink Reformat4c46d092018-04-07 15:32:3759
Philip Pfaffe939605d2021-06-25 12:20:0460 export const enum Commands {
61 AddRequestHeaders = 'addRequestHeaders',
62 AddTraceProvider = 'addTraceProvider',
63 ApplyStyleSheet = 'applyStyleSheet',
64 CompleteTraceSession = 'completeTra.eSession',
65 CreatePanel = 'createPanel',
66 CreateSidebarPane = 'createSidebarPane',
67 CreateToolbarButton = 'createToolbarButton',
68 EvaluateOnInspectedPage = 'evaluateOnInspectedPage',
69 ForwardKeyboardEvent = '_forwardKeyboardEvent',
70 GetHAR = 'getHAR',
71 GetPageResources = 'getPageResources',
72 GetRequestContent = 'getRequestContent',
73 GetResourceContent = 'getResourceContent',
74 OpenResource = 'openResource',
75 Reload = 'Reload',
76 Subscribe = 'subscribe',
77 SetOpenResourceHandler = 'setOpenResourceHandler',
78 SetResourceContent = 'setResourceContent',
79 SetSidebarContent = 'setSidebarContent',
80 SetSidebarHeight = 'setSidebarHeight',
81 SetSidebarPage = 'setSidebarPage',
82 ShowPanel = 'showPanel',
83 Unsubscribe = 'unsubscribe',
84 UpdateButton = 'updateButton',
85 RegisterLanguageExtensionPlugin = 'registerLanguageExtensionPlugin',
86 }
Philip Pfaffeedad8322020-07-20 10:24:2587
Philip Pfaffe939605d2021-06-25 12:20:0488 export const enum LanguageExtensionPluginCommands {
89 AddRawModule = 'addRawModule',
90 RemoveRawModule = 'removeRawModule',
91 SourceLocationToRawLocation = 'sourceLocationToRawLocation',
92 RawLocationToSourceLocation = 'rawLocationToSourceLocation',
93 GetScopeInfo = 'getScopeInfo',
94 ListVariablesInScope = 'listVariablesInScope',
95 GetTypeInfo = 'getTypeInfo',
96 GetFormatter = 'getFormatter',
97 GetInspectableAddress = 'getInspectableAddress',
98 GetFunctionInfo = 'getFunctionInfo',
99 GetInlinedFunctionRanges = 'getInlinedFunctionRanges',
100 GetInlinedCalleesRanges = 'getInlinedCalleesRanges',
101 GetMappedLines = 'getMappedLines',
102 }
Benedikt Meurer929fc7c2020-11-20 14:21:06103
Philip Pfaffe939605d2021-06-25 12:20:04104 export const enum LanguageExtensionPluginEvents {
105 UnregisteredLanguageExtensionPlugin = 'unregisteredLanguageExtensionPlugin',
106 }
Philip Pfaffed662bdf2021-06-25 13:30:32107
108 export interface EvaluateOptions {
109 frameURL?: string;
110 useContentScriptContext?: boolean;
111 scriptExecutionContext?: string;
112 }
113
Philip Pfaffed662bdf2021-06-25 13:30:32114 type RegisterLanguageExtensionPluginRequest = {
115 command: Commands.RegisterLanguageExtensionPlugin,
116 pluginName: string,
117 port: MessagePort,
Philip Pfaffe7523faf2021-06-28 14:23:14118 supportedScriptTypes: PublicAPI.Chrome.DevTools.SupportedScriptTypes,
Philip Pfaffed662bdf2021-06-25 13:30:32119 };
120 type SubscribeRequest = {command: Commands.Subscribe, type: string};
121 type UnsubscribeRequest = {command: Commands.Unsubscribe, type: string};
122 type AddRequestHeadersRequest = {
123 command: Commands.AddRequestHeaders,
124 extensionId: string,
125 headers: {[key: string]: string},
126 };
127 type ApplyStyleSheetRequest = {command: Commands.ApplyStyleSheet, styleSheet: string};
128 type CreatePanelRequest = {command: Commands.CreatePanel, id: string, title: string, page: string};
129 type ShowPanelRequest = {command: Commands.ShowPanel, id: string};
130 type CreateToolbarButtonRequest = {
131 command: Commands.CreateToolbarButton,
132 id: string,
133 icon: string,
134 panel: string,
135 tooltip?: string,
136 disabled?: boolean,
137 };
138 type UpdateButtonRequest =
139 {command: Commands.UpdateButton, id: string, icon?: string, tooltip?: string, disabled?: boolean};
140 type CompleteTraceSessionRequest =
141 {command: Commands.CompleteTraceSession, id: string, url: string, timeOffset: number};
142 type CreateSidebarPaneRequest = {command: Commands.CreateSidebarPane, id: string, panel: string, title: string};
143 type SetSidebarHeightRequest = {command: Commands.SetSidebarHeight, id: string, height: string};
144 type SetSidebarContentRequest = {
145 command: Commands.SetSidebarContent,
146 id: string,
147 evaluateOnPage?: boolean, expression: string,
148 rootTitle?: string,
149 evaluateOptions?: EvaluateOptions,
150 };
151 type SetSidebarPageRequest = {command: Commands.SetSidebarPage, id: string, page: string};
152 type OpenResourceRequest = {command: Commands.OpenResource, url: string, lineNumber: number};
153 type SetOpenResourceHandlerRequest = {command: Commands.SetOpenResourceHandler, handlerPresent: boolean};
154 type ReloadRequest = {
155 command: Commands.Reload,
156 options: null|{
157 userAgent?: string,
158 injectedScript?: string,
159 ignoreCache?: boolean,
160 },
161 };
162 type EvaluateOnInspectedPageRequest = {
163 command: Commands.EvaluateOnInspectedPage,
164 expression: string,
165 evaluateOptions?: EvaluateOptions,
166 };
167 type GetRequestContentRequest = {command: Commands.GetRequestContent, id: number};
168 type GetResourceContentRequest = {command: Commands.GetResourceContent, url: string};
169 type SetResourceContentRequest =
170 {command: Commands.SetResourceContent, url: string, content: string, commit: boolean};
171 type AddTraceProviderRequest =
172 {command: Commands.AddTraceProvider, id: string, categoryName: string, categoryTooltip: string};
173 type ForwardKeyboardEventRequest = {
174 command: Commands.ForwardKeyboardEvent,
175 entries: Array<KeyboardEventInit&{eventType: string}>,
176 };
177 type GetHARRequest = {command: Commands.GetHAR};
178 type GetPageResourcesRequest = {command: Commands.GetPageResources};
179
180 export type ServerRequests = RegisterLanguageExtensionPluginRequest|SubscribeRequest|UnsubscribeRequest|
181 AddRequestHeadersRequest|ApplyStyleSheetRequest|CreatePanelRequest|ShowPanelRequest|CreateToolbarButtonRequest|
182 UpdateButtonRequest|CompleteTraceSessionRequest|CreateSidebarPaneRequest|SetSidebarHeightRequest|
183 SetSidebarContentRequest|SetSidebarPageRequest|OpenResourceRequest|SetOpenResourceHandlerRequest|ReloadRequest|
184 EvaluateOnInspectedPageRequest|GetRequestContentRequest|GetResourceContentRequest|SetResourceContentRequest|
185 AddTraceProviderRequest|ForwardKeyboardEventRequest|GetHARRequest|GetPageResourcesRequest;
186 export type ExtensionServerRequestMessage = PrivateAPI.ServerRequests&{requestId?: number};
Blink Reformat4c46d092018-04-07 15:32:37187}
188
Philip Pfaffe939605d2021-06-25 12:20:04189declare global {
190 interface Window {
191 injectedExtensionAPI:
192 (extensionInfo: ExtensionDescriptor, inspectedTabId: string, themeName: string, keysToForward: number[],
Philip Pfaffe7523faf2021-06-28 14:23:14193 testHook:
194 (extensionServer: APIImpl.ExtensionServerClient, extensionAPI: APIImpl.InspectorExtensionAPI) => unknown,
195 injectedScriptId: number) => void;
Philip Pfaffe939605d2021-06-25 12:20:04196 buildExtensionAPIInjectedScript(
197 extensionInfo: ExtensionDescriptor, inspectedTabId: string, themeName: string, keysToForward: number[],
Philip Pfaffed662bdf2021-06-25 13:30:32198 testHook: undefined|((extensionServer: unknown, extensionAPI: unknown) => unknown)): string;
Philip Pfaffe7523faf2021-06-28 14:23:14199 chrome: PublicAPI.Chrome.DevTools.Chrome;
200 webInspector?: APIImpl.InspectorExtensionAPI;
Philip Pfaffe939605d2021-06-25 12:20:04201 }
202}
203
204export type ExtensionDescriptor = {
205 startPage: string,
206 name: string,
207 exposeExperimentalAPIs: boolean,
208 exposeWebInspectorNamespace?: boolean,
209};
210
Philip Pfaffe7523faf2021-06-28 14:23:14211namespace APIImpl {
212 export interface InspectorExtensionAPI {
213 languageServices: PublicAPI.Chrome.DevTools.LanguageExtensions;
214 network: PublicAPI.Chrome.DevTools.Network;
215 panels: PublicAPI.Chrome.DevTools.Panels;
216 inspectedWindow: PublicAPI.Chrome.DevTools.InspectedWindow;
217 }
218
219 export interface ExtensionServerClient {
220 _callbacks: {[key: string]: (response: unknown) => unknown};
221 _handlers: {[key: string]: (request: {arguments: unknown[]}) => unknown};
222 _lastRequestId: number;
223 _lastObjectId: number;
224 _port: MessagePort;
225
226 _onCallback(request: unknown): void;
227 _onMessage(event: MessageEvent<{command: string, requestId: number, arguments: unknown[]}>): void;
228 _registerCallback(callback: (response: unknown) => unknown): number;
229 registerHandler(command: string, handler: (request: {arguments: unknown[]}) => unknown): void;
230 unregisterHandler(command: string): void;
231 hasHandler(command: string): boolean;
232 sendRequest(request: PrivateAPI.ServerRequests, callback?: ((response: unknown) => unknown), transfers?: unknown[]):
233 void;
234 nextObjectId(): string;
235 }
236
237 // We cannot use the stronger `unknown` type in place of `any` in the following type definition. The type is used as
238 // the right-hand side of `extends` in a few places, which doesn't narrow `unknown`. Without narrowing, overload
239 // resolution and meaningful type inference of arguments break, for example.
240 // eslint-disable-next-line @typescript-eslint/no-explicit-any
241 export type Callable = (...args: any) => any;
242
243 export interface EventSink<ListenerT extends Callable> extends PublicAPI.Chrome.DevTools.EventSink<ListenerT> {
244 _type: string;
245 _listeners: ListenerT[];
246 _customDispatch: undefined|((this: EventSink<ListenerT>, request: {arguments: unknown[]}) => unknown);
247
248 _fire(..._vararg: Parameters<ListenerT>): void;
249 _dispatch(request: {arguments: unknown[]}): void;
250 }
Philip Pfaffe4b88c662021-06-25 12:30:47251
252 export interface Network extends PublicAPI.Chrome.DevTools.Network {
253 addRequestHeaders(headers: {[key: string]: string}): void;
254 }
255
256 export interface Request extends PublicAPI.Chrome.DevTools.Request, HAR.Log.EntryDTO {
257 _id: number;
258 }
Philip Pfaffe7523faf2021-06-28 14:23:14259}
Philip Pfaffe939605d2021-06-25 12:20:04260
Tim van der Lippe226fc222019-10-10 12:17:12261self.injectedExtensionAPI = function(
Philip Pfaffe7523faf2021-06-28 14:23:14262 extensionInfo: ExtensionDescriptor, inspectedTabId: string, themeName: string, keysToForward: number[],
263 testHook: (extensionServer: APIImpl.ExtensionServerClient, extensionAPI: APIImpl.InspectorExtensionAPI) => unknown,
264 injectedScriptId: number): void {
Jan Schefflerd76b4162021-03-29 07:52:16265 const keysToForwardSet = new Set<number>(keysToForward);
Blink Reformat4c46d092018-04-07 15:32:37266 const chrome = window.chrome || {};
Jan Schefflerd76b4162021-03-29 07:52:16267
Blink Reformat4c46d092018-04-07 15:32:37268 const devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, 'devtools');
Tim van der Lippe1d6e57a2019-09-30 11:55:34269 if (devtools_descriptor) {
Blink Reformat4c46d092018-04-07 15:32:37270 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34271 }
Blink Reformat4c46d092018-04-07 15:32:37272 let userAction = false;
273
274 // Here and below, all constructors are private to API implementation.
275 // For a public type Foo, if internal fields are present, these are on
276 // a private FooImpl type, an instance of FooImpl is used in a closure
277 // by Foo consutrctor to re-bind publicly exported members to an instance
278 // of Foo.
279
Philip Pfaffe7523faf2021-06-28 14:23:14280 function EventSinkImpl<ListenerT extends APIImpl.Callable>(
281 this: APIImpl.EventSink<ListenerT>, type: string,
282 customDispatch?: (this: APIImpl.EventSink<ListenerT>, request: {arguments: unknown[]}) => unknown): void {
Blink Reformat4c46d092018-04-07 15:32:37283 this._type = type;
284 this._listeners = [];
285 this._customDispatch = customDispatch;
286 }
287
288 EventSinkImpl.prototype = {
Philip Pfaffe7523faf2021-06-28 14:23:14289 addListener: function<ListenerT extends APIImpl.Callable>(this: APIImpl.EventSink<ListenerT>, callback: ListenerT):
290 void {
291 if (typeof callback !== 'function') {
292 throw 'addListener: callback is not a function';
293 }
294 if (this._listeners.length === 0) {
295 extensionServer.sendRequest({command: PrivateAPI.Commands.Subscribe, type: this._type});
296 }
297 this._listeners.push(callback);
298 extensionServer.registerHandler('notify-' + this._type, this._dispatch.bind(this));
299 },
Blink Reformat4c46d092018-04-07 15:32:37300
Jan Schefflerd76b4162021-03-29 07:52:16301
Philip Pfaffe7523faf2021-06-28 14:23:14302 removeListener: function<ListenerT extends APIImpl.Callable>(
303 this: APIImpl.EventSink<ListenerT>, callback: ListenerT): void {
Blink Reformat4c46d092018-04-07 15:32:37304 const listeners = this._listeners;
305
306 for (let i = 0; i < listeners.length; ++i) {
307 if (listeners[i] === callback) {
308 listeners.splice(i, 1);
309 break;
310 }
311 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34312 if (this._listeners.length === 0) {
Philip Pfaffe939605d2021-06-25 12:20:04313 extensionServer.sendRequest({command: PrivateAPI.Commands.Unsubscribe, type: this._type});
Tim van der Lippe1d6e57a2019-09-30 11:55:34314 }
Blink Reformat4c46d092018-04-07 15:32:37315 },
316
Jan Schefflerd76b4162021-03-29 07:52:16317
Philip Pfaffe7523faf2021-06-28 14:23:14318 _fire: function<ListenerT extends APIImpl.Callable>(
319 this: APIImpl.EventSink<ListenerT>, ..._vararg: Parameters<ListenerT>): void {
Blink Reformat4c46d092018-04-07 15:32:37320 const listeners = this._listeners.slice();
Tim van der Lippe1d6e57a2019-09-30 11:55:34321 for (let i = 0; i < listeners.length; ++i) {
Philip Pfaffe7523faf2021-06-28 14:23:14322 listeners[i].apply(null, Array.from(arguments));
Tim van der Lippe1d6e57a2019-09-30 11:55:34323 }
Blink Reformat4c46d092018-04-07 15:32:37324 },
325
Jan Schefflerd76b4162021-03-29 07:52:16326
Philip Pfaffe7523faf2021-06-28 14:23:14327 _dispatch: function<ListenerT extends APIImpl.Callable>(
328 this: APIImpl.EventSink<ListenerT>, request: {arguments: unknown[]}): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34329 if (this._customDispatch) {
Blink Reformat4c46d092018-04-07 15:32:37330 this._customDispatch.call(this, request);
Tim van der Lippe1d6e57a2019-09-30 11:55:34331 } else {
Philip Pfaffe7523faf2021-06-28 14:23:14332 this._fire.apply(this, request.arguments as Parameters<ListenerT>);
Tim van der Lippe1d6e57a2019-09-30 11:55:34333 }
Jan Schefflerd76b4162021-03-29 07:52:16334 },
Blink Reformat4c46d092018-04-07 15:32:37335 };
336
Philip Pfaffe7523faf2021-06-28 14:23:14337 function Constructor<NewT extends APIImpl.Callable>(ctor: NewT): new (...args: Parameters<NewT>) =>
338 ThisParameterType<NewT> {
339 return ctor as unknown as new (...args: Parameters<NewT>) => ThisParameterType<NewT>;
340 }
341
Blink Reformat4c46d092018-04-07 15:32:37342 /**
343 * @constructor
344 */
Jan Schefflerd76b4162021-03-29 07:52:16345
Philip Pfaffe7523faf2021-06-28 14:23:14346 function InspectorExtensionAPI(this: APIImpl.InspectorExtensionAPI): void {
Philip Pfaffe939605d2021-06-25 12:20:04347 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37348 this.inspectedWindow = new InspectedWindow();
Philip Pfaffe939605d2021-06-25 12:20:04349 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37350 this.panels = new Panels();
Philip Pfaffe4b88c662021-06-25 12:30:47351 this.network = new (Constructor(Network))();
Philip Pfaffe939605d2021-06-25 12:20:04352 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37353 this.timeline = new Timeline();
Philip Pfaffe939605d2021-06-25 12:20:04354 // @ts-ignore
Philip Pfaffeedad8322020-07-20 10:24:25355 this.languageServices = new LanguageServicesAPI();
Blink Reformat4c46d092018-04-07 15:32:37356 defineDeprecatedProperty(this, 'webInspector', 'resources', 'network');
357 }
358
359 /**
360 * @constructor
361 */
Jan Schefflerd76b4162021-03-29 07:52:16362
Philip Pfaffe4b88c662021-06-25 12:30:47363 function Network(this: APIImpl.Network): void {
364 function dispatchRequestEvent(
365 this: APIImpl.EventSink<(request: PublicAPI.Chrome.DevTools.Request) => unknown>,
366 message: {arguments: unknown[]}): void {
367 const request = message.arguments[1] as APIImpl.Request & {__proto__: APIImpl.Request};
368
369 request.__proto__ = new (Constructor(Request))(message.arguments[0] as number);
Blink Reformat4c46d092018-04-07 15:32:37370 this._fire(request);
371 }
Philip Pfaffe4b88c662021-06-25 12:30:47372
373 this.onRequestFinished =
374 new (Constructor(EventSink))(PrivateAPI.Events.NetworkRequestFinished, dispatchRequestEvent);
Blink Reformat4c46d092018-04-07 15:32:37375 defineDeprecatedProperty(this, 'network', 'onFinished', 'onRequestFinished');
Philip Pfaffe4b88c662021-06-25 12:30:47376
377 this.onNavigated = new (Constructor(EventSink))(PrivateAPI.Events.InspectedURLChanged);
Blink Reformat4c46d092018-04-07 15:32:37378 }
379
Philip Pfaffe4b88c662021-06-25 12:30:47380 (Network.prototype as Pick<APIImpl.Network, 'getHAR'|'addRequestHeaders'>) = {
381 getHAR: function(this: PublicAPI.Chrome.DevTools.Network, callback?: (harLog: Object) => unknown): void {
382 function callbackWrapper(response: unknown): void {
383 const result =
384 response as ({entries: Array<HAR.Log.EntryDTO&{__proto__?: APIImpl.Request, _requestId?: number}>});
Blink Reformat4c46d092018-04-07 15:32:37385 const entries = (result && result.entries) || [];
386 for (let i = 0; i < entries.length; ++i) {
Philip Pfaffe4b88c662021-06-25 12:30:47387 entries[i].__proto__ = new (Constructor(Request))(entries[i]._requestId as number);
Blink Reformat4c46d092018-04-07 15:32:37388 delete entries[i]._requestId;
389 }
Philip Pfaffe4b88c662021-06-25 12:30:47390 callback && callback(result as Object);
Blink Reformat4c46d092018-04-07 15:32:37391 }
Philip Pfaffe939605d2021-06-25 12:20:04392 extensionServer.sendRequest({command: PrivateAPI.Commands.GetHAR}, callback && callbackWrapper);
Blink Reformat4c46d092018-04-07 15:32:37393 },
394
Philip Pfaffe4b88c662021-06-25 12:30:47395 addRequestHeaders: function(headers: {[key: string]: string}): void {
Blink Reformat4c46d092018-04-07 15:32:37396 extensionServer.sendRequest(
Philip Pfaffe939605d2021-06-25 12:20:04397 {command: PrivateAPI.Commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname});
Jan Schefflerd76b4162021-03-29 07:52:16398 },
Blink Reformat4c46d092018-04-07 15:32:37399 };
400
Philip Pfaffe4b88c662021-06-25 12:30:47401 function RequestImpl(this: APIImpl.Request, id: number): void {
Blink Reformat4c46d092018-04-07 15:32:37402 this._id = id;
403 }
404
Philip Pfaffe4b88c662021-06-25 12:30:47405 (RequestImpl.prototype as Pick<APIImpl.Request, 'getContent'>) = {
406 getContent: function(this: APIImpl.Request, callback?: (content: string, encoding: string) => unknown): void {
407 function callbackWrapper(response: unknown): void {
408 const {content, encoding} = response as {content: string, encoding: string};
409 callback && callback(content, encoding);
Blink Reformat4c46d092018-04-07 15:32:37410 }
Philip Pfaffe939605d2021-06-25 12:20:04411 extensionServer.sendRequest(
412 {command: PrivateAPI.Commands.GetRequestContent, id: this._id}, callback && callbackWrapper);
Jan Schefflerd76b4162021-03-29 07:52:16413 },
Blink Reformat4c46d092018-04-07 15:32:37414 };
415
416 /**
417 * @constructor
418 */
Philip Pfaffe939605d2021-06-25 12:20:04419 function Panels(this: any): void {
420 const panels: {[key: string]: any} = {
Blink Reformat4c46d092018-04-07 15:32:37421 elements: new ElementsPanel(),
422 sources: new SourcesPanel(),
423 };
424
Jan Schefflerd76b4162021-03-29 07:52:16425 function panelGetter(name: any): any {
Blink Reformat4c46d092018-04-07 15:32:37426 return panels[name];
427 }
Tim van der Lippe1d6e57a2019-09-30 11:55:34428 for (const panel in panels) {
Tim van der Lippeffa78622019-09-16 12:07:12429 Object.defineProperty(this, panel, {get: panelGetter.bind(null, panel), enumerable: true});
Tim van der Lippe1d6e57a2019-09-30 11:55:34430 }
Jan Schefflerd76b4162021-03-29 07:52:16431 this.applyStyleSheet = function(styleSheet: any): void {
Philip Pfaffe939605d2021-06-25 12:20:04432 extensionServer.sendRequest({command: PrivateAPI.Commands.ApplyStyleSheet, styleSheet: styleSheet});
Blink Reformat4c46d092018-04-07 15:32:37433 };
434 }
435
436 Panels.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16437 create: function(title: any, icon: any, page: any, callback: any): void {
Blink Reformat4c46d092018-04-07 15:32:37438 const id = 'extension-panel-' + extensionServer.nextObjectId();
Philip Pfaffe939605d2021-06-25 12:20:04439 const request = {command: PrivateAPI.Commands.CreatePanel, id: id, title: title, icon: icon, page: page};
440 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37441 extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id)));
442 },
443
Jan Schefflerd76b4162021-03-29 07:52:16444 setOpenResourceHandler: function(callback: any): void {
Philip Pfaffe939605d2021-06-25 12:20:04445 const hadHandler = extensionServer.hasHandler(PrivateAPI.Events.OpenResource);
Blink Reformat4c46d092018-04-07 15:32:37446
Jan Schefflerd76b4162021-03-29 07:52:16447 function callbackWrapper(message: any): void {
Blink Reformat4c46d092018-04-07 15:32:37448 // Allow the panel to show itself when handling the event.
449 userAction = true;
450 try {
Philip Pfaffe939605d2021-06-25 12:20:04451 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37452 callback.call(null, new Resource(message.resource), message.lineNumber);
453 } finally {
454 userAction = false;
455 }
456 }
457
Tim van der Lippe1d6e57a2019-09-30 11:55:34458 if (!callback) {
Philip Pfaffe939605d2021-06-25 12:20:04459 extensionServer.unregisterHandler(PrivateAPI.Events.OpenResource);
Tim van der Lippe1d6e57a2019-09-30 11:55:34460 } else {
Philip Pfaffe939605d2021-06-25 12:20:04461 extensionServer.registerHandler(PrivateAPI.Events.OpenResource, callbackWrapper);
Tim van der Lippe1d6e57a2019-09-30 11:55:34462 }
Blink Reformat4c46d092018-04-07 15:32:37463
464 // Only send command if we either removed an existing handler or added handler and had none before.
Tim van der Lippe1d6e57a2019-09-30 11:55:34465 if (hadHandler === !callback) {
Philip Pfaffe939605d2021-06-25 12:20:04466 extensionServer.sendRequest(
467 {command: PrivateAPI.Commands.SetOpenResourceHandler, 'handlerPresent': Boolean(callback)});
Tim van der Lippe1d6e57a2019-09-30 11:55:34468 }
Blink Reformat4c46d092018-04-07 15:32:37469 },
470
Jan Schefflerd76b4162021-03-29 07:52:16471 openResource: function(url: any, lineNumber: any, callback: any): void {
Philip Pfaffe939605d2021-06-25 12:20:04472 extensionServer.sendRequest(
473 {command: PrivateAPI.Commands.OpenResource, 'url': url, 'lineNumber': lineNumber}, callback);
Blink Reformat4c46d092018-04-07 15:32:37474 },
475
Jan Schefflerd76b4162021-03-29 07:52:16476 get SearchAction(): any {
Philip Pfaffe939605d2021-06-25 12:20:04477 return {
478 CancelSearch: PrivateAPI.Panels.SearchAction.CancelSearch,
479 PerformSearch: PrivateAPI.Panels.SearchAction.PerformSearch,
480 NextSearchResult: PrivateAPI.Panels.SearchAction.NextSearchResult,
481 PreviousSearchResult: PrivateAPI.Panels.SearchAction.PreviousSearchResult,
482 };
Jan Schefflerd76b4162021-03-29 07:52:16483 },
Blink Reformat4c46d092018-04-07 15:32:37484 };
485
486 /**
487 * @constructor
488 */
Philip Pfaffe939605d2021-06-25 12:20:04489 function ExtensionViewImpl(this: any, id: any): void {
Blink Reformat4c46d092018-04-07 15:32:37490 this._id = id;
491
Philip Pfaffe939605d2021-06-25 12:20:04492 function dispatchShowEvent(this: any, message: any): void {
Blink Reformat4c46d092018-04-07 15:32:37493 const frameIndex = message.arguments[0];
Tim van der Lippe1d6e57a2019-09-30 11:55:34494 if (typeof frameIndex === 'number') {
Blink Reformat4c46d092018-04-07 15:32:37495 this._fire(window.parent.frames[frameIndex]);
Tim van der Lippe1d6e57a2019-09-30 11:55:34496 } else {
Blink Reformat4c46d092018-04-07 15:32:37497 this._fire();
Tim van der Lippe1d6e57a2019-09-30 11:55:34498 }
Blink Reformat4c46d092018-04-07 15:32:37499 }
500
501 if (id) {
Philip Pfaffe939605d2021-06-25 12:20:04502 // @ts-ignore
503 this.onShown = new EventSink(PrivateAPI.Events.ViewShown + id, dispatchShowEvent);
504 // @ts-ignore
505 this.onHidden = new EventSink(PrivateAPI.Events.ViewHidden + id);
Blink Reformat4c46d092018-04-07 15:32:37506 }
507 }
508
509 /**
510 * @constructor
511 * @extends {ExtensionViewImpl}
Blink Reformat4c46d092018-04-07 15:32:37512 */
Philip Pfaffe939605d2021-06-25 12:20:04513 function PanelWithSidebarImpl(this: any, hostPanelName: string): void {
Blink Reformat4c46d092018-04-07 15:32:37514 ExtensionViewImpl.call(this, null);
515 this._hostPanelName = hostPanelName;
Philip Pfaffe939605d2021-06-25 12:20:04516 // @ts-ignore
517 this.onSelectionChanged = new EventSink(PrivateAPI.Events.PanelObjectSelected + hostPanelName);
Blink Reformat4c46d092018-04-07 15:32:37518 }
519
520 PanelWithSidebarImpl.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16521 createSidebarPane: function(title: any, callback: any): void {
Blink Reformat4c46d092018-04-07 15:32:37522 const id = 'extension-sidebar-' + extensionServer.nextObjectId();
Jan Schefflerd76b4162021-03-29 07:52:16523 function callbackWrapper(): void {
Philip Pfaffe939605d2021-06-25 12:20:04524 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37525 callback(new ExtensionSidebarPane(id));
526 }
Philip Pfaffe7523faf2021-06-28 14:23:14527 extensionServer.sendRequest(
528 {command: PrivateAPI.Commands.CreateSidebarPane, panel: this._hostPanelName, id: id, title: title},
529 callback && callbackWrapper);
Blink Reformat4c46d092018-04-07 15:32:37530 },
531
Jan Schefflerd76b4162021-03-29 07:52:16532 __proto__: ExtensionViewImpl.prototype,
Blink Reformat4c46d092018-04-07 15:32:37533 };
534
Philip Pfaffeedad8322020-07-20 10:24:25535 /**
536 * @constructor
537 */
Philip Pfaffe939605d2021-06-25 12:20:04538 function LanguageServicesAPIImpl(this: any): void {
Benedikt Meurer929fc7c2020-11-20 14:21:06539 /** @type {!Map<*, !MessagePort>} */
Philip Pfaffeedad8322020-07-20 10:24:25540 this._plugins = new Map();
541 }
542
543 LanguageServicesAPIImpl.prototype = {
Philip Pfaffed662bdf2021-06-25 13:30:32544 registerLanguageExtensionPlugin: async function(
Philip Pfaffe7523faf2021-06-28 14:23:14545 plugin: any, pluginName: string, supportedScriptTypes: PublicAPI.Chrome.DevTools.SupportedScriptTypes):
546 Promise<void> {
547 if (this._plugins.has(plugin)) {
548 throw new Error(`Tried to register plugin '${pluginName}' twice`);
549 }
550 const channel = new MessageChannel();
551 const port = channel.port1;
552 this._plugins.set(plugin, port);
553 port.onmessage = ({data: {requestId, method, parameters}}: MessageEvent<any>): void => {
554 console.time(`${requestId}: ${method}`);
555 dispatchMethodCall(method, parameters)
556 .then(result => port.postMessage({requestId, result}))
557 .catch(error => port.postMessage({requestId, error: {message: error.message}}))
558 .finally(() => console.timeEnd(`${requestId}: ${method}`));
559 };
Philip Pfaffeedad8322020-07-20 10:24:25560
Philip Pfaffe7523faf2021-06-28 14:23:14561 function dispatchMethodCall(method: string, parameters: any): Promise<any> {
562 switch (method) {
563 case PrivateAPI.LanguageExtensionPluginCommands.AddRawModule:
564 return plugin.addRawModule(parameters.rawModuleId, parameters.symbolsURL, parameters.rawModule);
565 case PrivateAPI.LanguageExtensionPluginCommands.RemoveRawModule:
566 return plugin.removeRawModule(parameters.rawModuleId);
567 case PrivateAPI.LanguageExtensionPluginCommands.SourceLocationToRawLocation:
568 return plugin.sourceLocationToRawLocation(parameters.sourceLocation);
569 case PrivateAPI.LanguageExtensionPluginCommands.RawLocationToSourceLocation:
570 return plugin.rawLocationToSourceLocation(parameters.rawLocation);
571 case PrivateAPI.LanguageExtensionPluginCommands.GetScopeInfo:
572 return plugin.getScopeInfo(parameters.type);
573 case PrivateAPI.LanguageExtensionPluginCommands.ListVariablesInScope:
574 return plugin.listVariablesInScope(parameters.rawLocation);
575 case PrivateAPI.LanguageExtensionPluginCommands.GetTypeInfo:
576 return plugin.getTypeInfo(parameters.expression, parameters.context);
577 case PrivateAPI.LanguageExtensionPluginCommands.GetFormatter:
578 return plugin.getFormatter(parameters.expressionOrField, parameters.context);
579 case PrivateAPI.LanguageExtensionPluginCommands.GetInspectableAddress:
580 if ('getInspectableAddress' in plugin) {
581 return plugin.getInspectableAddress(parameters.field);
582 }
583 return Promise.resolve({js: ''});
584 case PrivateAPI.LanguageExtensionPluginCommands.GetFunctionInfo:
585 return plugin.getFunctionInfo(parameters.rawLocation);
586 case PrivateAPI.LanguageExtensionPluginCommands.GetInlinedFunctionRanges:
587 return plugin.getInlinedFunctionRanges(parameters.rawLocation);
588 case PrivateAPI.LanguageExtensionPluginCommands.GetInlinedCalleesRanges:
589 return plugin.getInlinedCalleesRanges(parameters.rawLocation);
590 case PrivateAPI.LanguageExtensionPluginCommands.GetMappedLines:
591 if ('getMappedLines' in plugin) {
592 return plugin.getMappedLines(parameters.rawModuleId, parameters.sourceFileURL);
593 }
594 return Promise.resolve(undefined);
Kim-Anh Tran8fd7d6f2021-01-28 11:07:02595 }
Philip Pfaffe7523faf2021-06-28 14:23:14596 throw new Error(`Unknown language plugin method ${method}`);
597 }
Philip Pfaffeedad8322020-07-20 10:24:25598
Philip Pfaffe7523faf2021-06-28 14:23:14599 await new Promise<void>(resolve => {
600 extensionServer.sendRequest(
601 {
602 command: PrivateAPI.Commands.RegisterLanguageExtensionPlugin,
603 pluginName,
604 port: channel.port2,
605 supportedScriptTypes,
606 },
607 () => resolve(), [channel.port2]);
608 });
609 },
Benedikt Meurer929fc7c2020-11-20 14:21:06610
Jan Schefflerd76b4162021-03-29 07:52:16611 unregisterLanguageExtensionPlugin: async function(plugin: any): Promise<void> {
Benedikt Meurer929fc7c2020-11-20 14:21:06612 const port = this._plugins.get(plugin);
613 if (!port) {
614 throw new Error('Tried to unregister a plugin that was not previously registered');
615 }
616 this._plugins.delete(plugin);
Philip Pfaffe939605d2021-06-25 12:20:04617 port.postMessage({event: PrivateAPI.LanguageExtensionPluginEvents.UnregisteredLanguageExtensionPlugin});
Benedikt Meurer929fc7c2020-11-20 14:21:06618 port.close();
Jan Schefflerd76b4162021-03-29 07:52:16619 },
Philip Pfaffeedad8322020-07-20 10:24:25620 };
621
Philip Pfaffe7523faf2021-06-28 14:23:14622 function declareInterfaceClass<ImplT extends APIImpl.Callable>(implConstructor: ImplT): (
623 this: ThisParameterType<ImplT>, ...args: Parameters<ImplT>) => void {
624 return function(this: ThisParameterType<ImplT>, ...args: Parameters<ImplT>): void {
Blink Reformat4c46d092018-04-07 15:32:37625 const impl = {__proto__: implConstructor.prototype};
Philip Pfaffe7523faf2021-06-28 14:23:14626 implConstructor.apply(impl, args);
627 populateInterfaceClass(this as {[key: string]: unknown}, impl);
Blink Reformat4c46d092018-04-07 15:32:37628 };
629 }
630
Philip Pfaffe7523faf2021-06-28 14:23:14631 // eslint-disable-next-line @typescript-eslint/no-explicit-any
632 function defineDeprecatedProperty(object: any, className: string, oldName: string, newName: string): void {
Blink Reformat4c46d092018-04-07 15:32:37633 let warningGiven = false;
Philip Pfaffe7523faf2021-06-28 14:23:14634 function getter(): unknown {
Blink Reformat4c46d092018-04-07 15:32:37635 if (!warningGiven) {
636 console.warn(className + '.' + oldName + ' is deprecated. Use ' + className + '.' + newName + ' instead');
637 warningGiven = true;
638 }
639 return object[newName];
640 }
641 object.__defineGetter__(oldName, getter);
642 }
643
Philip Pfaffe7523faf2021-06-28 14:23:14644 function extractCallbackArgument(args: IArguments): ((...args: unknown[]) => unknown)|undefined {
Blink Reformat4c46d092018-04-07 15:32:37645 const lastArgument = args[args.length - 1];
Philip Pfaffe7523faf2021-06-28 14:23:14646 return typeof lastArgument === 'function' ? lastArgument as (...args: unknown[]) => unknown : undefined;
Blink Reformat4c46d092018-04-07 15:32:37647 }
648
Philip Pfaffeedad8322020-07-20 10:24:25649 const LanguageServicesAPI = declareInterfaceClass(LanguageServicesAPIImpl);
Blink Reformat4c46d092018-04-07 15:32:37650 const Button = declareInterfaceClass(ButtonImpl);
651 const EventSink = declareInterfaceClass(EventSinkImpl);
652 const ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl);
653 const ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl);
Tim van der Lippeffa78622019-09-16 12:07:12654 /**
655 * @constructor
656 * @param {string} hostPanelName
657 */
658 const PanelWithSidebarClass = declareInterfaceClass(PanelWithSidebarImpl);
Blink Reformat4c46d092018-04-07 15:32:37659 const Request = declareInterfaceClass(RequestImpl);
660 const Resource = declareInterfaceClass(ResourceImpl);
661 const TraceSession = declareInterfaceClass(TraceSessionImpl);
662
Philip Pfaffe939605d2021-06-25 12:20:04663 // @ts-ignore
Tim van der Lippeffa78622019-09-16 12:07:12664 class ElementsPanel extends PanelWithSidebarClass {
665 constructor() {
666 super('elements');
667 }
Blink Reformat4c46d092018-04-07 15:32:37668 }
669
Philip Pfaffe939605d2021-06-25 12:20:04670 // @ts-ignore
Tim van der Lippeffa78622019-09-16 12:07:12671 class SourcesPanel extends PanelWithSidebarClass {
672 constructor() {
673 super('sources');
674 }
Blink Reformat4c46d092018-04-07 15:32:37675 }
676
Blink Reformat4c46d092018-04-07 15:32:37677 /**
678 * @constructor
679 * @extends {ExtensionViewImpl}
680 */
Philip Pfaffe939605d2021-06-25 12:20:04681 function ExtensionPanelImpl(this: any, id: any): void {
Blink Reformat4c46d092018-04-07 15:32:37682 ExtensionViewImpl.call(this, id);
Philip Pfaffe939605d2021-06-25 12:20:04683 // @ts-ignore
684 this.onSearch = new EventSink(PrivateAPI.Events.PanelSearch + id);
Blink Reformat4c46d092018-04-07 15:32:37685 }
686
687 ExtensionPanelImpl.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16688 createStatusBarButton: function(iconPath: any, tooltipText: any, disabled: any): Object {
Blink Reformat4c46d092018-04-07 15:32:37689 const id = 'button-' + extensionServer.nextObjectId();
Philip Pfaffe7523faf2021-06-28 14:23:14690 extensionServer.sendRequest({
Philip Pfaffe939605d2021-06-25 12:20:04691 command: PrivateAPI.Commands.CreateToolbarButton,
Blink Reformat4c46d092018-04-07 15:32:37692 panel: this._id,
693 id: id,
694 icon: iconPath,
695 tooltip: tooltipText,
Jan Schefflerd76b4162021-03-29 07:52:16696 disabled: Boolean(disabled),
Philip Pfaffe7523faf2021-06-28 14:23:14697 });
Philip Pfaffe939605d2021-06-25 12:20:04698 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37699 return new Button(id);
700 },
701
Jan Schefflerd76b4162021-03-29 07:52:16702 show: function(): void {
Tim van der Lippe1d6e57a2019-09-30 11:55:34703 if (!userAction) {
Blink Reformat4c46d092018-04-07 15:32:37704 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34705 }
Blink Reformat4c46d092018-04-07 15:32:37706
Philip Pfaffe7523faf2021-06-28 14:23:14707 extensionServer.sendRequest({command: PrivateAPI.Commands.ShowPanel, id: this._id});
Blink Reformat4c46d092018-04-07 15:32:37708 },
709
Jan Schefflerd76b4162021-03-29 07:52:16710 __proto__: ExtensionViewImpl.prototype,
Blink Reformat4c46d092018-04-07 15:32:37711 };
712
713 /**
714 * @constructor
715 * @extends {ExtensionViewImpl}
716 */
Philip Pfaffe939605d2021-06-25 12:20:04717 function ExtensionSidebarPaneImpl(this: any, id: any): void {
Blink Reformat4c46d092018-04-07 15:32:37718 ExtensionViewImpl.call(this, id);
719 }
720
721 ExtensionSidebarPaneImpl.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16722 setHeight: function(height: any): void {
Philip Pfaffe939605d2021-06-25 12:20:04723 extensionServer.sendRequest({command: PrivateAPI.Commands.SetSidebarHeight, id: this._id, height: height});
Blink Reformat4c46d092018-04-07 15:32:37724 },
725
Jan Schefflerd76b4162021-03-29 07:52:16726 setExpression: function(expression: any, rootTitle: any, evaluateOptions: any): void {
Philip Pfaffe7523faf2021-06-28 14:23:14727 extensionServer.sendRequest(
728 {
729 command: PrivateAPI.Commands.SetSidebarContent,
730 id: this._id,
731 expression: expression,
732 rootTitle: rootTitle,
733 evaluateOnPage: true,
734 evaluateOptions: (typeof evaluateOptions === 'object' ? evaluateOptions : undefined),
735 },
736 extractCallbackArgument(arguments));
Blink Reformat4c46d092018-04-07 15:32:37737 },
738
Jan Schefflerd76b4162021-03-29 07:52:16739 setObject: function(jsonObject: any, rootTitle: any, callback: any): void {
Blink Reformat4c46d092018-04-07 15:32:37740 extensionServer.sendRequest(
Philip Pfaffe939605d2021-06-25 12:20:04741 {command: PrivateAPI.Commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle},
742 callback);
Blink Reformat4c46d092018-04-07 15:32:37743 },
744
Jan Schefflerd76b4162021-03-29 07:52:16745 setPage: function(page: any): void {
Philip Pfaffe939605d2021-06-25 12:20:04746 extensionServer.sendRequest({command: PrivateAPI.Commands.SetSidebarPage, id: this._id, page: page});
Blink Reformat4c46d092018-04-07 15:32:37747 },
748
Jan Schefflerd76b4162021-03-29 07:52:16749 __proto__: ExtensionViewImpl.prototype,
Blink Reformat4c46d092018-04-07 15:32:37750 };
751
752 /**
753 * @constructor
754 */
Philip Pfaffe939605d2021-06-25 12:20:04755 function ButtonImpl(this: any, id: any): void {
Blink Reformat4c46d092018-04-07 15:32:37756 this._id = id;
Philip Pfaffe939605d2021-06-25 12:20:04757 // @ts-ignore
758 this.onClicked = new EventSink(PrivateAPI.Events.ButtonClicked + id);
Blink Reformat4c46d092018-04-07 15:32:37759 }
760
761 ButtonImpl.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16762 update: function(iconPath: any, tooltipText: any, disabled: any): void {
Philip Pfaffe7523faf2021-06-28 14:23:14763 extensionServer.sendRequest({
Philip Pfaffe939605d2021-06-25 12:20:04764 command: PrivateAPI.Commands.UpdateButton,
Tim van der Lipped7cfd142021-01-07 12:17:24765 id: this._id,
766 icon: iconPath,
767 tooltip: tooltipText,
Jan Schefflerd76b4162021-03-29 07:52:16768 disabled: Boolean(disabled),
Philip Pfaffe7523faf2021-06-28 14:23:14769 });
Jan Schefflerd76b4162021-03-29 07:52:16770 },
Blink Reformat4c46d092018-04-07 15:32:37771 };
772
773 /**
774 * @constructor
775 */
Jan Schefflerd76b4162021-03-29 07:52:16776 function Timeline(): void {
Blink Reformat4c46d092018-04-07 15:32:37777 }
778
779 Timeline.prototype = {
Philip Pfaffe939605d2021-06-25 12:20:04780 // @ts-ignore
Jan Schefflerd76b4162021-03-29 07:52:16781 addTraceProvider: function(categoryName: string, categoryTooltip: string): TraceProvider {
Blink Reformat4c46d092018-04-07 15:32:37782 const id = 'extension-trace-provider-' + extensionServer.nextObjectId();
Philip Pfaffe939605d2021-06-25 12:20:04783 extensionServer.sendRequest({
784 command: PrivateAPI.Commands.AddTraceProvider,
785 id: id,
786 categoryName: categoryName,
787 categoryTooltip: categoryTooltip,
788 });
789 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37790 return new TraceProvider(id);
Jan Schefflerd76b4162021-03-29 07:52:16791 },
Blink Reformat4c46d092018-04-07 15:32:37792 };
793
794 /**
795 * @constructor
Blink Reformat4c46d092018-04-07 15:32:37796 */
Philip Pfaffe939605d2021-06-25 12:20:04797 function TraceSessionImpl(this: any, id: string): void {
Blink Reformat4c46d092018-04-07 15:32:37798 this._id = id;
799 }
800
801 TraceSessionImpl.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16802 complete: function(url?: string, timeOffset?: number): void {
Philip Pfaffe7523faf2021-06-28 14:23:14803 extensionServer.sendRequest({
Philip Pfaffe939605d2021-06-25 12:20:04804 command: PrivateAPI.Commands.CompleteTraceSession,
805 id: this._id,
806 url: url || '',
807 timeOffset: timeOffset || 0,
Philip Pfaffe7523faf2021-06-28 14:23:14808 });
Jan Schefflerd76b4162021-03-29 07:52:16809 },
Blink Reformat4c46d092018-04-07 15:32:37810 };
811
812 /**
813 * @constructor
Blink Reformat4c46d092018-04-07 15:32:37814 */
Jan Schefflerd76b4162021-03-29 07:52:16815 function TraceProvider(id: string): void {
Philip Pfaffe939605d2021-06-25 12:20:04816 function dispatchRecordingStarted(this: any, message: any): void {
Blink Reformat4c46d092018-04-07 15:32:37817 const sessionId = message.arguments[0];
Philip Pfaffe939605d2021-06-25 12:20:04818 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37819 this._fire(new TraceSession(sessionId));
820 }
821
Philip Pfaffe939605d2021-06-25 12:20:04822 // @ts-ignore
823 this.onRecordingStarted = new EventSink(PrivateAPI.Events.RecordingStarted + id, dispatchRecordingStarted);
824 // @ts-ignore
825 this.onRecordingStopped = new EventSink(PrivateAPI.Events.RecordingStopped + id);
Blink Reformat4c46d092018-04-07 15:32:37826 }
827
828 /**
829 * @constructor
830 */
Philip Pfaffe939605d2021-06-25 12:20:04831 function InspectedWindow(this: any): void {
832 function dispatchResourceEvent(this: any, message: any): void {
833 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37834 this._fire(new Resource(message.arguments[0]));
835 }
836
Philip Pfaffe939605d2021-06-25 12:20:04837 function dispatchResourceContentEvent(this: any, message: any): void {
838 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37839 this._fire(new Resource(message.arguments[0]), message.arguments[1]);
840 }
841
Philip Pfaffe939605d2021-06-25 12:20:04842 // @ts-ignore
843 this.onResourceAdded = new EventSink(PrivateAPI.Events.ResourceAdded, dispatchResourceEvent);
844 this.onResourceContentCommitted =
845 // @ts-ignore
846 new EventSink(PrivateAPI.Events.ResourceContentCommitted, dispatchResourceContentEvent);
Blink Reformat4c46d092018-04-07 15:32:37847 }
848
849 InspectedWindow.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16850 reload: function(optionsOrUserAgent: any): void {
851 let options: {
852 userAgent: string,
853 }|null = null;
Blink Reformat4c46d092018-04-07 15:32:37854 if (typeof optionsOrUserAgent === 'object') {
855 options = optionsOrUserAgent;
856 } else if (typeof optionsOrUserAgent === 'string') {
857 options = {userAgent: optionsOrUserAgent};
858 console.warn(
859 'Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. ' +
860 'Use inspectedWindow.reload({ userAgent: value}) instead.');
861 }
Philip Pfaffe939605d2021-06-25 12:20:04862 extensionServer.sendRequest({command: PrivateAPI.Commands.Reload, options: options});
Blink Reformat4c46d092018-04-07 15:32:37863 },
864
Jan Schefflerd76b4162021-03-29 07:52:16865 eval: function(expression: any, evaluateOptions: any): Object |
866 null {
867 const callback = extractCallbackArgument(arguments);
868 function callbackWrapper(result: any): void {
869 if (result.isError || result.isException) {
Philip Pfaffe7523faf2021-06-28 14:23:14870 callback && callback(undefined, result);
Jan Schefflerd76b4162021-03-29 07:52:16871 } else {
Philip Pfaffe7523faf2021-06-28 14:23:14872 callback && callback(result.value);
Jan Schefflerd76b4162021-03-29 07:52:16873 }
874 }
Philip Pfaffe7523faf2021-06-28 14:23:14875 extensionServer.sendRequest(
876 {
877 command: PrivateAPI.Commands.EvaluateOnInspectedPage,
878 expression: expression,
879 evaluateOptions: (typeof evaluateOptions === 'object' ? evaluateOptions : undefined),
880 },
881 callback && callbackWrapper);
Jan Schefflerd76b4162021-03-29 07:52:16882 return null;
883 },
Blink Reformat4c46d092018-04-07 15:32:37884
Jan Schefflerd76b4162021-03-29 07:52:16885 getResources: function(callback: any): void {
886 function wrapResource(resourceData: any): any {
Philip Pfaffe939605d2021-06-25 12:20:04887 // @ts-ignore
Blink Reformat4c46d092018-04-07 15:32:37888 return new Resource(resourceData);
889 }
Jan Schefflerd76b4162021-03-29 07:52:16890 function callbackWrapper(resources: any): void {
Blink Reformat4c46d092018-04-07 15:32:37891 callback(resources.map(wrapResource));
892 }
Philip Pfaffe939605d2021-06-25 12:20:04893 extensionServer.sendRequest({command: PrivateAPI.Commands.GetPageResources}, callback && callbackWrapper);
Jan Schefflerd76b4162021-03-29 07:52:16894 },
Blink Reformat4c46d092018-04-07 15:32:37895 };
896
897 /**
898 * @constructor
899 */
Philip Pfaffe939605d2021-06-25 12:20:04900 function ResourceImpl(this: any, resourceData: any): void {
Blink Reformat4c46d092018-04-07 15:32:37901 this._url = resourceData.url;
902 this._type = resourceData.type;
903 }
904
905 ResourceImpl.prototype = {
Jan Schefflerd76b4162021-03-29 07:52:16906 get url(): string {
Blink Reformat4c46d092018-04-07 15:32:37907 return this._url;
908 },
909
Jan Schefflerd76b4162021-03-29 07:52:16910 get type(): string {
Blink Reformat4c46d092018-04-07 15:32:37911 return this._type;
912 },
913
Jan Schefflerd76b4162021-03-29 07:52:16914 getContent: function(callback: any): void {
915 function callbackWrapper(response: any): void {
Blink Reformat4c46d092018-04-07 15:32:37916 callback(response.content, response.encoding);
917 }
918
Philip Pfaffe939605d2021-06-25 12:20:04919 extensionServer.sendRequest(
920 {command: PrivateAPI.Commands.GetResourceContent, url: this._url}, callback && callbackWrapper);
Blink Reformat4c46d092018-04-07 15:32:37921 },
922
Jan Schefflerd76b4162021-03-29 07:52:16923 setContent: function(content: any, commit: any, callback: any): void {
Blink Reformat4c46d092018-04-07 15:32:37924 extensionServer.sendRequest(
Philip Pfaffe939605d2021-06-25 12:20:04925 {command: PrivateAPI.Commands.SetResourceContent, url: this._url, content: content, commit: commit},
926 callback);
Jan Schefflerd76b4162021-03-29 07:52:16927 },
Blink Reformat4c46d092018-04-07 15:32:37928 };
929
Jan Schefflerd76b4162021-03-29 07:52:16930 function getTabId(): string {
Blink Reformat4c46d092018-04-07 15:32:37931 return inspectedTabId;
932 }
933
Philip Pfaffe7523faf2021-06-28 14:23:14934 let keyboardEventRequestQueue: KeyboardEventInit&{eventType: string}[] = [];
Jan Schefflerd76b4162021-03-29 07:52:16935 let forwardTimer: number|null = null;
Philip Pfaffe7523faf2021-06-28 14:23:14936 function forwardKeyboardEvent(event: KeyboardEvent): void {
Jan Schefflere7d7bb12019-10-24 09:18:52937 // Check if the event should be forwarded.
938 // This is a workaround for crbug.com/923338.
939 const focused = document.activeElement;
940 if (focused) {
941 const isInput = focused.nodeName === 'INPUT' || focused.nodeName === 'TEXTAREA';
942 if (isInput && !(event.ctrlKey || event.altKey || event.metaKey)) {
943 return;
944 }
945 }
946
Joel Einbinder67f28fb2018-08-02 00:33:47947 let modifiers = 0;
Tim van der Lippe1d6e57a2019-09-30 11:55:34948 if (event.shiftKey) {
Joel Einbinder67f28fb2018-08-02 00:33:47949 modifiers |= 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:34950 }
951 if (event.ctrlKey) {
Joel Einbinder67f28fb2018-08-02 00:33:47952 modifiers |= 2;
Tim van der Lippe1d6e57a2019-09-30 11:55:34953 }
954 if (event.altKey) {
Joel Einbinder67f28fb2018-08-02 00:33:47955 modifiers |= 4;
Tim van der Lippe1d6e57a2019-09-30 11:55:34956 }
957 if (event.metaKey) {
Joel Einbinder67f28fb2018-08-02 00:33:47958 modifiers |= 8;
Tim van der Lippe1d6e57a2019-09-30 11:55:34959 }
Joel Einbinder67f28fb2018-08-02 00:33:47960 const num = (event.keyCode & 255) | (modifiers << 8);
Blink Reformat4c46d092018-04-07 15:32:37961 // We only care about global hotkeys, not about random text
Tim van der Lippe1d6e57a2019-09-30 11:55:34962 if (!keysToForwardSet.has(num)) {
Blink Reformat4c46d092018-04-07 15:32:37963 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34964 }
Joel Einbinder67f28fb2018-08-02 00:33:47965 event.preventDefault();
Blink Reformat4c46d092018-04-07 15:32:37966 const requestPayload = {
967 eventType: event.type,
968 ctrlKey: event.ctrlKey,
969 altKey: event.altKey,
970 metaKey: event.metaKey,
Joel Einbinder67f28fb2018-08-02 00:33:47971 shiftKey: event.shiftKey,
Philip Pfaffe7523faf2021-06-28 14:23:14972 // @ts-expect-error keyIdentifier is a deprecated non-standard property that typescript doesn't know about.
Blink Reformat4c46d092018-04-07 15:32:37973 keyIdentifier: event.keyIdentifier,
974 key: event.key,
975 code: event.code,
976 location: event.location,
Jan Schefflerd76b4162021-03-29 07:52:16977 keyCode: event.keyCode,
Blink Reformat4c46d092018-04-07 15:32:37978 };
979 keyboardEventRequestQueue.push(requestPayload);
Tim van der Lippe1d6e57a2019-09-30 11:55:34980 if (!forwardTimer) {
Blink Reformat4c46d092018-04-07 15:32:37981 forwardTimer = setTimeout(forwardEventQueue, 0);
Tim van der Lippe1d6e57a2019-09-30 11:55:34982 }
Blink Reformat4c46d092018-04-07 15:32:37983 }
984
Jan Schefflerd76b4162021-03-29 07:52:16985 function forwardEventQueue(): void {
Blink Reformat4c46d092018-04-07 15:32:37986 forwardTimer = null;
Philip Pfaffe7523faf2021-06-28 14:23:14987 extensionServer.sendRequest(
988 {command: PrivateAPI.Commands.ForwardKeyboardEvent, entries: keyboardEventRequestQueue});
Blink Reformat4c46d092018-04-07 15:32:37989 keyboardEventRequestQueue = [];
990 }
991
992 document.addEventListener('keydown', forwardKeyboardEvent, false);
Blink Reformat4c46d092018-04-07 15:32:37993
994 /**
995 * @constructor
996 */
Philip Pfaffe7523faf2021-06-28 14:23:14997 function ExtensionServerClient(this: APIImpl.ExtensionServerClient): void {
Blink Reformat4c46d092018-04-07 15:32:37998 this._callbacks = {};
999 this._handlers = {};
1000 this._lastRequestId = 0;
1001 this._lastObjectId = 0;
1002
1003 this.registerHandler('callback', this._onCallback.bind(this));
1004
1005 const channel = new MessageChannel();
1006 this._port = channel.port1;
1007 this._port.addEventListener('message', this._onMessage.bind(this), false);
1008 this._port.start();
1009
1010 window.parent.postMessage('registerExtension', '*', [channel.port2]);
1011 }
1012
Philip Pfaffe7523faf2021-06-28 14:23:141013 (ExtensionServerClient.prototype as Pick<
1014 APIImpl.ExtensionServerClient,
1015 'sendRequest'|'hasHandler'|'registerHandler'|'unregisterHandler'|'nextObjectId'|'_registerCallback'|
1016 '_onCallback'|'_onMessage'>) = {
1017 sendRequest: function(
1018 this: APIImpl.ExtensionServerClient, message: PrivateAPI.ServerRequests,
1019 callback?: (response: unknown) => unknown, transfers?: Transferable[]): void {
1020 if (typeof callback === 'function') {
1021 (message as PrivateAPI.ExtensionServerRequestMessage).requestId = this._registerCallback(callback);
1022 }
1023 // @ts-expect-error
1024 this._port.postMessage(message, transfers);
1025 },
Blink Reformat4c46d092018-04-07 15:32:371026
Philip Pfaffe7523faf2021-06-28 14:23:141027 hasHandler: function(this: APIImpl.ExtensionServerClient, command: string): boolean {
Tim van der Lipped7cfd142021-01-07 12:17:241028 return Boolean(this._handlers[command]);
Blink Reformat4c46d092018-04-07 15:32:371029 },
1030
Philip Pfaffe7523faf2021-06-28 14:23:141031 registerHandler: function(
1032 this: APIImpl.ExtensionServerClient, command: string, handler: (request: {arguments: unknown[]}) => unknown):
1033 void {
1034 this._handlers[command] = handler;
1035 },
Blink Reformat4c46d092018-04-07 15:32:371036
Philip Pfaffe7523faf2021-06-28 14:23:141037 unregisterHandler: function(this: APIImpl.ExtensionServerClient, command: string): void {
Blink Reformat4c46d092018-04-07 15:32:371038 delete this._handlers[command];
1039 },
1040
Philip Pfaffe7523faf2021-06-28 14:23:141041 nextObjectId: function(this: APIImpl.ExtensionServerClient): string {
Blink Reformat4c46d092018-04-07 15:32:371042 return injectedScriptId.toString() + '_' + ++this._lastObjectId;
1043 },
1044
Philip Pfaffe7523faf2021-06-28 14:23:141045 _registerCallback: function(this: APIImpl.ExtensionServerClient, callback: (response: unknown) => unknown): number {
Blink Reformat4c46d092018-04-07 15:32:371046 const id = ++this._lastRequestId;
1047 this._callbacks[id] = callback;
1048 return id;
1049 },
1050
Philip Pfaffe7523faf2021-06-28 14:23:141051 _onCallback: function(this: APIImpl.ExtensionServerClient, request: {requestId: number, result: unknown}): void {
Blink Reformat4c46d092018-04-07 15:32:371052 if (request.requestId in this._callbacks) {
1053 const callback = this._callbacks[request.requestId];
1054 delete this._callbacks[request.requestId];
1055 callback(request.result);
1056 }
1057 },
1058
Philip Pfaffe7523faf2021-06-28 14:23:141059 _onMessage: function(
1060 this: APIImpl.ExtensionServerClient,
1061 event: MessageEvent<{command: string, requestId: number, arguments: unknown[]}>): void {
Blink Reformat4c46d092018-04-07 15:32:371062 const request = event.data;
1063 const handler = this._handlers[request.command];
Tim van der Lippe1d6e57a2019-09-30 11:55:341064 if (handler) {
Blink Reformat4c46d092018-04-07 15:32:371065 handler.call(this, request);
Tim van der Lippe1d6e57a2019-09-30 11:55:341066 }
Jan Schefflerd76b4162021-03-29 07:52:161067 },
Blink Reformat4c46d092018-04-07 15:32:371068 };
1069
Philip Pfaffe7523faf2021-06-28 14:23:141070 function populateInterfaceClass(interfaze: {[key: string]: unknown}, implementation: {[key: string]: unknown}): void {
Blink Reformat4c46d092018-04-07 15:32:371071 for (const member in implementation) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341072 if (member.charAt(0) === '_') {
Blink Reformat4c46d092018-04-07 15:32:371073 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341074 }
Jan Schefflerd76b4162021-03-29 07:52:161075 let descriptor: (PropertyDescriptor|undefined)|null = null;
Blink Reformat4c46d092018-04-07 15:32:371076 // Traverse prototype chain until we find the owner.
Philip Pfaffe7523faf2021-06-28 14:23:141077 for (let owner = implementation; owner && !descriptor; owner = owner.__proto__ as {[key: string]: unknown}) {
Blink Reformat4c46d092018-04-07 15:32:371078 descriptor = Object.getOwnPropertyDescriptor(owner, member);
Tim van der Lippe1d6e57a2019-09-30 11:55:341079 }
1080 if (!descriptor) {
Blink Reformat4c46d092018-04-07 15:32:371081 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:341082 }
1083 if (typeof descriptor.value === 'function') {
Blink Reformat4c46d092018-04-07 15:32:371084 interfaze[member] = descriptor.value.bind(implementation);
Tim van der Lippe1d6e57a2019-09-30 11:55:341085 } else if (typeof descriptor.get === 'function') {
Philip Pfaffe7523faf2021-06-28 14:23:141086 // @ts-expect-error
Blink Reformat4c46d092018-04-07 15:32:371087 interfaze.__defineGetter__(member, descriptor.get.bind(implementation));
Tim van der Lippe1d6e57a2019-09-30 11:55:341088 } else {
Blink Reformat4c46d092018-04-07 15:32:371089 Object.defineProperty(interfaze, member, descriptor);
Tim van der Lippe1d6e57a2019-09-30 11:55:341090 }
Blink Reformat4c46d092018-04-07 15:32:371091 }
1092 }
1093
Philip Pfaffe7523faf2021-06-28 14:23:141094
1095 const extensionServer = new (Constructor(ExtensionServerClient))();
1096
1097 const coreAPI = new (Constructor(InspectorExtensionAPI))();
Blink Reformat4c46d092018-04-07 15:32:371098
1099 Object.defineProperty(chrome, 'devtools', {value: {}, enumerable: true});
1100
1101 // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
Philip Pfaffe7523faf2021-06-28 14:23:141102 // @ts-expect-error
1103 chrome.devtools!.inspectedWindow = {};
1104 Object.defineProperty(chrome.devtools!.inspectedWindow, 'tabId', {get: getTabId});
1105 // @ts-expect-error
1106 chrome.devtools!.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
1107 chrome.devtools!.network = coreAPI.network;
1108 chrome.devtools!.panels = coreAPI.panels;
1109 chrome.devtools!.panels.themeName = themeName;
1110 chrome.devtools!.languageServices = coreAPI.languageServices;
Blink Reformat4c46d092018-04-07 15:32:371111
1112 // default to expose experimental APIs for now.
1113 if (extensionInfo.exposeExperimentalAPIs !== false) {
1114 chrome.experimental = chrome.experimental || {};
1115 chrome.experimental.devtools = chrome.experimental.devtools || {};
1116
1117 const properties = Object.getOwnPropertyNames(coreAPI);
1118 for (let i = 0; i < properties.length; ++i) {
1119 const descriptor = Object.getOwnPropertyDescriptor(coreAPI, properties[i]);
Tim van der Lippe1d6e57a2019-09-30 11:55:341120 if (descriptor) {
Blink Reformat4c46d092018-04-07 15:32:371121 Object.defineProperty(chrome.experimental.devtools, properties[i], descriptor);
Tim van der Lippe1d6e57a2019-09-30 11:55:341122 }
Blink Reformat4c46d092018-04-07 15:32:371123 }
1124 chrome.experimental.devtools.inspectedWindow = chrome.devtools.inspectedWindow;
1125 }
1126
Tim van der Lippe1d6e57a2019-09-30 11:55:341127 if (extensionInfo.exposeWebInspectorNamespace) {
Blink Reformat4c46d092018-04-07 15:32:371128 window.webInspector = coreAPI;
Tim van der Lippe1d6e57a2019-09-30 11:55:341129 }
Blink Reformat4c46d092018-04-07 15:32:371130 testHook(extensionServer, coreAPI);
Tim van der Lippe226fc222019-10-10 12:17:121131};
Blink Reformat4c46d092018-04-07 15:32:371132
Jan Schefflerd76b4162021-03-29 07:52:161133self.buildExtensionAPIInjectedScript = function(
1134 extensionInfo: {
1135 startPage: string,
1136 name: string,
1137 exposeExperimentalAPIs: boolean,
1138 },
1139 inspectedTabId: string, themeName: string, keysToForward: number[],
Philip Pfaffe7523faf2021-06-28 14:23:141140 testHook:
1141 ((extensionServer: APIImpl.ExtensionServerClient, extensionAPI: APIImpl.InspectorExtensionAPI) => unknown)|
1142 undefined): string {
Philip Pfaffeedad8322020-07-20 10:24:251143 const argumentsJSON =
1144 [extensionInfo, inspectedTabId || null, themeName, keysToForward].map(_ => JSON.stringify(_)).join(',');
Tim van der Lippe1d6e57a2019-09-30 11:55:341145 if (!testHook) {
Jan Schefflerd76b4162021-03-29 07:52:161146 testHook = (): void => {};
Tim van der Lippe1d6e57a2019-09-30 11:55:341147 }
Philip Pfaffe939605d2021-06-25 12:20:041148 return '(function(injectedScriptId){ ' +
Tim van der Lippe226fc222019-10-10 12:17:121149 '(' + self.injectedExtensionAPI.toString() + ')(' + argumentsJSON + ',' + testHook + ', injectedScriptId);' +
Blink Reformat4c46d092018-04-07 15:32:371150 '})';
Tim van der Lippe29fab472019-08-15 14:46:481151};