chrome-devtools-mcp 0.2.0 → 0.2.2

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.
Files changed (62) hide show
  1. package/README.md +27 -8
  2. package/build/node_modules/chrome-devtools-frontend/front_end/core/common/Progress.js +60 -53
  3. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/GdpClient.js +1 -1
  4. package/build/node_modules/chrome-devtools-frontend/front_end/core/host/UserMetrics.js +5 -2
  5. package/build/node_modules/chrome-devtools-frontend/front_end/core/protocol_client/InspectorBackend.js +2 -0
  6. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSMatchedStyles.js +11 -10
  7. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSModel.js +1 -1
  8. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/CSSPropertyParserMatchers.js +24 -4
  9. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/DebuggerModel.js +1 -1
  10. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/EnhancedTracesParser.js +29 -24
  11. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkManager.js +1 -1
  12. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/NetworkRequest.js +1 -1
  13. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RehydratingConnection.js +9 -15
  14. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RemoteObject.js +1 -1
  15. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ResourceTreeModel.js +1 -1
  16. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/RuntimeModel.js +1 -1
  17. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/ServiceWorkerManager.js +1 -1
  18. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/SourceMap.js +4 -31
  19. package/build/node_modules/chrome-devtools-frontend/front_end/core/sdk/TraceObject.js +5 -2
  20. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.js +6 -4
  21. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/PerformanceInsightFormatter.js +259 -179
  22. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/data_formatters/UnitFormatters.js +10 -1
  23. package/build/node_modules/chrome-devtools-frontend/front_end/models/ai_assistance/performance/AIContext.js +14 -3
  24. package/build/node_modules/chrome-devtools-frontend/front_end/models/bindings/ContentProviderBasedProject.js +6 -4
  25. package/build/node_modules/chrome-devtools-frontend/front_end/models/formatter/FormatterWorkerPool.js +2 -2
  26. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/ModelImpl.js +4 -9
  27. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/Processor.js +17 -9
  28. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/AuctionWorkletsHandler.js +1 -1
  29. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/FramesHandler.js +2 -2
  30. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/LayoutShiftsHandler.js +3 -4
  31. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/MetaHandler.js +10 -9
  32. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/ScreenshotsHandler.js +0 -1
  33. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/ScriptsHandler.js +4 -4
  34. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/UserInteractionsHandler.js +2 -10
  35. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/handlers/UserTimingsHandler.js +3 -4
  36. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/helpers/SamplesIntegrator.js +8 -6
  37. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/CLSCulprits.js +1 -1
  38. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DocumentLatency.js +3 -3
  39. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/DuplicatedJavaScript.js +1 -1
  40. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/INPBreakdown.js +1 -1
  41. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ImageDelivery.js +1 -1
  42. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPBreakdown.js +1 -1
  43. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/LCPDiscovery.js +1 -1
  44. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/ModernHTTP.js +1 -1
  45. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/NetworkDependencyTree.js +1 -1
  46. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/insights/RenderBlocking.js +1 -1
  47. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace/types/TraceEvents.js +21 -21
  48. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace_source_maps_resolver/SourceMapsResolver.js +5 -3
  49. package/build/node_modules/chrome-devtools-frontend/front_end/models/trace_source_maps_resolver/trace_source_maps_resolver.js +1 -1
  50. package/build/src/McpContext.js +60 -10
  51. package/build/src/McpResponse.js +5 -4
  52. package/build/src/WaitForHelper.js +127 -0
  53. package/build/src/browser.js +12 -9
  54. package/build/src/index.js +20 -21
  55. package/build/src/logger.js +1 -0
  56. package/build/src/tools/input.js +5 -6
  57. package/build/src/tools/pages.js +2 -3
  58. package/build/src/tools/performance.js +16 -14
  59. package/build/src/tools/script.js +1 -2
  60. package/build/src/trace-processing/parse.js +23 -14
  61. package/package.json +15 -16
  62. package/build/src/waitForHelpers.js +0 -109
package/README.md CHANGED
@@ -2,15 +2,16 @@
2
2
 
3
3
  [![npm chrome-devtools-mcp package](https://img.shields.io/npm/v/chrome-devtools-mcp.svg)](https://npmjs.org/package/chrome-devtools-mcp)
4
4
 
5
- `chrome-devtools-mcp` is a Model-Context-Protocol (MCP) server that brings
6
- the power of Chrome DevTools to coding agents. Using it, coding agents can live
7
- debug style, performance or networking issues directly in Chrome.
5
+ `chrome-devtools-mcp` lets your coding agent (such as Gemini, Claude, Cursor or Copilot)
6
+ control and inspect a live Chrome browser. It acts as a Model-Context-Protocol
7
+ (MCP) server, giving your AI coding assistant access to the full power of
8
+ Chrome DevTools for reliable automation, in-depth debugging, and performance analysis.
8
9
 
9
10
  ## Key features
10
11
 
11
12
  - **Get performance insights**: Uses [Chrome
12
13
  DevTools](https://github.com/ChromeDevTools/devtools-frontend) to record
13
- traces and extract performance insights.
14
+ traces and extract actionable performance insights.
14
15
  - **Advanced browser debugging**: Analyze network requests, take screenshots and
15
16
  check the browser console.
16
17
  - **Reliable automation**. Uses
@@ -48,7 +49,7 @@ Add the following config to your MCP client:
48
49
  > [!NOTE]
49
50
  > Using `chrome-devtools-mcp@latest` ensures that your MCP client will always use the latest version of the Chrome DevTools MCP server.
50
51
 
51
- ### MCP Client specific configuration
52
+ ### MCP Client configuration
52
53
 
53
54
  <details>
54
55
  <summary>Claude Code</summary>
@@ -77,7 +78,15 @@ claude mcp add chrome-devtools npx chrome-devtools-mcp@latest
77
78
 
78
79
  <details>
79
80
  <summary>Cursor</summary>
80
- Follow https://docs.cursor.com/en/context/mcp#using-mcp-json and use the config provided above.
81
+
82
+ **Click the button to install:**
83
+
84
+ [<img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Install in Cursor">](https://cursor.com/en/install-mcp?name=chrome-devtools&config=eyJjb21tYW5kIjoibnB4IGNocm9tZS1kZXZ0b29scy1tY3BAbGF0ZXN0In0%3D)
85
+
86
+ **Or install manually:**
87
+
88
+ Go to `Cursor Settings` -> `MCP` -> `New MCP Server`. Use the config provided above.
89
+
81
90
  </details>
82
91
 
83
92
  <details>
@@ -156,10 +165,9 @@ The Chrome DevTools MCP server supports the following configuration option:
156
165
  - **Default:** `false`
157
166
 
158
167
  - **`--channel`**
159
- Specify a different Chrome channel that should be used.
168
+ Specify a different Chrome channel that should be used. The default is the stable channel version.
160
169
  - **Type:** string
161
170
  - **Choices:** `stable`, `canary`, `beta`, `dev`
162
- - **Default:** `stable`
163
171
 
164
172
  <!-- END AUTO GENERATED OPTIONS -->
165
173
 
@@ -197,3 +205,14 @@ The user data directory is not cleared between runs and shared across
197
205
  all instances of `chrome-devtools-mcp`. Set the `isolated` option to `true`
198
206
  to use a temporary user data dir instead which will be cleared automatically after
199
207
  the browser is closed.
208
+
209
+ ## Known limitations
210
+
211
+ ### Operating system sandboxes
212
+
213
+ Some MCP clients allow sandboxing the MCP server using macOS Seatbelt or Linux
214
+ containers. If sandboxes are enabled, `chrome-devtools-mcp` is not able to start
215
+ Chrome that requires permissions to create its own sandboxes. As a workaround,
216
+ either disable sandboxing for `chrome-devtools-mcp` in your MCP client or use
217
+ `--connect-url` to connect to a Chrome instance that you start manually outside
218
+ of the MCP client sandbox.
@@ -2,19 +2,11 @@
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
4
  export class Progress {
5
- setTotalWork(_totalWork) {
6
- }
7
- setTitle(_title) {
8
- }
9
- setWorked(_worked, _title) {
10
- }
11
- incrementWorked(_worked) {
12
- }
13
- done() {
14
- }
15
- isCanceled() {
16
- return false;
17
- }
5
+ totalWork = 0;
6
+ worked = 0;
7
+ title = undefined;
8
+ canceled = false;
9
+ done = false;
18
10
  }
19
11
  export class CompositeProgress {
20
12
  parent;
@@ -24,14 +16,14 @@ export class CompositeProgress {
24
16
  this.parent = parent;
25
17
  this.#children = [];
26
18
  this.#childrenDone = 0;
27
- this.parent.setTotalWork(1);
28
- this.parent.setWorked(0);
19
+ this.parent.totalWork = 1;
20
+ this.parent.worked = 0;
29
21
  }
30
22
  childDone() {
31
23
  if (++this.#childrenDone !== this.#children.length) {
32
24
  return;
33
25
  }
34
- this.parent.done();
26
+ this.parent.done = true;
35
27
  }
36
28
  createSubProgress(weight) {
37
29
  const child = new SubProgress(this, weight);
@@ -43,12 +35,12 @@ export class CompositeProgress {
43
35
  let done = 0;
44
36
  for (let i = 0; i < this.#children.length; ++i) {
45
37
  const child = this.#children[i];
46
- if (child.getTotalWork()) {
47
- done += child.getWeight() * child.getWorked() / child.getTotalWork();
38
+ if (child.totalWork) {
39
+ done += child.weight * child.worked / child.totalWork;
48
40
  }
49
- totalWeights += child.getWeight();
41
+ totalWeights += child.weight;
50
42
  }
51
- this.parent.setWorked(done / totalWeights);
43
+ this.parent.worked = done / totalWeights;
52
44
  }
53
45
  }
54
46
  export class SubProgress {
@@ -62,76 +54,91 @@ export class SubProgress {
62
54
  this.#worked = 0;
63
55
  this.#totalWork = 0;
64
56
  }
65
- isCanceled() {
66
- return this.#composite.parent.isCanceled();
57
+ get canceled() {
58
+ return this.#composite.parent.canceled;
67
59
  }
68
- setTitle(title) {
69
- this.#composite.parent.setTitle(title);
60
+ set title(title) {
61
+ this.#composite.parent.title = title;
70
62
  }
71
- done() {
72
- this.setWorked(this.#totalWork);
63
+ set done(done) {
64
+ if (!done) {
65
+ return;
66
+ }
67
+ this.worked = this.#totalWork;
73
68
  this.#composite.childDone();
74
69
  }
75
- setTotalWork(totalWork) {
70
+ set totalWork(totalWork) {
76
71
  this.#totalWork = totalWork;
77
72
  this.#composite.update();
78
73
  }
79
- setWorked(worked, title) {
74
+ set worked(worked) {
80
75
  this.#worked = worked;
81
- if (typeof title !== 'undefined') {
82
- this.setTitle(title);
83
- }
84
76
  this.#composite.update();
85
77
  }
86
- incrementWorked(worked) {
87
- this.setWorked(this.#worked + (worked || 1));
88
- }
89
- getWeight() {
78
+ get weight() {
90
79
  return this.#weight;
91
80
  }
92
- getWorked() {
81
+ get worked() {
93
82
  return this.#worked;
94
83
  }
95
- getTotalWork() {
84
+ get totalWork() {
96
85
  return this.#totalWork;
97
86
  }
98
87
  }
99
88
  export class ProgressProxy {
100
89
  #delegate;
101
90
  #doneCallback;
102
- constructor(delegate, doneCallback) {
91
+ #updateCallback;
92
+ constructor(delegate, doneCallback, updateCallback) {
103
93
  this.#delegate = delegate;
104
94
  this.#doneCallback = doneCallback;
95
+ this.#updateCallback = updateCallback;
105
96
  }
106
- isCanceled() {
107
- return this.#delegate ? this.#delegate.isCanceled() : false;
97
+ get canceled() {
98
+ return this.#delegate ? this.#delegate.canceled : false;
108
99
  }
109
- setTitle(title) {
100
+ set title(title) {
110
101
  if (this.#delegate) {
111
- this.#delegate.setTitle(title);
102
+ this.#delegate.title = title;
103
+ }
104
+ if (this.#updateCallback) {
105
+ this.#updateCallback();
112
106
  }
113
107
  }
114
- done() {
108
+ get title() {
109
+ return this.#delegate?.title ?? '';
110
+ }
111
+ set done(done) {
115
112
  if (this.#delegate) {
116
- this.#delegate.done();
113
+ this.#delegate.done = done;
117
114
  }
118
- if (this.#doneCallback) {
115
+ if (done && this.#doneCallback) {
119
116
  this.#doneCallback();
120
117
  }
121
118
  }
122
- setTotalWork(totalWork) {
123
- if (this.#delegate) {
124
- this.#delegate.setTotalWork(totalWork);
125
- }
119
+ get done() {
120
+ return this.#delegate ? this.#delegate.done : false;
126
121
  }
127
- setWorked(worked, title) {
122
+ set totalWork(totalWork) {
128
123
  if (this.#delegate) {
129
- this.#delegate.setWorked(worked, title);
124
+ this.#delegate.totalWork = totalWork;
130
125
  }
126
+ if (this.#updateCallback) {
127
+ this.#updateCallback();
128
+ }
129
+ }
130
+ get totalWork() {
131
+ return this.#delegate ? this.#delegate.totalWork : 0;
131
132
  }
132
- incrementWorked(worked) {
133
+ set worked(worked) {
133
134
  if (this.#delegate) {
134
- this.#delegate.incrementWorked(worked);
135
+ this.#delegate.worked = worked;
135
136
  }
137
+ if (this.#updateCallback) {
138
+ this.#updateCallback?.();
139
+ }
140
+ }
141
+ get worked() {
142
+ return this.#delegate ? this.#delegate.worked : 0;
136
143
  }
137
144
  }
@@ -39,7 +39,7 @@ function normalizeBadgeName(name) {
39
39
  }
40
40
  export const GOOGLE_DEVELOPER_PROGRAM_PROFILE_LINK = 'https://developers.google.com/profile/u/me';
41
41
  async function makeHttpRequest(request) {
42
- if (!Root.Runtime.hostConfig.devToolsGdpProfiles?.enabled) {
42
+ if (!Root.Runtime.hostConfig.devToolsGdpProfiles?.enabled || Root.Runtime.hostConfig.isOffTheRecord) {
43
43
  return null;
44
44
  }
45
45
  const response = await new Promise(resolve => {
@@ -418,7 +418,11 @@ export var Action;
418
418
  Action[Action["AiAssistanceOpenedFromPerformanceInsight"] = 182] = "AiAssistanceOpenedFromPerformanceInsight";
419
419
  Action[Action["AiAssistanceOpenedFromPerformanceFullButton"] = 183] = "AiAssistanceOpenedFromPerformanceFullButton";
420
420
  Action[Action["AiCodeCompletionResponseServedFromCache"] = 184] = "AiCodeCompletionResponseServedFromCache";
421
- Action[Action["MAX_VALUE"] = 185] = "MAX_VALUE";
421
+ Action[Action["AiCodeCompletionRequestTriggered"] = 185] = "AiCodeCompletionRequestTriggered";
422
+ Action[Action["AiCodeCompletionSuggestionDisplayed"] = 186] = "AiCodeCompletionSuggestionDisplayed";
423
+ Action[Action["AiCodeCompletionSuggestionAccepted"] = 187] = "AiCodeCompletionSuggestionAccepted";
424
+ Action[Action["AiCodeCompletionError"] = 188] = "AiCodeCompletionError";
425
+ Action[Action["MAX_VALUE"] = 189] = "MAX_VALUE";
422
426
  /* eslint-enable @typescript-eslint/naming-convention */
423
427
  })(Action || (Action = {}));
424
428
  export var PanelCodes;
@@ -694,7 +698,6 @@ export var DevtoolsExperiments;
694
698
  DevtoolsExperiments[DevtoolsExperiments["just-my-code"] = 65] = "just-my-code";
695
699
  DevtoolsExperiments[DevtoolsExperiments["use-source-map-scopes"] = 76] = "use-source-map-scopes";
696
700
  DevtoolsExperiments[DevtoolsExperiments["timeline-show-postmessage-events"] = 86] = "timeline-show-postmessage-events";
697
- DevtoolsExperiments[DevtoolsExperiments["timeline-save-as-gz"] = 108] = "timeline-save-as-gz";
698
701
  DevtoolsExperiments[DevtoolsExperiments["timeline-enhanced-traces"] = 90] = "timeline-enhanced-traces";
699
702
  DevtoolsExperiments[DevtoolsExperiments["timeline-compiled-sources"] = 91] = "timeline-compiled-sources";
700
703
  DevtoolsExperiments[DevtoolsExperiments["timeline-debug-mode"] = 93] = "timeline-debug-mode";
@@ -81,10 +81,12 @@ export class InspectorBackend {
81
81
  }
82
82
  let connectionFactory;
83
83
  export class Connection {
84
+ // on message from browser
84
85
  setOnMessage(_onMessage) {
85
86
  }
86
87
  setOnDisconnect(_onDisconnect) {
87
88
  }
89
+ // send raw CDP message to browser
88
90
  sendRawMessage(_message) {
89
91
  }
90
92
  disconnect() {
@@ -5,7 +5,7 @@ import * as Platform from '../platform/platform.js';
5
5
  import { CSSMetadata, cssMetadata } from './CSSMetadata.js';
6
6
  import { CSSProperty } from './CSSProperty.js';
7
7
  import * as PropertyParser from './CSSPropertyParser.js';
8
- import { AnchorFunctionMatcher, AngleMatcher, AttributeMatcher, AutoBaseMatcher, BaseVariableMatcher, BezierMatcher, BinOpMatcher, ColorMatcher, ColorMixMatcher, defaultValueForCSSType, EnvFunctionMatcher, FlexGridMatcher, GridTemplateMatcher, LengthMatcher, LightDarkColorMatcher, LinearGradientMatcher, LinkableNameMatcher, localEvalCSS, MathFunctionMatcher, PositionAnchorMatcher, PositionTryMatcher, RelativeColorChannelMatcher, ShadowMatcher, StringMatcher, URLMatcher, VariableMatcher } from './CSSPropertyParserMatchers.js';
8
+ import { AnchorFunctionMatcher, AngleMatcher, AttributeMatcher, AutoBaseMatcher, BaseVariableMatcher, BezierMatcher, BinOpMatcher, ColorMatcher, ColorMixMatcher, CustomFunctionMatcher, defaultValueForCSSType, EnvFunctionMatcher, FlexGridMatcher, GridTemplateMatcher, LengthMatcher, LightDarkColorMatcher, LinearGradientMatcher, LinkableNameMatcher, localEvalCSS, MathFunctionMatcher, PositionAnchorMatcher, PositionTryMatcher, RelativeColorChannelMatcher, ShadowMatcher, StringMatcher, URLMatcher, VariableMatcher } from './CSSPropertyParserMatchers.js';
9
9
  import { CSSFontPaletteValuesRule, CSSFunctionRule, CSSKeyframeRule, CSSKeyframesRule, CSSPositionTryRule, CSSPropertyRule, CSSStyleRule, } from './CSSRule.js';
10
10
  import { CSSStyleDeclaration, Type } from './CSSStyleDeclaration.js';
11
11
  function containsStyle(styles, query) {
@@ -713,6 +713,7 @@ export class CSSMatchedStyles {
713
713
  new PositionTryMatcher(),
714
714
  new LengthMatcher(),
715
715
  new MathFunctionMatcher(),
716
+ new CustomFunctionMatcher(),
716
717
  new AutoBaseMatcher(),
717
718
  new BinOpMatcher(),
718
719
  new RelativeColorChannelMatcher(),
@@ -997,9 +998,9 @@ class DOMInheritanceCascade {
997
998
  if (!nodeCascade) {
998
999
  return null;
999
1000
  }
1000
- return this.innerComputeCSSVariable(nodeCascade, variableName);
1001
+ return this.#computeCSSVariable(nodeCascade, variableName);
1001
1002
  }
1002
- innerComputeCSSVariable(nodeCascade, variableName, sccRecord = new SCCRecord()) {
1003
+ #computeCSSVariable(nodeCascade, variableName, sccRecord = new SCCRecord()) {
1003
1004
  const availableCSSVariables = this.#availableCSSVariables.get(nodeCascade);
1004
1005
  const computedCSSVariables = this.#computedCSSVariables.get(nodeCascade);
1005
1006
  if (!computedCSSVariables || !availableCSSVariables?.has(variableName)) {
@@ -1029,7 +1030,7 @@ class DOMInheritanceCascade {
1029
1030
  if (!ast) {
1030
1031
  return null;
1031
1032
  }
1032
- return this.innerWalkTree(nodeCascade, ast, definedValue.declaration.style, variableName, sccRecord, definedValue.declaration);
1033
+ return this.#walkTree(nodeCascade, ast, definedValue.declaration.style, variableName, sccRecord, definedValue.declaration);
1033
1034
  }
1034
1035
  computeAttribute(style, attributeName, type) {
1035
1036
  this.ensureInitialized();
@@ -1037,7 +1038,7 @@ class DOMInheritanceCascade {
1037
1038
  if (!nodeCascade) {
1038
1039
  return null;
1039
1040
  }
1040
- return this.innerComputeAttribute(nodeCascade, style, attributeName, type, new SCCRecord());
1041
+ return this.#computeAttribute(nodeCascade, style, attributeName, type, new SCCRecord());
1041
1042
  }
1042
1043
  attributeValueAsType(style, attributeName, type) {
1043
1044
  const rawValue = this.#matchedStyles.rawAttributeValueFromStyle(style, attributeName);
@@ -1055,9 +1056,9 @@ class DOMInheritanceCascade {
1055
1056
  if (!ast) {
1056
1057
  return null;
1057
1058
  }
1058
- return this.innerWalkTree(nodeCascade, ast, style, `attr(${attributeName})`, sccRecord)?.value ?? null;
1059
+ return this.#walkTree(nodeCascade, ast, style, `attr(${attributeName})`, sccRecord)?.value ?? null;
1059
1060
  }
1060
- innerComputeAttribute(nodeCascade, style, attributeName, type, sccRecord = new SCCRecord()) {
1061
+ #computeAttribute(nodeCascade, style, attributeName, type, sccRecord = new SCCRecord()) {
1061
1062
  if (type.isCSSTokens) {
1062
1063
  const value = this.attributeValueWithSubstitutions(nodeCascade, style, attributeName, sccRecord);
1063
1064
  if (value !== null && localEvalCSS(value, type.type) !== null) {
@@ -1067,7 +1068,7 @@ class DOMInheritanceCascade {
1067
1068
  }
1068
1069
  return this.attributeValueAsType(style, attributeName, type.type);
1069
1070
  }
1070
- innerWalkTree(outerNodeCascade, ast, parentStyle, substitutionName, sccRecord, declaration) {
1071
+ #walkTree(outerNodeCascade, ast, parentStyle, substitutionName, sccRecord, declaration) {
1071
1072
  const record = sccRecord.add(outerNodeCascade, substitutionName);
1072
1073
  const computedCSSVariablesMap = this.#computedCSSVariables;
1073
1074
  const innerNodeCascade = this.#styleToNodeCascade.get(parentStyle);
@@ -1081,7 +1082,7 @@ class DOMInheritanceCascade {
1081
1082
  // bubbling up the minimum discovery time whenever we close a cycle.
1082
1083
  const matching = PropertyParser.BottomUpTreeMatching.walk(ast, [
1083
1084
  new BaseVariableMatcher(match => {
1084
- const { value, mayFallback } = recurseWithCycleDetection(match.name, nodeCascade => this.innerComputeCSSVariable(nodeCascade, match.name, sccRecord)?.value ?? null);
1085
+ const { value, mayFallback } = recurseWithCycleDetection(match.name, nodeCascade => this.#computeCSSVariable(nodeCascade, match.name, sccRecord)?.value ?? null);
1085
1086
  if (!mayFallback || value !== null) {
1086
1087
  return value;
1087
1088
  }
@@ -1268,7 +1269,7 @@ class DOMInheritanceCascade {
1268
1269
  for (const variableName of variableNames) {
1269
1270
  const prevValue = accumulatedCSSVariables.get(variableName);
1270
1271
  accumulatedCSSVariables.delete(variableName);
1271
- const computedValue = this.innerComputeCSSVariable(nodeCascade, variableName);
1272
+ const computedValue = this.#computeCSSVariable(nodeCascade, variableName);
1272
1273
  if (prevValue && computedValue?.value === prevValue.value) {
1273
1274
  computedValue.declaration = prevValue.declaration;
1274
1275
  }
@@ -1,4 +1,4 @@
1
- // Copyright 2021 The Chromium Authors
1
+ // Copyright 2010 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
4
  import * as TextUtils from '../../models/text_utils/text_utils.js';
@@ -750,9 +750,6 @@ export class LinkableNameMatcher extends matcherBase(LinkableNameMatch) {
750
750
  if (!parentNode) {
751
751
  return null;
752
752
  }
753
- if (parentNode.name === 'CallExpression' && node.name === 'VariableName') {
754
- return new LinkableNameMatch(text, node, "function" /* LinkableNameProperties.FUNCTION */);
755
- }
756
753
  if (!(propertyName && LinkableNameMatcher.isLinkableNameProperty(propertyName))) {
757
754
  return null;
758
755
  }
@@ -906,7 +903,7 @@ export class LengthMatcher extends matcherBase(LengthMatch) {
906
903
  return new LengthMatch(text, node, unit);
907
904
  }
908
905
  }
909
- export class MathFunctionMatch {
906
+ export class BaseFunctionMatch {
910
907
  text;
911
908
  node;
912
909
  func;
@@ -917,6 +914,8 @@ export class MathFunctionMatch {
917
914
  this.func = func;
918
915
  this.args = args;
919
916
  }
917
+ }
918
+ export class MathFunctionMatch extends BaseFunctionMatch {
920
919
  isArithmeticFunctionCall() {
921
920
  const func = this.func;
922
921
  switch (func) {
@@ -969,6 +968,27 @@ export class MathFunctionMatcher extends matcherBase(MathFunctionMatch) {
969
968
  return match;
970
969
  }
971
970
  }
971
+ export class CustomFunctionMatch extends BaseFunctionMatch {
972
+ }
973
+ // clang-format off
974
+ export class CustomFunctionMatcher extends matcherBase(CustomFunctionMatch) {
975
+ // clang-format on
976
+ matches(node, matching) {
977
+ if (node.name !== 'CallExpression') {
978
+ return null;
979
+ }
980
+ const callee = matching.ast.text(node.getChild('VariableName'));
981
+ if (!callee?.startsWith('--')) {
982
+ return null;
983
+ }
984
+ const args = ASTUtils.callArgs(node);
985
+ if (args.some(arg => arg.length === 0 || matching.hasUnresolvedSubstitutionsRange(arg[0], arg[arg.length - 1]))) {
986
+ return null;
987
+ }
988
+ const text = matching.ast.text(node);
989
+ return new CustomFunctionMatch(text, node, callee, args);
990
+ }
991
+ }
972
992
  export class FlexGridMatch {
973
993
  text;
974
994
  node;
@@ -1,4 +1,4 @@
1
- // Copyright 2021 The Chromium Authors
1
+ // Copyright 2010 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
4
  import * as Common from '../common/common.js';
@@ -27,7 +27,7 @@ export class EnhancedTracesParser {
27
27
  }
28
28
  parseEnhancedTrace() {
29
29
  for (const event of this.#trace.traceEvents) {
30
- if (this.isTracingStartInBrowserEvent(event)) {
30
+ if (this.isTracingStartedInBrowser(event)) {
31
31
  // constructs all targets by devtools.timeline TracingStartedInBrowser
32
32
  const data = event.args?.data;
33
33
  for (const frame of data.frames) {
@@ -53,7 +53,7 @@ export class EnhancedTracesParser {
53
53
  this.#scriptToFrame.set(this.getScriptIsolateId(data.isolate, data.scriptId), data.frame);
54
54
  }
55
55
  }
56
- else if (this.isTargetRundownEvent(event)) {
56
+ else if (this.isRundownScriptCompiled(event)) {
57
57
  // Set up script to v8 context mapping
58
58
  const data = event.args?.data;
59
59
  this.#scriptToV8Context.set(this.getScriptIsolateId(data.isolate, data.scriptId), data.v8context);
@@ -64,7 +64,7 @@ export class EnhancedTracesParser {
64
64
  this.#targets.push({
65
65
  targetId: frameId,
66
66
  type: data.frameType,
67
- isolate: data.isolate,
67
+ isolate: String(data.isolate),
68
68
  pid: event.pid,
69
69
  url: data.url,
70
70
  });
@@ -80,34 +80,37 @@ export class EnhancedTracesParser {
80
80
  isDefault: data.isDefault,
81
81
  type: data.contextType,
82
82
  },
83
- isolate: data.isolate,
83
+ isolate: String(data.isolate),
84
+ name: data.origin,
85
+ uniqueId: `${data.v8context}-${data.isolate}`,
84
86
  });
85
87
  }
86
88
  }
87
- else if (this.isScriptRundownEvent(event)) {
89
+ else if (this.isRundownScript(event)) {
88
90
  this.#scriptRundownEvents.push(event);
89
91
  const data = event.args.data;
90
92
  // Add script
91
- if (!this.#scripts.find(script => script.scriptId === String(data.scriptId) && script.isolate === data.isolate)) {
93
+ if (!this.#scripts.find(script => script.scriptId === String(data.scriptId) && script.isolate === String(data.isolate))) {
92
94
  this.#scripts.push({
93
95
  scriptId: String(data.scriptId),
94
- isolate: data.isolate,
96
+ isolate: String(data.isolate),
97
+ buildId: '',
95
98
  executionContextId: data.executionContextId,
96
99
  startLine: data.startLine ?? 0,
97
100
  startColumn: data.startColumn ?? 0,
98
101
  endLine: data.endLine ?? 0,
99
102
  endColumn: data.endColumn ?? 0,
100
- hash: data.hash,
103
+ hash: data.hash ?? '',
101
104
  isModule: data.isModule,
102
- url: data.url,
105
+ url: data.url ?? '',
103
106
  hasSourceURL: data.hasSourceUrl,
104
- sourceURL: data.sourceUrl,
107
+ sourceURL: data.sourceUrl ?? '',
105
108
  sourceMapURL: data.sourceMapUrl,
106
109
  pid: event.pid,
107
110
  });
108
111
  }
109
112
  }
110
- else if (this.isScriptRundownSourceEvent(event)) {
113
+ else if (this.isRundownScriptSource(event)) {
111
114
  // Set up script to source text and length mapping
112
115
  const data = event.args.data;
113
116
  const scriptIsolateId = this.getScriptIsolateId(data.isolate, data.scriptId);
@@ -166,10 +169,10 @@ export class EnhancedTracesParser {
166
169
  // put in the aux data
167
170
  const linkedExecutionContext = this.#executionContexts.find(context => context.id === script.executionContextId && context.isolate === script.isolate);
168
171
  if (linkedExecutionContext) {
169
- script.auxData = linkedExecutionContext.auxData;
172
+ script.executionContextAuxData = linkedExecutionContext.auxData;
170
173
  // If a script successfully mapped to an execution context and aux data, link script to frame
171
- if (script.auxData?.frameId) {
172
- this.#scriptToFrame.set(scriptIsolateId, script.auxData?.frameId);
174
+ if (script.executionContextAuxData?.frameId) {
175
+ this.#scriptToFrame.set(scriptIsolateId, script.executionContextAuxData?.frameId);
173
176
  }
174
177
  }
175
178
  });
@@ -225,25 +228,25 @@ export class EnhancedTracesParser {
225
228
  return sourceMap;
226
229
  }
227
230
  getScriptIsolateId(isolate, scriptId) {
228
- return scriptId + '@' + isolate;
231
+ return `${scriptId}@${isolate}`;
229
232
  }
230
233
  getExecutionContextIsolateId(isolate, executionContextId) {
231
- return executionContextId + '@' + isolate;
234
+ return `${executionContextId}@${isolate}`;
232
235
  }
233
236
  isTraceEvent(event) {
234
- return 'cat' in event && 'pid' in event &&
235
- 'args' in event && 'data' in event.args;
237
+ return 'cat' in event && 'pid' in event && 'args' in event &&
238
+ 'data' in event.args;
236
239
  }
237
- isTargetRundownEvent(event) {
240
+ isRundownScriptCompiled(event) {
238
241
  return this.isTraceEvent(event) && event.cat === 'disabled-by-default-devtools.target-rundown';
239
242
  }
240
- isScriptRundownEvent(event) {
243
+ isRundownScript(event) {
241
244
  return this.isTraceEvent(event) && event.cat === 'disabled-by-default-devtools.v8-source-rundown';
242
245
  }
243
- isScriptRundownSourceEvent(event) {
246
+ isRundownScriptSource(event) {
244
247
  return this.isTraceEvent(event) && event.cat === 'disabled-by-default-devtools.v8-source-rundown-sources';
245
248
  }
246
- isTracingStartInBrowserEvent(event) {
249
+ isTracingStartedInBrowser(event) {
247
250
  return this.isTraceEvent(event) && event.cat === 'disabled-by-default-devtools.timeline' &&
248
251
  event.name === 'TracingStartedInBrowser';
249
252
  }
@@ -279,8 +282,8 @@ export class EnhancedTracesParser {
279
282
  // Put all of the scripts under respective targets with collected information
280
283
  for (const script of scripts) {
281
284
  const scriptExecutionContextIsolateId = this.getExecutionContextIsolateId(script.isolate, script.executionContextId);
282
- const scriptFrameId = script.auxData?.frameId;
283
- if (script.auxData?.frameId && targetIds.has(scriptFrameId)) {
285
+ const scriptFrameId = script.executionContextAuxData?.frameId;
286
+ if (script.executionContextAuxData?.frameId && targetIds.has(scriptFrameId)) {
284
287
  targetToScripts.get(scriptFrameId)?.push(script);
285
288
  executionContextIsolateToTarget.set(scriptExecutionContextIsolateId, scriptFrameId);
286
289
  }
@@ -328,12 +331,14 @@ export class EnhancedTracesParser {
328
331
  id: script.executionContextId,
329
332
  origin: '',
330
333
  v8Context: '',
334
+ name: '',
331
335
  auxData: {
332
336
  frameId: targetId,
333
337
  isDefault: false,
334
338
  type: 'type',
335
339
  },
336
340
  isolate: script.isolate,
341
+ uniqueId: `${targetId}-${script.isolate}`,
337
342
  };
338
343
  executionContexts.push(artificialContext);
339
344
  }
@@ -1,4 +1,4 @@
1
- // Copyright 2021 The Chromium Authors
1
+ // Copyright 2011 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
4
  import * as TextUtils from '../../models/text_utils/text_utils.js';
@@ -1,4 +1,4 @@
1
- // Copyright 2021 The Chromium Authors
1
+ // Copyright 2012 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
4
  import * as TextUtils from '../../models/text_utils/text_utils.js';