chrome-devtools-frontend 1.0.928589 → 1.0.929998
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 +7 -2
- package/config/gni/devtools_image_files.gni +1 -0
- package/front_end/Images/src/preview_feature_video_thumbnail.svg +92 -0
- package/front_end/Images/whatsnew.avif +0 -0
- package/front_end/core/common/CharacterIdMap.ts +12 -12
- package/front_end/core/common/Color.ts +71 -71
- package/front_end/core/common/Console.ts +4 -4
- package/front_end/core/common/ParsedURL.ts +14 -14
- package/front_end/core/common/Progress.ts +45 -45
- package/front_end/core/common/ResolverBase.ts +8 -8
- package/front_end/core/common/ResourceType.ts +20 -20
- package/front_end/core/common/SegmentedRange.ts +17 -16
- package/front_end/core/common/Settings.ts +84 -66
- package/front_end/core/common/SimpleHistoryManager.ts +33 -33
- package/front_end/core/common/StringOutputStream.ts +4 -4
- package/front_end/core/common/Throttler.ts +44 -40
- package/front_end/core/common/Trie.ts +42 -42
- package/front_end/core/common/WasmDisassembly.ts +11 -11
- package/front_end/core/common/Worker.ts +9 -9
- package/front_end/core/host/InspectorFrontendHost.ts +13 -13
- package/front_end/core/host/UserMetrics.ts +12 -13
- package/front_end/core/i18n/locales/en-US.json +53 -20
- package/front_end/core/i18n/locales/en-XL.json +53 -20
- package/front_end/core/platform/keyboard-utilities.ts +6 -0
- package/front_end/core/sdk/sdk-meta.ts +5 -0
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +1 -0
- package/front_end/entrypoints/main/MainImpl.ts +14 -5
- package/front_end/entrypoints/main/main-meta.ts +4 -0
- package/front_end/models/issues_manager/IssuesManager.ts +2 -2
- package/front_end/panels/application/BackForwardCacheView.ts +19 -31
- package/front_end/panels/application/components/OriginTrialTreeView.ts +16 -0
- package/front_end/panels/console/console-meta.ts +6 -0
- package/front_end/panels/css_overview/CSSOverviewPanel.ts +9 -6
- package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +171 -0
- package/front_end/panels/css_overview/components/components.ts +9 -0
- package/front_end/panels/css_overview/components/cssOverviewStartView.css +134 -0
- package/front_end/panels/css_overview/css_overview-meta.ts +2 -1
- package/front_end/panels/css_overview/css_overview.ts +0 -3
- package/front_end/panels/elements/ElementsTreeElement.ts +9 -0
- package/front_end/panels/elements/components/LayoutPane.ts +1 -1
- package/front_end/panels/elements/elements-meta.ts +1 -0
- package/front_end/panels/elements/layoutPane.css +1 -1
- package/front_end/panels/event_listeners/EventListenersView.ts +9 -0
- package/front_end/panels/help/ReleaseNoteText.ts +29 -0
- package/front_end/panels/help/help-meta.ts +1 -0
- package/front_end/panels/issues/IssueKindView.ts +36 -0
- package/front_end/panels/issues/IssueView.ts +19 -4
- package/front_end/panels/issues/IssuesPane.ts +2 -3
- package/front_end/panels/issues/components/HideIssuesMenu.ts +11 -40
- package/front_end/panels/settings/emulation/components/UserAgentClientHintsForm.ts +11 -0
- package/front_end/panels/sources/DebuggerPlugin.ts +23 -4
- package/front_end/panels/sources/FilteredUISourceCodeListProvider.ts +1 -1
- package/front_end/ui/components/helpers/get-stylesheet.ts +4 -0
- package/front_end/ui/components/text_prompt/TextPrompt.ts +21 -19
- package/front_end/ui/components/text_prompt/textPrompt.css +20 -9
- package/front_end/ui/legacy/Infobar.ts +1 -0
- package/front_end/ui/legacy/components/inline_editor/CSSLength.ts +4 -2
- package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +17 -7
- package/front_end/ui/legacy/components/quick_open/QuickOpen.ts +6 -6
- package/front_end/ui/legacy/tabbedPane.css +9 -0
- package/package.json +1 -1
- package/scripts/javascript_natives/index.js +31 -25
- package/front_end/panels/css_overview/CSSOverviewStartView.ts +0 -55
- package/front_end/panels/css_overview/cssOverviewStartView.css +0 -29
|
@@ -41,24 +41,24 @@ import {getLocalizedSettingsCategory, getRegisteredSettings, maybeRemoveSettingE
|
|
|
41
41
|
let settingsInstance: Settings|undefined;
|
|
42
42
|
|
|
43
43
|
export class Settings {
|
|
44
|
-
|
|
44
|
+
readonly #sessionStorage: SettingsStorage;
|
|
45
45
|
settingNameSet: Set<string>;
|
|
46
46
|
orderValuesBySettingCategory: Map<SettingCategory, Set<number>>;
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
#eventSupport: ObjectWrapper<GenericEvents>;
|
|
48
|
+
#registry: Map<string, Setting<unknown>>;
|
|
49
49
|
readonly moduleSettings: Map<string, Setting<unknown>>;
|
|
50
50
|
|
|
51
51
|
private constructor(
|
|
52
52
|
private readonly syncedStorage: SettingsStorage, readonly globalStorage: SettingsStorage,
|
|
53
53
|
private readonly localStorage: SettingsStorage) {
|
|
54
|
-
this
|
|
54
|
+
this.#sessionStorage = new SettingsStorage({});
|
|
55
55
|
|
|
56
56
|
this.settingNameSet = new Set();
|
|
57
57
|
|
|
58
58
|
this.orderValuesBySettingCategory = new Map();
|
|
59
59
|
|
|
60
|
-
this
|
|
61
|
-
this
|
|
60
|
+
this.#eventSupport = new ObjectWrapper<GenericEvents>();
|
|
61
|
+
this.#registry = new Map();
|
|
62
62
|
this.moduleSettings = new Map();
|
|
63
63
|
|
|
64
64
|
for (const registration of getRegisteredSettings()) {
|
|
@@ -139,7 +139,7 @@ export class Settings {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
settingForTest(settingName: string): Setting<unknown> {
|
|
142
|
-
const setting = this
|
|
142
|
+
const setting = this.#registry.get(settingName);
|
|
143
143
|
if (!setting) {
|
|
144
144
|
throw new Error('No setting registered: ' + settingName);
|
|
145
145
|
}
|
|
@@ -148,10 +148,10 @@ export class Settings {
|
|
|
148
148
|
|
|
149
149
|
createSetting<T>(key: string, defaultValue: T, storageType?: SettingStorageType): Setting<T> {
|
|
150
150
|
const storage = this.storageFromType(storageType);
|
|
151
|
-
let setting = (this
|
|
151
|
+
let setting = (this.#registry.get(key) as Setting<T>);
|
|
152
152
|
if (!setting) {
|
|
153
|
-
setting = new Setting(key, defaultValue, this
|
|
154
|
-
this
|
|
153
|
+
setting = new Setting(key, defaultValue, this.#eventSupport, storage);
|
|
154
|
+
this.#registry.set(key, setting);
|
|
155
155
|
}
|
|
156
156
|
return setting;
|
|
157
157
|
}
|
|
@@ -162,11 +162,11 @@ export class Settings {
|
|
|
162
162
|
|
|
163
163
|
createRegExpSetting(key: string, defaultValue: string, regexFlags?: string, storageType?: SettingStorageType):
|
|
164
164
|
RegExpSetting {
|
|
165
|
-
if (!this
|
|
166
|
-
this
|
|
167
|
-
key, new RegExpSetting(key, defaultValue, this
|
|
165
|
+
if (!this.#registry.get(key)) {
|
|
166
|
+
this.#registry.set(
|
|
167
|
+
key, new RegExpSetting(key, defaultValue, this.#eventSupport, this.storageFromType(storageType), regexFlags));
|
|
168
168
|
}
|
|
169
|
-
return this
|
|
169
|
+
return this.#registry.get(key) as RegExpSetting;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
clearAll(): void {
|
|
@@ -178,28 +178,32 @@ export class Settings {
|
|
|
178
178
|
|
|
179
179
|
private storageFromType(storageType?: SettingStorageType): SettingsStorage {
|
|
180
180
|
switch (storageType) {
|
|
181
|
-
case
|
|
181
|
+
case SettingStorageType.Local:
|
|
182
182
|
return this.localStorage;
|
|
183
|
-
case
|
|
184
|
-
return this
|
|
185
|
-
case
|
|
183
|
+
case SettingStorageType.Session:
|
|
184
|
+
return this.#sessionStorage;
|
|
185
|
+
case SettingStorageType.Global:
|
|
186
186
|
return this.globalStorage;
|
|
187
|
+
case SettingStorageType.Synced:
|
|
188
|
+
return this.syncedStorage;
|
|
187
189
|
}
|
|
188
190
|
return this.globalStorage;
|
|
189
191
|
}
|
|
190
192
|
|
|
191
193
|
getRegistry(): Map<string, Setting<unknown>> {
|
|
192
|
-
return this
|
|
194
|
+
return this.#registry;
|
|
193
195
|
}
|
|
194
196
|
}
|
|
195
197
|
|
|
196
198
|
export interface SettingsBackingStore {
|
|
199
|
+
register(setting: string): void;
|
|
197
200
|
set(setting: string, value: string): void;
|
|
198
201
|
remove(setting: string): void;
|
|
199
202
|
clear(): void;
|
|
200
203
|
}
|
|
201
204
|
|
|
202
205
|
export const NOOP_STORAGE: SettingsBackingStore = {
|
|
206
|
+
register: () => {},
|
|
203
207
|
set: () => {},
|
|
204
208
|
remove: () => {},
|
|
205
209
|
clear: () => {},
|
|
@@ -211,6 +215,11 @@ export class SettingsStorage {
|
|
|
211
215
|
private readonly storagePrefix: string = '') {
|
|
212
216
|
}
|
|
213
217
|
|
|
218
|
+
register(name: string): void {
|
|
219
|
+
name = this.storagePrefix + name;
|
|
220
|
+
this.backingStore.register(name);
|
|
221
|
+
}
|
|
222
|
+
|
|
214
223
|
set(name: string, value: string): void {
|
|
215
224
|
name = this.storagePrefix + name;
|
|
216
225
|
this.object[name] = value;
|
|
@@ -273,22 +282,23 @@ function removeSetting(setting: Setting<unknown>): void {
|
|
|
273
282
|
}
|
|
274
283
|
|
|
275
284
|
export class Setting<V> {
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
285
|
+
#titleFunction?: () => Platform.UIString.LocalizedString;
|
|
286
|
+
#titleInternal!: string;
|
|
287
|
+
#registration: SettingRegistration|null = null;
|
|
288
|
+
#requiresUserAction?: boolean;
|
|
289
|
+
#value?: V;
|
|
281
290
|
// TODO(crbug.com/1172300) Type cannot be inferred without changes to consumers. See above.
|
|
282
|
-
|
|
283
|
-
|
|
291
|
+
#serializer: Serializer<unknown, V> = JSON;
|
|
292
|
+
#hadUserAction?: boolean;
|
|
284
293
|
|
|
285
294
|
constructor(
|
|
286
295
|
readonly name: string, readonly defaultValue: V, private readonly eventSupport: ObjectWrapper<GenericEvents>,
|
|
287
296
|
readonly storage: SettingsStorage) {
|
|
297
|
+
storage.register(name);
|
|
288
298
|
}
|
|
289
299
|
|
|
290
300
|
setSerializer(serializer: Serializer<unknown, V>): void {
|
|
291
|
-
this
|
|
301
|
+
this.#serializer = serializer;
|
|
292
302
|
}
|
|
293
303
|
|
|
294
304
|
addChangeListener(listener: (arg0: EventTargetEvent<V>) => void, thisObject?: Object): EventDescriptor {
|
|
@@ -300,54 +310,54 @@ export class Setting<V> {
|
|
|
300
310
|
}
|
|
301
311
|
|
|
302
312
|
title(): string {
|
|
303
|
-
if (this
|
|
304
|
-
return this
|
|
313
|
+
if (this.#titleInternal) {
|
|
314
|
+
return this.#titleInternal;
|
|
305
315
|
}
|
|
306
|
-
if (this
|
|
307
|
-
return this
|
|
316
|
+
if (this.#titleFunction) {
|
|
317
|
+
return this.#titleFunction();
|
|
308
318
|
}
|
|
309
319
|
return '';
|
|
310
320
|
}
|
|
311
321
|
|
|
312
322
|
setTitleFunction(titleFunction: (() => Platform.UIString.LocalizedString)|undefined): void {
|
|
313
323
|
if (titleFunction) {
|
|
314
|
-
this
|
|
324
|
+
this.#titleFunction = titleFunction;
|
|
315
325
|
}
|
|
316
326
|
}
|
|
317
327
|
|
|
318
328
|
setTitle(title: string): void {
|
|
319
|
-
this
|
|
329
|
+
this.#titleInternal = title;
|
|
320
330
|
}
|
|
321
331
|
|
|
322
332
|
setRequiresUserAction(requiresUserAction: boolean): void {
|
|
323
|
-
this
|
|
333
|
+
this.#requiresUserAction = requiresUserAction;
|
|
324
334
|
}
|
|
325
335
|
|
|
326
336
|
get(): V {
|
|
327
|
-
if (this
|
|
337
|
+
if (this.#requiresUserAction && !this.#hadUserAction) {
|
|
328
338
|
return this.defaultValue;
|
|
329
339
|
}
|
|
330
340
|
|
|
331
|
-
if (typeof this
|
|
332
|
-
return this
|
|
341
|
+
if (typeof this.#value !== 'undefined') {
|
|
342
|
+
return this.#value;
|
|
333
343
|
}
|
|
334
344
|
|
|
335
|
-
this
|
|
345
|
+
this.#value = this.defaultValue;
|
|
336
346
|
if (this.storage.has(this.name)) {
|
|
337
347
|
try {
|
|
338
|
-
this
|
|
348
|
+
this.#value = this.#serializer.parse(this.storage.get(this.name));
|
|
339
349
|
} catch (e) {
|
|
340
350
|
this.storage.remove(this.name);
|
|
341
351
|
}
|
|
342
352
|
}
|
|
343
|
-
return this
|
|
353
|
+
return this.#value;
|
|
344
354
|
}
|
|
345
355
|
|
|
346
356
|
set(value: V): void {
|
|
347
|
-
this
|
|
348
|
-
this
|
|
357
|
+
this.#hadUserAction = true;
|
|
358
|
+
this.#value = value;
|
|
349
359
|
try {
|
|
350
|
-
const settingString = this
|
|
360
|
+
const settingString = this.#serializer.stringify(value);
|
|
351
361
|
try {
|
|
352
362
|
this.storage.set(this.name, settingString);
|
|
353
363
|
} catch (e) {
|
|
@@ -360,19 +370,19 @@ export class Setting<V> {
|
|
|
360
370
|
}
|
|
361
371
|
|
|
362
372
|
setRegistration(registration: SettingRegistration): void {
|
|
363
|
-
this
|
|
373
|
+
this.#registration = registration;
|
|
364
374
|
}
|
|
365
375
|
|
|
366
376
|
type(): SettingType|null {
|
|
367
|
-
if (this
|
|
368
|
-
return this
|
|
377
|
+
if (this.#registration) {
|
|
378
|
+
return this.#registration.settingType;
|
|
369
379
|
}
|
|
370
380
|
return null;
|
|
371
381
|
}
|
|
372
382
|
|
|
373
383
|
options(): SimpleSettingOption[] {
|
|
374
|
-
if (this
|
|
375
|
-
return this
|
|
384
|
+
if (this.#registration && this.#registration.options) {
|
|
385
|
+
return this.#registration.options.map(opt => {
|
|
376
386
|
const {value, title, text, raw} = opt;
|
|
377
387
|
return {
|
|
378
388
|
value: value,
|
|
@@ -386,30 +396,30 @@ export class Setting<V> {
|
|
|
386
396
|
}
|
|
387
397
|
|
|
388
398
|
reloadRequired(): boolean|null {
|
|
389
|
-
if (this
|
|
390
|
-
return this
|
|
399
|
+
if (this.#registration) {
|
|
400
|
+
return this.#registration.reloadRequired || null;
|
|
391
401
|
}
|
|
392
402
|
return null;
|
|
393
403
|
}
|
|
394
404
|
|
|
395
405
|
category(): SettingCategory|null {
|
|
396
|
-
if (this
|
|
397
|
-
return this
|
|
406
|
+
if (this.#registration) {
|
|
407
|
+
return this.#registration.category || null;
|
|
398
408
|
}
|
|
399
409
|
return null;
|
|
400
410
|
}
|
|
401
411
|
|
|
402
412
|
tags(): string|null {
|
|
403
|
-
if (this
|
|
413
|
+
if (this.#registration && this.#registration.tags) {
|
|
404
414
|
// Get localized keys and separate by null character to prevent fuzzy matching from matching across them.
|
|
405
|
-
return this
|
|
415
|
+
return this.#registration.tags.map(tag => tag()).join('\0');
|
|
406
416
|
}
|
|
407
417
|
return null;
|
|
408
418
|
}
|
|
409
419
|
|
|
410
420
|
order(): number|null {
|
|
411
|
-
if (this
|
|
412
|
-
return this
|
|
421
|
+
if (this.#registration) {
|
|
422
|
+
return this.#registration.order || null;
|
|
413
423
|
}
|
|
414
424
|
return null;
|
|
415
425
|
}
|
|
@@ -426,14 +436,14 @@ export class Setting<V> {
|
|
|
426
436
|
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
|
|
427
437
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
428
438
|
export class RegExpSetting extends Setting<any> {
|
|
429
|
-
|
|
430
|
-
|
|
439
|
+
#regexFlags: string|undefined;
|
|
440
|
+
#regex?: RegExp|null;
|
|
431
441
|
|
|
432
442
|
constructor(
|
|
433
443
|
name: string, defaultValue: string, eventSupport: ObjectWrapper<GenericEvents>, storage: SettingsStorage,
|
|
434
444
|
regexFlags?: string) {
|
|
435
445
|
super(name, defaultValue ? [{pattern: defaultValue}] : [], eventSupport, storage);
|
|
436
|
-
this
|
|
446
|
+
this.#regexFlags = regexFlags;
|
|
437
447
|
}
|
|
438
448
|
|
|
439
449
|
get(): string {
|
|
@@ -457,23 +467,23 @@ export class RegExpSetting extends Setting<any> {
|
|
|
457
467
|
}
|
|
458
468
|
|
|
459
469
|
setAsArray(value: RegExpSettingItem[]): void {
|
|
460
|
-
|
|
470
|
+
this.#regex = undefined;
|
|
461
471
|
super.set(value);
|
|
462
472
|
}
|
|
463
473
|
|
|
464
474
|
asRegExp(): RegExp|null {
|
|
465
|
-
if (typeof this
|
|
466
|
-
return this
|
|
475
|
+
if (typeof this.#regex !== 'undefined') {
|
|
476
|
+
return this.#regex;
|
|
467
477
|
}
|
|
468
|
-
this
|
|
478
|
+
this.#regex = null;
|
|
469
479
|
try {
|
|
470
480
|
const pattern = this.get();
|
|
471
481
|
if (pattern) {
|
|
472
|
-
this
|
|
482
|
+
this.#regex = new RegExp(pattern, this.#regexFlags || '');
|
|
473
483
|
}
|
|
474
484
|
} catch (e) {
|
|
475
485
|
}
|
|
476
|
-
return this
|
|
486
|
+
return this.#regex;
|
|
477
487
|
}
|
|
478
488
|
}
|
|
479
489
|
|
|
@@ -971,7 +981,7 @@ export class VersionController {
|
|
|
971
981
|
const openTabsInPanel = panelCloseableTabSetting.get();
|
|
972
982
|
const openTabsInDrawer = panelCloseableTabSetting.get();
|
|
973
983
|
|
|
974
|
-
// Set value of new setting
|
|
984
|
+
// Set #value of new setting
|
|
975
985
|
const newValue = Object.assign(openTabsInDrawer, openTabsInPanel);
|
|
976
986
|
closeableTabSetting.set(newValue);
|
|
977
987
|
|
|
@@ -1029,8 +1039,16 @@ export class VersionController {
|
|
|
1029
1039
|
// TODO(crbug.com/1167717): Make this a const enum again
|
|
1030
1040
|
// eslint-disable-next-line rulesdir/const_enum
|
|
1031
1041
|
export enum SettingStorageType {
|
|
1042
|
+
/**
|
|
1043
|
+
* Synced storage persists settings with the active Chrome profile but also
|
|
1044
|
+
* syncs the settings across devices via Chrome Sync.
|
|
1045
|
+
*/
|
|
1046
|
+
Synced = 'Synced',
|
|
1047
|
+
/** Global storage persists settings with the active Chrome profile */
|
|
1032
1048
|
Global = 'Global',
|
|
1049
|
+
/** Uses Window.localStorage */
|
|
1033
1050
|
Local = 'Local',
|
|
1051
|
+
/** Session storage dies when DevTools window closes */
|
|
1034
1052
|
Session = 'Session',
|
|
1035
1053
|
}
|
|
1036
1054
|
|
|
@@ -38,27 +38,27 @@ export interface HistoryEntry {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export class SimpleHistoryManager {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
#entries: HistoryEntry[];
|
|
42
|
+
#activeEntryIndex: number;
|
|
43
|
+
#coalescingReadonly: number;
|
|
44
|
+
readonly #historyDepth: number;
|
|
45
45
|
constructor(historyDepth: number) {
|
|
46
|
-
this
|
|
47
|
-
this
|
|
46
|
+
this.#entries = [];
|
|
47
|
+
this.#activeEntryIndex = -1;
|
|
48
48
|
|
|
49
49
|
// Lock is used to make sure that reveal() does not
|
|
50
50
|
// make any changes to the history while we are
|
|
51
51
|
// rolling back or rolling over.
|
|
52
|
-
this
|
|
53
|
-
this
|
|
52
|
+
this.#coalescingReadonly = 0;
|
|
53
|
+
this.#historyDepth = historyDepth;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
private readOnlyLock(): void {
|
|
57
|
-
++this
|
|
57
|
+
++this.#coalescingReadonly;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
private releaseReadOnlyLock(): void {
|
|
61
|
-
--this
|
|
61
|
+
--this.#coalescingReadonly;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
private getPreviousValidIndex(): number {
|
|
@@ -66,8 +66,8 @@ export class SimpleHistoryManager {
|
|
|
66
66
|
return -1;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
let revealIndex = this
|
|
70
|
-
while (revealIndex >= 0 && !this
|
|
69
|
+
let revealIndex = this.#activeEntryIndex - 1;
|
|
70
|
+
while (revealIndex >= 0 && !this.#entries[revealIndex].valid()) {
|
|
71
71
|
--revealIndex;
|
|
72
72
|
}
|
|
73
73
|
if (revealIndex < 0) {
|
|
@@ -78,12 +78,12 @@ export class SimpleHistoryManager {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
private getNextValidIndex(): number {
|
|
81
|
-
let revealIndex = this
|
|
81
|
+
let revealIndex = this.#activeEntryIndex + 1;
|
|
82
82
|
|
|
83
|
-
while (revealIndex < this
|
|
83
|
+
while (revealIndex < this.#entries.length && !this.#entries[revealIndex].valid()) {
|
|
84
84
|
++revealIndex;
|
|
85
85
|
}
|
|
86
|
-
if (revealIndex >= this
|
|
86
|
+
if (revealIndex >= this.#entries.length) {
|
|
87
87
|
return -1;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -91,7 +91,7 @@ export class SimpleHistoryManager {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
private readOnly(): boolean {
|
|
94
|
-
return Boolean(this
|
|
94
|
+
return Boolean(this.#coalescingReadonly);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
filterOut(filterOutCallback: (arg0: HistoryEntry) => boolean): void {
|
|
@@ -100,23 +100,23 @@ export class SimpleHistoryManager {
|
|
|
100
100
|
}
|
|
101
101
|
const filteredEntries = [];
|
|
102
102
|
let removedBeforeActiveEntry = 0;
|
|
103
|
-
for (let i = 0; i < this
|
|
104
|
-
if (!filterOutCallback(this
|
|
105
|
-
filteredEntries.push(this
|
|
106
|
-
} else if (i <= this
|
|
103
|
+
for (let i = 0; i < this.#entries.length; ++i) {
|
|
104
|
+
if (!filterOutCallback(this.#entries[i])) {
|
|
105
|
+
filteredEntries.push(this.#entries[i]);
|
|
106
|
+
} else if (i <= this.#activeEntryIndex) {
|
|
107
107
|
++removedBeforeActiveEntry;
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
|
-
this
|
|
111
|
-
this
|
|
110
|
+
this.#entries = filteredEntries;
|
|
111
|
+
this.#activeEntryIndex = Math.max(0, this.#activeEntryIndex - removedBeforeActiveEntry);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
empty(): boolean {
|
|
115
|
-
return !this
|
|
115
|
+
return !this.#entries.length;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
active(): HistoryEntry|null {
|
|
119
|
-
return this.empty() ? null : this
|
|
119
|
+
return this.empty() ? null : this.#entries[this.#activeEntryIndex];
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
push(entry: HistoryEntry): void {
|
|
@@ -124,13 +124,13 @@ export class SimpleHistoryManager {
|
|
|
124
124
|
return;
|
|
125
125
|
}
|
|
126
126
|
if (!this.empty()) {
|
|
127
|
-
this
|
|
127
|
+
this.#entries.splice(this.#activeEntryIndex + 1);
|
|
128
128
|
}
|
|
129
|
-
this
|
|
130
|
-
if (this
|
|
131
|
-
this
|
|
129
|
+
this.#entries.push(entry);
|
|
130
|
+
if (this.#entries.length > this.#historyDepth) {
|
|
131
|
+
this.#entries.shift();
|
|
132
132
|
}
|
|
133
|
-
this
|
|
133
|
+
this.#activeEntryIndex = this.#entries.length - 1;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
canRollback(): boolean {
|
|
@@ -147,8 +147,8 @@ export class SimpleHistoryManager {
|
|
|
147
147
|
return false;
|
|
148
148
|
}
|
|
149
149
|
this.readOnlyLock();
|
|
150
|
-
this
|
|
151
|
-
this
|
|
150
|
+
this.#activeEntryIndex = revealIndex;
|
|
151
|
+
this.#entries[revealIndex].reveal();
|
|
152
152
|
this.releaseReadOnlyLock();
|
|
153
153
|
|
|
154
154
|
return true;
|
|
@@ -161,8 +161,8 @@ export class SimpleHistoryManager {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
this.readOnlyLock();
|
|
164
|
-
this
|
|
165
|
-
this
|
|
164
|
+
this.#activeEntryIndex = revealIndex;
|
|
165
|
+
this.#entries[revealIndex].reveal();
|
|
166
166
|
this.releaseReadOnlyLock();
|
|
167
167
|
|
|
168
168
|
return true;
|
|
@@ -8,19 +8,19 @@ export interface OutputStream {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export class StringOutputStream implements OutputStream {
|
|
11
|
-
|
|
11
|
+
#dataInternal: string;
|
|
12
12
|
constructor() {
|
|
13
|
-
this
|
|
13
|
+
this.#dataInternal = '';
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
async write(chunk: string): Promise<void> {
|
|
17
|
-
this
|
|
17
|
+
this.#dataInternal += chunk;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
async close(): Promise<void> {
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
data(): string {
|
|
24
|
-
return this
|
|
24
|
+
return this.#dataInternal;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
@@ -5,31 +5,31 @@
|
|
|
5
5
|
export type FinishCallback = (err: Error) => void;
|
|
6
6
|
|
|
7
7
|
export class Throttler {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
readonly #timeout: number;
|
|
9
|
+
#isRunningProcess: boolean;
|
|
10
|
+
#asSoonAsPossible: boolean;
|
|
11
|
+
#process: (() => (Promise<unknown>))|null;
|
|
12
|
+
#lastCompleteTime: number;
|
|
13
|
+
#schedulePromise: Promise<unknown>;
|
|
14
|
+
#scheduleResolve!: (value: unknown) => void;
|
|
15
|
+
#processTimeout?: number;
|
|
16
16
|
|
|
17
17
|
constructor(timeout: number) {
|
|
18
|
-
this
|
|
19
|
-
this
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
this
|
|
23
|
-
|
|
24
|
-
this
|
|
25
|
-
this
|
|
18
|
+
this.#timeout = timeout;
|
|
19
|
+
this.#isRunningProcess = false;
|
|
20
|
+
this.#asSoonAsPossible = false;
|
|
21
|
+
this.#process = null;
|
|
22
|
+
this.#lastCompleteTime = 0;
|
|
23
|
+
|
|
24
|
+
this.#schedulePromise = new Promise(fulfill => {
|
|
25
|
+
this.#scheduleResolve = fulfill;
|
|
26
26
|
});
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
private processCompleted(): void {
|
|
30
|
-
this
|
|
31
|
-
this
|
|
32
|
-
if (this
|
|
30
|
+
this.#lastCompleteTime = this.getTime();
|
|
31
|
+
this.#isRunningProcess = false;
|
|
32
|
+
if (this.#process) {
|
|
33
33
|
this.innerSchedule(false);
|
|
34
34
|
}
|
|
35
35
|
this.processCompletedForTests();
|
|
@@ -39,52 +39,56 @@ export class Throttler {
|
|
|
39
39
|
// For sniffing in tests.
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
get process(): (() => (Promise<unknown>))|null {
|
|
43
|
+
return this.#process;
|
|
44
|
+
}
|
|
45
|
+
|
|
42
46
|
private onTimeout(): void {
|
|
43
|
-
|
|
44
|
-
this
|
|
45
|
-
this
|
|
47
|
+
this.#processTimeout = undefined;
|
|
48
|
+
this.#asSoonAsPossible = false;
|
|
49
|
+
this.#isRunningProcess = true;
|
|
46
50
|
|
|
47
51
|
Promise.resolve()
|
|
48
|
-
.then(this
|
|
52
|
+
.then(this.#process)
|
|
49
53
|
.catch(console.error.bind(console))
|
|
50
54
|
.then(this.processCompleted.bind(this))
|
|
51
|
-
.then(this
|
|
52
|
-
this
|
|
53
|
-
this
|
|
55
|
+
.then(this.#scheduleResolve);
|
|
56
|
+
this.#schedulePromise = new Promise(fulfill => {
|
|
57
|
+
this.#scheduleResolve = fulfill;
|
|
54
58
|
});
|
|
55
|
-
this
|
|
59
|
+
this.#process = null;
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
schedule(process: () => (Promise<unknown>), asSoonAsPossible?: boolean): Promise<void> {
|
|
59
|
-
// Deliberately skip previous process.
|
|
60
|
-
this
|
|
63
|
+
// Deliberately skip previous #process.
|
|
64
|
+
this.#process = process;
|
|
61
65
|
|
|
62
66
|
// Run the first scheduled task instantly.
|
|
63
|
-
const hasScheduledTasks = Boolean(this
|
|
64
|
-
const okToFire = this.getTime() - this
|
|
67
|
+
const hasScheduledTasks = Boolean(this.#processTimeout) || this.#isRunningProcess;
|
|
68
|
+
const okToFire = this.getTime() - this.#lastCompleteTime > this.#timeout;
|
|
65
69
|
asSoonAsPossible = Boolean(asSoonAsPossible) || (!hasScheduledTasks && okToFire);
|
|
66
70
|
|
|
67
|
-
const forceTimerUpdate = asSoonAsPossible && !this
|
|
68
|
-
this
|
|
71
|
+
const forceTimerUpdate = asSoonAsPossible && !this.#asSoonAsPossible;
|
|
72
|
+
this.#asSoonAsPossible = this.#asSoonAsPossible || asSoonAsPossible;
|
|
69
73
|
|
|
70
74
|
this.innerSchedule(forceTimerUpdate);
|
|
71
75
|
|
|
72
|
-
return this
|
|
76
|
+
return this.#schedulePromise as Promise<void>;
|
|
73
77
|
}
|
|
74
78
|
|
|
75
79
|
private innerSchedule(forceTimerUpdate: boolean): void {
|
|
76
|
-
if (this
|
|
80
|
+
if (this.#isRunningProcess) {
|
|
77
81
|
return;
|
|
78
82
|
}
|
|
79
|
-
if (this
|
|
83
|
+
if (this.#processTimeout && !forceTimerUpdate) {
|
|
80
84
|
return;
|
|
81
85
|
}
|
|
82
|
-
if (this
|
|
83
|
-
this.clearTimeout(this
|
|
86
|
+
if (this.#processTimeout) {
|
|
87
|
+
this.clearTimeout(this.#processTimeout);
|
|
84
88
|
}
|
|
85
89
|
|
|
86
|
-
const timeout = this
|
|
87
|
-
this
|
|
90
|
+
const timeout = this.#asSoonAsPossible ? 0 : this.#timeout;
|
|
91
|
+
this.#processTimeout = this.setTimeout(this.onTimeout.bind(this), timeout);
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
private clearTimeout(timeoutId: number): void {
|