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.
- package/config/gni/devtools_grd_files.gni +4 -3
- package/front_end/.eslintrc.js +1 -0
- package/front_end/core/common/ParsedURL.ts +3 -3
- package/front_end/core/host/InspectorFrontendHost.ts +30 -1
- package/front_end/core/i18n/locales/en-US.json +177 -12
- package/front_end/core/i18n/locales/en-XL.json +177 -12
- package/front_end/core/protocol_client/InspectorBackend.ts +4 -0
- package/front_end/core/root/Runtime.ts +7 -3
- package/front_end/core/sdk/ServiceWorkerManager.ts +6 -5
- package/front_end/entrypoints/formatter_worker/FormatterActions.ts +14 -0
- package/front_end/entrypoints/formatter_worker/ScopeParser.ts +491 -0
- package/front_end/entrypoints/formatter_worker/Substitute.ts +4 -440
- package/front_end/entrypoints/formatter_worker/formatter_worker.ts +2 -0
- package/front_end/generated/InspectorBackendCommands.js +38 -10
- package/front_end/generated/protocol-mapping.d.ts +5 -1
- package/front_end/generated/protocol-proxy-api.d.ts +4 -1
- package/front_end/generated/protocol.ts +50 -10
- package/front_end/models/bindings/BreakpointManager.ts +12 -11
- package/front_end/models/bindings/CompilerScriptMapping.ts +1 -1
- package/front_end/models/issues_manager/AttributionReportingIssue.ts +5 -36
- package/front_end/models/issues_manager/DeprecationIssue.ts +233 -257
- package/front_end/models/issues_manager/Issue.ts +8 -4
- package/front_end/models/persistence/PersistenceImpl.ts +2 -2
- package/front_end/models/timeline_model/TimelineModel.ts +0 -48
- package/front_end/panels/application/AppManifestView.ts +3 -3
- package/front_end/panels/application/ApplicationPanelCacheSection.ts +3 -1
- package/front_end/panels/application/ApplicationPanelSidebar.ts +11 -6
- package/front_end/panels/application/ApplicationPanelTreeElement.ts +2 -2
- package/front_end/panels/application/BackgroundServiceView.ts +5 -4
- package/front_end/panels/application/ResourcesPanel.ts +1 -1
- package/front_end/panels/application/components/BackForwardCacheView.ts +4 -5
- package/front_end/panels/application/components/FrameDetailsView.ts +19 -19
- package/front_end/panels/application/components/PermissionsPolicySection.ts +2 -2
- package/front_end/panels/console/ConsoleViewMessage.ts +6 -3
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +1 -1
- package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +3 -2
- package/front_end/panels/css_overview/cssOverviewCompletedView.css +4 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +19 -13
- package/front_end/panels/elements/StylesSidebarPane.ts +53 -0
- package/front_end/panels/elements/components/QueryContainer.ts +1 -1
- package/front_end/panels/issues/AffectedResourcesView.ts +4 -3
- package/front_end/panels/issues/AffectedSourcesView.ts +2 -1
- package/front_end/panels/issues/AttributionReportingIssueDetailsView.ts +0 -43
- package/front_end/panels/issues/IssueView.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +5 -3
- package/front_end/panels/lighthouse/LighthouseReporterTypes.ts +2 -1
- package/front_end/panels/lighthouse/lighthousePanel.css +4 -0
- package/front_end/panels/network/components/RequestTrustTokensView.ts +7 -7
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +2 -2
- package/front_end/panels/profiler/HeapSnapshotView.ts +2 -1
- package/front_end/panels/profiler/ProfileDataGrid.ts +1 -1
- package/front_end/panels/security/SecurityPanel.ts +6 -5
- package/front_end/panels/settings/SettingsScreen.ts +2 -3
- package/front_end/panels/sources/DebuggerPlugin.ts +10 -9
- package/front_end/panels/sources/JavaScriptBreakpointsSidebarPane.ts +3 -3
- package/front_end/panels/timeline/PerformanceModel.ts +2 -6
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -14
- package/front_end/panels/timeline/TimelineUIUtils.ts +14 -12
- package/front_end/third_party/lighthouse/lighthouse-dt-bundle.js +1036 -1088
- package/front_end/third_party/lighthouse/locales/en-US.json +241 -4
- package/front_end/third_party/lighthouse/locales/en-XL.json +241 -4
- package/front_end/third_party/lighthouse/report/bundle.d.ts +2 -0
- package/front_end/third_party/lighthouse/report/bundle.js +18 -12
- package/front_end/third_party/lighthouse/report-assets/report-generator.mjs +1 -1
- package/front_end/third_party/puppeteer/package/README.md +11 -11
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Debug.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Debug.js +26 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Debug.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/FrameManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/FrameManager.js +7 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/FrameManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.js +19 -11
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.js +6 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Page.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/Page.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.d.ts.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.js +18 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/compat.js.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.d.ts +2 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.d.ts.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.js +7 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/constants.js.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts +2 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.d.ts.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js +5 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/generated/version.js.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/initialize-node.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/initialize-node.js +2 -15
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/initialize-node.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.js +23 -15
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/BrowserFetcher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/Launcher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/Launcher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/Launcher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.js +17 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/NodeWebSocketTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/install.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/install.js +1 -6
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/node/install.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/package.json +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Debug.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Debug.js +3 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Debug.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/FrameManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/FrameManager.js +7 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/FrameManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.js +19 -11
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPRequest.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.d.ts +2 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.js +6 -2
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/HTTPResponse.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Page.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/Page.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.d.ts +3 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.d.ts.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.js +17 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/compat.js.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.d.ts +2 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.d.ts.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.js +4 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/constants.js.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts +2 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.d.ts.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js +2 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/generated/version.js.map +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/initialize-node.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/initialize-node.js +2 -15
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/initialize-node.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.js +21 -13
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/BrowserFetcher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/Launcher.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/Launcher.js +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/Launcher.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.js +17 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/NodeWebSocketTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/install.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/install.js +1 -6
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/node/install.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/types.d.ts +6 -6
- package/front_end/third_party/puppeteer/package/package.json +33 -18
- package/front_end/third_party/puppeteer/puppeteer-tsconfig.json +4 -1
- package/front_end/ui/components/data_grid/DataGrid.ts +1 -1
- package/front_end/ui/components/data_grid/DataGridUtils.ts +1 -1
- package/front_end/ui/components/docs/linkifier/simple-url.ts +2 -1
- package/front_end/ui/components/docs/panel_feedback/basic.ts +3 -2
- package/front_end/ui/components/docs/panel_feedback/button.ts +2 -1
- package/front_end/ui/components/linkifier/LinkifierImpl.ts +4 -3
- package/front_end/ui/components/linkifier/LinkifierUtils.ts +2 -3
- package/front_end/ui/components/panel_feedback/FeedbackButton.ts +4 -6
- package/front_end/ui/components/panel_feedback/PanelFeedback.ts +5 -4
- package/front_end/ui/components/request_link_icon/RequestLinkIcon.ts +4 -4
- package/front_end/ui/legacy/EmptyWidget.ts +2 -1
- package/front_end/ui/legacy/UIUtils.ts +4 -4
- package/front_end/ui/legacy/XLink.ts +12 -13
- package/front_end/ui/legacy/components/color_picker/ContrastDetails.ts +2 -4
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/LineLevelProfile.ts +0 -2
- package/front_end/ui/legacy/components/utils/ImagePreview.ts +3 -7
- package/front_end/ui/legacy/components/utils/Linkifier.ts +23 -23
- package/front_end/ui/legacy/toolbar.css +1 -1
- package/front_end/ui/lit-html/lit-html.ts +3 -0
- package/package.json +1 -1
- package/scripts/eslint_rules/lib/lit_template_result_or_nothing.js +4 -0
- package/scripts/eslint_rules/tests/lit_template_result_or_nothing_test.js +13 -0
- package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourceEventId.md +0 -3
- package/front_end/models/issues_manager/descriptions/arInvalidAttributionSourceExpiry.md +0 -4
- 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!:
|
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!:
|
500
|
-
securityOrigin!:
|
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
|
+
}
|