chrome-devtools-frontend 1.0.1543082 → 1.0.1543472
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/AUTHORS +1 -0
- package/front_end/core/common/Gzip.ts +4 -4
- package/front_end/core/common/common.ts +0 -2
- package/front_end/core/root/DevToolsContext.ts +60 -0
- package/front_end/core/root/root.ts +6 -1
- package/front_end/core/sdk/TargetManager.ts +5 -6
- package/front_end/entrypoints/inspector_main/InspectorMain.ts +1 -13
- package/front_end/entrypoints/main/MainImpl.ts +3 -5
- package/front_end/foundation/Universe.ts +13 -1
- package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +11 -8
- package/front_end/models/trace/handlers/SamplesHandler.ts +64 -6
- package/front_end/models/trace/types/TraceEvents.ts +16 -0
- package/front_end/models/workspace/IgnoreListManager.ts +10 -9
- package/front_end/models/workspace/WorkspaceImpl.ts +5 -10
- package/front_end/panels/application/ApplicationPanelSidebar.ts +0 -1
- package/front_end/panels/application/OpenedWindowDetailsView.ts +0 -2
- package/front_end/panels/application/ServiceWorkersView.ts +0 -2
- package/front_end/panels/application/StorageView.ts +0 -1
- package/front_end/panels/application/components/FrameDetailsView.ts +468 -447
- package/front_end/panels/console/ConsoleView.ts +9 -7
- package/front_end/panels/console/ConsoleViewMessage.ts +19 -9
- package/front_end/panels/explain/components/ConsoleInsight.ts +314 -310
- package/front_end/panels/settings/SettingsScreen.ts +3 -6
- package/front_end/panels/settings/components/SyncSection.ts +218 -226
- package/front_end/panels/settings/components/syncSection.css +81 -80
- package/front_end/panels/sources/DebuggerPlugin.ts +3 -1
- package/front_end/panels/sources/ResourceOriginPlugin.ts +7 -3
- package/front_end/panels/timeline/TimelinePanel.ts +0 -21
- package/front_end/ui/components/docs/component_docs.ts +0 -4
- package/front_end/ui/components/report_view/ReportView.ts +4 -1
- package/front_end/ui/legacy/ReportView.ts +0 -5
- package/front_end/ui/legacy/TextPrompt.ts +65 -19
- package/front_end/ui/legacy/components/object_ui/JavaScriptREPL.ts +8 -4
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +90 -92
- package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +114 -184
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
- package/front_end/ui/{components/docs/theme_colors/basic.ts → legacy/theme_support/ThemeColors.docs.ts} +33 -23
- package/package.json +1 -1
- package/front_end/core/common/QueryParamHandler.ts +0 -7
- package/front_end/ui/components/docs/input/basic.html +0 -31
- package/front_end/ui/components/docs/input/basic.ts +0 -12
- package/front_end/ui/components/docs/report/basic.html +0 -27
- package/front_end/ui/components/docs/report/basic.ts +0 -48
- package/front_end/ui/components/docs/theme_colors/basic.html +0 -56
- package/front_end/ui/components/docs/toggle_dark_mode.ts +0 -36
- package/front_end/ui/components/docs/toggle_fonts.ts +0 -74
- package/front_end/ui/components/docs/user_agent_client_hints/basic.html +0 -25
- package/front_end/ui/components/docs/user_agent_client_hints/basic.ts +0 -26
package/AUTHORS
CHANGED
|
@@ -68,6 +68,7 @@ Michael Rienstra <mrienstra@gmail.com>
|
|
|
68
68
|
Mostafa Aboalkasim <mostafa.aboalkasim.offical@gmail.com>
|
|
69
69
|
Muhammad Mahad <mahadtxt@gmail.com>
|
|
70
70
|
Naoto Ono <onoto1998@gmail.com>
|
|
71
|
+
Nourhan Hasan <nourhan.m.hasan@gmail.com>
|
|
71
72
|
Paras Awasthi <awasthiparas6@gmail.com>
|
|
72
73
|
Paul Fisher <paul@pfish.zone>
|
|
73
74
|
Peng Zhou <zhoupeng.1996@bytedance.com>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* Quickly determine if gzipped, by seeing if the first 3 bytes of the file header match the gzip signature
|
|
7
7
|
*/
|
|
8
|
-
export function isGzip(ab:
|
|
8
|
+
export function isGzip(ab: ArrayBufferLike): boolean {
|
|
9
9
|
const buf = new Uint8Array(ab);
|
|
10
10
|
if (!buf || buf.length < 3) {
|
|
11
11
|
return false;
|
|
@@ -15,7 +15,7 @@ export function isGzip(ab: ArrayBuffer): boolean {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/** Decode a gzipped _or_ plain text ArrayBuffer to a decoded string */
|
|
18
|
-
export async function arrayBufferToString(ab:
|
|
18
|
+
export async function arrayBufferToString(ab: ArrayBufferLike): Promise<string> {
|
|
19
19
|
if (isGzip(ab)) {
|
|
20
20
|
return await decompress(ab);
|
|
21
21
|
}
|
|
@@ -37,7 +37,7 @@ export async function fileToString(file: File): Promise<string> {
|
|
|
37
37
|
* Decompress a gzipped ArrayBuffer to a string.
|
|
38
38
|
* Consider using `arrayBufferToString` instead, which can handle both gzipped and plain text buffers.
|
|
39
39
|
*/
|
|
40
|
-
export async function decompress(gzippedBuffer:
|
|
40
|
+
export async function decompress(gzippedBuffer: ArrayBufferLike): Promise<string> {
|
|
41
41
|
const buffer = await gzipCodec(gzippedBuffer, new DecompressionStream('gzip'));
|
|
42
42
|
const str = new TextDecoder('utf-8').decode(buffer);
|
|
43
43
|
return str;
|
|
@@ -50,7 +50,7 @@ export async function compress(str: string): Promise<ArrayBuffer> {
|
|
|
50
50
|
|
|
51
51
|
/** Private coder/decoder **/
|
|
52
52
|
async function gzipCodec(
|
|
53
|
-
buffer: Uint8Array<ArrayBufferLike>|
|
|
53
|
+
buffer: Uint8Array<ArrayBufferLike>|ArrayBufferLike,
|
|
54
54
|
codecStream: CompressionStream|DecompressionStream): Promise<ArrayBuffer> {
|
|
55
55
|
const readable = new ReadableStream({
|
|
56
56
|
start(controller) {
|
|
@@ -21,7 +21,6 @@ import * as Mutex from './Mutex.js';
|
|
|
21
21
|
import * as ObjectWrapper from './Object.js';
|
|
22
22
|
import * as ParsedURL from './ParsedURL.js';
|
|
23
23
|
import * as Progress from './Progress.js';
|
|
24
|
-
import * as QueryParamHandler from './QueryParamHandler.js';
|
|
25
24
|
import * as ResolverBase from './ResolverBase.js';
|
|
26
25
|
import * as ResourceType from './ResourceType.js';
|
|
27
26
|
import * as ReturnToPanel from './ReturnToPanel.js';
|
|
@@ -63,7 +62,6 @@ export {
|
|
|
63
62
|
ObjectWrapper,
|
|
64
63
|
ParsedURL,
|
|
65
64
|
Progress,
|
|
66
|
-
QueryParamHandler,
|
|
67
65
|
ResolverBase,
|
|
68
66
|
ResourceType,
|
|
69
67
|
ReturnToPanel,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Copyright 2025 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
export type ConstructorT<T> = new (...args: any[]) => T;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Container for singletons scoped to a single DevTools universe.
|
|
9
|
+
*/
|
|
10
|
+
export class DevToolsContext {
|
|
11
|
+
readonly #instances = new Map<ConstructorT<unknown>, unknown>();
|
|
12
|
+
|
|
13
|
+
get<T>(ctor: ConstructorT<T>): T {
|
|
14
|
+
const instance = this.#instances.get(ctor) as T | undefined;
|
|
15
|
+
if (!instance) {
|
|
16
|
+
throw new Error(`No instance for ${ctor.name}. Ensure the bootstrapper creates it.`);
|
|
17
|
+
}
|
|
18
|
+
return instance;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** @deprecated Should only be used by existing `instance` accessors. */
|
|
22
|
+
has<T>(ctor: ConstructorT<T>): boolean {
|
|
23
|
+
return this.#instances.has(ctor);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @deprecated Should only be used by existing `instance` accessors and the bootstrapper.
|
|
28
|
+
* Exists on the public interface only for migration purposes for now.
|
|
29
|
+
*/
|
|
30
|
+
set<T>(ctor: ConstructorT<T>, instance: T): void {
|
|
31
|
+
// TODO(crbug.com/458180550): We need to throw here if an instance was already set!
|
|
32
|
+
this.#instances.set(ctor, instance);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @deprecated Should only be used by existing `removeInstance` static methods. */
|
|
36
|
+
delete<T>(ctor: ConstructorT<T>): void {
|
|
37
|
+
this.#instances.delete(ctor);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let gInstance: DevToolsContext|null = null;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @deprecated Exists to migrate instance() methods.
|
|
45
|
+
*/
|
|
46
|
+
export function globalInstance(): DevToolsContext {
|
|
47
|
+
if (!gInstance) {
|
|
48
|
+
// TODO(crbug.com/458180550): This should really throw to prevent side-effects and globals
|
|
49
|
+
// from leaking all over the place.
|
|
50
|
+
gInstance = new DevToolsContext();
|
|
51
|
+
}
|
|
52
|
+
return gInstance;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @deprecated Should only be called by test setup and MainImpl
|
|
57
|
+
*/
|
|
58
|
+
export function setGlobalInstance(context: DevToolsContext|null): void {
|
|
59
|
+
gInstance = context;
|
|
60
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// Copyright 2020 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import * as DevToolsContext from './DevToolsContext.js';
|
|
4
6
|
import * as Runtime from './Runtime.js';
|
|
5
7
|
|
|
6
|
-
export {
|
|
8
|
+
export {
|
|
9
|
+
DevToolsContext,
|
|
10
|
+
Runtime,
|
|
11
|
+
};
|
|
@@ -13,7 +13,6 @@ import * as Root from '../root/root.js';
|
|
|
13
13
|
import {SDKModel} from './SDKModel.js';
|
|
14
14
|
import {Target, Type as TargetType} from './Target.js';
|
|
15
15
|
|
|
16
|
-
let targetManagerInstance: TargetManager|undefined;
|
|
17
16
|
type ModelClass<T = SDKModel> = new (arg1: Target) => T;
|
|
18
17
|
|
|
19
18
|
export class TargetManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
@@ -35,7 +34,7 @@ export class TargetManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
|
35
34
|
#defaultScopeSet: boolean;
|
|
36
35
|
readonly #scopeChangeListeners: Set<() => void>;
|
|
37
36
|
|
|
38
|
-
|
|
37
|
+
constructor() {
|
|
39
38
|
super();
|
|
40
39
|
this.#targets = new Set();
|
|
41
40
|
this.#observers = new Set();
|
|
@@ -52,15 +51,15 @@ export class TargetManager extends Common.ObjectWrapper.ObjectWrapper<EventTypes
|
|
|
52
51
|
static instance({forceNew}: {
|
|
53
52
|
forceNew: boolean,
|
|
54
53
|
} = {forceNew: false}): TargetManager {
|
|
55
|
-
if (!
|
|
56
|
-
|
|
54
|
+
if (!Root.DevToolsContext.globalInstance().has(TargetManager) || forceNew) {
|
|
55
|
+
Root.DevToolsContext.globalInstance().set(TargetManager, new TargetManager());
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
return
|
|
58
|
+
return Root.DevToolsContext.globalInstance().get(TargetManager);
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
static removeInstance(): void {
|
|
63
|
-
|
|
62
|
+
Root.DevToolsContext.globalInstance().delete(TargetManager);
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
onInspectedURLChange(target: Target): void {
|
|
@@ -46,20 +46,8 @@ const UIStrings = {
|
|
|
46
46
|
} as const;
|
|
47
47
|
const str_ = i18n.i18n.registerUIStrings('entrypoints/inspector_main/InspectorMain.ts', UIStrings);
|
|
48
48
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
49
|
-
let inspectorMainImplInstance: InspectorMainImpl;
|
|
50
49
|
|
|
51
50
|
export class InspectorMainImpl implements Common.Runnable.Runnable {
|
|
52
|
-
static instance(opts: {
|
|
53
|
-
forceNew: boolean|null,
|
|
54
|
-
} = {forceNew: null}): InspectorMainImpl {
|
|
55
|
-
const {forceNew} = opts;
|
|
56
|
-
if (!inspectorMainImplInstance || forceNew) {
|
|
57
|
-
inspectorMainImplInstance = new InspectorMainImpl();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return inspectorMainImplInstance;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
51
|
async run(): Promise<void> {
|
|
64
52
|
let firstCall = true;
|
|
65
53
|
await SDK.Connections.initMainConnection(async () => {
|
|
@@ -162,7 +150,7 @@ export class InspectorMainImpl implements Common.Runnable.Runnable {
|
|
|
162
150
|
}
|
|
163
151
|
}
|
|
164
152
|
|
|
165
|
-
Common.Runnable.registerEarlyInitializationRunnable(InspectorMainImpl
|
|
153
|
+
Common.Runnable.registerEarlyInitializationRunnable(() => new InspectorMainImpl());
|
|
166
154
|
|
|
167
155
|
export class ReloadActionDelegate implements UI.ActionRegistration.ActionDelegate {
|
|
168
156
|
handleAction(_context: UI.Context.Context, actionId: string): boolean {
|
|
@@ -175,7 +175,8 @@ export class MainImpl {
|
|
|
175
175
|
runSettingsMigration: !Host.InspectorFrontendHost.isUnderTest(),
|
|
176
176
|
},
|
|
177
177
|
};
|
|
178
|
-
new Foundation.Universe.Universe(creationOptions);
|
|
178
|
+
const universe = new Foundation.Universe.Universe(creationOptions);
|
|
179
|
+
Root.DevToolsContext.setGlobalInstance(universe.context);
|
|
179
180
|
|
|
180
181
|
await this.requestAndRegisterLocaleData();
|
|
181
182
|
|
|
@@ -445,7 +446,6 @@ export class MainImpl {
|
|
|
445
446
|
SDK.TargetManager.Events.SUSPEND_STATE_CHANGED, this.#onSuspendStateChanged.bind(this));
|
|
446
447
|
|
|
447
448
|
Workspace.FileManager.FileManager.instance({forceNew: true});
|
|
448
|
-
Workspace.Workspace.WorkspaceImpl.instance();
|
|
449
449
|
|
|
450
450
|
Bindings.NetworkProject.NetworkProjectManager.instance();
|
|
451
451
|
const resourceMapping = new Bindings.ResourceMapping.ResourceMapping(
|
|
@@ -458,14 +458,12 @@ export class MainImpl {
|
|
|
458
458
|
resourceMapping,
|
|
459
459
|
targetManager,
|
|
460
460
|
});
|
|
461
|
-
Workspace.IgnoreListManager.IgnoreListManager.instance({
|
|
462
|
-
forceNew: true,
|
|
463
|
-
});
|
|
464
461
|
Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance({
|
|
465
462
|
forceNew: true,
|
|
466
463
|
resourceMapping,
|
|
467
464
|
targetManager,
|
|
468
465
|
ignoreListManager: Workspace.IgnoreListManager.IgnoreListManager.instance(),
|
|
466
|
+
workspace: Workspace.Workspace.WorkspaceImpl.instance(),
|
|
469
467
|
});
|
|
470
468
|
targetManager.setScopeTarget(targetManager.primaryPageTarget());
|
|
471
469
|
UI.Context.Context.instance().addFlavorChangeListener(SDK.Target.Target, ({data}) => {
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
5
|
import * as Common from '../core/common/common.js';
|
|
6
|
+
import * as Root from '../core/root/root.js';
|
|
7
|
+
import * as SDK from '../core/sdk/sdk.js';
|
|
8
|
+
import * as Workspace from '../models/workspace/workspace.js';
|
|
6
9
|
|
|
7
10
|
export interface CreationOptions {
|
|
8
11
|
// Settings things
|
|
@@ -10,12 +13,21 @@ export interface CreationOptions {
|
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export class Universe {
|
|
16
|
+
readonly context = new Root.DevToolsContext.DevToolsContext();
|
|
17
|
+
|
|
13
18
|
constructor(options: CreationOptions) {
|
|
14
19
|
// TODO(crbug.com/458180550): Store instance on a "DevToolsContext" instead.
|
|
15
20
|
// For now the global is fine as we don't anticipate the MCP server to change settings.
|
|
16
|
-
Common.Settings.Settings.instance({
|
|
21
|
+
const settings = Common.Settings.Settings.instance({
|
|
17
22
|
forceNew: true,
|
|
18
23
|
...options.settingsCreationOptions,
|
|
19
24
|
});
|
|
25
|
+
|
|
26
|
+
const targetManager = new SDK.TargetManager.TargetManager();
|
|
27
|
+
this.context.set(SDK.TargetManager.TargetManager, targetManager);
|
|
28
|
+
this.context.set(Workspace.Workspace.WorkspaceImpl, new Workspace.Workspace.WorkspaceImpl());
|
|
29
|
+
|
|
30
|
+
const ignoreListManager = new Workspace.IgnoreListManager.IgnoreListManager(settings, targetManager);
|
|
31
|
+
this.context.set(Workspace.IgnoreListManager.IgnoreListManager, ignoreListManager);
|
|
20
32
|
}
|
|
21
33
|
}
|
|
@@ -28,12 +28,14 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
|
|
|
28
28
|
readonly #liveLocationPromises: Set<Promise<void|Location|StackTraceTopFrameLocation|null>>;
|
|
29
29
|
readonly pluginManager: DebuggerLanguagePluginManager;
|
|
30
30
|
readonly ignoreListManager: Workspace.IgnoreListManager.IgnoreListManager;
|
|
31
|
+
readonly workspace: Workspace.Workspace.WorkspaceImpl;
|
|
31
32
|
|
|
32
33
|
private constructor(
|
|
33
34
|
resourceMapping: ResourceMapping, targetManager: SDK.TargetManager.TargetManager,
|
|
34
|
-
ignoreListManager: Workspace.IgnoreListManager.IgnoreListManager) {
|
|
35
|
+
ignoreListManager: Workspace.IgnoreListManager.IgnoreListManager, workspace: Workspace.Workspace.WorkspaceImpl) {
|
|
35
36
|
this.resourceMapping = resourceMapping;
|
|
36
37
|
this.ignoreListManager = ignoreListManager;
|
|
38
|
+
this.workspace = workspace;
|
|
37
39
|
|
|
38
40
|
this.#debuggerModelToData = new Map();
|
|
39
41
|
targetManager.addModelListener(
|
|
@@ -62,17 +64,19 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
|
|
|
62
64
|
resourceMapping: ResourceMapping|null,
|
|
63
65
|
targetManager: SDK.TargetManager.TargetManager|null,
|
|
64
66
|
ignoreListManager: Workspace.IgnoreListManager.IgnoreListManager|null,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
workspace: Workspace.Workspace.WorkspaceImpl|null,
|
|
68
|
+
} = {forceNew: null, resourceMapping: null, targetManager: null, ignoreListManager: null, workspace: null}):
|
|
69
|
+
DebuggerWorkspaceBinding {
|
|
70
|
+
const {forceNew, resourceMapping, targetManager, ignoreListManager, workspace} = opts;
|
|
67
71
|
if (!debuggerWorkspaceBindingInstance || forceNew) {
|
|
68
|
-
if (!resourceMapping || !targetManager || !ignoreListManager) {
|
|
72
|
+
if (!resourceMapping || !targetManager || !ignoreListManager || !workspace) {
|
|
69
73
|
throw new Error(
|
|
70
74
|
`Unable to create DebuggerWorkspaceBinding: resourceMapping, targetManager and IgnoreLIstManager must be provided: ${
|
|
71
75
|
new Error().stack}`);
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
debuggerWorkspaceBindingInstance =
|
|
75
|
-
new DebuggerWorkspaceBinding(resourceMapping, targetManager, ignoreListManager);
|
|
79
|
+
new DebuggerWorkspaceBinding(resourceMapping, targetManager, ignoreListManager, workspace);
|
|
76
80
|
}
|
|
77
81
|
|
|
78
82
|
return debuggerWorkspaceBindingInstance;
|
|
@@ -271,11 +275,10 @@ export class DebuggerWorkspaceBinding implements SDK.TargetManager.SDKModelObser
|
|
|
271
275
|
waitForUISourceCodeAdded(url: Platform.DevToolsPath.UrlString, target: SDK.Target.Target):
|
|
272
276
|
Promise<Workspace.UISourceCode.UISourceCode> {
|
|
273
277
|
return new Promise(resolve => {
|
|
274
|
-
const
|
|
275
|
-
const descriptor = workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, event => {
|
|
278
|
+
const descriptor = this.workspace.addEventListener(Workspace.Workspace.Events.UISourceCodeAdded, event => {
|
|
276
279
|
const uiSourceCode = event.data;
|
|
277
280
|
if (uiSourceCode.url() === url && NetworkProject.targetForUISourceCode(uiSourceCode) === target) {
|
|
278
|
-
workspace.removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, descriptor.listener);
|
|
281
|
+
this.workspace.removeEventListener(Workspace.Workspace.Events.UISourceCodeAdded, descriptor.listener);
|
|
279
282
|
resolve(uiSourceCode);
|
|
280
283
|
}
|
|
281
284
|
});
|
|
@@ -22,25 +22,73 @@ let entryToNode = new Map<Types.Events.Event, Helpers.TreeHelpers.TraceEntryNode
|
|
|
22
22
|
// events matched by thread id.
|
|
23
23
|
let preprocessedData = new Map<Types.Events.ProcessID, Map<Types.Events.ProfileID, PreprocessedData>>();
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Profile source selection priority when multiple profiles exist for the same thread.
|
|
27
|
+
*
|
|
28
|
+
* Profile sources and their typical scenarios:
|
|
29
|
+
* - 'Internal': Browser-initiated profiling performance panel traces.
|
|
30
|
+
* This is the profiling mechanism when users click "Record" in the Devtools UI.
|
|
31
|
+
* - 'Inspector': User-initiated via console.profile()/profileEnd() calls.
|
|
32
|
+
* Represents explicit developer intent to profile specific code.
|
|
33
|
+
* - 'SelfProfiling': Page-initiated via JS Self-Profiling API.
|
|
34
|
+
* Lower signal vs the two above; treated as fallback.
|
|
35
|
+
*
|
|
36
|
+
* Selection strategy:
|
|
37
|
+
* - CPU Profile mode: Prefer 'Inspector' (explicit user request).
|
|
38
|
+
* - Performance trace: Prefer 'Internal' (integrated timeline context), then 'Inspector'.
|
|
39
|
+
* - Sources not in the priority list (including 'SelfProfiling') act as fallbacks.
|
|
40
|
+
* When no priority source matches, the first candidate profile is selected.
|
|
41
|
+
*/
|
|
42
|
+
const PROFILE_SOURCES_BY_PRIORITY = {
|
|
43
|
+
cpuProfile: ['Inspector'] as Types.Events.ProfileSource[],
|
|
44
|
+
performanceTrace: ['Internal', 'Inspector'] as Types.Events.ProfileSource[],
|
|
45
|
+
};
|
|
46
|
+
|
|
25
47
|
function parseCPUProfileData(parseOptions: Types.Configuration.ParseOptions): void {
|
|
48
|
+
const priorityList =
|
|
49
|
+
parseOptions.isCPUProfile ? PROFILE_SOURCES_BY_PRIORITY.cpuProfile : PROFILE_SOURCES_BY_PRIORITY.performanceTrace;
|
|
50
|
+
|
|
26
51
|
for (const [processId, profiles] of preprocessedData) {
|
|
52
|
+
const profilesByThread =
|
|
53
|
+
new Map<Types.Events.ThreadID, Array<{id: Types.Events.ProfileID, data: PreprocessedData}>>();
|
|
27
54
|
for (const [profileId, preProcessedData] of profiles) {
|
|
28
55
|
const threadId = preProcessedData.threadId;
|
|
29
|
-
if (
|
|
56
|
+
if (threadId === undefined) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const listForThread = Platform.MapUtilities.getWithDefault(profilesByThread, threadId, () => []);
|
|
60
|
+
listForThread.push({id: profileId, data: preProcessedData});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const [threadId, candidates] of profilesByThread) {
|
|
64
|
+
if (!candidates.length) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
let chosen = candidates[0];
|
|
68
|
+
for (const source of priorityList) {
|
|
69
|
+
const match = candidates.find(p => p.data.source === source);
|
|
70
|
+
if (match) {
|
|
71
|
+
chosen = match;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const chosenData = chosen.data;
|
|
76
|
+
if (!chosenData.rawProfile.nodes.length) {
|
|
30
77
|
continue;
|
|
31
78
|
}
|
|
32
79
|
const indexStack: number[] = [];
|
|
33
80
|
|
|
34
|
-
const profileModel = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(
|
|
81
|
+
const profileModel = new CPUProfile.CPUProfileDataModel.CPUProfileDataModel(chosenData.rawProfile);
|
|
35
82
|
const profileTree = Helpers.TreeHelpers.makeEmptyTraceEntryTree();
|
|
36
83
|
profileTree.maxDepth = profileModel.maxDepth;
|
|
37
84
|
|
|
85
|
+
const selectedProfileId = chosen.id;
|
|
38
86
|
const finalizedData: ProfileData = {
|
|
39
|
-
rawProfile:
|
|
87
|
+
rawProfile: chosenData.rawProfile,
|
|
40
88
|
parsedProfile: profileModel,
|
|
41
89
|
profileCalls: [],
|
|
42
90
|
profileTree,
|
|
43
|
-
profileId,
|
|
91
|
+
profileId: selectedProfileId,
|
|
44
92
|
};
|
|
45
93
|
const dataByThread = Platform.MapUtilities.getWithDefault(profilesInProcess, processId, () => new Map());
|
|
46
94
|
dataByThread.set(threadId, finalizedData);
|
|
@@ -62,7 +110,8 @@ function parseCPUProfileData(parseOptions: Types.Configuration.ParseOptions): vo
|
|
|
62
110
|
const ts = Helpers.Timing.milliToMicro(Types.Timing.Milli(timeStampMilliseconds));
|
|
63
111
|
const nodeId = node.id as Helpers.TreeHelpers.TraceEntryNodeId;
|
|
64
112
|
|
|
65
|
-
const profileCall =
|
|
113
|
+
const profileCall =
|
|
114
|
+
Helpers.Trace.makeProfileCall(node, selectedProfileId, sampleIndex, ts, processId, threadId);
|
|
66
115
|
finalizedData.profileCalls.push(profileCall);
|
|
67
116
|
indexStack.push(finalizedData.profileCalls.length - 1);
|
|
68
117
|
const traceEntryNode = Helpers.TreeHelpers.makeEmptyTraceEntryNode(profileCall, nodeId);
|
|
@@ -83,7 +132,7 @@ function parseCPUProfileData(parseOptions: Types.Configuration.ParseOptions): vo
|
|
|
83
132
|
}
|
|
84
133
|
const {callFrame, ts, pid, tid} = profileCall;
|
|
85
134
|
const traceEntryNode = entryToNode.get(profileCall);
|
|
86
|
-
if (callFrame === undefined || ts === undefined || pid === undefined ||
|
|
135
|
+
if (callFrame === undefined || ts === undefined || pid === undefined || selectedProfileId === undefined ||
|
|
87
136
|
tid === undefined || traceEntryNode === undefined) {
|
|
88
137
|
return;
|
|
89
138
|
}
|
|
@@ -138,6 +187,7 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
138
187
|
const profileData = getOrCreatePreProcessedData(event.pid, event.id);
|
|
139
188
|
profileData.rawProfile.startTime = event.ts;
|
|
140
189
|
profileData.threadId = event.tid;
|
|
190
|
+
assignProfileSourceIfKnown(profileData, event.args?.data?.source);
|
|
141
191
|
return;
|
|
142
192
|
}
|
|
143
193
|
if (Types.Events.isProfileChunk(event)) {
|
|
@@ -186,6 +236,7 @@ export function handleEvent(event: Types.Events.Event): void {
|
|
|
186
236
|
const timeDeltas: number[] = cdpProfile.timeDeltas;
|
|
187
237
|
cdpProfile.endTime = timeDeltas.reduce((x, y) => x + y, cdpProfile.startTime);
|
|
188
238
|
}
|
|
239
|
+
assignProfileSourceIfKnown(profileData, event.args?.data?.source);
|
|
189
240
|
return;
|
|
190
241
|
}
|
|
191
242
|
}
|
|
@@ -194,6 +245,12 @@ export async function finalize(parseOptions: Types.Configuration.ParseOptions =
|
|
|
194
245
|
parseCPUProfileData(parseOptions);
|
|
195
246
|
}
|
|
196
247
|
|
|
248
|
+
function assignProfileSourceIfKnown(profileData: PreprocessedData, source: unknown): void {
|
|
249
|
+
if (Types.Events.VALID_PROFILE_SOURCES.includes(source as Types.Events.ProfileSource)) {
|
|
250
|
+
profileData.source = source as Types.Events.ProfileSource;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
197
254
|
export function data(): SamplesHandlerData {
|
|
198
255
|
return {
|
|
199
256
|
profilesInProcess,
|
|
@@ -251,6 +308,7 @@ interface PreprocessedData {
|
|
|
251
308
|
rawProfile: CPUProfile.CPUProfileDataModel.ExtendedProfile;
|
|
252
309
|
profileId: Types.Events.ProfileID;
|
|
253
310
|
threadId?: Types.Events.ThreadID;
|
|
311
|
+
source?: Types.Events.ProfileSource;
|
|
254
312
|
}
|
|
255
313
|
|
|
256
314
|
/**
|
|
@@ -161,6 +161,7 @@ export interface Profile extends Sample {
|
|
|
161
161
|
args: Args&{
|
|
162
162
|
data: ArgsData & {
|
|
163
163
|
startTime: Micro,
|
|
164
|
+
source?: ProfileSource,
|
|
164
165
|
},
|
|
165
166
|
};
|
|
166
167
|
}
|
|
@@ -174,6 +175,7 @@ export interface ProfileChunk extends Sample {
|
|
|
174
175
|
cpuProfile?: PartialProfile,
|
|
175
176
|
timeDeltas?: Micro[],
|
|
176
177
|
lines?: Micro[],
|
|
178
|
+
source?: ProfileSource,
|
|
177
179
|
},
|
|
178
180
|
};
|
|
179
181
|
}
|
|
@@ -191,6 +193,20 @@ export interface PartialProfile {
|
|
|
191
193
|
/* eslint-enable @typescript-eslint/naming-convention */
|
|
192
194
|
}
|
|
193
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Source of profile data, used to select the most relevant profile when
|
|
198
|
+
* multiple profiles exist for the same thread.
|
|
199
|
+
*
|
|
200
|
+
* - 'Inspector': User-initiated via console.profile()/profileEnd().
|
|
201
|
+
* - 'Internal': Browser-initiated during performance traces.
|
|
202
|
+
* - 'SelfProfiling': Page-initiated via JS Self-Profiling API.
|
|
203
|
+
*
|
|
204
|
+
* Selection priority (see PROFILE_SOURCES_BY_PRIORITY in SamplesHandler.ts).
|
|
205
|
+
*/
|
|
206
|
+
export type ProfileSource = 'Inspector'|'SelfProfiling'|'Internal';
|
|
207
|
+
|
|
208
|
+
export const VALID_PROFILE_SOURCES: readonly ProfileSource[] = ['Inspector', 'SelfProfiling', 'Internal'] as const;
|
|
209
|
+
|
|
194
210
|
export interface PartialNode {
|
|
195
211
|
callFrame: CallFrame;
|
|
196
212
|
id: CallFrameID;
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
7
7
|
import * as Platform from '../../core/platform/platform.js';
|
|
8
|
+
import * as Root from '../../core/root/root.js';
|
|
8
9
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
9
10
|
|
|
10
11
|
import type {UISourceCode} from './UISourceCode.js';
|
|
@@ -40,8 +41,6 @@ const UIStrings = {
|
|
|
40
41
|
const str_ = i18n.i18n.registerUIStrings('models/workspace/IgnoreListManager.ts', UIStrings);
|
|
41
42
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
42
43
|
|
|
43
|
-
let ignoreListManagerInstance: IgnoreListManager|undefined;
|
|
44
|
-
|
|
45
44
|
export interface IgnoreListGeneralRules {
|
|
46
45
|
isContentScript?: boolean;
|
|
47
46
|
isKnownThirdParty?: boolean;
|
|
@@ -57,7 +56,7 @@ export class IgnoreListManager extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
57
56
|
readonly #isIgnoreListedURLCache = new Map<string, boolean>();
|
|
58
57
|
readonly #contentScriptExecutionContexts = new Set<string>();
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
constructor(settings: Common.Settings.Settings, targetManager: SDK.TargetManager.TargetManager) {
|
|
61
60
|
super();
|
|
62
61
|
this.#settings = settings;
|
|
63
62
|
this.#targetManager = targetManager;
|
|
@@ -89,17 +88,19 @@ export class IgnoreListManager extends Common.ObjectWrapper.ObjectWrapper<EventT
|
|
|
89
88
|
forceNew: null,
|
|
90
89
|
}): IgnoreListManager {
|
|
91
90
|
const {forceNew} = opts;
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
if (forceNew) {
|
|
92
|
+
Root.DevToolsContext.globalInstance().set(
|
|
93
|
+
IgnoreListManager,
|
|
94
|
+
new IgnoreListManager(
|
|
95
|
+
opts.settings ?? Common.Settings.Settings.instance(),
|
|
96
|
+
opts.targetManager ?? SDK.TargetManager.TargetManager.instance()));
|
|
96
97
|
}
|
|
97
98
|
|
|
98
|
-
return
|
|
99
|
+
return Root.DevToolsContext.globalInstance().get(IgnoreListManager);
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
static removeInstance(): void {
|
|
102
|
-
|
|
103
|
+
Root.DevToolsContext.globalInstance().delete(IgnoreListManager);
|
|
103
104
|
}
|
|
104
105
|
|
|
105
106
|
addChangeListener(listener: () => void): void {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
import type * as Platform from '../../core/platform/platform.js';
|
|
7
|
+
import * as Root from '../../core/root/root.js';
|
|
7
8
|
import type * as TextUtils from '../text_utils/text_utils.js';
|
|
8
9
|
|
|
9
10
|
import type {SearchConfig} from './SearchConfig.js';
|
|
@@ -183,27 +184,21 @@ export abstract class ProjectStore implements Project {
|
|
|
183
184
|
progress: Common.Progress.Progress): Promise<Map<UISourceCode, TextUtils.ContentProvider.SearchMatch[]|null>>;
|
|
184
185
|
}
|
|
185
186
|
|
|
186
|
-
let workspaceInstance: WorkspaceImpl|undefined;
|
|
187
|
-
|
|
188
187
|
export class WorkspaceImpl extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
189
188
|
#projects = new Map<string, Project>();
|
|
190
189
|
#hasResourceContentTrackingExtensions = false;
|
|
191
190
|
|
|
192
|
-
private constructor() {
|
|
193
|
-
super();
|
|
194
|
-
}
|
|
195
|
-
|
|
196
191
|
static instance(opts: {forceNew: boolean|null} = {forceNew: null}): WorkspaceImpl {
|
|
197
192
|
const {forceNew} = opts;
|
|
198
|
-
if (!
|
|
199
|
-
|
|
193
|
+
if (!Root.DevToolsContext.globalInstance().has(WorkspaceImpl) || forceNew) {
|
|
194
|
+
Root.DevToolsContext.globalInstance().set(WorkspaceImpl, new WorkspaceImpl());
|
|
200
195
|
}
|
|
201
196
|
|
|
202
|
-
return
|
|
197
|
+
return Root.DevToolsContext.globalInstance().get(WorkspaceImpl);
|
|
203
198
|
}
|
|
204
199
|
|
|
205
200
|
static removeInstance(): void {
|
|
206
|
-
|
|
201
|
+
Root.DevToolsContext.globalInstance().delete(WorkspaceImpl);
|
|
207
202
|
}
|
|
208
203
|
|
|
209
204
|
uiSourceCode(projectId: string, url: Platform.DevToolsPath.UrlString): UISourceCode|null {
|
|
@@ -1158,7 +1158,6 @@ export class AppManifestTreeElement extends ApplicationPanelTreeElement {
|
|
|
1158
1158
|
self.onInvokeElement(this.listItemElement, this.onInvoke.bind(this));
|
|
1159
1159
|
const emptyView = new UI.EmptyWidget.EmptyWidget(
|
|
1160
1160
|
i18nString(UIStrings.noManifestDetected), i18nString(UIStrings.manifestDescription));
|
|
1161
|
-
// TODO(crbug.com/1156978): Replace UI.ReportView.ReportView with ReportView.ts web component.
|
|
1162
1161
|
const reportView = new UI.ReportView.ReportView(i18nString(UIStrings.appManifest));
|
|
1163
1162
|
this.view = new AppManifestView(emptyView, reportView, new Common.Throttler.Throttler(1000));
|
|
1164
1163
|
UI.ARIAUtils.setLabel(this.listItemElement, i18nString(UIStrings.onInvokeManifestAlert));
|
|
@@ -153,7 +153,6 @@ export class OpenedWindowDetailsView extends UI.Widget.VBox {
|
|
|
153
153
|
this.isWindowClosed = isWindowClosed;
|
|
154
154
|
|
|
155
155
|
this.contentElement.classList.add('frame-details-container');
|
|
156
|
-
// TODO(crbug.com/1156978): Replace UI.ReportView.ReportView with ReportView.ts web component.
|
|
157
156
|
this.reportView = new UI.ReportView.ReportView(this.buildTitle());
|
|
158
157
|
|
|
159
158
|
this.reportView.show(this.contentElement);
|
|
@@ -221,7 +220,6 @@ export class WorkerDetailsView extends UI.Widget.VBox {
|
|
|
221
220
|
this.targetInfo = targetInfo;
|
|
222
221
|
|
|
223
222
|
this.contentElement.classList.add('frame-details-container');
|
|
224
|
-
// TODO(crbug.com/1156978): Replace UI.ReportView.ReportView with ReportView.ts web component.
|
|
225
223
|
this.reportView =
|
|
226
224
|
new UI.ReportView.ReportView(this.targetInfo.title || this.targetInfo.url || i18nString(UIStrings.worker));
|
|
227
225
|
|
|
@@ -202,7 +202,6 @@ export class ServiceWorkersView extends UI.Widget.VBox implements
|
|
|
202
202
|
});
|
|
203
203
|
this.registerRequiredCSS(serviceWorkersViewStyles);
|
|
204
204
|
|
|
205
|
-
// TODO(crbug.com/1156978): Replace UI.ReportView.ReportView with ReportView.ts web component.
|
|
206
205
|
this.currentWorkersView = new UI.ReportView.ReportView(i18n.i18n.lockedString('Service workers'));
|
|
207
206
|
this.currentWorkersView.setBodyScrollable(false);
|
|
208
207
|
this.contentElement.classList.add('service-worker-list');
|
|
@@ -221,7 +220,6 @@ export class ServiceWorkersView extends UI.Widget.VBox implements
|
|
|
221
220
|
|
|
222
221
|
const othersDiv = this.contentElement.createChild('div', 'service-workers-other-origin');
|
|
223
222
|
othersDiv.setAttribute('jslog', `${VisualLogging.section('other-origin')}`);
|
|
224
|
-
// TODO(crbug.com/1156978): Replace UI.ReportView.ReportView with ReportView.ts web component.
|
|
225
223
|
const othersView = new UI.ReportView.ReportView();
|
|
226
224
|
othersView.setHeaderVisible(false);
|
|
227
225
|
othersView.show(othersDiv);
|
|
@@ -181,7 +181,6 @@ export class StorageView extends UI.Widget.VBox {
|
|
|
181
181
|
[Protocol.Storage.StorageType.Service_workers, 'rgb(255, 167, 36)'], // orange
|
|
182
182
|
]);
|
|
183
183
|
|
|
184
|
-
// TODO(crbug.com/1156978): Replace UI.ReportView.ReportView with ReportView.ts web component.
|
|
185
184
|
this.reportView = new UI.ReportView.ReportView(i18nString(UIStrings.storageTitle));
|
|
186
185
|
this.reportView.registerRequiredCSS(storageViewStyles);
|
|
187
186
|
|