chrome-devtools-frontend 1.0.930109 → 1.0.930993

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 (61) hide show
  1. package/config/gni/devtools_grd_files.gni +2 -1
  2. package/front_end/core/host/InspectorFrontendHost.ts +8 -1
  3. package/front_end/core/host/InspectorFrontendHostAPI.ts +12 -0
  4. package/front_end/core/i18n/locales/en-US.json +3 -0
  5. package/front_end/core/i18n/locales/en-XL.json +3 -0
  6. package/front_end/core/protocol_client/InspectorBackend.ts +71 -71
  7. package/front_end/core/sdk/NetworkManager.ts +6 -2
  8. package/front_end/devtools_compatibility.js +8 -0
  9. package/front_end/legacy_test_runner/sources_test_runner/DebuggerTestRunner.js +2 -2
  10. package/front_end/legacy_test_runner/test_runner/TestRunner.js +2 -3
  11. package/front_end/models/bindings/BreakpointManager.ts +158 -154
  12. package/front_end/models/bindings/CSSWorkspaceBinding.ts +64 -56
  13. package/front_end/models/bindings/CompilerScriptMapping.ts +70 -70
  14. package/front_end/models/bindings/ContentProviderBasedProject.ts +20 -20
  15. package/front_end/models/bindings/DebuggerLanguagePlugins.ts +132 -132
  16. package/front_end/models/bindings/DebuggerWorkspaceBinding.ts +73 -72
  17. package/front_end/models/bindings/DefaultScriptMapping.ts +22 -22
  18. package/front_end/models/bindings/FileUtils.ts +81 -81
  19. package/front_end/models/bindings/IgnoreListManager.ts +17 -17
  20. package/front_end/models/bindings/LiveLocation.ts +21 -21
  21. package/front_end/models/bindings/PresentationConsoleMessageHelper.ts +28 -28
  22. package/front_end/models/bindings/ResourceMapping.ts +50 -50
  23. package/front_end/models/bindings/ResourceScriptMapping.ts +71 -71
  24. package/front_end/models/bindings/SASSSourceMapping.ts +32 -32
  25. package/front_end/models/bindings/StylesSourceMapping.ts +57 -57
  26. package/front_end/models/bindings/TempFile.ts +34 -34
  27. package/front_end/models/emulation/DeviceModeModel.ts +208 -203
  28. package/front_end/models/emulation/EmulatedDevices.ts +34 -34
  29. package/front_end/panels/console/ConsoleView.ts +2 -1
  30. package/front_end/panels/console/ConsoleViewMessage.ts +3 -3
  31. package/front_end/panels/css_overview/CSSOverviewCompletedView.ts +133 -133
  32. package/front_end/panels/css_overview/CSSOverviewModel.ts +16 -16
  33. package/front_end/panels/css_overview/CSSOverviewPanel.ts +77 -77
  34. package/front_end/panels/css_overview/CSSOverviewProcessingView.ts +5 -5
  35. package/front_end/panels/css_overview/components/CSSOverviewStartView.ts +4 -4
  36. package/front_end/panels/elements/ElementsTreeElement.ts +6 -10
  37. package/front_end/panels/elements/ElementsTreeOutline.ts +3 -1
  38. package/front_end/panels/elements/components/LayoutPane.ts +6 -0
  39. package/front_end/panels/elements/elementsPanel.css +0 -1
  40. package/front_end/panels/elements/elementsTreeOutline.css +0 -4
  41. package/front_end/panels/lighthouse/LighthouseProtocolService.ts +7 -2
  42. package/front_end/panels/network/BlockedURLsPane.ts +8 -5
  43. package/front_end/panels/network/blockedURLsPane.css +0 -1
  44. package/front_end/panels/search/SearchView.ts +0 -2
  45. package/front_end/panels/sources/BreakpointEditDialog.ts +98 -81
  46. package/front_end/panels/sources/DebuggerPlugin.ts +15 -14
  47. package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +18 -2
  48. package/front_end/ui/components/text_editor/config.ts +6 -0
  49. package/front_end/ui/components/text_editor/cursor_tooltip.ts +70 -0
  50. package/front_end/ui/components/text_editor/javascript.ts +590 -0
  51. package/front_end/ui/components/text_editor/text_editor.ts +1 -0
  52. package/front_end/ui/components/text_editor/theme.ts +11 -0
  53. package/front_end/ui/components/tree_outline/TreeOutline.ts +3 -1
  54. package/front_end/ui/legacy/ARIAUtils.ts +24 -8
  55. package/front_end/ui/legacy/components/text_editor/cmdevtools.css +1 -0
  56. package/front_end/ui/legacy/components/text_editor/text_editor-legacy.ts +0 -3
  57. package/front_end/ui/legacy/components/text_editor/text_editor.ts +0 -2
  58. package/package.json +1 -1
  59. package/scripts/migration/class-fields/migrate.js +15 -2
  60. package/scripts/migration/class-fields/migrate.sh +10 -0
  61. package/front_end/ui/legacy/components/text_editor/SyntaxHighlighter.ts +0 -62
@@ -0,0 +1,590 @@
1
+ // Copyright 2021 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ import * as SDK from '../../../core/sdk/sdk.js';
6
+ import * as Formatter from '../../../models/formatter/formatter.js';
7
+ import * as JavaScriptMetaData from '../../../models/javascript_metadata/javascript_metadata.js';
8
+ import * as CodeMirror from '../../../third_party/codemirror.next/codemirror.next.js';
9
+ import * as UI from '../../legacy/legacy.js';
10
+ import {cursorTooltip} from './cursor_tooltip.js';
11
+
12
+ export async function completion(): Promise<CodeMirror.Extension> {
13
+ const {javascriptLanguage} = await CodeMirror.javascript();
14
+ return javascriptLanguage.data.of({
15
+ autocomplete: javascriptCompletionSource,
16
+ });
17
+ }
18
+
19
+ class CompletionSet {
20
+ constructor(
21
+ readonly completions: CodeMirror.Completion[] = [],
22
+ readonly seen: Set<string> = new Set(),
23
+ ) {
24
+ }
25
+
26
+ add(completion: CodeMirror.Completion): void {
27
+ if (!this.seen.has(completion.label)) {
28
+ this.seen.add(completion.label);
29
+ this.completions.push(completion);
30
+ }
31
+ }
32
+
33
+ copy(): CompletionSet {
34
+ return new CompletionSet(this.completions.slice(), new Set(this.seen));
35
+ }
36
+ }
37
+
38
+ const javascriptKeywords = [
39
+ 'async', 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default',
40
+ 'delete', 'do', 'else', 'export', 'extends', 'finally', 'for', 'function', 'if', 'import',
41
+ 'in', 'instanceof', 'let', 'new', 'of', 'return', 'static', 'super', 'switch', 'this',
42
+ 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield',
43
+ ];
44
+ const consoleBuiltinFunctions = [
45
+ 'clear',
46
+ 'copy',
47
+ 'debug',
48
+ 'dir',
49
+ 'dirxml',
50
+ 'getEventListeners',
51
+ 'inspect',
52
+ 'keys',
53
+ 'monitor',
54
+ 'monitorEvents',
55
+ 'profile',
56
+ 'profileEnd',
57
+ 'queryObjects',
58
+ 'table',
59
+ 'undebug',
60
+ 'unmonitor',
61
+ 'unmonitorEvents',
62
+ 'values',
63
+ ];
64
+ const consoleBuiltinVariables = ['$', '$$', '$x', '$0', '$_'];
65
+
66
+ const baseCompletions = new CompletionSet();
67
+ for (const kw of javascriptKeywords) {
68
+ baseCompletions.add({label: kw, type: 'keyword'});
69
+ }
70
+ for (const builtin of consoleBuiltinFunctions) {
71
+ baseCompletions.add({label: builtin, type: 'function'});
72
+ }
73
+ for (const varName of consoleBuiltinVariables) {
74
+ baseCompletions.add({label: varName, type: 'variable'});
75
+ }
76
+
77
+ const dontCompleteIn = new Set([
78
+ 'TemplateString',
79
+ 'LineComment',
80
+ 'BlockComment',
81
+ 'TypeDefinition',
82
+ 'VariableDefinition',
83
+ 'PropertyDefinition',
84
+ 'TypeName',
85
+ ]);
86
+
87
+ // FIXME Implement Map property completion?
88
+ export const enum QueryType {
89
+ Expression = 0,
90
+ PropertyName = 1,
91
+ PropertyExpression = 2,
92
+ }
93
+
94
+ export function getQueryType(tree: CodeMirror.Tree, pos: number): {
95
+ type: QueryType,
96
+ from?: number,
97
+ relatedNode?: CodeMirror.SyntaxNode,
98
+ }|null {
99
+ let node = tree.resolveInner(pos, -1);
100
+ const parent = node.parent;
101
+ if (dontCompleteIn.has(node.name)) {
102
+ return null;
103
+ }
104
+
105
+ if (node.name === 'VariableName') {
106
+ return {type: QueryType.Expression, from: node.from};
107
+ }
108
+ if (node.name === 'PropertyName') {
109
+ return parent?.name !== 'MemberExpression' ? null :
110
+ {type: QueryType.PropertyName, from: node.from, relatedNode: parent};
111
+ }
112
+ if (node.name === 'String') {
113
+ const parent = node.parent;
114
+ return parent?.name === 'MemberExpression' && parent.childBefore(node.from)?.name === '[' ?
115
+ {type: QueryType.PropertyExpression, from: node.from, relatedNode: parent} :
116
+ null;
117
+ }
118
+ // Enter unfinished nodes before the position.
119
+ node = node.enterUnfinishedNodesBefore(pos);
120
+ // Normalize to parent node when pointing after a child of a member expr.
121
+ if (node.to === pos && node.parent?.name === 'MemberExpression') {
122
+ node = node.parent;
123
+ }
124
+ if (node.name === 'MemberExpression') {
125
+ const before = node.childBefore(Math.min(pos, node.to));
126
+ if (before?.name === '[') {
127
+ return {type: QueryType.PropertyExpression, relatedNode: node};
128
+ }
129
+ if (before?.name === '.' || before?.name === '?.') {
130
+ return {type: QueryType.PropertyName, relatedNode: node};
131
+ }
132
+ }
133
+ return {type: QueryType.Expression};
134
+ }
135
+
136
+ export async function javascriptCompletionSource(cx: CodeMirror.CompletionContext):
137
+ Promise<CodeMirror.CompletionResult|null> {
138
+ const query = getQueryType(CodeMirror.syntaxTree(cx.state), cx.pos);
139
+ if (!query || query.from === undefined && !cx.explicit) {
140
+ return null;
141
+ }
142
+
143
+ let result: CompletionSet;
144
+ if (query.type === QueryType.Expression) {
145
+ const [scope, global] = await Promise.all([
146
+ completeExpressionInScope(),
147
+ completeExpressionGlobal(),
148
+ ]);
149
+ if (scope.completions.length) {
150
+ result = scope;
151
+ for (const r of global.completions) {
152
+ result.add(r);
153
+ }
154
+ } else {
155
+ result = global;
156
+ }
157
+ } else if (query.type === QueryType.PropertyName || query.type === QueryType.PropertyExpression) {
158
+ const objectExpr = (query.relatedNode as CodeMirror.SyntaxNode).getChild('Expression');
159
+ let quote = undefined;
160
+ if (query.type === QueryType.PropertyExpression) {
161
+ quote = query.from === undefined ? '\'' : cx.state.sliceDoc(query.from, query.from + 1);
162
+ }
163
+ if (!objectExpr) {
164
+ return null;
165
+ }
166
+ result = await completeProperties(cx.state.sliceDoc(objectExpr.from, objectExpr.to), quote);
167
+ } else {
168
+ return null;
169
+ }
170
+ return {
171
+ from: query.from ?? cx.pos,
172
+ options: result.completions,
173
+ span: /^[\w\P{ASCII}]*/u,
174
+ };
175
+ }
176
+
177
+ function getExecutionContext(): SDK.RuntimeModel.ExecutionContext|null {
178
+ return UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext);
179
+ }
180
+
181
+ async function evaluateExpression(
182
+ context: SDK.RuntimeModel.ExecutionContext,
183
+ expression: string,
184
+ group: string,
185
+ ): Promise<SDK.RemoteObject.RemoteObject|null> {
186
+ const result = await context.evaluate(
187
+ {
188
+ expression,
189
+ objectGroup: group,
190
+ includeCommandLineAPI: true,
191
+ silent: true,
192
+ returnByValue: false,
193
+ generatePreview: false,
194
+ throwOnSideEffect: true,
195
+ timeout: 500,
196
+ },
197
+ false, false);
198
+ if ('error' in result || result.exceptionDetails || !result.object) {
199
+ return null;
200
+ }
201
+ return result.object;
202
+ }
203
+
204
+ const primitivePrototypes = new Map<string, string>([
205
+ ['string', 'String'],
206
+ ['number', 'Number'],
207
+ ['boolean', 'Boolean'],
208
+ ['bigint', 'BigInt'],
209
+ ]);
210
+
211
+ const maxCacheAge = 30_000;
212
+
213
+ let cacheInstance: PropertyCache|null = null;
214
+
215
+ // Store recent collections of property completions. The empty string
216
+ // is used to store the set of global bindings.
217
+ class PropertyCache {
218
+ private readonly cache: Map<string, Promise<CompletionSet>> = new Map();
219
+
220
+ constructor() {
221
+ const clear = (): void => this.cache.clear();
222
+ SDK.ConsoleModel.ConsoleModel.instance().addEventListener(SDK.ConsoleModel.Events.CommandEvaluated, clear);
223
+ UI.Context.Context.instance().addFlavorChangeListener(SDK.RuntimeModel.ExecutionContext, clear);
224
+ SDK.TargetManager.TargetManager.instance().addModelListener(
225
+ SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerResumed, clear);
226
+ SDK.TargetManager.TargetManager.instance().addModelListener(
227
+ SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.DebuggerPaused, clear);
228
+ }
229
+
230
+ get(expression: string): Promise<CompletionSet>|undefined {
231
+ return this.cache.get(expression);
232
+ }
233
+
234
+ set(expression: string, value: Promise<CompletionSet>): void {
235
+ this.cache.set(expression, value);
236
+ setTimeout(() => {
237
+ if (this.cache.get(expression) === value) {
238
+ this.cache.delete(expression);
239
+ }
240
+ }, maxCacheAge);
241
+ }
242
+
243
+ static instance(): PropertyCache {
244
+ if (!cacheInstance) {
245
+ cacheInstance = new PropertyCache();
246
+ }
247
+ return cacheInstance;
248
+ }
249
+ }
250
+
251
+ async function completeProperties(
252
+ expression: string,
253
+ quoted?: string,
254
+ ): Promise<CompletionSet> {
255
+ const cache = PropertyCache.instance();
256
+ if (!quoted) {
257
+ const cached = cache.get(expression);
258
+ if (cached) {
259
+ return cached;
260
+ }
261
+ }
262
+ const context = getExecutionContext();
263
+ if (!context) {
264
+ return new CompletionSet();
265
+ }
266
+ const result = completePropertiesInner(expression, context, quoted);
267
+ if (!quoted) {
268
+ cache.set(expression, result);
269
+ }
270
+ return result;
271
+ }
272
+
273
+ const prototypePropertyPenalty = -80;
274
+
275
+ async function completePropertiesInner(
276
+ expression: string,
277
+ context: SDK.RuntimeModel.ExecutionContext,
278
+ quoted?: string,
279
+ ): Promise<CompletionSet> {
280
+ const result = new CompletionSet();
281
+ if (!context) {
282
+ return result;
283
+ }
284
+ let object = await evaluateExpression(context, expression, 'completion');
285
+ if (!object) {
286
+ return result;
287
+ }
288
+
289
+ while (object.type === 'object' && object.subtype === 'proxy') {
290
+ const properties = await object.getOwnProperties(false);
291
+ const innerObject = properties.internalProperties?.find(p => p.name === '[[Target]]')?.value;
292
+ if (!innerObject) {
293
+ break;
294
+ }
295
+ object = innerObject as SDK.RemoteObject.RemoteObject;
296
+ }
297
+
298
+ const toPrototype = object.subtype === 'array' ?
299
+ 'Array' :
300
+ object.subtype === 'typedarray' ? 'Uint8Array' : primitivePrototypes.get(object.type);
301
+ if (toPrototype) {
302
+ object = await evaluateExpression(context, toPrototype + '.prototype', 'completion');
303
+ }
304
+
305
+ const functionType = expression === 'window' ? 'function' : 'method';
306
+ const otherType = expression === 'window' ? 'variable' : 'property';
307
+ if (object && (object.type === 'object' || object.type === 'function')) {
308
+ const properties = await object.getAllProperties(false, false);
309
+ const isFunction = object.type === 'function';
310
+ for (const prop of properties.properties || []) {
311
+ if (!prop.symbol && !(isFunction && (prop.name === 'arguments' || prop.name === 'caller'))) {
312
+ const label = quoted ? quoted + prop.name + quoted : prop.name;
313
+ const completion: CodeMirror.Completion = {
314
+ label,
315
+ type: prop.value?.type === 'function' ? functionType : otherType,
316
+ };
317
+ if (quoted) {
318
+ completion.apply = label + ']';
319
+ }
320
+ if (!prop.isOwn) {
321
+ completion.boost = prototypePropertyPenalty;
322
+ }
323
+ result.add(completion);
324
+ }
325
+ }
326
+ }
327
+ context.runtimeModel.releaseObjectGroup('completion');
328
+ return result;
329
+ }
330
+
331
+ async function completeExpressionInScope(): Promise<CompletionSet> {
332
+ const result = new CompletionSet();
333
+ const selectedFrame = getExecutionContext()?.debuggerModel.selectedCallFrame();
334
+ if (!selectedFrame) {
335
+ return result;
336
+ }
337
+
338
+ const frames =
339
+ await Promise.all(selectedFrame.scopeChain().map(scope => scope.object().getAllProperties(false, false)));
340
+ for (const frame of frames) {
341
+ for (const property of frame.properties || []) {
342
+ result.add({
343
+ label: property.name,
344
+ type: property.value?.type === 'function' ? 'function' : 'variable',
345
+ });
346
+ }
347
+ }
348
+ return result;
349
+ }
350
+
351
+ async function completeExpressionGlobal(): Promise<CompletionSet> {
352
+ const cache = PropertyCache.instance();
353
+ const cached = cache.get('');
354
+ if (cached) {
355
+ return cached;
356
+ }
357
+
358
+ const context = getExecutionContext();
359
+ if (!context) {
360
+ return baseCompletions;
361
+ }
362
+ const result = baseCompletions.copy();
363
+
364
+ const fetchNames = completePropertiesInner('window', context).then(fromWindow => {
365
+ return context.globalLexicalScopeNames().then(globals => {
366
+ for (const option of fromWindow.completions) {
367
+ result.add(option);
368
+ }
369
+ for (const name of globals || []) {
370
+ result.add({label: name, type: 'variable'});
371
+ }
372
+ return result;
373
+ });
374
+ });
375
+ cache.set('', fetchNames);
376
+ return fetchNames;
377
+ }
378
+
379
+ export function isExpressionComplete(state: CodeMirror.EditorState): boolean {
380
+ for (const cursor = CodeMirror.syntaxTree(state).cursor(); cursor.next();) {
381
+ if (cursor.type.isError) {
382
+ return false;
383
+ }
384
+ }
385
+ return true;
386
+ }
387
+
388
+ export function argumentHints(): CodeMirror.Extension {
389
+ return cursorTooltip(getArgumentHints);
390
+ }
391
+
392
+ async function getArgumentHints(
393
+ state: CodeMirror.EditorState, pos: number): Promise<(() => CodeMirror.TooltipView)|null> {
394
+ const node = CodeMirror.syntaxTree(state).resolveInner(pos).enterUnfinishedNodesBefore(pos);
395
+
396
+ if (node.name !== 'ArgList') {
397
+ return null;
398
+ }
399
+ const callee = node.parent?.getChild('Expression');
400
+ if (!callee) {
401
+ return null;
402
+ }
403
+ const argumentList = await getArgumentsForExpression(callee, state.doc);
404
+ if (!argumentList) {
405
+ return null;
406
+ }
407
+
408
+ let argumentIndex = 0;
409
+ for (let scanPos = pos;;) {
410
+ const before = node.childBefore(scanPos);
411
+ if (!before) {
412
+ break;
413
+ }
414
+ if (before.type.is('Expression')) {
415
+ argumentIndex++;
416
+ }
417
+ scanPos = before.from;
418
+ }
419
+ return (): {dom: HTMLElement} => tooltipBuilder(argumentList, argumentIndex);
420
+ }
421
+
422
+ async function getArgumentsForExpression(
423
+ callee: CodeMirror.SyntaxNode, doc: CodeMirror.Text): Promise<string[][]|null> {
424
+ const context = getExecutionContext();
425
+ if (!context) {
426
+ return null;
427
+ }
428
+ try {
429
+ const expression = doc.sliceString(callee.from, callee.to);
430
+ const result = await evaluateExpression(context, expression, 'argumentsHint');
431
+ if (!result || result.type !== 'function') {
432
+ return null;
433
+ }
434
+ return getArgumentsForFunctionValue(result, async () => {
435
+ const first = callee.firstChild;
436
+ if (!first || callee.name !== 'MemberExpression') {
437
+ return null;
438
+ }
439
+ return evaluateExpression(context, doc.sliceString(first.from, first.to), 'argumentsHint');
440
+ }, expression);
441
+ } finally {
442
+ context.runtimeModel.releaseObjectGroup('argumentsHint');
443
+ }
444
+ }
445
+
446
+ async function getArgumentsForFunctionValue(
447
+ object: SDK.RemoteObject.RemoteObject,
448
+ receiverObjGetter: () => Promise<SDK.RemoteObject.RemoteObject|null>,
449
+ functionName?: string,
450
+ ): Promise<string[][]|null> {
451
+ const description = object.description;
452
+ if (!description) {
453
+ return null;
454
+ }
455
+ if (!description.endsWith('{ [native code] }')) {
456
+ return [await Formatter.FormatterWorkerPool.formatterWorkerPool().argumentsList(description)];
457
+ }
458
+
459
+ // Check if this is a bound function.
460
+ if (description === 'function () { [native code] }') {
461
+ const fromBound = await getArgumentsForBoundFunction(object);
462
+ if (fromBound) {
463
+ return fromBound;
464
+ }
465
+ }
466
+
467
+ const javaScriptMetadata = JavaScriptMetaData.JavaScriptMetadata.JavaScriptMetadataImpl.instance();
468
+
469
+ const descriptionRegexResult = /^function ([^(]*)\(/.exec(description);
470
+ const name = descriptionRegexResult && descriptionRegexResult[1] || functionName;
471
+ if (!name) {
472
+ return null;
473
+ }
474
+ const uniqueSignatures = javaScriptMetadata.signaturesForNativeFunction(name);
475
+ if (uniqueSignatures) {
476
+ return uniqueSignatures;
477
+ }
478
+ const receiverObj = await receiverObjGetter();
479
+ if (!receiverObj) {
480
+ return null;
481
+ }
482
+ const className = receiverObj.className;
483
+ if (className) {
484
+ const instanceMethods = javaScriptMetadata.signaturesForInstanceMethod(name, className);
485
+ if (instanceMethods) {
486
+ return instanceMethods;
487
+ }
488
+ }
489
+
490
+ // Check for static methods on a constructor.
491
+ if (receiverObj.description && receiverObj.type === 'function' &&
492
+ receiverObj.description.endsWith('{ [native code] }')) {
493
+ const receiverDescriptionRegexResult = /^function ([^(]*)\(/.exec(receiverObj.description);
494
+ if (receiverDescriptionRegexResult) {
495
+ const receiverName = receiverDescriptionRegexResult[1];
496
+ const staticSignatures = javaScriptMetadata.signaturesForStaticMethod(name, receiverName);
497
+ if (staticSignatures) {
498
+ return staticSignatures;
499
+ }
500
+ }
501
+ }
502
+
503
+ for (const proto of await prototypesFromObject(receiverObj)) {
504
+ const instanceSignatures = javaScriptMetadata.signaturesForInstanceMethod(name, proto);
505
+ if (instanceSignatures) {
506
+ return instanceSignatures;
507
+ }
508
+ }
509
+ return null;
510
+ }
511
+
512
+ async function prototypesFromObject(object: SDK.RemoteObject.RemoteObject): Promise<string[]> {
513
+ if (object.type === 'number') {
514
+ return ['Number', 'Object'];
515
+ }
516
+ if (object.type === 'string') {
517
+ return ['String', 'Object'];
518
+ }
519
+ if (object.type === 'symbol') {
520
+ return ['Symbol', 'Object'];
521
+ }
522
+ if (object.type === 'bigint') {
523
+ return ['BigInt', 'Object'];
524
+ }
525
+ if (object.type === 'boolean') {
526
+ return ['Boolean', 'Object'];
527
+ }
528
+ if (object.type === 'undefined' || object.subtype === 'null') {
529
+ return [];
530
+ }
531
+ return await object.callFunctionJSON(function() {
532
+ const result = [];
533
+ for (let object: Object = this; object; object = Object.getPrototypeOf(object)) {
534
+ if (typeof object === 'object' && object.constructor && object.constructor.name) {
535
+ result[result.length] = object.constructor.name;
536
+ }
537
+ }
538
+ return result;
539
+ }, []);
540
+ }
541
+
542
+ // Given a function object that is probably a bound function, try to
543
+ // retrieve the argument list from its target function.
544
+ async function getArgumentsForBoundFunction(object: SDK.RemoteObject.RemoteObject): Promise<string[][]|null> {
545
+ const {internalProperties} = await object.getOwnProperties(false);
546
+ if (!internalProperties) {
547
+ return null;
548
+ }
549
+ const target = internalProperties.find(p => p.name === '[[TargetFunction]]')?.value;
550
+ const args = internalProperties.find(p => p.name === '[[BoundArgs]]')?.value;
551
+ const thisValue = internalProperties.find(p => p.name === '[[BoundThis]]')?.value;
552
+ if (!thisValue || !target || !args) {
553
+ return null;
554
+ }
555
+ const originalSignatures = await getArgumentsForFunctionValue(target, () => Promise.resolve(thisValue));
556
+ const boundArgsLength = SDK.RemoteObject.RemoteObject.arrayLength(args);
557
+ if (!originalSignatures) {
558
+ return null;
559
+ }
560
+ return originalSignatures.map(signature => {
561
+ const restIndex = signature.findIndex(arg => arg.startsWith('...'));
562
+ return restIndex > -1 && restIndex < boundArgsLength ? signature.slice(restIndex) :
563
+ signature.slice(boundArgsLength);
564
+ });
565
+ }
566
+
567
+ function tooltipBuilder(signatures: string[][], currentIndex: number): {dom: HTMLElement} {
568
+ const tooltip = document.createElement('div');
569
+ tooltip.className = 'cm-argumentHints';
570
+ for (const args of signatures) {
571
+ const argumentsElement = document.createElement('span');
572
+ for (let i = 0; i < args.length; i++) {
573
+ if (i === currentIndex || (i < currentIndex && args[i].startsWith('...'))) {
574
+ const argElement = argumentsElement.appendChild(document.createElement('b'));
575
+ argElement.appendChild(document.createTextNode(args[i]));
576
+ } else {
577
+ argumentsElement.appendChild(document.createTextNode(args[i]));
578
+ }
579
+ if (i < args.length - 1) {
580
+ argumentsElement.appendChild(document.createTextNode(', '));
581
+ }
582
+ }
583
+ const signatureElement = tooltip.appendChild(document.createElement('div'));
584
+ signatureElement.className = 'source-code';
585
+ signatureElement.appendChild(document.createTextNode('\u0192('));
586
+ signatureElement.appendChild(argumentsElement);
587
+ signatureElement.appendChild(document.createTextNode(')'));
588
+ }
589
+ return {dom: tooltip};
590
+ }
@@ -3,4 +3,5 @@
3
3
  // found in the LICENSE file.
4
4
 
5
5
  export * as Config from './config.js';
6
+ export * as JavaScript from './javascript.js';
6
7
  export * as TextEditor from './TextEditor.js';
@@ -98,6 +98,17 @@ export const editorTheme = CM.EditorView.theme({
98
98
  color: 'var(--color-text-secondary)',
99
99
  },
100
100
 
101
+ '.cm-argumentHints': {
102
+ pointerEvents: 'none',
103
+ padding: '0 4px',
104
+ whiteSpace: 'nowrap',
105
+ lineHeight: '20px',
106
+ marginBottom: '4px',
107
+ boxShadow: 'var(--drop-shadow)',
108
+ backgroundColor: 'var(--color-background)',
109
+ width: 'fit-content',
110
+ },
111
+
101
112
  '.cm-highlightedLine': {
102
113
  animation: 'cm-fading-highlight 2s 0s',
103
114
  },
@@ -4,8 +4,10 @@
4
4
 
5
5
  import * as Platform from '../../../core/platform/platform.js';
6
6
  import * as LitHtml from '../../lit-html/lit-html.js';
7
+ import * as CodeHighlighter from '../code_highlighter/code_highlighter.js';
7
8
  import * as ComponentHelpers from '../helpers/helpers.js';
8
9
  import * as Coordinator from '../render_coordinator/render_coordinator.js';
10
+
9
11
  import treeOutlineStyles from './treeOutline.css.js';
10
12
 
11
13
  import type {TreeNode, TreeNodeWithChildren} from './TreeOutlineUtils.js';
@@ -119,7 +121,7 @@ export class TreeOutline<TreeNodeDataType> extends HTMLElement {
119
121
  connectedCallback(): void {
120
122
  this.setTopLevelNodeBorderColorCSSVariable(this.getAttribute('toplevelbordercolor'));
121
123
  this.setNodeKeyNoWrapCSSVariable(this.getAttribute('nowrap'));
122
- this.shadow.adoptedStyleSheets = [treeOutlineStyles];
124
+ this.shadow.adoptedStyleSheets = [treeOutlineStyles, CodeHighlighter.Style.default];
123
125
  }
124
126
 
125
127
  get data(): TreeOutlineData<TreeNodeDataType> {
@@ -460,17 +460,37 @@ function hideFromLayout(element: HTMLElement): void {
460
460
  element.style.overflow = 'hidden';
461
461
  }
462
462
 
463
- let alertElement: HTMLElement|undefined;
463
+ let alertElementOne: HTMLElement|undefined;
464
+ let alertElementTwo: HTMLElement|undefined;
465
+ let alertToggle: boolean = false;
464
466
 
467
+ /**
468
+ * This function instantiates and switches off returning one of two offscreen alert elements.
469
+ * We utilize two alert elements to ensure that alerts with the same string are still registered
470
+ * as changes and trigger screen reader announcement.
471
+ */
465
472
  export function alertElementInstance(): HTMLElement {
466
- if (!alertElement) {
473
+ if (!alertElementOne) {
467
474
  const element = document.body.createChild('div') as HTMLElement;
468
475
  hideFromLayout(element);
469
476
  element.setAttribute('role', 'alert');
470
477
  element.setAttribute('aria-atomic', 'true');
471
- alertElement = element;
478
+ alertElementOne = element;
472
479
  }
473
- return alertElement;
480
+ if (!alertElementTwo) {
481
+ const element = document.body.createChild('div') as HTMLElement;
482
+ hideFromLayout(element);
483
+ element.setAttribute('role', 'alert');
484
+ element.setAttribute('aria-atomic', 'true');
485
+ alertElementTwo = element;
486
+ }
487
+ alertToggle = !alertToggle;
488
+ if (alertToggle) {
489
+ alertElementTwo.textContent = '';
490
+ return alertElementOne;
491
+ }
492
+ alertElementOne.textContent = '';
493
+ return alertElementTwo;
474
494
  }
475
495
 
476
496
  /**
@@ -479,9 +499,5 @@ export function alertElementInstance(): HTMLElement {
479
499
  */
480
500
  export function alert(message: string): void {
481
501
  const element = alertElementInstance();
482
-
483
- // We first set the textContent to blank so that the string will announce even if it is replaced
484
- // with the same string.
485
- element.textContent = '';
486
502
  element.textContent = Platform.StringUtilities.trimEndWithMaxLength(message, 10000);
487
503
  }
@@ -23,6 +23,7 @@
23
23
 
24
24
  .CodeMirror-linewidget {
25
25
  overflow: visible !important; /* stylelint-disable-line declaration-no-important */
26
+ z-index: 100;
26
27
  }
27
28
 
28
29
  .CodeMirror-gutter-performance {