chrome-devtools-frontend 1.0.998787 → 1.0.1000057
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/.clang-format +1 -0
- package/front_end/.eslintrc.js +4 -4
- package/front_end/core/common/Color.ts +9 -1
- package/front_end/core/common/Object.ts +2 -1
- package/front_end/core/common/ParsedURL.ts +3 -3
- package/front_end/core/common/Settings.ts +13 -1
- package/front_end/core/dom_extension/DOMExtension.ts +0 -10
- package/front_end/core/host/InspectorFrontendHost.ts +4 -1
- package/front_end/core/i18n/locales/en-US.json +4 -10
- package/front_end/core/i18n/locales/en-XL.json +4 -10
- package/front_end/core/sdk/CSSProperty.ts +6 -7
- package/front_end/core/sdk/ChildTargetManager.ts +0 -3
- package/front_end/core/sdk/ConsoleModel.ts +2 -1
- package/front_end/core/sdk/NetworkManager.ts +3 -1
- package/front_end/core/sdk/RuntimeModel.ts +7 -1
- package/front_end/core/sdk/SourceMapManager.ts +10 -1
- package/front_end/entrypoints/formatter_worker/FormatterWorker.ts +5 -1
- package/front_end/legacy/legacy-defs.d.ts +2 -2
- package/front_end/models/formatter/ScriptFormatter.ts +3 -1
- package/front_end/models/issues_manager/DeprecationIssue.ts +1 -1
- package/front_end/models/issues_manager/SourceFrameIssuesManager.ts +5 -1
- package/front_end/models/text_utils/CodeMirrorUtils.ts +14 -17
- package/front_end/models/timeline_model/TimelineModel.ts +1 -1
- package/front_end/models/workspace/WorkspaceImpl.ts +1 -1
- package/front_end/panels/application/IndexedDBViews.ts +5 -2
- package/front_end/panels/console/ConsoleView.ts +9 -1
- package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +3 -1
- package/front_end/panels/elements/PropertiesWidget.ts +0 -1
- package/front_end/panels/elements/StylesSidebarPane.ts +7 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +15 -0
- package/front_end/panels/lighthouse/LighthousePanel.ts +2 -1
- package/front_end/panels/lighthouse/LighthouseTimespanView.ts +9 -2
- package/front_end/panels/lighthouse/lighthouseDialog.css +5 -0
- package/front_end/panels/mobile_throttling/ThrottlingManager.ts +3 -1
- package/front_end/panels/network/NetworkLogView.ts +5 -1
- package/front_end/panels/network/NetworkLogViewColumns.ts +3 -1
- package/front_end/panels/network/RequestTimingView.ts +1 -1
- package/front_end/panels/profiler/HeapSnapshotDataGrids.ts +8 -1
- package/front_end/panels/profiler/HeapSnapshotGridNodes.ts +3 -1
- package/front_end/panels/profiler/HeapSnapshotView.ts +14 -2
- package/front_end/panels/sources/AddSourceMapURLDialog.ts +5 -4
- package/front_end/panels/sources/DebuggerPausedMessage.ts +2 -1
- package/front_end/panels/sources/DebuggerPlugin.ts +2 -2
- package/front_end/panels/sources/EditingLocationHistoryManager.ts +2 -4
- package/front_end/panels/sources/NavigatorView.ts +4 -5
- package/front_end/panels/sources/ScriptFormatterEditorAction.ts +2 -1
- package/front_end/panels/sources/SourcesPanel.ts +7 -1
- package/front_end/panels/sources/TabbedEditorContainer.ts +14 -13
- package/front_end/panels/timeline/TimelineController.ts +1 -1
- package/front_end/panels/timeline/TimelineEventOverview.ts +0 -60
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -9
- package/front_end/panels/timeline/TimelineFlameChartView.ts +4 -1
- package/front_end/panels/timeline/TimelineHistoryManager.ts +5 -2
- package/front_end/panels/timeline/TimelinePanel.ts +9 -2
- package/front_end/panels/timeline/TimelineUIUtils.ts +0 -6
- package/front_end/panels/timeline/timeline-legacy.ts +0 -3
- package/front_end/panels/timeline/timelinePanel.css +0 -6
- package/front_end/panels/web_audio/graph_visualizer/GraphView.ts +3 -1
- package/front_end/panels/web_audio/graph_visualizer/NodeRendererUtility.ts +8 -1
- package/front_end/panels/web_audio/graph_visualizer/NodeView.ts +13 -1
- package/front_end/panels/web_audio/web_audio.ts +8 -1
- package/front_end/ui/components/buttons/button.css +16 -3
- package/front_end/ui/components/data_grid/DataGrid.ts +9 -1
- package/front_end/ui/components/docs/button/basic.ts +10 -0
- package/front_end/ui/components/linear_memory_inspector/LinearMemoryInspector.ts +11 -3
- package/front_end/ui/components/linear_memory_inspector/ValueInterpreterDisplay.ts +12 -1
- package/front_end/ui/components/tree_outline/TreeOutline.ts +16 -11
- package/front_end/ui/legacy/Fragment.ts +2 -2
- package/front_end/ui/legacy/ViewManager.ts +12 -1
- package/front_end/ui/legacy/XLink.ts +6 -1
- package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +8 -1
- package/front_end/ui/legacy/components/inline_editor/CSSAngleEditor.ts +7 -1
- package/package.json +1 -1
- package/scripts/eslint_rules/lib/enforce_bound_render_for_schedule_render.js +110 -0
- package/scripts/eslint_rules/tests/enforce_bound_render_for_schedule_render_test.js +74 -0
- package/scripts/reformat-clang-js-ts.js +60 -0
@@ -5,7 +5,19 @@
|
|
5
5
|
import * as UI from '../../../ui/legacy/legacy.js';
|
6
6
|
|
7
7
|
import type {NodeCreationData, NodeLayout, Port} from './GraphStyle.js';
|
8
|
-
import {
|
8
|
+
import {
|
9
|
+
BottomPaddingWithoutParam,
|
10
|
+
BottomPaddingWithParam,
|
11
|
+
LeftMarginOfText,
|
12
|
+
LeftSideTopPadding,
|
13
|
+
NodeLabelFontStyle,
|
14
|
+
ParamLabelFontStyle,
|
15
|
+
PortTypes,
|
16
|
+
RightMarginOfText,
|
17
|
+
TotalInputPortHeight,
|
18
|
+
TotalOutputPortHeight,
|
19
|
+
TotalParamPortHeight,
|
20
|
+
} from './GraphStyle.js';
|
9
21
|
import {calculateInputPortXY, calculateOutputPortXY, calculateParamPortXY} from './NodeRendererUtility.js';
|
10
22
|
|
11
23
|
// A class that represents a node of a graph, consisting of the information needed to layout the
|
@@ -7,7 +7,14 @@ import * as AudioContextSelector from './AudioContextSelector.js';
|
|
7
7
|
import * as WebAudioModel from './WebAudioModel.js';
|
8
8
|
import * as WebAudioView from './WebAudioView.js';
|
9
9
|
|
10
|
-
export {
|
10
|
+
export {
|
11
|
+
EdgeView,
|
12
|
+
GraphManager,
|
13
|
+
GraphStyle,
|
14
|
+
GraphView,
|
15
|
+
NodeRendererUtility,
|
16
|
+
NodeView,
|
17
|
+
} from './graph_visualizer/graph_visualizer.js';
|
11
18
|
export {
|
12
19
|
AudioContextContentBuilder,
|
13
20
|
AudioContextSelector,
|
@@ -27,8 +27,21 @@
|
|
27
27
|
}
|
28
28
|
|
29
29
|
button {
|
30
|
+
/*
|
31
|
+
--override-button-no-right-border-radius decides
|
32
|
+
whether button has border radius on the right or not.
|
33
|
+
|
34
|
+
It works as a boolean variable:
|
35
|
+
* If it is 1, `--button-has-right-border-radius` becomes a 0 multiplier
|
36
|
+
for the border-radius-top-right and border-radius-bottom-right properties.
|
37
|
+
* If it is not set or 0, it becomes a 1 multiplier
|
38
|
+
for the same properties which means they'll continue to have the given
|
39
|
+
border radius.
|
40
|
+
*/
|
41
|
+
--button-has-right-border-radius: calc(1 - var(--override-button-no-right-border-radius, 0));
|
42
|
+
|
30
43
|
align-items: center;
|
31
|
-
border-radius: 4px;
|
44
|
+
border-radius: 4px calc(var(--button-has-right-border-radius) * 4px) calc(var(--button-has-right-border-radius) * 4px) 4px;
|
32
45
|
display: inline-flex;
|
33
46
|
font-family: inherit;
|
34
47
|
font-size: 12px;
|
@@ -42,7 +55,7 @@ button {
|
|
42
55
|
|
43
56
|
button.small {
|
44
57
|
height: 18px;
|
45
|
-
border-radius: 2px;
|
58
|
+
border-radius: 2px calc(var(--button-has-right-border-radius) * 2px) calc(var(--button-has-right-border-radius) * 2px) 2px;
|
46
59
|
}
|
47
60
|
|
48
61
|
button:focus-visible {
|
@@ -52,7 +65,7 @@ button:focus-visible {
|
|
52
65
|
button.toolbar,
|
53
66
|
button.round {
|
54
67
|
background: transparent;
|
55
|
-
border-radius: 2px;
|
68
|
+
border-radius: 2px calc(var(--button-has-right-border-radius) * 2px) calc(var(--button-has-right-border-radius) * 2px) 2px;
|
56
69
|
border: none;
|
57
70
|
height: 24px;
|
58
71
|
width: 24px;
|
@@ -16,7 +16,15 @@ const coordinator = Coordinator.RenderCoordinator.RenderCoordinator.instance();
|
|
16
16
|
|
17
17
|
import {addColumnVisibilityCheckboxes, addSortableColumnItems} from './DataGridContextMenuUtils.js';
|
18
18
|
import type {CellPosition, Column, Row, SortState} from './DataGridUtils.js';
|
19
|
-
import {
|
19
|
+
import {
|
20
|
+
calculateColumnWidthPercentageFromWeighting,
|
21
|
+
calculateFirstFocusableCell,
|
22
|
+
getCellTitleFromCellContent,
|
23
|
+
getRowEntryForColumnId,
|
24
|
+
handleArrowKeyNavigation,
|
25
|
+
renderCellValue,
|
26
|
+
SortDirection,
|
27
|
+
} from './DataGridUtils.js';
|
20
28
|
|
21
29
|
import * as i18n from '../../../core/i18n/i18n.js';
|
22
30
|
const UIStrings = {
|
@@ -33,6 +33,16 @@ primaryButton.title = 'Custom title';
|
|
33
33
|
primaryButton.onclick = () => alert('clicked');
|
34
34
|
appendButton(primaryButton);
|
35
35
|
|
36
|
+
const primaryButtonWithoutRightBorderRadius = new Buttons.Button.Button();
|
37
|
+
primaryButtonWithoutRightBorderRadius.data = {
|
38
|
+
variant: Buttons.Button.Variant.PRIMARY,
|
39
|
+
};
|
40
|
+
primaryButtonWithoutRightBorderRadius.style.setProperty('--override-button-no-right-border-radius', '1');
|
41
|
+
primaryButtonWithoutRightBorderRadius.innerText = 'No right border radius';
|
42
|
+
primaryButtonWithoutRightBorderRadius.title = 'Custom title';
|
43
|
+
primaryButtonWithoutRightBorderRadius.onclick = () => alert('clicked');
|
44
|
+
appendButton(primaryButtonWithoutRightBorderRadius);
|
45
|
+
|
36
46
|
// Primary (forced active)
|
37
47
|
const forcedActive = new Buttons.Button.Button();
|
38
48
|
forcedActive.data = {
|
@@ -9,13 +9,21 @@ import linearMemoryInspectorStyles from './linearMemoryInspector.css.js';
|
|
9
9
|
|
10
10
|
const {render, html} = LitHtml;
|
11
11
|
|
12
|
-
import type {
|
12
|
+
import type {
|
13
|
+
AddressInputChangedEvent, HistoryNavigationEvent, LinearMemoryNavigatorData, PageNavigationEvent} from
|
14
|
+
'./LinearMemoryNavigator.js';
|
13
15
|
import {Mode, Navigation, LinearMemoryNavigator} from './LinearMemoryNavigator.js';
|
14
|
-
import type {
|
16
|
+
import type {
|
17
|
+
EndiannessChangedEvent, LinearMemoryValueInterpreterData, ValueTypeToggledEvent} from
|
18
|
+
'./LinearMemoryValueInterpreter.js';
|
15
19
|
import {LinearMemoryValueInterpreter} from './LinearMemoryValueInterpreter.js';
|
16
20
|
import type {ByteSelectedEvent, LinearMemoryViewerData, ResizeEvent} from './LinearMemoryViewer.js';
|
17
21
|
import type {ValueType, ValueTypeMode} from './ValueInterpreterDisplayUtils.js';
|
18
|
-
import {
|
22
|
+
import {
|
23
|
+
VALUE_INTEPRETER_MAX_NUM_BYTES,
|
24
|
+
Endianness,
|
25
|
+
getDefaultValueTypeMapping,
|
26
|
+
} from './ValueInterpreterDisplayUtils.js';
|
19
27
|
import {formatAddress, parseAddress} from './LinearMemoryInspectorUtils.js';
|
20
28
|
import type {JumpToPointerAddressEvent, ValueTypeModeChangedEvent} from './ValueInterpreterDisplay.js';
|
21
29
|
import {LinearMemoryViewer} from './LinearMemoryViewer.js';
|
@@ -9,7 +9,18 @@ import * as ComponentHelpers from '../helpers/helpers.js';
|
|
9
9
|
import * as IconButton from '../icon_button/icon_button.js';
|
10
10
|
|
11
11
|
import valueInterpreterDisplayStyles from './valueInterpreterDisplay.css.js';
|
12
|
-
import {
|
12
|
+
import {
|
13
|
+
Endianness,
|
14
|
+
format,
|
15
|
+
getDefaultValueTypeMapping,
|
16
|
+
getPointerAddress,
|
17
|
+
isNumber,
|
18
|
+
isPointer,
|
19
|
+
isValidMode,
|
20
|
+
VALUE_TYPE_MODE_LIST,
|
21
|
+
ValueType,
|
22
|
+
ValueTypeMode,
|
23
|
+
} from './ValueInterpreterDisplayUtils.js';
|
13
24
|
|
14
25
|
const UIStrings = {
|
15
26
|
/**
|
@@ -11,7 +11,13 @@ import * as Coordinator from '../render_coordinator/render_coordinator.js';
|
|
11
11
|
import treeOutlineStyles from './treeOutline.css.js';
|
12
12
|
|
13
13
|
import type {TreeNodeId, TreeNode, TreeNodeWithChildren} from './TreeOutlineUtils.js';
|
14
|
-
import {
|
14
|
+
import {
|
15
|
+
findNextNodeForTreeOutlineKeyboardNavigation,
|
16
|
+
getNodeChildren,
|
17
|
+
getPathToTreeNode,
|
18
|
+
isExpandableNode,
|
19
|
+
trackDOMNodeToTreeNode,
|
20
|
+
} from './TreeOutlineUtils.js';
|
15
21
|
|
16
22
|
const coordinator = Coordinator.RenderCoordinator.RenderCoordinator.instance();
|
17
23
|
|
@@ -95,16 +101,15 @@ export class TreeOutline<TreeNodeDataType> extends HTMLElement {
|
|
95
101
|
*/
|
96
102
|
#nodeIdPendingFocus: TreeNodeId|null = null;
|
97
103
|
#selectedTreeNode: TreeNode<TreeNodeDataType>|null = null;
|
98
|
-
#defaultRenderer =
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
};
|
104
|
+
#defaultRenderer = (node: TreeNode<TreeNodeDataType>, _state: {isExpanded: boolean}): LitHtml.TemplateResult => {
|
105
|
+
if (typeof node.treeNodeData !== 'string') {
|
106
|
+
console.warn(`The default TreeOutline renderer simply stringifies its given value. You passed in ${
|
107
|
+
JSON.stringify(
|
108
|
+
node.treeNodeData, null,
|
109
|
+
2)}. Consider providing a different defaultRenderer that can handle nodes of this type.`);
|
110
|
+
}
|
111
|
+
return LitHtml.html`${String(node.treeNodeData)}`;
|
112
|
+
};
|
108
113
|
#nodeFilter?: ((node: TreeNodeDataType) => FilterOption);
|
109
114
|
|
110
115
|
/**
|
@@ -66,8 +66,8 @@ export class Fragment {
|
|
66
66
|
|
67
67
|
const template = document.createElement('template');
|
68
68
|
template.innerHTML = html;
|
69
|
-
const walker =
|
70
|
-
template.content, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null);
|
69
|
+
const walker =
|
70
|
+
template.ownerDocument.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, null);
|
71
71
|
let valueIndex = 0;
|
72
72
|
const emptyTextNodes = [];
|
73
73
|
const binds: Bind[] = [];
|
@@ -15,7 +15,18 @@ import type {ToolbarItem} from './Toolbar.js';
|
|
15
15
|
import {Toolbar, ToolbarMenuButton} from './Toolbar.js';
|
16
16
|
import {createTextChild} from './UIUtils.js';
|
17
17
|
import type {TabbedViewLocation, View, ViewLocation, ViewLocationResolver} from './View.js';
|
18
|
-
import {
|
18
|
+
import {
|
19
|
+
getRegisteredLocationResolvers,
|
20
|
+
getRegisteredViewExtensions,
|
21
|
+
maybeRemoveViewExtension,
|
22
|
+
registerLocationResolver,
|
23
|
+
registerViewExtension,
|
24
|
+
ViewLocationCategoryValues,
|
25
|
+
ViewLocationValues,
|
26
|
+
ViewPersistence,
|
27
|
+
type ViewRegistration,
|
28
|
+
resetViewRegistration,
|
29
|
+
} from './ViewRegistration.js';
|
19
30
|
import type {Widget, WidgetElement} from './Widget.js';
|
20
31
|
import {VBox} from './Widget.js';
|
21
32
|
import viewContainersStyles from './viewContainers.css.legacy.js';
|
@@ -13,7 +13,12 @@ import * as ARIAUtils from './ARIAUtils.js';
|
|
13
13
|
import type {ContextMenu, Provider} from './ContextMenu.js';
|
14
14
|
import {html} from './Fragment.js';
|
15
15
|
import {Tooltip} from './Tooltip.js';
|
16
|
-
import {
|
16
|
+
import {
|
17
|
+
addReferrerToURLIfNecessary,
|
18
|
+
copyLinkAddressLabel,
|
19
|
+
MaxLengthForDisplayedURLs,
|
20
|
+
openLinkExternallyLabel,
|
21
|
+
} from './UIUtils.js';
|
17
22
|
import {XElement} from './XElement.js';
|
18
23
|
|
19
24
|
export class XLink extends XElement {
|
@@ -7,7 +7,14 @@ import * as LitHtml from '../../../lit-html/lit-html.js';
|
|
7
7
|
import cssAngleStyles from './cssAngle.css.js';
|
8
8
|
|
9
9
|
import type {Angle} from './CSSAngleUtils.js';
|
10
|
-
import {
|
10
|
+
import {
|
11
|
+
AngleUnit,
|
12
|
+
convertAngleUnit,
|
13
|
+
getNewAngleFromEvent,
|
14
|
+
getNextUnit,
|
15
|
+
parseText,
|
16
|
+
roundAngleByUnit,
|
17
|
+
} from './CSSAngleUtils.js';
|
11
18
|
import {ValueChangedEvent} from './InlineEditorUtils.js';
|
12
19
|
|
13
20
|
import type {CSSAngleEditorData} from './CSSAngleEditor.js';
|
@@ -8,7 +8,13 @@ import * as LitHtml from '../../../lit-html/lit-html.js';
|
|
8
8
|
import cssAngleEditorStyles from './cssAngleEditor.css.js';
|
9
9
|
|
10
10
|
import type {Angle} from './CSSAngleUtils.js';
|
11
|
-
import {
|
11
|
+
import {
|
12
|
+
AngleUnit,
|
13
|
+
get2DTranslationsForAngle,
|
14
|
+
getAngleFromRadians,
|
15
|
+
getNewAngleFromEvent,
|
16
|
+
getRadiansFromAngle,
|
17
|
+
} from './CSSAngleUtils.js';
|
12
18
|
|
13
19
|
const {render, html} = LitHtml;
|
14
20
|
const styleMap = LitHtml.Directives.styleMap;
|
package/package.json
CHANGED
@@ -0,0 +1,110 @@
|
|
1
|
+
// Copyright 2020 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
|
+
'use strict';
|
5
|
+
|
6
|
+
function goToClassDeclaration(node) {
|
7
|
+
if (!node) {
|
8
|
+
return null;
|
9
|
+
}
|
10
|
+
|
11
|
+
if (node.type === 'ClassDeclaration') {
|
12
|
+
return node;
|
13
|
+
}
|
14
|
+
|
15
|
+
return goToClassDeclaration(node.parent);
|
16
|
+
}
|
17
|
+
|
18
|
+
function isMemberExpressionOnThis(memberExpression) {
|
19
|
+
if (!memberExpression) {
|
20
|
+
return false;
|
21
|
+
}
|
22
|
+
|
23
|
+
if (memberExpression.object.type === 'ThisExpression') {
|
24
|
+
// Take into `a.this.bind()` case into account
|
25
|
+
// `this` must be the last object in the `MemberExpression` chain
|
26
|
+
return !memberExpression.object.object;
|
27
|
+
}
|
28
|
+
|
29
|
+
return isMemberExpressionOnThis(memberExpression.object);
|
30
|
+
}
|
31
|
+
|
32
|
+
// Whether the right hand side of property definition is `this.xxx.yyy.bind(this);`
|
33
|
+
function isPropertyDefinitionViaBindCallToThis(propertyDefinition) {
|
34
|
+
if (propertyDefinition.value.type !== 'CallExpression' ||
|
35
|
+
propertyDefinition.value.callee.type !== 'MemberExpression') {
|
36
|
+
return false;
|
37
|
+
}
|
38
|
+
|
39
|
+
const isCalleeObjectThis = isMemberExpressionOnThis(propertyDefinition.value.callee);
|
40
|
+
// Whether the CallExpression is on a property of `this` (this.xxx.yyy.bind)
|
41
|
+
if (!isCalleeObjectThis) {
|
42
|
+
return false;
|
43
|
+
}
|
44
|
+
|
45
|
+
const isItBindCall = propertyDefinition.value.callee.property.name === 'bind';
|
46
|
+
// Whether the CallExpression is a `bind` call on a property of `this`
|
47
|
+
if (!isItBindCall) {
|
48
|
+
return false;
|
49
|
+
}
|
50
|
+
|
51
|
+
const callArgument = propertyDefinition.value.arguments[0];
|
52
|
+
// Call argument to `bind` is not `this`
|
53
|
+
if (!callArgument || callArgument.type !== 'ThisExpression') {
|
54
|
+
return false;
|
55
|
+
}
|
56
|
+
|
57
|
+
return true;
|
58
|
+
}
|
59
|
+
|
60
|
+
// Whether the property definition is arrow function like `#render = () => {}`
|
61
|
+
function isPropertyDefinitionViaArrowFunction(propertyDefinition) {
|
62
|
+
return propertyDefinition.value.type === 'ArrowFunctionExpression';
|
63
|
+
}
|
64
|
+
|
65
|
+
module.exports = {
|
66
|
+
meta: {
|
67
|
+
type: 'problem',
|
68
|
+
docs: {
|
69
|
+
description: 'Enforce render method to be bound while calling scheduleRender',
|
70
|
+
category: 'Possible Errors',
|
71
|
+
},
|
72
|
+
fixable: 'code',
|
73
|
+
schema: [] // no options
|
74
|
+
},
|
75
|
+
create: function(context) {
|
76
|
+
return {
|
77
|
+
CallExpression(node) {
|
78
|
+
// Calls in the form of `ScheduledRender.scheduleRender`
|
79
|
+
const isScheduleRenderCall = node.callee.type === 'MemberExpression' &&
|
80
|
+
node.callee.object?.property?.name === 'ScheduledRender' && node.callee.property?.name === 'scheduleRender';
|
81
|
+
if (!isScheduleRenderCall) {
|
82
|
+
return;
|
83
|
+
}
|
84
|
+
|
85
|
+
const callbackArgument = node.arguments[1];
|
86
|
+
// Whether the second argument points to a property of `this`
|
87
|
+
// like `ScheduledRender.scheduleRender(<any>, this.<any>)
|
88
|
+
if (callbackArgument.type !== 'MemberExpression' || callbackArgument.object.type !== 'ThisExpression') {
|
89
|
+
return;
|
90
|
+
}
|
91
|
+
|
92
|
+
const containingClassForTheCall = goToClassDeclaration(node);
|
93
|
+
// Only care about the calls in custom components
|
94
|
+
if (!containingClassForTheCall.superClass || containingClassForTheCall.superClass.name !== 'HTMLElement') {
|
95
|
+
return;
|
96
|
+
}
|
97
|
+
|
98
|
+
const calledMethod = callbackArgument.property;
|
99
|
+
// Check whether the called method is bound (it should be 'PropertyDefinition')
|
100
|
+
const propertyDefinition = containingClassForTheCall.body.body.find(
|
101
|
+
bodyNode => bodyNode.type === 'PropertyDefinition' && bodyNode.key.name === calledMethod.name);
|
102
|
+
if (!propertyDefinition ||
|
103
|
+
(!isPropertyDefinitionViaArrowFunction(propertyDefinition) &&
|
104
|
+
!isPropertyDefinitionViaBindCallToThis(propertyDefinition))) {
|
105
|
+
context.report({node, message: 'Bind `render` method of `scheduleRender` to `this` in components'});
|
106
|
+
}
|
107
|
+
}
|
108
|
+
};
|
109
|
+
}
|
110
|
+
};
|
@@ -0,0 +1,74 @@
|
|
1
|
+
// Copyright 2020 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
|
+
'use strict';
|
5
|
+
|
6
|
+
const rule = require('../lib/enforce_bound_render_for_schedule_render.js');
|
7
|
+
const ruleTester = new (require('eslint').RuleTester)({
|
8
|
+
parserOptions: {ecmaVersion: 9, sourceType: 'module'},
|
9
|
+
parser: require.resolve('@typescript-eslint/parser'),
|
10
|
+
});
|
11
|
+
|
12
|
+
ruleTester.run('enforce_bound_render_for_schedule_render', rule, {
|
13
|
+
valid: [
|
14
|
+
{
|
15
|
+
code: `
|
16
|
+
class Component extends HTMLElement {
|
17
|
+
#boundRender = this.#render.bind(this);
|
18
|
+
get data(data) {
|
19
|
+
this.data = data;
|
20
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
21
|
+
}
|
22
|
+
|
23
|
+
#render() {}
|
24
|
+
}
|
25
|
+
`,
|
26
|
+
filename: 'front_end/ui/components/foo/Foo.ts',
|
27
|
+
},
|
28
|
+
{
|
29
|
+
code: `
|
30
|
+
class Component extends HTMLElement {
|
31
|
+
get data(data) {
|
32
|
+
this.data = data;
|
33
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
|
34
|
+
}
|
35
|
+
|
36
|
+
#render = () => {};
|
37
|
+
}
|
38
|
+
`,
|
39
|
+
filename: 'front_end/ui/components/foo/Foo.ts',
|
40
|
+
},
|
41
|
+
{
|
42
|
+
code: `
|
43
|
+
class Renderer {
|
44
|
+
render() {
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
class Component extends HTMLElement {
|
49
|
+
#renderer = new Renderer();
|
50
|
+
#boundRender = this.#renderer.render.bind(this);
|
51
|
+
get data(data) {
|
52
|
+
this.data = data;
|
53
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#boundRender);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
`,
|
57
|
+
filename: 'front_end/ui/components/foo/Foo.ts',
|
58
|
+
},
|
59
|
+
],
|
60
|
+
invalid: [
|
61
|
+
{
|
62
|
+
code: `class Component extends HTMLElement {
|
63
|
+
get data(data) {
|
64
|
+
this.data = data;
|
65
|
+
void ComponentHelpers.ScheduledRender.scheduleRender(this, this.#render);
|
66
|
+
}
|
67
|
+
|
68
|
+
#render() {}
|
69
|
+
}`,
|
70
|
+
filename: 'front_end/components/test.ts',
|
71
|
+
errors: [{message: 'Bind `render` method of `scheduleRender` to `this` in components'}],
|
72
|
+
},
|
73
|
+
]
|
74
|
+
});
|
@@ -0,0 +1,60 @@
|
|
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
|
+
/**
|
6
|
+
* Run this script to re-format all .js and .ts files found
|
7
|
+
* node scripts/reformat-clang-js-ts.js --directory=front_end
|
8
|
+
* The script starts in the given directory and recursively finds all `.js` and `.ts` files to reformat.
|
9
|
+
* Any `.clang-format` with `DisableFormat: true` is respected; those
|
10
|
+
* directories will not be used.
|
11
|
+
**/
|
12
|
+
|
13
|
+
const fs = require('fs');
|
14
|
+
const path = require('path');
|
15
|
+
const childProcess = require('child_process');
|
16
|
+
|
17
|
+
const yargs = require('yargs')
|
18
|
+
.option('dry-run', {
|
19
|
+
type: 'boolean',
|
20
|
+
default: false,
|
21
|
+
desc: 'Logs which files will be formatted, but doesn\'t write to disk',
|
22
|
+
})
|
23
|
+
.option('directory', {type: 'string', demandOption: true, desc: 'The starting directory to run in.'})
|
24
|
+
.strict()
|
25
|
+
.argv;
|
26
|
+
|
27
|
+
const startingDirectory = path.join(process.cwd(), yargs.directory);
|
28
|
+
|
29
|
+
const filesToFormat = [];
|
30
|
+
function processDirectory(dir) {
|
31
|
+
const contents = fs.readdirSync(dir);
|
32
|
+
|
33
|
+
if (contents.includes('.clang-format')) {
|
34
|
+
const clangFormatConfig = fs.readFileSync(path.join(dir, '.clang-format'), 'utf8');
|
35
|
+
if (clangFormatConfig.includes('DisableFormat: true')) {
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
}
|
39
|
+
for (const item of contents) {
|
40
|
+
const fullPath = path.join(dir, item);
|
41
|
+
if (fs.lstatSync(fullPath).isDirectory()) {
|
42
|
+
processDirectory(fullPath);
|
43
|
+
} else if (['.ts', '.js'].includes(path.extname(fullPath))) {
|
44
|
+
filesToFormat.push(fullPath);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
processDirectory(startingDirectory);
|
50
|
+
filesToFormat.forEach((file, index) => {
|
51
|
+
console.log(`Formatting ${index + 1}/${filesToFormat.length}`, path.relative(process.cwd(), file));
|
52
|
+
|
53
|
+
if (yargs.dryRun) {
|
54
|
+
return;
|
55
|
+
}
|
56
|
+
const out = String(childProcess.execSync(`clang-format -i ${file}`));
|
57
|
+
if (out.trim() !== '') {
|
58
|
+
console.log(out);
|
59
|
+
}
|
60
|
+
});
|