chrome-devtools-frontend 1.0.1539972 → 1.0.1541169
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/eslint.config.mjs +167 -151
- package/front_end/core/common/Revealer.ts +5 -0
- package/front_end/core/host/InspectorFrontendHost.ts +10 -10
- package/front_end/core/sdk/NetworkManager.ts +16 -11
- package/front_end/core/sdk/sdk-meta.ts +0 -35
- package/front_end/entrypoints/shell/shell.ts +1 -0
- package/front_end/entrypoints/trace_app/trace_app.ts +1 -0
- package/front_end/generated/InspectorBackendCommands.ts +6 -3
- package/front_end/generated/SupportedCSSProperties.js +13 -0
- package/front_end/generated/protocol.ts +58 -2
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +121 -56
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +104 -62
- package/front_end/models/ai_assistance/performance/AIQueries.ts +56 -2
- package/front_end/{panels/issues → models/issues_manager}/IssueAggregator.ts +83 -65
- package/front_end/models/issues_manager/issues_manager.ts +2 -0
- package/front_end/models/trace/Processor.ts +5 -4
- package/front_end/models/trace/insights/types.ts +1 -1
- package/front_end/models/trace/types/TraceEvents.ts +1 -1
- package/front_end/models/workspace/IgnoreListManager.ts +41 -47
- package/front_end/models/workspace/workspace-meta.ts +40 -0
- package/front_end/panels/animation/AnimationTimeline.ts +4 -4
- package/front_end/panels/animation/AnimationUI.ts +28 -34
- package/front_end/panels/elements/ElementsTreeElement.ts +37 -9
- package/front_end/panels/elements/LayoutPane.ts +2 -2
- package/front_end/panels/elements/components/AdornerManager.ts +9 -9
- package/front_end/panels/elements/layoutPane.css +5 -9
- package/front_end/panels/event_listeners/EventListenersView.ts +1 -1
- package/front_end/panels/explain/components/ConsoleInsight.ts +498 -449
- package/front_end/panels/issues/AffectedResourcesView.ts +3 -4
- package/front_end/panels/issues/CorsIssueDetailsView.ts +1 -2
- package/front_end/panels/issues/IssueView.ts +1 -1
- package/front_end/panels/issues/IssuesPane.ts +12 -15
- package/front_end/panels/issues/issues.ts +0 -2
- package/front_end/panels/network/NetworkDataGridNode.ts +2 -1
- package/front_end/panels/network/RequestConditionsDrawer.ts +149 -46
- package/front_end/panels/network/RequestTimingView.ts +13 -8
- package/front_end/panels/network/network-meta.ts +11 -0
- package/front_end/panels/settings/emulation/components/userAgentClientHintsForm.css +1 -1
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +1 -1
- package/front_end/panels/sources/breakpointsView.css +1 -1
- package/front_end/panels/sources/sourcesPanel.css +2 -2
- package/front_end/panels/timeline/TimelineFlameChartView.ts +3 -3
- package/front_end/panels/timeline/TimelinePanel.ts +3 -3
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +16 -10
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/markdown_view/MarkdownView.ts +1 -0
- package/front_end/ui/components/snackbars/Snackbars.docs.ts +46 -0
- package/front_end/ui/{components/docs/context_menu/basic.ts → legacy/ContextMenu.docs.ts} +58 -25
- package/front_end/ui/legacy/UIUtils.ts +2 -1
- package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +105 -92
- package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +3 -3
- package/front_end/ui/legacy/components/perf_ui/pieChart.css +1 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
- package/front_end/ui/legacy/inspectorCommon.css +3 -2
- package/mcp/mcp.ts +15 -1
- package/package.json +2 -1
- package/front_end/ui/components/docs/context_menu/basic.html +0 -45
- package/front_end/ui/components/docs/linkifier/simple-url.html +0 -25
- package/front_end/ui/components/docs/linkifier/simple-url.ts +0 -25
- package/front_end/ui/components/docs/panel_feedback/basic.html +0 -25
- package/front_end/ui/components/docs/panel_feedback/basic.ts +0 -21
- package/front_end/ui/components/docs/panel_feedback/button.html +0 -25
- package/front_end/ui/components/docs/panel_feedback/button.ts +0 -19
- package/front_end/ui/components/docs/panel_introduction_steps/basic.html +0 -25
- package/front_end/ui/components/docs/panel_introduction_steps/basic.ts +0 -28
- package/front_end/ui/components/docs/perf_piechart/basic-with-legend.html +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-with-legend.ts +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-without-legend.html +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-without-legend.ts +0 -18
- package/front_end/ui/components/docs/snackbars/basic.html +0 -17
- package/front_end/ui/components/docs/snackbars/basic.ts +0 -50
|
@@ -17,6 +17,14 @@ export interface NetworkRequestFormatOptions {
|
|
|
17
17
|
customTitle?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
interface FormatFactByInsightSetOptions {
|
|
21
|
+
insights: Trace.Insights.Types.TraceInsightSets|null;
|
|
22
|
+
title: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
empty: string;
|
|
25
|
+
cb: (insightSet: Trace.Insights.Types.InsightSet) => string | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
export class PerformanceTraceFormatter {
|
|
21
29
|
#focus: AgentFocus;
|
|
22
30
|
#parsedTrace: Trace.TraceModel.ParsedTrace;
|
|
@@ -214,21 +222,47 @@ export class PerformanceTraceFormatter {
|
|
|
214
222
|
return parts.join('\n');
|
|
215
223
|
}
|
|
216
224
|
|
|
217
|
-
|
|
218
|
-
const
|
|
219
|
-
const
|
|
225
|
+
#formatFactByInsightSet(options: FormatFactByInsightSetOptions): string {
|
|
226
|
+
const {insights, title, description, empty, cb} = options;
|
|
227
|
+
const lines = [`# ${title}\n`];
|
|
220
228
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
};
|
|
229
|
+
if (description) {
|
|
230
|
+
lines.push(`${description}\n`);
|
|
231
|
+
}
|
|
225
232
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
233
|
+
if (insights?.size) {
|
|
234
|
+
const multipleInsightSets = insights.size > 1;
|
|
235
|
+
for (const insightSet of insights.values()) {
|
|
236
|
+
if (multipleInsightSets) {
|
|
237
|
+
lines.push(`## insight set id: ${insightSet.id}\n`);
|
|
238
|
+
}
|
|
239
|
+
lines.push((cb(insightSet) ?? empty) + '\n');
|
|
240
|
+
}
|
|
241
|
+
} else {
|
|
242
|
+
lines.push(empty + '\n');
|
|
229
243
|
}
|
|
230
244
|
|
|
231
|
-
return '
|
|
245
|
+
return lines.join('\n');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
formatCriticalRequests(): string {
|
|
249
|
+
const parsedTrace = this.#parsedTrace;
|
|
250
|
+
return this.#formatFactByInsightSet({
|
|
251
|
+
insights: parsedTrace.insights,
|
|
252
|
+
title: 'Critical network requests',
|
|
253
|
+
empty: 'none',
|
|
254
|
+
cb: insightSet => {
|
|
255
|
+
const criticalRequests: Trace.Types.Events.SyntheticNetworkRequest[] = [];
|
|
256
|
+
|
|
257
|
+
const walkRequest = (node: Trace.Insights.Models.NetworkDependencyTree.CriticalRequestNode): void => {
|
|
258
|
+
criticalRequests.push(node.request);
|
|
259
|
+
node.children.forEach(walkRequest);
|
|
260
|
+
};
|
|
261
|
+
insightSet.model.NetworkDependencyTree.rootNodes.forEach(walkRequest);
|
|
262
|
+
|
|
263
|
+
return criticalRequests.length ? this.formatNetworkRequests(criticalRequests, {verbose: false}) : null;
|
|
264
|
+
},
|
|
265
|
+
});
|
|
232
266
|
}
|
|
233
267
|
|
|
234
268
|
#serializeBottomUpRootNode(rootNode: Trace.Extras.TraceTree.BottomUpRootNode, limit: number): string {
|
|
@@ -265,27 +299,31 @@ export class PerformanceTraceFormatter {
|
|
|
265
299
|
return `- self: ${millis(node.selfTime)}, total: ${millis(node.totalTime)}, source: ${source}`;
|
|
266
300
|
}
|
|
267
301
|
|
|
268
|
-
|
|
269
|
-
|
|
302
|
+
return topNodes.map(node => nodeToText.call(this, node)).join('\n');
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
#getSerializeBottomUpRootNodeFormat(limit: number): string {
|
|
306
|
+
return `This is the bottom-up summary for the entire trace. Only the top ${
|
|
270
307
|
limit} activities (sorted by self time) are shown. An activity is all the aggregated time spent on the same type of work. For example, it can be all the time spent in a specific JavaScript function, or all the time spent in a specific browser rendering stage (like layout, v8 compile, parsing html). "Self time" represents the aggregated time spent directly in an activity, across all occurrences. "Total time" represents the aggregated time spent in an activity or any of its children.`;
|
|
271
|
-
return `${format}\n\n${listText}`;
|
|
272
308
|
}
|
|
273
309
|
|
|
274
310
|
formatMainThreadBottomUpSummary(): string {
|
|
275
311
|
const parsedTrace = this.#parsedTrace;
|
|
276
|
-
const
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
312
|
+
const limit = 10;
|
|
313
|
+
return this.#formatFactByInsightSet({
|
|
314
|
+
insights: parsedTrace.insights,
|
|
315
|
+
title: 'Main thread bottom-up summary',
|
|
316
|
+
description: this.#getSerializeBottomUpRootNodeFormat(limit),
|
|
317
|
+
empty: 'no activity',
|
|
318
|
+
cb: insightSet => {
|
|
319
|
+
const rootNode = AIQueries.mainThreadActivityBottomUpSingleNavigation(
|
|
320
|
+
insightSet.navigation?.args.data?.navigationId,
|
|
321
|
+
insightSet.bounds,
|
|
322
|
+
parsedTrace,
|
|
323
|
+
);
|
|
324
|
+
return rootNode ? this.#serializeBottomUpRootNode(rootNode, limit) : null;
|
|
325
|
+
},
|
|
326
|
+
});
|
|
289
327
|
}
|
|
290
328
|
|
|
291
329
|
#formatThirdPartyEntitySummaries(summaries: Trace.Extras.ThirdParties.EntitySummary[]): string {
|
|
@@ -305,43 +343,40 @@ export class PerformanceTraceFormatter {
|
|
|
305
343
|
}
|
|
306
344
|
|
|
307
345
|
formatThirdPartySummary(): string {
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
const listText = this.#formatThirdPartyEntitySummaries(summaries);
|
|
320
|
-
if (!listText) {
|
|
321
|
-
return '';
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
return `Third party summary:\n${listText}`;
|
|
346
|
+
const parsedTrace = this.#parsedTrace;
|
|
347
|
+
return this.#formatFactByInsightSet({
|
|
348
|
+
insights: parsedTrace.insights,
|
|
349
|
+
title: '3rd party summary',
|
|
350
|
+
empty: 'no 3rd parties',
|
|
351
|
+
cb: insightSet => {
|
|
352
|
+
const thirdPartySummaries =
|
|
353
|
+
Trace.Extras.ThirdParties.summarizeByThirdParty(parsedTrace.data, insightSet.bounds);
|
|
354
|
+
return thirdPartySummaries.length ? this.#formatThirdPartyEntitySummaries(thirdPartySummaries) : null;
|
|
355
|
+
},
|
|
356
|
+
});
|
|
325
357
|
}
|
|
326
358
|
|
|
327
359
|
formatLongestTasks(): string {
|
|
328
360
|
const parsedTrace = this.#parsedTrace;
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
361
|
+
return this.#formatFactByInsightSet({
|
|
362
|
+
insights: parsedTrace.insights,
|
|
363
|
+
title: 'Longest tasks',
|
|
364
|
+
empty: 'none',
|
|
365
|
+
cb: insightSet => {
|
|
366
|
+
const longestTaskTrees =
|
|
367
|
+
AIQueries.longestTasks(insightSet.navigation?.args.data?.navigationId, insightSet.bounds, parsedTrace, 3);
|
|
368
|
+
if (!longestTaskTrees?.length) {
|
|
369
|
+
return null;
|
|
370
|
+
}
|
|
337
371
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
372
|
+
return longestTaskTrees
|
|
373
|
+
.map(tree => {
|
|
374
|
+
const time = millis(tree.rootNode.totalTime);
|
|
375
|
+
return `- total time: ${time}, event: ${this.serializeEvent(tree.rootNode.event)}`;
|
|
376
|
+
})
|
|
377
|
+
.join('\n');
|
|
378
|
+
},
|
|
379
|
+
});
|
|
345
380
|
}
|
|
346
381
|
|
|
347
382
|
#serializeRelatedInsightsForEvents(events: Trace.Types.Events.Event[]): string {
|
|
@@ -386,10 +421,16 @@ export class PerformanceTraceFormatter {
|
|
|
386
421
|
}
|
|
387
422
|
|
|
388
423
|
formatMainThreadTrackSummary(bounds: Trace.Types.Timing.TraceWindowMicro): string {
|
|
424
|
+
if (!this.#parsedTrace.insights) {
|
|
425
|
+
return 'No main thread activity found';
|
|
426
|
+
}
|
|
427
|
+
|
|
389
428
|
const results = [];
|
|
390
429
|
|
|
430
|
+
const insightSet = this.#parsedTrace.insights?.values().find(
|
|
431
|
+
insightSet => Trace.Helpers.Timing.boundsIncludeTimeRange({bounds, timeRange: insightSet.bounds}));
|
|
391
432
|
const topDownTree = AIQueries.mainThreadActivityTopDown(
|
|
392
|
-
|
|
433
|
+
insightSet?.navigation?.args.data?.navigationId,
|
|
393
434
|
bounds,
|
|
394
435
|
this.#parsedTrace,
|
|
395
436
|
);
|
|
@@ -399,13 +440,14 @@ export class PerformanceTraceFormatter {
|
|
|
399
440
|
}
|
|
400
441
|
|
|
401
442
|
const bottomUpRootNode = AIQueries.mainThreadActivityBottomUp(
|
|
402
|
-
this.#insightSet?.navigation?.args.data?.navigationId,
|
|
403
443
|
bounds,
|
|
404
444
|
this.#parsedTrace,
|
|
405
445
|
);
|
|
406
446
|
if (bottomUpRootNode) {
|
|
407
447
|
results.push('# Bottom-up main thread summary');
|
|
408
|
-
|
|
448
|
+
const limit = 20;
|
|
449
|
+
results.push(this.#getSerializeBottomUpRootNodeFormat(limit));
|
|
450
|
+
results.push(this.#serializeBottomUpRootNode(bottomUpRootNode, limit));
|
|
409
451
|
}
|
|
410
452
|
|
|
411
453
|
const thirdPartySummaries = Trace.Extras.ThirdParties.summarizeByThirdParty(this.#parsedTrace.data, bounds);
|
|
@@ -35,6 +35,10 @@ export class AIQueries {
|
|
|
35
35
|
|
|
36
36
|
const threads = Trace.Handlers.Threads.threadsInTrace(parsedTrace.data);
|
|
37
37
|
const thread = threads.find(thread => {
|
|
38
|
+
if (!thread.processIsOnMainFrame) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
if (mainThreadPID && mainThreadTID) {
|
|
39
43
|
return thread.pid === mainThreadPID && thread.tid === mainThreadTID;
|
|
40
44
|
}
|
|
@@ -45,9 +49,9 @@ export class AIQueries {
|
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
/**
|
|
48
|
-
* Returns bottom up activity for the given range.
|
|
52
|
+
* Returns bottom up activity for the given range (within a single navigation / thread).
|
|
49
53
|
*/
|
|
50
|
-
static
|
|
54
|
+
static mainThreadActivityBottomUpSingleNavigation(
|
|
51
55
|
navigationId: string|undefined, bounds: Trace.Types.Timing.TraceWindowMicro,
|
|
52
56
|
parsedTrace: Trace.TraceModel.ParsedTrace): Trace.Extras.TraceTree.BottomUpRootNode|null {
|
|
53
57
|
const thread = this.findMainThread(navigationId, parsedTrace);
|
|
@@ -76,6 +80,56 @@ export class AIQueries {
|
|
|
76
80
|
});
|
|
77
81
|
}
|
|
78
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Returns bottom up activity for the given range (no matter the navigation / thread).
|
|
85
|
+
*/
|
|
86
|
+
static mainThreadActivityBottomUp(
|
|
87
|
+
bounds: Trace.Types.Timing.TraceWindowMicro,
|
|
88
|
+
parsedTrace: Trace.TraceModel.ParsedTrace): Trace.Extras.TraceTree.BottomUpRootNode|null {
|
|
89
|
+
const threads: Trace.Handlers.Threads.ThreadData[] = [];
|
|
90
|
+
if (parsedTrace.insights) {
|
|
91
|
+
for (const insightSet of parsedTrace.insights?.values()) {
|
|
92
|
+
const thread = this.findMainThread(insightSet.navigation?.args.data?.navigationId, parsedTrace);
|
|
93
|
+
if (thread) {
|
|
94
|
+
threads.push(thread);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
const navigationId = parsedTrace.data.Meta.mainFrameNavigations[0].args.data?.navigationId;
|
|
99
|
+
const thread = this.findMainThread(navigationId, parsedTrace);
|
|
100
|
+
if (thread) {
|
|
101
|
+
threads.push(thread);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (threads.length === 0) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const threadEvents =
|
|
110
|
+
[...new Set(threads)].map(thread => AICallTree.findEventsForThread({thread, parsedTrace, bounds}) ?? []);
|
|
111
|
+
const events = threadEvents.flat();
|
|
112
|
+
|
|
113
|
+
if (events.length === 0) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Use the same filtering as front_end/panels/timeline/TimelineTreeView.ts.
|
|
118
|
+
const visibleEvents = Trace.Helpers.Trace.VISIBLE_TRACE_EVENT_TYPES.values().toArray();
|
|
119
|
+
const filter = new Trace.Extras.TraceFilter.VisibleEventsFilter(
|
|
120
|
+
visibleEvents.concat([Trace.Types.Events.Name.SYNTHETIC_NETWORK_REQUEST]));
|
|
121
|
+
|
|
122
|
+
// The bottom up root node handles all the "in Tracebounds" checks we need for the insight.
|
|
123
|
+
const startTime = Trace.Helpers.Timing.microToMilli(bounds.min);
|
|
124
|
+
const endTime = Trace.Helpers.Timing.microToMilli(bounds.max);
|
|
125
|
+
return new Trace.Extras.TraceTree.BottomUpRootNode(events, {
|
|
126
|
+
textFilter: new Trace.Extras.TraceFilter.ExclusiveNameFilter([]),
|
|
127
|
+
filters: [filter],
|
|
128
|
+
startTime,
|
|
129
|
+
endTime,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
79
133
|
/**
|
|
80
134
|
* Returns an AI Call Tree representing the activity on the main thread for
|
|
81
135
|
* the relevant time range of the given insight.
|
|
@@ -4,7 +4,29 @@
|
|
|
4
4
|
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
|
6
6
|
import type * as Protocol from '../../generated/protocol.js';
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
import {AttributionReportingIssue} from './AttributionReportingIssue.js';
|
|
9
|
+
import {ContentSecurityPolicyIssue} from './ContentSecurityPolicyIssue.js';
|
|
10
|
+
import {CookieDeprecationMetadataIssue} from './CookieDeprecationMetadataIssue.js';
|
|
11
|
+
import {CookieIssue} from './CookieIssue.js';
|
|
12
|
+
import {CorsIssue} from './CorsIssue.js';
|
|
13
|
+
import {DeprecationIssue} from './DeprecationIssue.js';
|
|
14
|
+
import {ElementAccessibilityIssue} from './ElementAccessibilityIssue.js';
|
|
15
|
+
import {GenericIssue} from './GenericIssue.js';
|
|
16
|
+
import {HeavyAdIssue} from './HeavyAdIssue.js';
|
|
17
|
+
import {Issue, IssueCategory, IssueKind, unionIssueKind} from './Issue.js';
|
|
18
|
+
import type {EventTypes as IssuesManagerEventsTypes, IssueAddedEvent} from './IssuesManager.js';
|
|
19
|
+
import {Events as IssuesManagerEvents} from './IssuesManagerEvents.js';
|
|
20
|
+
import {LowTextContrastIssue} from './LowTextContrastIssue.js';
|
|
21
|
+
import type {MarkdownIssueDescription} from './MarkdownIssueDescription.js';
|
|
22
|
+
import {MixedContentIssue} from './MixedContentIssue.js';
|
|
23
|
+
import {PartitioningBlobURLIssue} from './PartitioningBlobURLIssue.js';
|
|
24
|
+
import {QuirksModeIssue} from './QuirksModeIssue.js';
|
|
25
|
+
import {SharedArrayBufferIssue} from './SharedArrayBufferIssue.js';
|
|
26
|
+
|
|
27
|
+
export interface IssuesProvider extends Common.EventTarget.EventTarget<IssuesManagerEventsTypes> {
|
|
28
|
+
issues(): Iterable<Issue>;
|
|
29
|
+
}
|
|
8
30
|
|
|
9
31
|
interface AggregationKeyTag {
|
|
10
32
|
aggregationKeyTag: undefined;
|
|
@@ -24,7 +46,7 @@ export type AggregationKey = {
|
|
|
24
46
|
* Currently only grouping by issue code, is supported. The class provides helpers to support displaying
|
|
25
47
|
* of all resources that are affected by the aggregated issues.
|
|
26
48
|
*/
|
|
27
|
-
export class AggregatedIssue extends
|
|
49
|
+
export class AggregatedIssue extends Issue {
|
|
28
50
|
#affectedCookies = new Map<string, {
|
|
29
51
|
cookie: Protocol.Audits.AffectedCookie,
|
|
30
52
|
hasRequest: boolean,
|
|
@@ -33,24 +55,23 @@ export class AggregatedIssue extends IssuesManager.Issue.Issue {
|
|
|
33
55
|
#affectedRequests: Protocol.Audits.AffectedRequest[] = [];
|
|
34
56
|
#affectedRequestIds = new Set<Protocol.Network.RequestId>();
|
|
35
57
|
#affectedLocations = new Map<string, Protocol.Audits.SourceCodeLocation>();
|
|
36
|
-
#heavyAdIssues = new Set<
|
|
58
|
+
#heavyAdIssues = new Set<HeavyAdIssue>();
|
|
37
59
|
#blockedByResponseDetails = new Map<string, Protocol.Audits.BlockedByResponseIssueDetails>();
|
|
38
60
|
#bounceTrackingSites = new Set<string>();
|
|
39
|
-
#corsIssues = new Set<
|
|
40
|
-
#cspIssues = new Set<
|
|
41
|
-
#deprecationIssues = new Set<
|
|
42
|
-
#issueKind =
|
|
43
|
-
#lowContrastIssues = new Set<
|
|
44
|
-
#cookieDeprecationMetadataIssues =
|
|
45
|
-
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#representative?: IssuesManager.Issue.Issue;
|
|
61
|
+
#corsIssues = new Set<CorsIssue>();
|
|
62
|
+
#cspIssues = new Set<ContentSecurityPolicyIssue>();
|
|
63
|
+
#deprecationIssues = new Set<DeprecationIssue>();
|
|
64
|
+
#issueKind = IssueKind.IMPROVEMENT;
|
|
65
|
+
#lowContrastIssues = new Set<LowTextContrastIssue>();
|
|
66
|
+
#cookieDeprecationMetadataIssues = new Set<CookieDeprecationMetadataIssue>();
|
|
67
|
+
#mixedContentIssues = new Set<MixedContentIssue>();
|
|
68
|
+
#partitioningBlobURLIssues = new Set<PartitioningBlobURLIssue>();
|
|
69
|
+
#sharedArrayBufferIssues = new Set<SharedArrayBufferIssue>();
|
|
70
|
+
#quirksModeIssues = new Set<QuirksModeIssue>();
|
|
71
|
+
#attributionReportingIssues = new Set<AttributionReportingIssue>();
|
|
72
|
+
#genericIssues = new Set<GenericIssue>();
|
|
73
|
+
#elementAccessibilityIssues = new Set<ElementAccessibilityIssue>();
|
|
74
|
+
#representative?: Issue;
|
|
54
75
|
#aggregatedIssuesCount = 0;
|
|
55
76
|
#key: AggregationKey;
|
|
56
77
|
|
|
@@ -94,32 +115,31 @@ export class AggregatedIssue extends IssuesManager.Issue.Issue {
|
|
|
94
115
|
return this.#affectedCookies.values();
|
|
95
116
|
}
|
|
96
117
|
|
|
97
|
-
getHeavyAdIssues(): Iterable<
|
|
118
|
+
getHeavyAdIssues(): Iterable<HeavyAdIssue> {
|
|
98
119
|
return this.#heavyAdIssues;
|
|
99
120
|
}
|
|
100
121
|
|
|
101
|
-
getCookieDeprecationMetadataIssues():
|
|
102
|
-
Iterable<IssuesManager.CookieDeprecationMetadataIssue.CookieDeprecationMetadataIssue> {
|
|
122
|
+
getCookieDeprecationMetadataIssues(): Iterable<CookieDeprecationMetadataIssue> {
|
|
103
123
|
return this.#cookieDeprecationMetadataIssues;
|
|
104
124
|
}
|
|
105
125
|
|
|
106
|
-
getMixedContentIssues(): Iterable<
|
|
126
|
+
getMixedContentIssues(): Iterable<MixedContentIssue> {
|
|
107
127
|
return this.#mixedContentIssues;
|
|
108
128
|
}
|
|
109
129
|
|
|
110
|
-
getCorsIssues(): Set<
|
|
130
|
+
getCorsIssues(): Set<CorsIssue> {
|
|
111
131
|
return this.#corsIssues;
|
|
112
132
|
}
|
|
113
133
|
|
|
114
|
-
getCspIssues(): Iterable<
|
|
134
|
+
getCspIssues(): Iterable<ContentSecurityPolicyIssue> {
|
|
115
135
|
return this.#cspIssues;
|
|
116
136
|
}
|
|
117
137
|
|
|
118
|
-
getDeprecationIssues(): Iterable<
|
|
138
|
+
getDeprecationIssues(): Iterable<DeprecationIssue> {
|
|
119
139
|
return this.#deprecationIssues;
|
|
120
140
|
}
|
|
121
141
|
|
|
122
|
-
getLowContrastIssues(): Iterable<
|
|
142
|
+
getLowContrastIssues(): Iterable<LowTextContrastIssue> {
|
|
123
143
|
return this.#lowContrastIssues;
|
|
124
144
|
}
|
|
125
145
|
|
|
@@ -127,45 +147,45 @@ export class AggregatedIssue extends IssuesManager.Issue.Issue {
|
|
|
127
147
|
return this.#affectedRequests.values();
|
|
128
148
|
}
|
|
129
149
|
|
|
130
|
-
getSharedArrayBufferIssues(): Iterable<
|
|
150
|
+
getSharedArrayBufferIssues(): Iterable<SharedArrayBufferIssue> {
|
|
131
151
|
return this.#sharedArrayBufferIssues;
|
|
132
152
|
}
|
|
133
153
|
|
|
134
|
-
getQuirksModeIssues(): Iterable<
|
|
154
|
+
getQuirksModeIssues(): Iterable<QuirksModeIssue> {
|
|
135
155
|
return this.#quirksModeIssues;
|
|
136
156
|
}
|
|
137
157
|
|
|
138
|
-
getAttributionReportingIssues(): ReadonlySet<
|
|
158
|
+
getAttributionReportingIssues(): ReadonlySet<AttributionReportingIssue> {
|
|
139
159
|
return this.#attributionReportingIssues;
|
|
140
160
|
}
|
|
141
161
|
|
|
142
|
-
getGenericIssues(): ReadonlySet<
|
|
162
|
+
getGenericIssues(): ReadonlySet<GenericIssue> {
|
|
143
163
|
return this.#genericIssues;
|
|
144
164
|
}
|
|
145
165
|
|
|
146
|
-
getElementAccessibilityIssues(): Iterable<
|
|
166
|
+
getElementAccessibilityIssues(): Iterable<ElementAccessibilityIssue> {
|
|
147
167
|
return this.#elementAccessibilityIssues;
|
|
148
168
|
}
|
|
149
169
|
|
|
150
|
-
getDescription():
|
|
170
|
+
getDescription(): MarkdownIssueDescription|null {
|
|
151
171
|
if (this.#representative) {
|
|
152
172
|
return this.#representative.getDescription();
|
|
153
173
|
}
|
|
154
174
|
return null;
|
|
155
175
|
}
|
|
156
176
|
|
|
157
|
-
getCategory():
|
|
177
|
+
getCategory(): IssueCategory {
|
|
158
178
|
if (this.#representative) {
|
|
159
179
|
return this.#representative.getCategory();
|
|
160
180
|
}
|
|
161
|
-
return
|
|
181
|
+
return IssueCategory.OTHER;
|
|
162
182
|
}
|
|
163
183
|
|
|
164
184
|
getAggregatedIssuesCount(): number {
|
|
165
185
|
return this.#aggregatedIssuesCount;
|
|
166
186
|
}
|
|
167
187
|
|
|
168
|
-
getPartitioningBlobURLIssues(): Iterable<
|
|
188
|
+
getPartitioningBlobURLIssues(): Iterable<PartitioningBlobURLIssue> {
|
|
169
189
|
return this.#partitioningBlobURLIssues;
|
|
170
190
|
}
|
|
171
191
|
|
|
@@ -178,12 +198,12 @@ export class AggregatedIssue extends IssuesManager.Issue.Issue {
|
|
|
178
198
|
return `${domain};${path};${name}`;
|
|
179
199
|
}
|
|
180
200
|
|
|
181
|
-
addInstance(issue:
|
|
201
|
+
addInstance(issue: Issue): void {
|
|
182
202
|
this.#aggregatedIssuesCount++;
|
|
183
203
|
if (!this.#representative) {
|
|
184
204
|
this.#representative = issue;
|
|
185
205
|
}
|
|
186
|
-
this.#issueKind =
|
|
206
|
+
this.#issueKind = unionIssueKind(this.#issueKind, issue.getKind());
|
|
187
207
|
let hasRequest = false;
|
|
188
208
|
for (const request of issue.requests()) {
|
|
189
209
|
const {requestId} = request;
|
|
@@ -217,52 +237,52 @@ export class AggregatedIssue extends IssuesManager.Issue.Issue {
|
|
|
217
237
|
this.#affectedLocations.set(key, location);
|
|
218
238
|
}
|
|
219
239
|
}
|
|
220
|
-
if (issue instanceof
|
|
240
|
+
if (issue instanceof CookieDeprecationMetadataIssue) {
|
|
221
241
|
this.#cookieDeprecationMetadataIssues.add(issue);
|
|
222
242
|
}
|
|
223
|
-
if (issue instanceof
|
|
243
|
+
if (issue instanceof MixedContentIssue) {
|
|
224
244
|
this.#mixedContentIssues.add(issue);
|
|
225
245
|
}
|
|
226
|
-
if (issue instanceof
|
|
246
|
+
if (issue instanceof HeavyAdIssue) {
|
|
227
247
|
this.#heavyAdIssues.add(issue);
|
|
228
248
|
}
|
|
229
249
|
for (const details of issue.getBlockedByResponseDetails()) {
|
|
230
250
|
const key = JSON.stringify(details, ['parentFrame', 'blockedFrame', 'requestId', 'frameId', 'reason', 'request']);
|
|
231
251
|
this.#blockedByResponseDetails.set(key, details);
|
|
232
252
|
}
|
|
233
|
-
if (issue instanceof
|
|
253
|
+
if (issue instanceof ContentSecurityPolicyIssue) {
|
|
234
254
|
this.#cspIssues.add(issue);
|
|
235
255
|
}
|
|
236
|
-
if (issue instanceof
|
|
256
|
+
if (issue instanceof DeprecationIssue) {
|
|
237
257
|
this.#deprecationIssues.add(issue);
|
|
238
258
|
}
|
|
239
|
-
if (issue instanceof
|
|
259
|
+
if (issue instanceof SharedArrayBufferIssue) {
|
|
240
260
|
this.#sharedArrayBufferIssues.add(issue);
|
|
241
261
|
}
|
|
242
|
-
if (issue instanceof
|
|
262
|
+
if (issue instanceof LowTextContrastIssue) {
|
|
243
263
|
this.#lowContrastIssues.add(issue);
|
|
244
264
|
}
|
|
245
|
-
if (issue instanceof
|
|
265
|
+
if (issue instanceof CorsIssue) {
|
|
246
266
|
this.#corsIssues.add(issue);
|
|
247
267
|
}
|
|
248
|
-
if (issue instanceof
|
|
268
|
+
if (issue instanceof QuirksModeIssue) {
|
|
249
269
|
this.#quirksModeIssues.add(issue);
|
|
250
270
|
}
|
|
251
|
-
if (issue instanceof
|
|
271
|
+
if (issue instanceof AttributionReportingIssue) {
|
|
252
272
|
this.#attributionReportingIssues.add(issue);
|
|
253
273
|
}
|
|
254
|
-
if (issue instanceof
|
|
274
|
+
if (issue instanceof GenericIssue) {
|
|
255
275
|
this.#genericIssues.add(issue);
|
|
256
276
|
}
|
|
257
|
-
if (issue instanceof
|
|
277
|
+
if (issue instanceof ElementAccessibilityIssue) {
|
|
258
278
|
this.#elementAccessibilityIssues.add(issue);
|
|
259
279
|
}
|
|
260
|
-
if (issue instanceof
|
|
280
|
+
if (issue instanceof PartitioningBlobURLIssue) {
|
|
261
281
|
this.#partitioningBlobURLIssues.add(issue);
|
|
262
282
|
}
|
|
263
283
|
}
|
|
264
284
|
|
|
265
|
-
getKind():
|
|
285
|
+
getKind(): IssueKind {
|
|
266
286
|
return this.#issueKind;
|
|
267
287
|
}
|
|
268
288
|
|
|
@@ -278,17 +298,16 @@ export class AggregatedIssue extends IssuesManager.Issue.Issue {
|
|
|
278
298
|
export class IssueAggregator extends Common.ObjectWrapper.ObjectWrapper<EventTypes> {
|
|
279
299
|
readonly #aggregatedIssuesByKey = new Map<AggregationKey, AggregatedIssue>();
|
|
280
300
|
readonly #hiddenAggregatedIssuesByKey = new Map<AggregationKey, AggregatedIssue>();
|
|
281
|
-
constructor(private readonly issuesManager:
|
|
301
|
+
constructor(private readonly issuesManager: IssuesProvider) {
|
|
282
302
|
super();
|
|
283
|
-
this.issuesManager.addEventListener(
|
|
284
|
-
this.issuesManager.addEventListener(
|
|
285
|
-
IssuesManager.IssuesManager.Events.FULL_UPDATE_REQUIRED, this.#onFullUpdateRequired, this);
|
|
303
|
+
this.issuesManager.addEventListener(IssuesManagerEvents.ISSUE_ADDED, this.#onIssueAdded, this);
|
|
304
|
+
this.issuesManager.addEventListener(IssuesManagerEvents.FULL_UPDATE_REQUIRED, this.#onFullUpdateRequired, this);
|
|
286
305
|
for (const issue of this.issuesManager.issues()) {
|
|
287
306
|
this.#aggregateIssue(issue);
|
|
288
307
|
}
|
|
289
308
|
}
|
|
290
309
|
|
|
291
|
-
#onIssueAdded(event: Common.EventTarget.EventTargetEvent<
|
|
310
|
+
#onIssueAdded(event: Common.EventTarget.EventTargetEvent<IssueAddedEvent>): void {
|
|
292
311
|
this.#aggregateIssue(event.data.issue);
|
|
293
312
|
}
|
|
294
313
|
|
|
@@ -301,8 +320,8 @@ export class IssueAggregator extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
301
320
|
this.dispatchEventToListeners(Events.FULL_UPDATE_REQUIRED);
|
|
302
321
|
}
|
|
303
322
|
|
|
304
|
-
#aggregateIssue(issue:
|
|
305
|
-
if (
|
|
323
|
+
#aggregateIssue(issue: Issue): AggregatedIssue|undefined {
|
|
324
|
+
if (CookieIssue.isThirdPartyCookiePhaseoutRelatedIssue(issue)) {
|
|
306
325
|
return;
|
|
307
326
|
}
|
|
308
327
|
|
|
@@ -312,8 +331,7 @@ export class IssueAggregator extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
312
331
|
return aggregatedIssue;
|
|
313
332
|
}
|
|
314
333
|
|
|
315
|
-
#aggregateIssueByStatus(aggregatedIssuesMap: Map<AggregationKey, AggregatedIssue>, issue:
|
|
316
|
-
AggregatedIssue {
|
|
334
|
+
#aggregateIssueByStatus(aggregatedIssuesMap: Map<AggregationKey, AggregatedIssue>, issue: Issue): AggregatedIssue {
|
|
317
335
|
const key = issue.code() as unknown as AggregationKey;
|
|
318
336
|
let aggregatedIssue = aggregatedIssuesMap.get(key);
|
|
319
337
|
if (!aggregatedIssue) {
|
|
@@ -332,16 +350,16 @@ export class IssueAggregator extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
332
350
|
return new Set([...this.#aggregatedIssuesByKey.keys(), ...this.#hiddenAggregatedIssuesByKey.keys()]);
|
|
333
351
|
}
|
|
334
352
|
|
|
335
|
-
aggregatedIssueCategories(): Set<
|
|
336
|
-
const result = new Set<
|
|
353
|
+
aggregatedIssueCategories(): Set<IssueCategory> {
|
|
354
|
+
const result = new Set<IssueCategory>();
|
|
337
355
|
for (const issue of this.#aggregatedIssuesByKey.values()) {
|
|
338
356
|
result.add(issue.getCategory());
|
|
339
357
|
}
|
|
340
358
|
return result;
|
|
341
359
|
}
|
|
342
360
|
|
|
343
|
-
aggregatedIssueKinds(): Set<
|
|
344
|
-
const result = new Set<
|
|
361
|
+
aggregatedIssueKinds(): Set<IssueKind> {
|
|
362
|
+
const result = new Set<IssueKind>();
|
|
345
363
|
for (const issue of this.#aggregatedIssuesByKey.values()) {
|
|
346
364
|
result.add(issue.getKind());
|
|
347
365
|
}
|
|
@@ -356,7 +374,7 @@ export class IssueAggregator extends Common.ObjectWrapper.ObjectWrapper<EventTyp
|
|
|
356
374
|
return this.#hiddenAggregatedIssuesByKey.size;
|
|
357
375
|
}
|
|
358
376
|
|
|
359
|
-
keyForIssue(issue:
|
|
377
|
+
keyForIssue(issue: Issue<string>): AggregationKey {
|
|
360
378
|
return issue.code() as unknown as AggregationKey;
|
|
361
379
|
}
|
|
362
380
|
}
|
|
@@ -17,6 +17,7 @@ import * as FederatedAuthUserInfoRequestIssue from './FederatedAuthUserInfoReque
|
|
|
17
17
|
import * as GenericIssue from './GenericIssue.js';
|
|
18
18
|
import * as HeavyAdIssue from './HeavyAdIssue.js';
|
|
19
19
|
import * as Issue from './Issue.js';
|
|
20
|
+
import * as IssueAggregator from './IssueAggregator.js';
|
|
20
21
|
import * as IssueResolver from './IssueResolver.js';
|
|
21
22
|
import * as IssuesManager from './IssuesManager.js';
|
|
22
23
|
import * as LowTextContrastIssue from './LowTextContrastIssue.js';
|
|
@@ -49,6 +50,7 @@ export {
|
|
|
49
50
|
GenericIssue,
|
|
50
51
|
HeavyAdIssue,
|
|
51
52
|
Issue,
|
|
53
|
+
IssueAggregator,
|
|
52
54
|
IssueResolver,
|
|
53
55
|
IssuesManager,
|
|
54
56
|
LowTextContrastIssue,
|