chrome-devtools-frontend 1.0.1000934 → 1.0.1002543

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 (187) hide show
  1. package/config/gni/devtools_grd_files.gni +4 -3
  2. package/front_end/.eslintrc.js +1 -0
  3. package/front_end/core/common/ParsedURL.ts +3 -3
  4. package/front_end/core/host/InspectorFrontendHost.ts +30 -1
  5. package/front_end/core/i18n/locales/en-US.json +177 -12
  6. package/front_end/core/i18n/locales/en-XL.json +177 -12
  7. package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
  8. package/front_end/core/root/Runtime.ts +7 -3
  9. package/front_end/core/sdk/ServiceWorkerManager.ts +6 -5
  10. package/front_end/entrypoints/formatter_worker/FormatterActions.ts +14 -0
  11. package/front_end/entrypoints/formatter_worker/ScopeParser.ts +491 -0
  12. package/front_end/entrypoints/formatter_worker/Substitute.ts +4 -440
  13. package/front_end/entrypoints/formatter_worker/formatter_worker.ts +2 -0
  14. package/front_end/generated/InspectorBackendCommands.js +38 -10
  15. package/front_end/generated/protocol-mapping.d.ts +5 -1
  16. package/front_end/generated/protocol-proxy-api.d.ts +4 -1
  17. package/front_end/generated/protocol.ts +50 -10
  18. package/front_end/models/bindings/BreakpointManager.ts +12 -11
  19. package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
  20. package/front_end/models/issues_manager/AttributionReportingIssue.ts +5 -36
  21. package/front_end/models/issues_manager/DeprecationIssue.ts +233 -257
  22. package/front_end/models/issues_manager/Issue.ts +8 -4
  23. package/front_end/models/persistence/PersistenceImpl.ts +2 -2
  24. package/front_end/models/timeline_model/TimelineModel.ts +0 -48
  25. package/front_end/panels/application/AppManifestView.ts +3 -3
  26. package/front_end/panels/application/ApplicationPanelCacheSection.ts +3 -1
  27. package/front_end/panels/application/ApplicationPanelSidebar.ts +11 -6
  28. package/front_end/panels/application/ApplicationPanelTreeElement.ts +2 -2
  29. package/front_end/panels/application/BackgroundServiceView.ts +5 -4
  30. package/front_end/panels/application/ResourcesPanel.ts +1 -1
  31. package/front_end/panels/application/components/BackForwardCacheView.ts +4 -5
  32. package/front_end/panels/application/components/FrameDetailsView.ts +19 -19
  33. package/front_end/panels/application/components/PermissionsPolicySection.ts +2 -2
  34. package/front_end/panels/console/ConsoleViewMessage.ts +6 -3
  35. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +1 -1
  36. package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +3 -2
  37. package/front_end/panels/css_overview/cssOverviewCompletedView.css +4 -0
  38. package/front_end/panels/elements/StylePropertyTreeElement.ts +19 -13
  39. package/front_end/panels/elements/StylesSidebarPane.ts +53 -0
  40. package/front_end/panels/elements/components/QueryContainer.ts +1 -1
  41. package/front_end/panels/issues/AffectedResourcesView.ts +4 -3
  42. package/front_end/panels/issues/AffectedSourcesView.ts +2 -1
  43. package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +0 -43
  44. package/front_end/panels/issues/IssueView.ts +1 -1
  45. package/front_end/panels/lighthouse/LighthouseController.ts +5 -3
  46. package/front_end/panels/lighthouse/LighthouseReporterTypes.ts +2 -1
  47. package/front_end/panels/lighthouse/lighthousePanel.css +4 -0
  48. package/front_end/panels/network/components/RequestTrustTokensView.ts +7 -7
  49. package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +2 -2
  50. package/front_end/panels/profiler/HeapSnapshotView.ts +2 -1
  51. package/front_end/panels/profiler/ProfileDataGrid.ts +1 -1
  52. package/front_end/panels/security/SecurityPanel.ts +6 -5
  53. package/front_end/panels/settings/SettingsScreen.ts +2 -3
  54. package/front_end/panels/sources/DebuggerPlugin.ts +10 -9
  55. package/front_end/panels/sources/JavaScriptBreakpointsSidebarPane.ts +3 -3
  56. package/front_end/panels/timeline/PerformanceModel.ts +2 -6
  57. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -14
  58. package/front_end/panels/timeline/TimelineUIUtils.ts +14 -12
  59. package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1036 -1088
  60. package/front_end/third_party/lighthouse/locales/en-US.json +241 -4
  61. package/front_end/third_party/lighthouse/locales/en-XL.json +241 -4
  62. package/front_end/third_party/lighthouse/report/bundle.d.ts +2 -0
  63. package/front_end/third_party/lighthouse/report/bundle.js +18 -12
  64. package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
  65. package/front_end/third_party/puppeteer/package/README.md +11 -11
  66. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Debug.d.ts.map +1 -1
  67. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Debug.js +26 -2
  68. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Debug.js.map +1 -1
  69. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/FrameManager.d.ts.map +1 -1
  70. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/FrameManager.js +7 -0
  71. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/FrameManager.js.map +1 -1
  72. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.d.ts +2 -2
  73. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.d.ts.map +1 -1
  74. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.js +19 -11
  75. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.js.map +1 -1
  76. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.d.ts +2 -2
  77. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.d.ts.map +1 -1
  78. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.js +6 -2
  79. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.js.map +1 -1
  80. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Page.d.ts +1 -1
  81. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Page.js +1 -1
  82. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.d.ts +3 -0
  83. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.d.ts.map +1 -0
  84. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.js +18 -0
  85. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.js.map +1 -0
  86. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.d.ts +2 -0
  87. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.d.ts.map +1 -0
  88. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.js +7 -0
  89. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.js.map +1 -0
  90. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +2 -0
  91. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts.map +1 -0
  92. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +5 -0
  93. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js.map +1 -0
  94. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/initialize-node.d.ts.map +1 -1
  95. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/initialize-node.js +2 -15
  96. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/initialize-node.js.map +1 -1
  97. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.d.ts +1 -1
  98. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.d.ts.map +1 -1
  99. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.js +23 -15
  100. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.js.map +1 -1
  101. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/Launcher.d.ts.map +1 -1
  102. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/Launcher.js +1 -0
  103. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/Launcher.js.map +1 -1
  104. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.d.ts +1 -1
  105. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.d.ts.map +1 -1
  106. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.js +17 -3
  107. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.js.map +1 -1
  108. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/install.d.ts.map +1 -1
  109. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/install.js +1 -6
  110. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/install.js.map +1 -1
  111. package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +1 -1
  112. package/front_end/third_party/puppeteer/package/lib/esm/package.json +1 -0
  113. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Debug.d.ts.map +1 -1
  114. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Debug.js +3 -2
  115. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Debug.js.map +1 -1
  116. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/FrameManager.d.ts.map +1 -1
  117. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/FrameManager.js +7 -0
  118. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/FrameManager.js.map +1 -1
  119. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.d.ts +2 -2
  120. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.d.ts.map +1 -1
  121. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.js +19 -11
  122. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.js.map +1 -1
  123. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.d.ts +2 -2
  124. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.d.ts.map +1 -1
  125. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.js +6 -2
  126. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.js.map +1 -1
  127. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Page.d.ts +1 -1
  128. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Page.js +1 -1
  129. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.d.ts +3 -0
  130. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.d.ts.map +1 -0
  131. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.js +17 -0
  132. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.js.map +1 -0
  133. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.d.ts +2 -0
  134. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.d.ts.map +1 -0
  135. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.js +4 -0
  136. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.js.map +1 -0
  137. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +2 -0
  138. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts.map +1 -0
  139. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +2 -0
  140. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js.map +1 -0
  141. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/initialize-node.d.ts.map +1 -1
  142. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/initialize-node.js +2 -15
  143. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/initialize-node.js.map +1 -1
  144. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.d.ts +1 -1
  145. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.d.ts.map +1 -1
  146. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.js +21 -13
  147. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.js.map +1 -1
  148. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/Launcher.d.ts.map +1 -1
  149. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/Launcher.js +1 -0
  150. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/Launcher.js.map +1 -1
  151. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.d.ts +1 -1
  152. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.d.ts.map +1 -1
  153. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.js +17 -3
  154. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.js.map +1 -1
  155. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/install.d.ts.map +1 -1
  156. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/install.js +1 -6
  157. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/install.js.map +1 -1
  158. package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +1 -1
  159. package/front_end/third_party/puppeteer/package/lib/types.d.ts +6 -6
  160. package/front_end/third_party/puppeteer/package/package.json +33 -18
  161. package/front_end/third_party/puppeteer/puppeteer-tsconfig.json +4 -1
  162. package/front_end/ui/components/data_grid/DataGrid.ts +1 -1
  163. package/front_end/ui/components/data_grid/DataGridUtils.ts +1 -1
  164. package/front_end/ui/components/docs/linkifier/simple-url.ts +2 -1
  165. package/front_end/ui/components/docs/panel_feedback/basic.ts +3 -2
  166. package/front_end/ui/components/docs/panel_feedback/button.ts +2 -1
  167. package/front_end/ui/components/linkifier/LinkifierImpl.ts +4 -3
  168. package/front_end/ui/components/linkifier/LinkifierUtils.ts +2 -3
  169. package/front_end/ui/components/panel_feedback/FeedbackButton.ts +4 -6
  170. package/front_end/ui/components/panel_feedback/PanelFeedback.ts +5 -4
  171. package/front_end/ui/components/request_link_icon/RequestLinkIcon.ts +4 -4
  172. package/front_end/ui/legacy/EmptyWidget.ts +2 -1
  173. package/front_end/ui/legacy/UIUtils.ts +4 -4
  174. package/front_end/ui/legacy/XLink.ts +12 -13
  175. package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +2 -4
  176. package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +1 -1
  177. package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +0 -2
  178. package/front_end/ui/legacy/components/utils/ImagePreview.ts +3 -7
  179. package/front_end/ui/legacy/components/utils/Linkifier.ts +23 -23
  180. package/front_end/ui/legacy/toolbar.css +1 -1
  181. package/front_end/ui/lit-html/lit-html.ts +3 -0
  182. package/package.json +1 -1
  183. package/scripts/eslint_rules/lib/lit_template_result_or_nothing.js +4 -0
  184. package/scripts/eslint_rules/tests/lit_template_result_or_nothing_test.js +13 -0
  185. package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourceEventId.md +0 -3
  186. package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourceExpiry.md +0 -4
  187. package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourcePriority.md +0 -4
@@ -34,6 +34,7 @@
34
34
 
35
35
  import * as Common from '../common/common.js';
36
36
  import * as i18n from '../i18n/i18n.js';
37
+ import type * as Platform from '../platform/platform.js';
37
38
  import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
38
39
  import * as Protocol from '../../generated/protocol.js';
39
40
 
@@ -364,7 +365,7 @@ export class ServiceWorkerVersionState {
364
365
 
365
366
  export class ServiceWorkerVersion {
366
367
  id!: string;
367
- scriptURL!: string;
368
+ scriptURL!: Platform.DevToolsPath.UrlString;
368
369
  parsedURL!: Common.ParsedURL.ParsedURL;
369
370
  securityOrigin!: string;
370
371
  scriptLastModified!: number|undefined;
@@ -380,7 +381,7 @@ export class ServiceWorkerVersion {
380
381
 
381
382
  update(payload: Protocol.ServiceWorker.ServiceWorkerVersion): void {
382
383
  this.id = payload.versionId;
383
- this.scriptURL = payload.scriptURL;
384
+ this.scriptURL = payload.scriptURL as Platform.DevToolsPath.UrlString;
384
385
  const parsedURL = new Common.ParsedURL.ParsedURL(payload.scriptURL);
385
386
  this.securityOrigin = parsedURL.securityOrigin();
386
387
  this.currentState =
@@ -496,8 +497,8 @@ export namespace ServiceWorkerVersion {
496
497
  export class ServiceWorkerRegistration {
497
498
  #fingerprintInternal!: symbol;
498
499
  id!: Protocol.ServiceWorker.RegistrationID;
499
- scopeURL!: string;
500
- securityOrigin!: string;
500
+ scopeURL!: Platform.DevToolsPath.UrlString;
501
+ securityOrigin!: Platform.DevToolsPath.UrlString;
501
502
  isDeleted!: boolean;
502
503
  versions: Map<string, ServiceWorkerVersion>;
503
504
  deleting: boolean;
@@ -513,7 +514,7 @@ export class ServiceWorkerRegistration {
513
514
  update(payload: Protocol.ServiceWorker.ServiceWorkerRegistration): void {
514
515
  this.#fingerprintInternal = Symbol('fingerprint');
515
516
  this.id = payload.registrationId;
516
- this.scopeURL = payload.scopeURL;
517
+ this.scopeURL = payload.scopeURL as Platform.DevToolsPath.UrlString;
517
518
  const parsedURL = new Common.ParsedURL.ParsedURL(payload.scopeURL);
518
519
  this.securityOrigin = parsedURL.securityOrigin();
519
520
  this.isDeleted = payload.isDeleted;
@@ -22,3 +22,17 @@ export interface FormatResult {
22
22
  content: string;
23
23
  mapping: FormatMapping;
24
24
  }
25
+
26
+ export const enum DefinitionKind {
27
+ None = 0,
28
+ Let = 1,
29
+ Var = 2,
30
+ Fixed = 3,
31
+ }
32
+
33
+ export interface ScopeTreeNode {
34
+ variables: {name: string, kind: DefinitionKind, offsets: number[]}[];
35
+ start: number;
36
+ end: number;
37
+ children: ScopeTreeNode[];
38
+ }
@@ -0,0 +1,491 @@
1
+ // Copyright 2022 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as Acorn from '../../third_party/acorn/acorn.js';
6
+
7
+ import {ECMA_VERSION} from './AcornTokenizer.js';
8
+ import type {ScopeTreeNode} from './FormatterActions.js';
9
+ import {DefinitionKind} from './FormatterActions.js';
10
+
11
+ export function parseScopes(expression: string): Scope|null {
12
+ // Parse the expression and find variables and scopes.
13
+ let root: Acorn.ESTree.Node|null = null;
14
+ try {
15
+ root = Acorn.parse(expression, {ecmaVersion: ECMA_VERSION, allowAwaitOutsideFunction: true, ranges: false}) as
16
+ Acorn.ESTree.Node;
17
+ } catch {
18
+ return null;
19
+ }
20
+ return new ScopeVariableAnalysis(root).run();
21
+ }
22
+
23
+ export interface Use {
24
+ offset: number;
25
+ scope: Scope;
26
+ isShorthandAssignmentProperty: boolean;
27
+ }
28
+
29
+ export interface VariableUses {
30
+ definitionKind: DefinitionKind;
31
+ uses: Use[];
32
+ }
33
+
34
+ export class Scope {
35
+ readonly variables = new Map<string, VariableUses>();
36
+ readonly parent: Scope|null;
37
+ readonly start: number;
38
+ readonly end: number;
39
+ readonly children: Scope[] = [];
40
+
41
+ constructor(start: number, end: number, parent: Scope|null) {
42
+ this.start = start;
43
+ this.end = end;
44
+ this.parent = parent;
45
+ if (parent) {
46
+ parent.children.push(this);
47
+ }
48
+ }
49
+
50
+ export(): ScopeTreeNode {
51
+ const variables = [];
52
+ for (const variable of this.variables) {
53
+ const offsets = [];
54
+ for (const use of variable[1].uses) {
55
+ offsets.push(use.offset);
56
+ }
57
+ variables.push({name: variable[0], kind: variable[1].definitionKind, offsets});
58
+ }
59
+ const children = this.children.map(c => c.export());
60
+ return {
61
+ start: this.start,
62
+ end: this.end,
63
+ variables,
64
+ children,
65
+ };
66
+ }
67
+
68
+ addVariable(name: string, offset: number, definitionKind: DefinitionKind, isShorthandAssignmentProperty: boolean):
69
+ void {
70
+ const variable = this.variables.get(name);
71
+ const use = {offset, scope: this, isShorthandAssignmentProperty};
72
+ if (!variable) {
73
+ this.variables.set(name, {definitionKind, uses: [use]});
74
+ return;
75
+ }
76
+ if (variable.definitionKind === DefinitionKind.None) {
77
+ variable.definitionKind = definitionKind;
78
+ }
79
+ variable.uses.push(use);
80
+ }
81
+
82
+ findBinders(name: string): VariableUses[] {
83
+ const result = [];
84
+ let scope: Scope|null = this;
85
+ while (scope !== null) {
86
+ const defUse = scope.variables.get(name);
87
+ if (defUse && defUse.definitionKind !== DefinitionKind.None) {
88
+ result.push(defUse);
89
+ }
90
+ scope = scope.parent;
91
+ }
92
+ return result;
93
+ }
94
+
95
+ #mergeChildDefUses(name: string, defUses: VariableUses): void {
96
+ const variable = this.variables.get(name);
97
+ if (!variable) {
98
+ this.variables.set(name, defUses);
99
+ return;
100
+ }
101
+ variable.uses.push(...defUses.uses);
102
+ if (defUses.definitionKind === DefinitionKind.Var) {
103
+ console.assert(variable.definitionKind !== DefinitionKind.Let);
104
+ if (variable.definitionKind === DefinitionKind.None) {
105
+ variable.definitionKind = defUses.definitionKind;
106
+ }
107
+ } else {
108
+ console.assert(defUses.definitionKind === DefinitionKind.None);
109
+ }
110
+ }
111
+
112
+ finalizeToParent(isFunctionScope: boolean): void {
113
+ if (!this.parent) {
114
+ console.error('Internal error: wrong nesting in scope analysis.');
115
+ throw new Error('Internal error');
116
+ }
117
+
118
+ // Move all unbound variables to the parent (also move var-bound variables
119
+ // if the parent is not a function).
120
+ const keysToRemove = [];
121
+ for (const [name, defUse] of this.variables.entries()) {
122
+ if (defUse.definitionKind === DefinitionKind.None ||
123
+ (defUse.definitionKind === DefinitionKind.Var && !isFunctionScope)) {
124
+ this.parent.#mergeChildDefUses(name, defUse);
125
+ keysToRemove.push(name);
126
+ }
127
+ }
128
+ keysToRemove.forEach(k => this.variables.delete(k));
129
+ }
130
+ }
131
+
132
+ export class ScopeVariableAnalysis {
133
+ readonly #rootScope: Scope;
134
+ readonly #allNames = new Set<string>();
135
+ #currentScope: Scope;
136
+ readonly #rootNode: Acorn.ESTree.Node;
137
+
138
+ constructor(node: Acorn.ESTree.Node) {
139
+ this.#rootNode = node;
140
+ this.#rootScope = new Scope(node.start, node.end, null);
141
+ this.#currentScope = this.#rootScope;
142
+ }
143
+
144
+ run(): Scope {
145
+ this.#processNode(this.#rootNode);
146
+ return this.#rootScope;
147
+ }
148
+
149
+ #processNode(node: Acorn.ESTree.Node|null): void {
150
+ if (node === null) {
151
+ return;
152
+ }
153
+ switch (node.type) {
154
+ case 'AwaitExpression':
155
+ this.#processNode(node.argument);
156
+ break;
157
+ case 'ArrayExpression':
158
+ node.elements.forEach(item => this.#processNode(item));
159
+ break;
160
+ case 'ExpressionStatement':
161
+ this.#processNode(node.expression);
162
+ break;
163
+ case 'Program':
164
+ console.assert(this.#currentScope === this.#rootScope);
165
+ node.body.forEach(item => this.#processNode(item));
166
+ console.assert(this.#currentScope === this.#rootScope);
167
+ break;
168
+ case 'ArrayPattern':
169
+ node.elements.forEach(item => this.#processNode(item));
170
+ break;
171
+ case 'ArrowFunctionExpression': {
172
+ this.#pushScope(node.start, node.end);
173
+ node.params.forEach(this.#processNodeAsDefinition.bind(this, DefinitionKind.Var));
174
+ this.#processNode(node.body);
175
+ this.#popScope(true);
176
+ break;
177
+ }
178
+ case 'AssignmentExpression':
179
+ case 'AssignmentPattern':
180
+ case 'BinaryExpression':
181
+ case 'LogicalExpression':
182
+ this.#processNode(node.left);
183
+ this.#processNode(node.right);
184
+ break;
185
+ case 'BlockStatement':
186
+ this.#pushScope(node.start, node.end);
187
+ node.body.forEach(this.#processNode.bind(this));
188
+ this.#popScope(false);
189
+ break;
190
+ case 'CallExpression':
191
+ this.#processNode(node.callee);
192
+ node.arguments.forEach(this.#processNode.bind(this));
193
+ break;
194
+ case 'VariableDeclaration': {
195
+ const definitionKind = node.kind === 'var' ? DefinitionKind.Var : DefinitionKind.Let;
196
+ node.declarations.forEach(this.#processVariableDeclarator.bind(this, definitionKind));
197
+ break;
198
+ }
199
+ case 'CatchClause':
200
+ this.#pushScope(node.start, node.end);
201
+ this.#processNodeAsDefinition(DefinitionKind.Let, node.param);
202
+ node.body.body.forEach(this.#processNode.bind(this));
203
+ this.#popScope(false);
204
+ break;
205
+ case 'ClassBody':
206
+ node.body.forEach(this.#processNode.bind(this));
207
+ break;
208
+ case 'ClassDeclaration':
209
+ this.#processNodeAsDefinition(DefinitionKind.Let, node.id);
210
+ this.#pushScope(node.start, node.end);
211
+ this.#processNode(node.superClass ?? null);
212
+ this.#processNode(node.body);
213
+ this.#popScope(false);
214
+ break;
215
+ case 'ClassExpression':
216
+ this.#pushScope(node.start, node.end);
217
+ // Intentionally ignore the id.
218
+ this.#processNode(node.superClass ?? null);
219
+ this.#processNode(node.body);
220
+ this.#popScope(false);
221
+ break;
222
+ case 'ChainExpression':
223
+ this.#processNode(node.expression);
224
+ break;
225
+ case 'ConditionalExpression':
226
+ this.#processNode(node.test);
227
+ this.#processNode(node.consequent);
228
+ this.#processNode(node.alternate);
229
+ break;
230
+ case 'DoWhileStatement':
231
+ this.#processNode(node.body);
232
+ this.#processNode(node.test);
233
+ break;
234
+ case 'ForInStatement':
235
+ case 'ForOfStatement':
236
+ this.#pushScope(node.start, node.end);
237
+ this.#processNode(node.left);
238
+ this.#processNode(node.right);
239
+ this.#processNode(node.body);
240
+ this.#popScope(false);
241
+ break;
242
+ case 'ForStatement':
243
+ this.#pushScope(node.start, node.end);
244
+ this.#processNode(node.init ?? null);
245
+ this.#processNode(node.test ?? null);
246
+ this.#processNode(node.update ?? null);
247
+ this.#processNode(node.body);
248
+ this.#popScope(false);
249
+ break;
250
+ case 'FunctionDeclaration':
251
+ this.#processNodeAsDefinition(DefinitionKind.Var, node.id);
252
+ this.#pushScope(node.id?.end ?? node.start, node.end);
253
+ this.#addVariable('this', node.start, DefinitionKind.Fixed);
254
+ this.#addVariable('arguments', node.start, DefinitionKind.Fixed);
255
+ node.params.forEach(this.#processNodeAsDefinition.bind(this, DefinitionKind.Let));
256
+ this.#processNode(node.body);
257
+ this.#popScope(true);
258
+ break;
259
+ case 'FunctionExpression':
260
+ // Id is intentionally ignored in function expressions.
261
+ this.#pushScope(node.start, node.end);
262
+ this.#addVariable('this', node.start, DefinitionKind.Fixed);
263
+ this.#addVariable('arguments', node.start, DefinitionKind.Fixed);
264
+ node.params.forEach(this.#processNodeAsDefinition.bind(this, DefinitionKind.Let));
265
+ this.#processNode(node.body);
266
+ this.#popScope(true);
267
+ break;
268
+ case 'Identifier':
269
+ this.#addVariable(node.name, node.start);
270
+ break;
271
+ case 'IfStatement':
272
+ this.#processNode(node.test);
273
+ this.#processNode(node.consequent);
274
+ this.#processNode(node.alternate ?? null);
275
+ break;
276
+ case 'LabeledStatement':
277
+ this.#processNode(node.body);
278
+ break;
279
+ case 'MetaProperty':
280
+ break;
281
+ case 'MethodDefinition':
282
+ if (node.computed) {
283
+ this.#processNode(node.key);
284
+ }
285
+ this.#processNode(node.value);
286
+ break;
287
+ case 'NewExpression':
288
+ this.#processNode(node.callee);
289
+ node.arguments.forEach(this.#processNode.bind(this));
290
+ break;
291
+ case 'MemberExpression':
292
+ this.#processNode(node.object);
293
+ if (node.computed) {
294
+ this.#processNode(node.property);
295
+ }
296
+ break;
297
+ case 'ObjectExpression':
298
+ node.properties.forEach(this.#processNode.bind(this));
299
+ break;
300
+ case 'ObjectPattern':
301
+ node.properties.forEach(this.#processNode.bind(this));
302
+ break;
303
+ case 'PrivateIdentifier':
304
+ break;
305
+ case 'PropertyDefinition':
306
+ if (node.computed) {
307
+ this.#processNode(node.key);
308
+ }
309
+ this.#processNode(node.value ?? null);
310
+ break;
311
+ case 'Property':
312
+ if (node.shorthand) {
313
+ console.assert(node.value === node.key);
314
+ console.assert(node.value.type === 'Identifier');
315
+ this.#addVariable((node.value as Acorn.ESTree.Identifier).name, node.value.start, DefinitionKind.None, true);
316
+ } else {
317
+ if (node.computed) {
318
+ this.#processNode(node.key);
319
+ }
320
+ this.#processNode(node.value);
321
+ }
322
+ break;
323
+ case 'RestElement':
324
+ this.#processNodeAsDefinition(DefinitionKind.Let, node.argument);
325
+ break;
326
+ case 'ReturnStatement':
327
+ this.#processNode(node.argument ?? null);
328
+ break;
329
+ case 'SequenceExpression':
330
+ node.expressions.forEach(this.#processNode.bind(this));
331
+ break;
332
+ case 'SpreadElement':
333
+ this.#processNode(node.argument);
334
+ break;
335
+ case 'SwitchCase':
336
+ this.#processNode(node.test ?? null);
337
+ node.consequent.forEach(this.#processNode.bind(this));
338
+ break;
339
+ case 'SwitchStatement':
340
+ this.#processNode(node.discriminant);
341
+ node.cases.forEach(this.#processNode.bind(this));
342
+ break;
343
+ case 'TaggedTemplateExpression':
344
+ this.#processNode(node.tag);
345
+ this.#processNode(node.quasi);
346
+ break;
347
+ case 'TemplateLiteral':
348
+ node.expressions.forEach(this.#processNode.bind(this));
349
+ break;
350
+ case 'ThisExpression':
351
+ this.#addVariable('this', node.start);
352
+ break;
353
+ case 'ThrowStatement':
354
+ this.#processNode(node.argument);
355
+ break;
356
+ case 'TryStatement':
357
+ this.#processNode(node.block);
358
+ this.#processNode(node.handler ?? null);
359
+ this.#processNode(node.finalizer ?? null);
360
+ break;
361
+ case 'WithStatement':
362
+ this.#processNode(node.object);
363
+ // TODO jarin figure how to treat the with body.
364
+ this.#processNode(node.body);
365
+ break;
366
+ case 'YieldExpression':
367
+ this.#processNode(node.argument ?? null);
368
+ break;
369
+ case 'UnaryExpression':
370
+ case 'UpdateExpression':
371
+ this.#processNode(node.argument);
372
+ break;
373
+ case 'WhileStatement':
374
+ this.#processNode(node.test);
375
+ this.#processNode(node.body);
376
+ break;
377
+
378
+ // Ignore, no expressions involved.
379
+ case 'BreakStatement':
380
+ case 'ContinueStatement':
381
+ case 'DebuggerStatement':
382
+ case 'EmptyStatement':
383
+ case 'Literal':
384
+ case 'Super':
385
+ case 'TemplateElement':
386
+ break;
387
+ // Ignore, cannot be used outside of a module.
388
+ case 'ImportDeclaration':
389
+ case 'ImportDefaultSpecifier':
390
+ case 'ImportNamespaceSpecifier':
391
+ case 'ImportSpecifier':
392
+ case 'ImportExpression':
393
+ case 'ExportAllDeclaration':
394
+ case 'ExportDefaultDeclaration':
395
+ case 'ExportNamedDeclaration':
396
+ case 'ExportSpecifier':
397
+ break;
398
+
399
+ case 'VariableDeclarator':
400
+ console.error('Should not encounter VariableDeclarator in general traversal.');
401
+ break;
402
+ }
403
+ }
404
+
405
+ getFreeVariables(): Map<string, Use[]> {
406
+ const result = new Map<string, Use[]>();
407
+ for (const [name, defUse] of this.#rootScope.variables) {
408
+ if (defUse.definitionKind !== DefinitionKind.None) {
409
+ // Skip bound variables.
410
+ continue;
411
+ }
412
+ result.set(name, defUse.uses);
413
+ }
414
+ return result;
415
+ }
416
+
417
+ getAllNames(): Set<string> {
418
+ return this.#allNames;
419
+ }
420
+
421
+ #pushScope(start: number, end: number): void {
422
+ this.#currentScope = new Scope(start, end, this.#currentScope);
423
+ }
424
+
425
+ #popScope(isFunctionContext: boolean): void {
426
+ if (this.#currentScope.parent === null) {
427
+ console.error('Internal error: wrong nesting in scope analysis.');
428
+ throw new Error('Internal error');
429
+ }
430
+ this.#currentScope.finalizeToParent(isFunctionContext);
431
+ this.#currentScope = this.#currentScope.parent;
432
+ }
433
+
434
+ #addVariable(
435
+ name: string, offset: number, definitionKind: DefinitionKind = DefinitionKind.None,
436
+ isShorthandAssignmentProperty: boolean = false): void {
437
+ this.#allNames.add(name);
438
+ this.#currentScope.addVariable(name, offset, definitionKind, isShorthandAssignmentProperty);
439
+ }
440
+
441
+ #processNodeAsDefinition(
442
+ definitionKind: DefinitionKind.Let|DefinitionKind.Var,
443
+ node: Acorn.ESTree.Pattern|Acorn.ESTree.AssignmentProperty|null): void {
444
+ if (node === null) {
445
+ return;
446
+ }
447
+ switch (node.type) {
448
+ case 'ArrayPattern':
449
+ node.elements.forEach(this.#processNodeAsDefinition.bind(this, definitionKind));
450
+ break;
451
+ case 'AssignmentPattern':
452
+ this.#processNodeAsDefinition(definitionKind, node.left);
453
+ this.#processNode(node.right);
454
+ break;
455
+ case 'Identifier':
456
+ this.#addVariable(node.name, node.start, definitionKind);
457
+ break;
458
+ case 'MemberExpression':
459
+ this.#processNode(node.object);
460
+ if (node.computed) {
461
+ this.#processNode(node.property);
462
+ }
463
+ break;
464
+ case 'ObjectPattern':
465
+ node.properties.forEach(this.#processNodeAsDefinition.bind(this, definitionKind));
466
+ break;
467
+ case 'Property':
468
+ // This is AssignmentProperty inside an object pattern.
469
+ if (node.shorthand) {
470
+ console.assert(node.value === node.key);
471
+ console.assert(node.value.type === 'Identifier');
472
+ this.#addVariable((node.value as Acorn.ESTree.Identifier).name, node.value.start, definitionKind, true);
473
+ } else {
474
+ if (node.computed) {
475
+ this.#processNode(node.key);
476
+ }
477
+ this.#processNodeAsDefinition(definitionKind, node.value);
478
+ }
479
+ break;
480
+ case 'RestElement':
481
+ this.#processNodeAsDefinition(definitionKind, node.argument);
482
+ break;
483
+ }
484
+ }
485
+
486
+ #processVariableDeclarator(
487
+ definitionKind: DefinitionKind.Let|DefinitionKind.Var, decl: Acorn.ESTree.VariableDeclarator): void {
488
+ this.#processNodeAsDefinition(definitionKind, decl.id);
489
+ this.#processNode(decl.init ?? null);
490
+ }
491
+ }