chrome-devtools-frontend 1.0.978673 → 1.0.979150

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.
@@ -27,6 +27,7 @@ module.exports = {
27
27
  'files': ['*.ts'],
28
28
  'rules': {
29
29
  '@typescript-eslint/explicit-function-return-type': 2,
30
+ 'rulesdir/no_importing_images_from_src': 2,
30
31
  'rulesdir/enforce_custom_event_names': 2,
31
32
  'rulesdir/set_data_type_reference': 2,
32
33
  'rulesdir/lit_html_data_as_type': 2,
@@ -6,6 +6,7 @@ import * as TextUtils from '../../models/text_utils/text_utils.js';
6
6
  import * as Common from '../common/common.js';
7
7
  import * as i18n from '../i18n/i18n.js';
8
8
  import type * as Platform from '../platform/platform.js';
9
+ import * as Root from '../root/root.js';
9
10
  import type * as Protocol from '../../generated/protocol.js';
10
11
 
11
12
  import type {CSSModel} from './CSSModel.js';
@@ -104,27 +105,38 @@ export class CSSStyleSheetHeader implements TextUtils.ContentProvider.ContentPro
104
105
  }
105
106
 
106
107
  resourceURL(): Platform.DevToolsPath.UrlString {
107
- return (this.isViaInspector() ? this.viaInspectorResourceURL() : this.sourceURL);
108
+ const url = this.isViaInspector() ? this.viaInspectorResourceURL() : this.sourceURL;
109
+ if (!url && Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.STYLES_PANE_CSS_CHANGES)) {
110
+ return this.dynamicStyleURL();
111
+ }
112
+ return url;
108
113
  }
109
114
 
110
- private viaInspectorResourceURL(): Platform.DevToolsPath.UrlString {
115
+ private getFrameURLPath(): string {
111
116
  const model = this.#cssModelInternal.target().model(ResourceTreeModel);
112
117
  console.assert(Boolean(model));
113
118
  if (!model) {
114
- return '' as Platform.DevToolsPath.UrlString;
119
+ return '';
115
120
  }
116
121
  const frame = model.frameForId(this.frameId);
117
122
  if (!frame) {
118
- return '' as Platform.DevToolsPath.UrlString;
123
+ return '';
119
124
  }
120
125
  console.assert(Boolean(frame));
121
126
  const parsedURL = new Common.ParsedURL.ParsedURL(frame.url);
122
- let fakeURL = 'inspector://' + parsedURL.host + parsedURL.folderPathComponents;
123
- if (!fakeURL.endsWith('/')) {
124
- fakeURL += '/';
127
+ let urlPath = parsedURL.host + parsedURL.folderPathComponents;
128
+ if (!urlPath.endsWith('/')) {
129
+ urlPath += '/';
125
130
  }
126
- fakeURL += 'inspector-stylesheet';
127
- return fakeURL as Platform.DevToolsPath.UrlString;
131
+ return urlPath;
132
+ }
133
+
134
+ private viaInspectorResourceURL(): Platform.DevToolsPath.UrlString {
135
+ return `inspector://${this.getFrameURLPath()}inspector-stylesheet` as Platform.DevToolsPath.UrlString;
136
+ }
137
+
138
+ private dynamicStyleURL(): Platform.DevToolsPath.UrlString {
139
+ return `stylesheet://${this.getFrameURLPath()}style#${this.id}` as Platform.DevToolsPath.UrlString;
128
140
  }
129
141
 
130
142
  lineNumberInSource(lineNumberInStyleSheet: number): number {
@@ -8,6 +8,7 @@ export const enum FormatterActions {
8
8
  HTML_OUTLINE = 'htmlOutline',
9
9
  JAVASCRIPT_OUTLINE = 'javaScriptOutline',
10
10
  JAVASCRIPT_IDENTIFIERS = 'javaScriptIdentifiers',
11
+ JAVASCRIPT_SUBSTITUTE = 'javaScriptSubstitute',
11
12
  EVALUATE_JAVASCRIPT_SUBSTRING = 'evaluatableJavaScriptSubstring',
12
13
  ARGUMENTS_LIST = 'argumentsList',
13
14
  }
@@ -42,7 +42,7 @@ import {HTMLFormatter} from './HTMLFormatter.js';
42
42
  import {IdentityFormatter} from './IdentityFormatter.js';
43
43
  import {JavaScriptFormatter} from './JavaScriptFormatter.js';
44
44
  import {JSONFormatter} from './JSONFormatter.js';
45
- import {computeSubstitution, applySubstitution} from './Substitute.js';
45
+ import {substituteExpression} from './Substitute.js';
46
46
 
47
47
  export interface Chunk {
48
48
  // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
@@ -306,4 +306,4 @@ export function argumentsList(content: string): string[] {
306
306
  }
307
307
  })();
308
308
 
309
- export {applySubstitution, computeSubstitution};
309
+ export {substituteExpression};
@@ -6,7 +6,12 @@ import * as Acorn from '../../third_party/acorn/acorn.js';
6
6
 
7
7
  import {ECMA_VERSION} from './AcornTokenizer.js';
8
8
 
9
- export interface Replacement {
9
+ export function substituteExpression(expression: string, nameMap: Map<string, string>): string {
10
+ const replacements = computeSubstitution(expression, nameMap);
11
+ return applySubstitution(expression, replacements);
12
+ }
13
+
14
+ interface Replacement {
10
15
  from: string;
11
16
  to: string;
12
17
  offset: number;
@@ -17,7 +22,7 @@ export interface Replacement {
17
22
  // function returns a list of replacements sorted by the offset. The function throws if
18
23
  // it cannot parse the expression or the substitution is impossible to perform (for example
19
24
  // if the substitution target is 'this' within a function, it would become bound there).
20
- export function computeSubstitution(expression: string, nameMap: Map<string, string>): Replacement[] {
25
+ function computeSubstitution(expression: string, nameMap: Map<string, string>): Replacement[] {
21
26
  // Parse the expression and find variables and scopes.
22
27
  const root = Acorn.parse(expression, {ecmaVersion: ECMA_VERSION, allowAwaitOutsideFunction: true, ranges: false}) as
23
28
  Acorn.ESTree.Node;
@@ -80,7 +85,7 @@ export function computeSubstitution(expression: string, nameMap: Map<string, str
80
85
  return result;
81
86
  }
82
87
 
83
- export function applySubstitution(expression: string, replacements: Replacement[]): string {
88
+ function applySubstitution(expression: string, replacements: Replacement[]): string {
84
89
  const accumulator = [];
85
90
  let last = 0;
86
91
  for (const r of replacements) {
@@ -10,7 +10,8 @@ import {FormatterActions} from './FormatterActions.js';
10
10
 
11
11
  self.onmessage = function(event: MessageEvent): void {
12
12
  const method: FormatterActions = event.data.method;
13
- const params: {indentString: string, content: string, mimeType: string} = event.data.params;
13
+ const params: {indentString: string, content: string, mimeType: string, mapping: [string, string][]} =
14
+ event.data.params;
14
15
  if (!method) {
15
16
  return;
16
17
  }
@@ -31,6 +32,11 @@ self.onmessage = function(event: MessageEvent): void {
31
32
  case FormatterActions.JAVASCRIPT_IDENTIFIERS:
32
33
  self.postMessage(FormatterWorker.FormatterWorker.javaScriptIdentifiers(params.content));
33
34
  break;
35
+ case FormatterActions.JAVASCRIPT_SUBSTITUTE: {
36
+ const mapping = new Map<string, string>(params.mapping);
37
+ self.postMessage(FormatterWorker.Substitute.substituteExpression(params.content, mapping));
38
+ break;
39
+ }
34
40
  case FormatterActions.EVALUATE_JAVASCRIPT_SUBSTRING:
35
41
  self.postMessage(FormatterWorker.FormatterWorker.evaluatableJavaScriptSubstring(params.content));
36
42
  break;
@@ -108,7 +108,7 @@ export class FormatterWorkerPool {
108
108
  }
109
109
 
110
110
  private runTask(methodName: FormatterActions.FormatterActions, params: {
111
- [x: string]: string,
111
+ [x: string]: string|string[][],
112
112
  // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
113
113
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
114
114
  }): Promise<any> {
@@ -132,6 +132,14 @@ export class FormatterWorkerPool {
132
132
  .then(ids => ids || []);
133
133
  }
134
134
 
135
+ javaScriptSubstitute(expression: string, mapping: Map<string, string>): Promise<string> {
136
+ return this
137
+ .runTask(
138
+ FormatterActions.FormatterActions.JAVASCRIPT_SUBSTITUTE,
139
+ {content: expression, mapping: Array.from(mapping.entries())})
140
+ .then(result => result || '');
141
+ }
142
+
135
143
  evaluatableJavaScriptSubstring(content: string): Promise<string> {
136
144
  return this.runTask(FormatterActions.FormatterActions.EVALUATE_JAVASCRIPT_SUBSTRING, {content: content})
137
145
  .then(text => text || '');
@@ -179,13 +187,13 @@ export class FormatterWorkerPool {
179
187
  class Task {
180
188
  method: string;
181
189
  params: {
182
- [x: string]: string,
190
+ [x: string]: string|string[][],
183
191
  };
184
192
  callback: (arg0: MessageEvent|null) => void;
185
193
  isChunked: boolean|undefined;
186
194
  constructor(
187
195
  method: string, params: {
188
- [x: string]: string,
196
+ [x: string]: string|string[][],
189
197
  },
190
198
  callback: (arg0: MessageEvent|null) => void, isChunked?: boolean) {
191
199
  this.method = method;
@@ -7,6 +7,7 @@ import * as Host from '../../core/host/host.js';
7
7
  import * as i18n from '../../core/i18n/i18n.js';
8
8
  import * as Root from '../../core/root/root.js';
9
9
  import * as SDK from '../../core/sdk/sdk.js';
10
+ import * as Formatter from '../../models/formatter/formatter.js';
10
11
  import * as SourceMapScopes from '../../models/source_map_scopes/source_map_scopes.js';
11
12
  import * as CodeMirror from '../../third_party/codemirror.next/codemirror.next.js';
12
13
  import * as TextEditor from '../../ui/components/text_editor/text_editor.js';
@@ -309,7 +310,7 @@ export class ConsolePrompt extends Common.ObjectWrapper.eventMixin<EventTypes, t
309
310
  const callFrame = executionContext.debuggerModel.selectedCallFrame();
310
311
  if (callFrame) {
311
312
  const nameMap = await SourceMapScopes.NamesResolver.allVariablesInCallFrame(callFrame);
312
- expression = this.substituteNames(expression, nameMap);
313
+ expression = await this.substituteNames(expression, nameMap);
313
314
  }
314
315
  }
315
316
 
@@ -317,11 +318,12 @@ export class ConsolePrompt extends Common.ObjectWrapper.eventMixin<EventTypes, t
317
318
  executionContext, message, expression, useCommandLineAPI);
318
319
  }
319
320
 
320
- private substituteNames(expression: string, mapping: Map<string, string>): string {
321
- // TODO(jarin) Build a more reliable replacer, based on the parsed AST.
322
- // Here, we just replace exact occurrences.
323
- const replacement = mapping.get(expression);
324
- return replacement ?? expression;
321
+ private async substituteNames(expression: string, mapping: Map<string, string>): Promise<string> {
322
+ try {
323
+ return await Formatter.FormatterWorkerPool.formatterWorkerPool().javaScriptSubstitute(expression, mapping);
324
+ } catch {
325
+ return expression;
326
+ }
325
327
  }
326
328
 
327
329
  private editorUpdate(update: CodeMirror.ViewUpdate): void {
@@ -219,9 +219,7 @@ const HIGHLIGHTABLE_PROPERTIES = [
219
219
  {mode: 'flexibility', properties: ['flex', 'flex-basis', 'flex-grow', 'flex-shrink']},
220
220
  ];
221
221
 
222
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
223
- // eslint-disable-next-line @typescript-eslint/naming-convention
224
- let _stylesSidebarPaneInstance: StylesSidebarPane;
222
+ let stylesSidebarPaneInstance: StylesSidebarPane;
225
223
 
226
224
  // TODO(crbug.com/1172300) This workaround is needed to keep the linter happy.
227
225
  // Otherwise it complains about: Unknown word CssSyntaxError
@@ -258,10 +256,10 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
258
256
  #urlToChangeTracker: Map<string, ChangeTracker> = new Map();
259
257
 
260
258
  static instance(): StylesSidebarPane {
261
- if (!_stylesSidebarPaneInstance) {
262
- _stylesSidebarPaneInstance = new StylesSidebarPane();
259
+ if (!stylesSidebarPaneInstance) {
260
+ stylesSidebarPaneInstance = new StylesSidebarPane();
263
261
  }
264
- return _stylesSidebarPaneInstance;
262
+ return stylesSidebarPaneInstance;
265
263
  }
266
264
 
267
265
  private constructor() {
@@ -292,7 +290,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
292
290
  this.swatchPopoverHelperInternal = new InlineEditor.SwatchPopoverHelper.SwatchPopoverHelper();
293
291
  this.swatchPopoverHelperInternal.addEventListener(
294
292
  InlineEditor.SwatchPopoverHelper.Events.WillShowPopover, this.hideAllPopovers, this);
295
- this.linkifier = new Components.Linkifier.Linkifier(_maxLinkLength, /* useLinkDecorator */ true);
293
+ this.linkifier = new Components.Linkifier.Linkifier(MAX_LINK_LENGTH, /* useLinkDecorator */ true);
296
294
  this.decorator = new StylePropertyHighlighter(this);
297
295
  this.lastRevealedProperty = null;
298
296
  this.userOperation = false;
@@ -307,7 +305,7 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
307
305
  this.sectionBlocks = [];
308
306
  this.idleCallbackManager = null;
309
307
  this.needsForceUpdate = false;
310
- _stylesSidebarPaneInstance = this;
308
+ stylesSidebarPaneInstance = this;
311
309
  UI.Context.Context.instance().addFlavorChangeListener(SDK.DOMModel.DOMNode, this.forceUpdate, this);
312
310
  this.contentElement.addEventListener('copy', this.clipboardCopy.bind(this));
313
311
  this.resizeThrottler = new Common.Throttler.Throttler(100);
@@ -1392,9 +1390,7 @@ async function buildPropertyRuleMaps(content: string):
1392
1390
  return {propertyToSelector, ruleToSelector};
1393
1391
  }
1394
1392
 
1395
- // TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration
1396
- // eslint-disable-next-line @typescript-eslint/naming-convention
1397
- export const _maxLinkLength = 23;
1393
+ const MAX_LINK_LENGTH = 23;
1398
1394
 
1399
1395
  export class SectionBlock {
1400
1396
  private readonly titleElementInternal: Element|null;
@@ -44,6 +44,7 @@ slot[name="property-value"] {
44
44
 
45
45
  .goto {
46
46
  display: none;
47
+ cursor: pointer;
47
48
  position: absolute;
48
49
  width: var(--goto-size);
49
50
  height: var(--goto-size);
@@ -24,6 +24,7 @@
24
24
  --size: 16px;
25
25
 
26
26
  display: none;
27
+ cursor: pointer;
27
28
  position: absolute;
28
29
  width: var(--size);
29
30
  height: var(--size);
@@ -75,14 +75,18 @@
75
75
  margin: auto;
76
76
  }
77
77
 
78
+ .authenticator-section-header {
79
+ display: flex;
80
+ justify-content: space-between;
81
+ align-items: flex-end;
82
+ }
83
+
78
84
  .authenticator-section-title {
79
85
  line-height: 24px;
80
- width: 260px;
81
86
  display: inline-block;
82
87
  }
83
88
 
84
89
  .authenticator-section-title .authenticator-name-field {
85
- width: 220px;
86
90
  display: inline-block;
87
91
  font-weight: bold;
88
92
  border: none;
package/package.json CHANGED
@@ -54,5 +54,5 @@
54
54
  "unittest": "scripts/test/run_unittests.py --no-text-coverage",
55
55
  "watch": "third_party/node/node.py --output scripts/watch_build.js"
56
56
  },
57
- "version": "1.0.978673"
57
+ "version": "1.0.979150"
58
58
  }
@@ -0,0 +1,61 @@
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
+ 'use strict';
5
+
6
+ /**
7
+ * @fileoverview Prevent importing SVG urls from the `src` directory, and
8
+ * ensure they are read from `Images/foo.svg`.
9
+ * Images in the `src/` directory are minified and put into `Images/` as part
10
+ * of the build process, so we should never import from 'src'.
11
+ */
12
+
13
+ // ------------------------------------------------------------------------------
14
+ // Rule Definition
15
+ // ------------------------------------------------------------------------------
16
+
17
+ const SRC_DIRECTORY_PATH_TO_MATCH = 'Images/src/';
18
+
19
+ module.exports = {
20
+ meta: {
21
+ type: 'problem',
22
+
23
+ docs: {
24
+ description: 'ensure image imports do not include the src/ directory',
25
+ category: 'Possible Errors',
26
+ },
27
+ fixable: 'code',
28
+ schema: [],
29
+ messages: {
30
+ imageImportUsingSrc:
31
+ 'Found an image import containing the `src/` directory. You should always import `Images/foo.svg`.',
32
+ },
33
+ },
34
+ create: function(context) {
35
+ return {
36
+ // Matches new URL(...)
37
+ 'NewExpression[callee.name=\'URL\']'(node) {
38
+ if (!node.arguments || node.arguments.length < 1) {
39
+ // Invalid code: user is probably mid-way through typing! Just leave
40
+ // it; TypeScript will error if it ends up being invalid.
41
+ return;
42
+ }
43
+ /** @type {String} */
44
+ const filePath = node.arguments[0].value;
45
+ if (!filePath) {
46
+ return;
47
+ }
48
+ if (filePath.includes(SRC_DIRECTORY_PATH_TO_MATCH)) {
49
+ context.report({
50
+ node: node.arguments[0],
51
+ messageId: 'imageImportUsingSrc',
52
+ fix(fixer) {
53
+ return fixer.replaceText(
54
+ node.arguments[0], `'${filePath.replace(SRC_DIRECTORY_PATH_TO_MATCH, 'Images/')}'`);
55
+ }
56
+ });
57
+ }
58
+ }
59
+ };
60
+ }
61
+ };
@@ -0,0 +1,40 @@
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
+ 'use strict';
5
+
6
+ const rule = require('../lib/no_importing_images_from_src.js');
7
+ const ruleTester = new (require('eslint').RuleTester)({
8
+ parser: require.resolve('@typescript-eslint/parser'),
9
+ parserOptions: {ecmaVersion: 9, sourceType: 'module'},
10
+ });
11
+
12
+ ruleTester.run('no_importing_images_from_src', rule, {
13
+ valid: [
14
+ {
15
+ code: 'const someIcon = new URL(\'../../../Images/test_icon.svg\', import.meta.url).toString()',
16
+ filename: 'front_end/ui/components/component/file.ts',
17
+ },
18
+ ],
19
+
20
+ invalid: [
21
+ {
22
+ code: 'const someIcon = new URL(\'../../../Images/src/test_icon.svg\', import.meta.url).toString()',
23
+ filename: 'front_end/ui/components/component/file.ts',
24
+ output: 'const someIcon = new URL(\'../../../Images/test_icon.svg\', import.meta.url).toString()',
25
+ errors: [{
26
+ messageId: 'imageImportUsingSrc',
27
+ }],
28
+ },
29
+ {
30
+ code:
31
+ 'const someIcon = new URL(\'../../../devtools-frontend/front_end/Images/src/test_icon.svg\', import.meta.url).toString()',
32
+ filename: 'front_end/ui/components/component/file.ts',
33
+ output:
34
+ 'const someIcon = new URL(\'../../../devtools-frontend/front_end/Images/test_icon.svg\', import.meta.url).toString()',
35
+ errors: [{
36
+ messageId: 'imageImportUsingSrc',
37
+ }],
38
+ },
39
+ ],
40
+ });