chrome-devtools-frontend 1.0.999279 → 1.0.1000679
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/front_end/.eslintrc.js +4 -4
- package/front_end/core/common/ParsedURL.ts +3 -3
- package/front_end/core/dom_extension/DOMExtension.ts +0 -10
- package/front_end/core/i18n/locales/en-US.json +6 -9
- package/front_end/core/i18n/locales/en-XL.json +6 -9
- package/front_end/models/extensions/ExtensionAPI.ts +4 -4
- package/front_end/models/extensions/ExtensionTraceProvider.ts +2 -1
- package/front_end/models/issues_manager/DeprecationIssue.ts +7 -2
- package/front_end/models/workspace/WorkspaceImpl.ts +1 -1
- package/front_end/panels/lighthouse/LighthouseController.ts +15 -0
- package/front_end/panels/network/NetworkItemView.ts +1 -1
- 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/TabbedEditorContainer.ts +14 -13
- package/front_end/panels/timeline/ExtensionTracingSession.ts +2 -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 +1 -1
- package/front_end/panels/timeline/TimelineHistoryManager.ts +0 -2
- package/front_end/panels/timeline/TimelineLoader.ts +2 -1
- package/front_end/panels/timeline/TimelinePanel.ts +3 -5
- package/front_end/panels/timeline/TimelineTreeView.ts +4 -4
- package/front_end/panels/timeline/TimelineUIUtils.ts +3 -9
- package/front_end/panels/timeline/timeline-legacy.ts +0 -3
- package/front_end/panels/timeline/timelinePanel.css +0 -6
- package/front_end/panels/webauthn/WebauthnPane.ts +49 -15
- 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
@@ -131,12 +131,6 @@ const UIStrings = {
|
|
131
131
|
occurrencesS: 'Occurrences: {PH1}',
|
132
132
|
/**
|
133
133
|
*@description Text in Timeline Flame Chart Data Provider of the Performance panel
|
134
|
-
*@example {10ms} PH1
|
135
|
-
*@example {100.0} PH2
|
136
|
-
*/
|
137
|
-
sFfps: '{PH1} ~ {PH2} fps',
|
138
|
-
/**
|
139
|
-
*@description Text in Timeline Flame Chart Data Provider of the Performance panel
|
140
134
|
*/
|
141
135
|
idleFrame: 'Idle Frame',
|
142
136
|
/**
|
@@ -1005,9 +999,7 @@ export class TimelineFlameChartDataProvider extends Common.ObjectWrapper.ObjectW
|
|
1005
999
|
|
1006
1000
|
} else if (type === EntryType.Frame) {
|
1007
1001
|
const frame = (this.entryData[entryIndex] as TimelineModel.TimelineFrameModel.TimelineFrame);
|
1008
|
-
time =
|
1009
|
-
UIStrings.sFfps,
|
1010
|
-
{PH1: i18n.TimeUtilities.preciseMillisToString(frame.duration, 1), PH2: (1000 / frame.duration).toFixed(0)});
|
1002
|
+
time = i18n.TimeUtilities.preciseMillisToString(frame.duration, 1);
|
1011
1003
|
|
1012
1004
|
if (frame.idle) {
|
1013
1005
|
title = i18nString(UIStrings.idleFrame);
|
@@ -161,7 +161,7 @@ export class TimelineFlameChartView extends UI.Widget.VBox implements PerfUI.Fla
|
|
161
161
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
162
162
|
private readonly groupBySetting: Common.Settings.Setting<any>;
|
163
163
|
private searchableView!: UI.SearchableView.SearchableView;
|
164
|
-
private urlToColorCache?: Map<
|
164
|
+
private urlToColorCache?: Map<Platform.DevToolsPath.UrlString, string>;
|
165
165
|
private needsResizeToPreferredHeights?: boolean;
|
166
166
|
private selectedSearchResult?: number;
|
167
167
|
private searchRegex?: RegExp;
|
@@ -12,7 +12,6 @@ import timelineHistoryManagerStyles from './timelineHistoryManager.css.js';
|
|
12
12
|
import type {PerformanceModel} from './PerformanceModel.js';
|
13
13
|
import {
|
14
14
|
TimelineEventOverviewCPUActivity,
|
15
|
-
TimelineEventOverviewFrames,
|
16
15
|
TimelineEventOverviewNetwork,
|
17
16
|
TimelineEventOverviewResponsiveness,
|
18
17
|
} from './TimelineEventOverview.js';
|
@@ -86,7 +85,6 @@ export class TimelineHistoryManager {
|
|
86
85
|
|
87
86
|
this.allOverviews = [
|
88
87
|
{constructor: TimelineEventOverviewResponsiveness, height: 3},
|
89
|
-
{constructor: TimelineEventOverviewFrames, height: 16},
|
90
88
|
{constructor: TimelineEventOverviewCPUActivity, height: 20},
|
91
89
|
{constructor: TimelineEventOverviewNetwork, height: 8},
|
92
90
|
];
|
@@ -5,6 +5,7 @@
|
|
5
5
|
import * as Common from '../../core/common/common.js';
|
6
6
|
import * as Host from '../../core/host/host.js';
|
7
7
|
import * as i18n from '../../core/i18n/i18n.js';
|
8
|
+
import type * as Platform from '../../core/platform/platform.js';
|
8
9
|
import * as SDK from '../../core/sdk/sdk.js';
|
9
10
|
import * as Bindings from '../../models/bindings/bindings.js';
|
10
11
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
@@ -95,7 +96,7 @@ export class TimelineLoader implements Common.StringOutputStream.OutputStream {
|
|
95
96
|
return loader;
|
96
97
|
}
|
97
98
|
|
98
|
-
static loadFromURL(url:
|
99
|
+
static loadFromURL(url: Platform.DevToolsPath.UrlString, client: Client): TimelineLoader {
|
99
100
|
const loader = new TimelineLoader(client);
|
100
101
|
Host.ResourceLoader.loadAsStream(url, null, loader);
|
101
102
|
return loader;
|
@@ -60,7 +60,6 @@ import type {TimelineEventOverview} from './TimelineEventOverview.js';
|
|
60
60
|
import {
|
61
61
|
TimelineEventOverviewCoverage,
|
62
62
|
TimelineEventOverviewCPUActivity,
|
63
|
-
TimelineEventOverviewFrames,
|
64
63
|
TimelineEventOverviewInput,
|
65
64
|
TimelineEventOverviewMemory,
|
66
65
|
TimelineEventOverviewNetwork,
|
@@ -696,7 +695,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
|
|
696
695
|
this.createFileSelector();
|
697
696
|
}
|
698
697
|
|
699
|
-
loadFromURL(url:
|
698
|
+
loadFromURL(url: Platform.DevToolsPath.UrlString): void {
|
700
699
|
if (this.state !== State.Idle) {
|
701
700
|
return;
|
702
701
|
}
|
@@ -710,7 +709,6 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
|
|
710
709
|
if (Root.Runtime.experiments.isEnabled('inputEventsOnTimelineOverview')) {
|
711
710
|
this.overviewControls.push(new TimelineEventOverviewInput());
|
712
711
|
}
|
713
|
-
this.overviewControls.push(new TimelineEventOverviewFrames());
|
714
712
|
this.overviewControls.push(new TimelineEventOverviewCPUActivity());
|
715
713
|
this.overviewControls.push(new TimelineEventOverviewNetwork());
|
716
714
|
if (this.showScreenshotsSetting.get() && this.performanceModel &&
|
@@ -1251,7 +1249,7 @@ export class TimelinePanel extends UI.Panel.Panel implements Client, TimelineMod
|
|
1251
1249
|
const item = items[0];
|
1252
1250
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.PerfPanelTraceImported);
|
1253
1251
|
if (item.kind === 'string') {
|
1254
|
-
const url = dataTransfer.getData('text/uri-list');
|
1252
|
+
const url = dataTransfer.getData('text/uri-list') as Platform.DevToolsPath.UrlString;
|
1255
1253
|
if (new Common.ParsedURL.ParsedURL(url).isValid) {
|
1256
1254
|
this.loadFromURL(url);
|
1257
1255
|
}
|
@@ -1494,7 +1492,7 @@ export class LoadTimelineHandler implements Common.QueryParamHandler.QueryParamH
|
|
1494
1492
|
|
1495
1493
|
handleQueryParam(value: string): void {
|
1496
1494
|
void UI.ViewManager.ViewManager.instance().showView('timeline').then(() => {
|
1497
|
-
TimelinePanel.instance().loadFromURL(window.decodeURIComponent(value));
|
1495
|
+
TimelinePanel.instance().loadFromURL(window.decodeURIComponent(value) as Platform.DevToolsPath.UrlString);
|
1498
1496
|
});
|
1499
1497
|
}
|
1500
1498
|
}
|
@@ -756,9 +756,9 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
|
|
756
756
|
}
|
757
757
|
|
758
758
|
private beautifyDomainName(this: AggregatedTimelineTreeView, name: string): string {
|
759
|
-
if (AggregatedTimelineTreeView.isExtensionInternalURL(name)) {
|
759
|
+
if (AggregatedTimelineTreeView.isExtensionInternalURL(name as Platform.DevToolsPath.UrlString)) {
|
760
760
|
name = i18nString(UIStrings.chromeExtensionsOverhead);
|
761
|
-
} else if (AggregatedTimelineTreeView.isV8NativeURL(name)) {
|
761
|
+
} else if (AggregatedTimelineTreeView.isV8NativeURL(name as Platform.DevToolsPath.UrlString)) {
|
762
762
|
name = i18nString(UIStrings.vRuntime);
|
763
763
|
} else if (name.startsWith('chrome-extension')) {
|
764
764
|
name = this.executionContextNamesByOrigin.get(name) || name;
|
@@ -949,11 +949,11 @@ export class AggregatedTimelineTreeView extends TimelineTreeView {
|
|
949
949
|
contextMenu.appendApplicableItems(frame.ownerNode);
|
950
950
|
}
|
951
951
|
|
952
|
-
private static isExtensionInternalURL(url:
|
952
|
+
private static isExtensionInternalURL(url: Platform.DevToolsPath.UrlString): boolean {
|
953
953
|
return url.startsWith(AggregatedTimelineTreeView.extensionInternalPrefix);
|
954
954
|
}
|
955
955
|
|
956
|
-
private static isV8NativeURL(url:
|
956
|
+
private static isV8NativeURL(url: Platform.DevToolsPath.UrlString): boolean {
|
957
957
|
return url.startsWith(AggregatedTimelineTreeView.v8NativePrefix);
|
958
958
|
}
|
959
959
|
|
@@ -1069,10 +1069,6 @@ const UIStrings = {
|
|
1069
1069
|
*/
|
1070
1070
|
frame: 'Frame',
|
1071
1071
|
/**
|
1072
|
-
*@description Text in Timeline Event Overview of the Performance panel
|
1073
|
-
*/
|
1074
|
-
fps: 'FPS',
|
1075
|
-
/**
|
1076
1072
|
*@description Text in Timeline UIUtils of the Performance panel
|
1077
1073
|
*/
|
1078
1074
|
cpuTime: 'CPU time',
|
@@ -1477,7 +1473,7 @@ export class TimelineUIUtils {
|
|
1477
1473
|
}
|
1478
1474
|
}
|
1479
1475
|
|
1480
|
-
static eventURL(event: SDK.TracingModel.Event):
|
1476
|
+
static eventURL(event: SDK.TracingModel.Event): Platform.DevToolsPath.UrlString|null {
|
1481
1477
|
const data = event.args['data'] || event.args['beginData'];
|
1482
1478
|
const url = data && data.url;
|
1483
1479
|
if (url) {
|
@@ -1486,7 +1482,7 @@ export class TimelineUIUtils {
|
|
1486
1482
|
const stackTrace = data && data['stackTrace'];
|
1487
1483
|
const frame = stackTrace && stackTrace.length && stackTrace[0] ||
|
1488
1484
|
TimelineModel.TimelineModel.TimelineData.forEvent(event).topFrame();
|
1489
|
-
return frame && frame.url || null;
|
1485
|
+
return frame && frame.url as Platform.DevToolsPath.UrlString || null;
|
1490
1486
|
}
|
1491
1487
|
|
1492
1488
|
static eventStyle(event: SDK.TracingModel.Event): TimelineRecordStyle {
|
@@ -1537,7 +1533,7 @@ export class TimelineUIUtils {
|
|
1537
1533
|
static eventColorByProduct(
|
1538
1534
|
model: TimelineModel.TimelineModel.TimelineModelImpl, urlToColorCache: Map<string, string>,
|
1539
1535
|
event: SDK.TracingModel.Event): string {
|
1540
|
-
const url = TimelineUIUtils.eventURL(event) ||
|
1536
|
+
const url = TimelineUIUtils.eventURL(event) || Platform.DevToolsPath.EmptyUrlString;
|
1541
1537
|
let color = urlToColorCache.get(url);
|
1542
1538
|
if (color) {
|
1543
1539
|
return color;
|
@@ -3089,8 +3085,6 @@ export class TimelineUIUtils {
|
|
3089
3085
|
|
3090
3086
|
const duration = TimelineUIUtils.frameDuration(frame);
|
3091
3087
|
contentHelper.appendElementRow(i18nString(UIStrings.duration), duration, frame.hasWarnings());
|
3092
|
-
const durationInMillis = frame.endTime - frame.startTime;
|
3093
|
-
contentHelper.appendTextRow(i18nString(UIStrings.fps), Math.floor(1000 / durationInMillis));
|
3094
3088
|
contentHelper.appendTextRow(i18nString(UIStrings.cpuTime), i18n.TimeUtilities.millisToString(frame.cpuTime, true));
|
3095
3089
|
if (filmStripFrame) {
|
3096
3090
|
const filmStripPreview = document.createElement('div');
|
@@ -74,9 +74,6 @@ Timeline.TimelineEventOverviewResponsiveness = TimelineModule.TimelineEventOverv
|
|
74
74
|
/** @constructor */
|
75
75
|
Timeline.TimelineFilmStripOverview = TimelineModule.TimelineEventOverview.TimelineFilmStripOverview;
|
76
76
|
|
77
|
-
/** @constructor */
|
78
|
-
Timeline.TimelineEventOverviewFrames = TimelineModule.TimelineEventOverview.TimelineEventOverviewFrames;
|
79
|
-
|
80
77
|
/** @constructor */
|
81
78
|
Timeline.TimelineEventOverviewMemory = TimelineModule.TimelineEventOverview.TimelineEventOverviewMemory;
|
82
79
|
|
@@ -111,11 +111,6 @@
|
|
111
111
|
flex-basis: 8px;
|
112
112
|
}
|
113
113
|
|
114
|
-
#timeline-overview-framerate {
|
115
|
-
flex-basis: 16px;
|
116
|
-
margin-top: 0 !important; /* stylelint-disable-line declaration-no-important */
|
117
|
-
}
|
118
|
-
|
119
114
|
#timeline-overview-filmstrip {
|
120
115
|
flex-basis: 30px;
|
121
116
|
}
|
@@ -124,7 +119,6 @@
|
|
124
119
|
flex-basis: 20px;
|
125
120
|
}
|
126
121
|
|
127
|
-
#timeline-overview-framerate::before,
|
128
122
|
#timeline-overview-network::before,
|
129
123
|
#timeline-overview-cpu-activity::before {
|
130
124
|
content: "";
|
@@ -84,6 +84,12 @@ const UIStrings = {
|
|
84
84
|
*/
|
85
85
|
supportsResidentKeys: 'Supports resident keys',
|
86
86
|
/**
|
87
|
+
*@description Label for checkbox that toggles large blob support on virtual authenticators. Large blobs are opaque data associated
|
88
|
+
* with a WebAuthn credential that a website can store, like an SSH certificate or a symmetric encryption key.
|
89
|
+
* See https://w3c.github.io/webauthn/#sctn-large-blob-extension
|
90
|
+
*/
|
91
|
+
supportsLargeBlob: 'Supports large blob',
|
92
|
+
/**
|
87
93
|
*@description Text to add something
|
88
94
|
*/
|
89
95
|
add: 'Add',
|
@@ -244,10 +250,12 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
244
250
|
#protocolSelect: HTMLSelectElement|undefined;
|
245
251
|
#transportSelect: HTMLSelectElement|undefined;
|
246
252
|
#residentKeyCheckboxLabel: UI.UIUtils.CheckboxLabel|undefined;
|
247
|
-
|
253
|
+
residentKeyCheckbox: HTMLInputElement|undefined;
|
248
254
|
#userVerificationCheckboxLabel: UI.UIUtils.CheckboxLabel|undefined;
|
249
255
|
#userVerificationCheckbox: HTMLInputElement|undefined;
|
250
|
-
#
|
256
|
+
#largeBlobCheckboxLabel: UI.UIUtils.CheckboxLabel|undefined;
|
257
|
+
largeBlobCheckbox: HTMLInputElement|undefined;
|
258
|
+
addAuthenticatorButton: HTMLButtonElement|undefined;
|
251
259
|
#isEnabling?: Promise<void>;
|
252
260
|
|
253
261
|
constructor() {
|
@@ -475,13 +483,18 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
475
483
|
}
|
476
484
|
|
477
485
|
#updateNewAuthenticatorSectionOptions(): void {
|
478
|
-
if (!this.#protocolSelect || !this
|
486
|
+
if (!this.#protocolSelect || !this.residentKeyCheckbox || !this.#userVerificationCheckbox ||
|
487
|
+
!this.largeBlobCheckbox) {
|
479
488
|
return;
|
480
489
|
}
|
481
490
|
|
482
491
|
if (this.#protocolSelect.value === Protocol.WebAuthn.AuthenticatorProtocol.Ctap2) {
|
483
|
-
this
|
492
|
+
this.residentKeyCheckbox.disabled = false;
|
484
493
|
this.#userVerificationCheckbox.disabled = false;
|
494
|
+
this.largeBlobCheckbox.disabled = !this.residentKeyCheckbox.checked;
|
495
|
+
if (this.largeBlobCheckbox.disabled) {
|
496
|
+
this.largeBlobCheckbox.checked = false;
|
497
|
+
}
|
485
498
|
this.#updateEnabledTransportOptions([
|
486
499
|
Protocol.WebAuthn.AuthenticatorTransport.Usb,
|
487
500
|
Protocol.WebAuthn.AuthenticatorTransport.Ble,
|
@@ -491,10 +504,12 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
491
504
|
Protocol.WebAuthn.AuthenticatorTransport.Internal,
|
492
505
|
]);
|
493
506
|
} else {
|
494
|
-
this
|
495
|
-
this
|
507
|
+
this.residentKeyCheckbox.checked = false;
|
508
|
+
this.residentKeyCheckbox.disabled = true;
|
496
509
|
this.#userVerificationCheckbox.checked = false;
|
497
510
|
this.#userVerificationCheckbox.disabled = true;
|
511
|
+
this.largeBlobCheckbox.checked = false;
|
512
|
+
this.largeBlobCheckbox.disabled = true;
|
498
513
|
this.#updateEnabledTransportOptions([
|
499
514
|
Protocol.WebAuthn.AuthenticatorTransport.Usb,
|
500
515
|
Protocol.WebAuthn.AuthenticatorTransport.Ble,
|
@@ -524,6 +539,7 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
524
539
|
const transportGroup = this.#newAuthenticatorForm.createChild('div', 'authenticator-option');
|
525
540
|
const residentKeyGroup = this.#newAuthenticatorForm.createChild('div', 'authenticator-option');
|
526
541
|
const userVerificationGroup = this.#newAuthenticatorForm.createChild('div', 'authenticator-option');
|
542
|
+
const largeBlobGroup = this.#newAuthenticatorForm.createChild('div', 'authenticator-option');
|
527
543
|
const addButtonGroup = this.#newAuthenticatorForm.createChild('div', 'authenticator-option');
|
528
544
|
|
529
545
|
const protocolSelectTitle = UI.UIUtils.createLabel(i18nString(UIStrings.protocol), 'authenticator-option-label');
|
@@ -551,9 +567,9 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
551
567
|
this.#residentKeyCheckboxLabel = UI.UIUtils.CheckboxLabel.create(i18nString(UIStrings.supportsResidentKeys), false);
|
552
568
|
this.#residentKeyCheckboxLabel.textElement.classList.add('authenticator-option-label');
|
553
569
|
residentKeyGroup.appendChild(this.#residentKeyCheckboxLabel.textElement);
|
554
|
-
this
|
555
|
-
this
|
556
|
-
this
|
570
|
+
this.residentKeyCheckbox = this.#residentKeyCheckboxLabel.checkboxElement;
|
571
|
+
this.residentKeyCheckbox.checked = false;
|
572
|
+
this.residentKeyCheckbox.classList.add('authenticator-option-checkbox');
|
557
573
|
residentKeyGroup.appendChild(this.#residentKeyCheckboxLabel);
|
558
574
|
|
559
575
|
this.#userVerificationCheckboxLabel = UI.UIUtils.CheckboxLabel.create('Supports user verification', false);
|
@@ -564,17 +580,29 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
564
580
|
this.#userVerificationCheckbox.classList.add('authenticator-option-checkbox');
|
565
581
|
userVerificationGroup.appendChild(this.#userVerificationCheckboxLabel);
|
566
582
|
|
567
|
-
this.#
|
583
|
+
this.#largeBlobCheckboxLabel = UI.UIUtils.CheckboxLabel.create(i18nString(UIStrings.supportsLargeBlob), false);
|
584
|
+
this.#largeBlobCheckboxLabel.textElement.classList.add('authenticator-option-label');
|
585
|
+
largeBlobGroup.appendChild(this.#largeBlobCheckboxLabel.textElement);
|
586
|
+
this.largeBlobCheckbox = this.#largeBlobCheckboxLabel.checkboxElement;
|
587
|
+
this.largeBlobCheckbox.checked = false;
|
588
|
+
this.largeBlobCheckbox.classList.add('authenticator-option-checkbox');
|
589
|
+
this.largeBlobCheckbox.name = 'large-blob-checkbox';
|
590
|
+
largeBlobGroup.appendChild(this.#largeBlobCheckboxLabel);
|
591
|
+
|
592
|
+
this.addAuthenticatorButton =
|
568
593
|
UI.UIUtils.createTextButton(i18nString(UIStrings.add), this.#handleAddAuthenticatorButton.bind(this), '');
|
569
594
|
addButtonGroup.createChild('div', 'authenticator-option-label');
|
570
|
-
addButtonGroup.appendChild(this
|
595
|
+
addButtonGroup.appendChild(this.addAuthenticatorButton);
|
571
596
|
const addAuthenticatorTitle = UI.UIUtils.createLabel(i18nString(UIStrings.addAuthenticator), '');
|
572
|
-
UI.ARIAUtils.bindLabelToControl(addAuthenticatorTitle, this
|
597
|
+
UI.ARIAUtils.bindLabelToControl(addAuthenticatorTitle, this.addAuthenticatorButton);
|
573
598
|
|
574
599
|
this.#updateNewAuthenticatorSectionOptions();
|
575
600
|
if (this.#protocolSelect) {
|
576
601
|
this.#protocolSelect.addEventListener('change', this.#updateNewAuthenticatorSectionOptions.bind(this));
|
577
602
|
}
|
603
|
+
if (this.residentKeyCheckbox) {
|
604
|
+
this.residentKeyCheckbox.addEventListener('change', this.#updateNewAuthenticatorSectionOptions.bind(this));
|
605
|
+
}
|
578
606
|
}
|
579
607
|
|
580
608
|
async #handleAddAuthenticatorButton(): Promise<void> {
|
@@ -702,6 +730,7 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
702
730
|
const protocolField = sectionFields.createChild('div', 'authenticator-field');
|
703
731
|
const transportField = sectionFields.createChild('div', 'authenticator-field');
|
704
732
|
const srkField = sectionFields.createChild('div', 'authenticator-field');
|
733
|
+
const slbField = sectionFields.createChild('div', 'authenticator-field');
|
705
734
|
const suvField = sectionFields.createChild('div', 'authenticator-field');
|
706
735
|
|
707
736
|
uuidField.appendChild(UI.UIUtils.createLabel(i18nString(UIStrings.uuid), 'authenticator-option-label'));
|
@@ -709,6 +738,7 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
709
738
|
transportField.appendChild(UI.UIUtils.createLabel(i18nString(UIStrings.transport), 'authenticator-option-label'));
|
710
739
|
srkField.appendChild(
|
711
740
|
UI.UIUtils.createLabel(i18nString(UIStrings.supportsResidentKeys), 'authenticator-option-label'));
|
741
|
+
slbField.appendChild(UI.UIUtils.createLabel(i18nString(UIStrings.supportsLargeBlob), 'authenticator-option-label'));
|
712
742
|
suvField.appendChild(
|
713
743
|
UI.UIUtils.createLabel(i18nString(UIStrings.supportsUserVerification), 'authenticator-option-label'));
|
714
744
|
|
@@ -717,6 +747,8 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
717
747
|
transportField.createChild('div', 'authenticator-field-value').textContent = options.transport;
|
718
748
|
srkField.createChild('div', 'authenticator-field-value').textContent =
|
719
749
|
options.hasResidentKey ? i18nString(UIStrings.yes) : i18nString(UIStrings.no);
|
750
|
+
slbField.createChild('div', 'authenticator-field-value').textContent =
|
751
|
+
options.hasLargeBlob ? i18nString(UIStrings.yes) : i18nString(UIStrings.no);
|
720
752
|
suvField.createChild('div', 'authenticator-field-value').textContent =
|
721
753
|
options.hasUserVerification ? i18nString(UIStrings.yes) : i18nString(UIStrings.no);
|
722
754
|
}
|
@@ -779,18 +811,20 @@ export class WebauthnPaneImpl extends UI.Widget.VBox implements
|
|
779
811
|
|
780
812
|
#createOptionsFromCurrentInputs(): Protocol.WebAuthn.VirtualAuthenticatorOptions {
|
781
813
|
// TODO(crbug.com/1034663): Add optionality for isUserVerified param.
|
782
|
-
if (!this.#protocolSelect || !this.#transportSelect || !this
|
783
|
-
!this.#userVerificationCheckbox) {
|
814
|
+
if (!this.#protocolSelect || !this.#transportSelect || !this.residentKeyCheckbox ||
|
815
|
+
!this.#userVerificationCheckbox || !this.largeBlobCheckbox) {
|
784
816
|
throw new Error('Unable to create options from current inputs');
|
785
817
|
}
|
786
818
|
|
787
819
|
return {
|
788
820
|
protocol: this.#protocolSelect.options[this.#protocolSelect.selectedIndex].value as
|
789
821
|
Protocol.WebAuthn.AuthenticatorProtocol,
|
822
|
+
ctap2Version: Protocol.WebAuthn.Ctap2Version.Ctap2_1,
|
790
823
|
transport: this.#transportSelect.options[this.#transportSelect.selectedIndex].value as
|
791
824
|
Protocol.WebAuthn.AuthenticatorTransport,
|
792
|
-
hasResidentKey: this
|
825
|
+
hasResidentKey: this.residentKeyCheckbox.checked,
|
793
826
|
hasUserVerification: this.#userVerificationCheckbox.checked,
|
827
|
+
hasLargeBlob: this.largeBlobCheckbox.checked,
|
794
828
|
automaticPresenceSimulation: true,
|
795
829
|
isUserVerified: true,
|
796
830
|
};
|
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
|
+
});
|