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.
Files changed (34) hide show
  1. package/front_end/.eslintrc.js +4 -4
  2. package/front_end/core/common/ParsedURL.ts +3 -3
  3. package/front_end/core/dom_extension/DOMExtension.ts +0 -10
  4. package/front_end/core/i18n/locales/en-US.json +6 -9
  5. package/front_end/core/i18n/locales/en-XL.json +6 -9
  6. package/front_end/models/extensions/ExtensionAPI.ts +4 -4
  7. package/front_end/models/extensions/ExtensionTraceProvider.ts +2 -1
  8. package/front_end/models/issues_manager/DeprecationIssue.ts +7 -2
  9. package/front_end/models/workspace/WorkspaceImpl.ts +1 -1
  10. package/front_end/panels/lighthouse/LighthouseController.ts +15 -0
  11. package/front_end/panels/network/NetworkItemView.ts +1 -1
  12. package/front_end/panels/sources/AddSourceMapURLDialog.ts +5 -4
  13. package/front_end/panels/sources/DebuggerPausedMessage.ts +2 -1
  14. package/front_end/panels/sources/DebuggerPlugin.ts +2 -2
  15. package/front_end/panels/sources/EditingLocationHistoryManager.ts +2 -4
  16. package/front_end/panels/sources/NavigatorView.ts +4 -5
  17. package/front_end/panels/sources/ScriptFormatterEditorAction.ts +2 -1
  18. package/front_end/panels/sources/TabbedEditorContainer.ts +14 -13
  19. package/front_end/panels/timeline/ExtensionTracingSession.ts +2 -1
  20. package/front_end/panels/timeline/TimelineEventOverview.ts +0 -60
  21. package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +1 -9
  22. package/front_end/panels/timeline/TimelineFlameChartView.ts +1 -1
  23. package/front_end/panels/timeline/TimelineHistoryManager.ts +0 -2
  24. package/front_end/panels/timeline/TimelineLoader.ts +2 -1
  25. package/front_end/panels/timeline/TimelinePanel.ts +3 -5
  26. package/front_end/panels/timeline/TimelineTreeView.ts +4 -4
  27. package/front_end/panels/timeline/TimelineUIUtils.ts +3 -9
  28. package/front_end/panels/timeline/timeline-legacy.ts +0 -3
  29. package/front_end/panels/timeline/timelinePanel.css +0 -6
  30. package/front_end/panels/webauthn/WebauthnPane.ts +49 -15
  31. package/package.json +1 -1
  32. package/scripts/eslint_rules/lib/enforce_bound_render_for_schedule_render.js +110 -0
  33. package/scripts/eslint_rules/tests/enforce_bound_render_for_schedule_render_test.js +74 -0
  34. 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 = i18nString(
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<string, string>;
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: string, client: Client): TimelineLoader {
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: string): void {
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: string): boolean {
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: string): boolean {
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): string|null {
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
- #residentKeyCheckbox: HTMLInputElement|undefined;
253
+ residentKeyCheckbox: HTMLInputElement|undefined;
248
254
  #userVerificationCheckboxLabel: UI.UIUtils.CheckboxLabel|undefined;
249
255
  #userVerificationCheckbox: HTMLInputElement|undefined;
250
- #addAuthenticatorButton: HTMLButtonElement|undefined;
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.#residentKeyCheckbox || !this.#userVerificationCheckbox) {
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.#residentKeyCheckbox.disabled = false;
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.#residentKeyCheckbox.checked = false;
495
- this.#residentKeyCheckbox.disabled = true;
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.#residentKeyCheckbox = this.#residentKeyCheckboxLabel.checkboxElement;
555
- this.#residentKeyCheckbox.checked = false;
556
- this.#residentKeyCheckbox.classList.add('authenticator-option-checkbox');
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.#addAuthenticatorButton =
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.#addAuthenticatorButton);
595
+ addButtonGroup.appendChild(this.addAuthenticatorButton);
571
596
  const addAuthenticatorTitle = UI.UIUtils.createLabel(i18nString(UIStrings.addAuthenticator), '');
572
- UI.ARIAUtils.bindLabelToControl(addAuthenticatorTitle, this.#addAuthenticatorButton);
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.#residentKeyCheckbox ||
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.#residentKeyCheckbox.checked,
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
@@ -55,5 +55,5 @@
55
55
  "unittest": "scripts/test/run_unittests.py --no-text-coverage",
56
56
  "watch": "vpython third_party/node/node.py --output scripts/watch_build.js"
57
57
  },
58
- "version": "1.0.999279"
58
+ "version": "1.0.1000679"
59
59
  }
@@ -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
+ });