Skip to content

Commit 0c4a9c0

Browse files
ergunshDevtools-frontend LUCI CQ
authored andcommitted
[UIEngineering] Update inject-checkbox-styles for widgetScoped calls
We'll wrap styles inside `widgetScoped` calls in `<style>` tags. We'll need to account for them in the `inject-checkbox-styles` rule. Bug: 431945418 Change-Id: I0c625cc5300c0d05c43d28a5ce5b407455a582ee Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6765324 Auto-Submit: Ergün Erdoğmuş <ergunsh@chromium.org> Commit-Queue: Ergün Erdoğmuş <ergunsh@chromium.org> Reviewed-by: Nikolay Vitkov <nvitkov@chromium.org> Reviewed-by: Danil Somsikov <dsv@chromium.org>
1 parent dc69375 commit 0c4a9c0

File tree

4 files changed

+62
-22
lines changed

4 files changed

+62
-22
lines changed

scripts/eslint_rules/lib/inject-checkbox-styles.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import path from 'path';
66

77
import {isLitHtmlTemplateCall} from './utils/lit.ts';
88
import {createRule} from './utils/ruleCreator.ts';
9+
import {isWidgetScopedCall} from './utils/stylingHelpers.ts';
910

1011
type AssignmentExpression = TSESTree.AssignmentExpression;
1112
type TemplateElement = TSESTree.TemplateElement;
@@ -161,8 +162,19 @@ export default createRule<[], MessageIds>({
161162
};
162163

163164
function isCheckboxStylesReference(elem: Node|null): boolean {
164-
// Ensure elem is not null and is a MemberExpression before accessing properties
165-
if (!elem || elem.type !== 'MemberExpression') {
165+
// Ensure elem is not null.
166+
if (!elem) {
167+
return false;
168+
}
169+
170+
// If this is a `widgetScoped(styles)` call, extract
171+
// `elem` to be the `styles` directly
172+
if (elem.type === 'CallExpression' && isWidgetScopedCall(elem)) {
173+
elem = elem.arguments[0];
174+
}
175+
176+
// Ensure this node is a MemberExpression before accessing properties
177+
if (elem.type !== 'MemberExpression') {
166178
return false;
167179
}
168180

scripts/eslint_rules/lib/no-unscoped-styles-in-views.ts

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,35 +8,16 @@ import type {TSESTree} from '@typescript-eslint/utils';
88

99
import {isLitHtmlRenderCall, isLitHtmlTemplateCall, isViewFunction} from './utils/lit.ts';
1010
import {createRule} from './utils/ruleCreator.ts';
11+
import {isWidgetScopedCall} from './utils/stylingHelpers.ts';
1112

1213
type CallExpression = TSESTree.CallExpression;
13-
type Expression = TSESTree.Expression;
1414

1515
function containsMeaningfulCss(text: string): boolean {
1616
const noComments = text.replace(/\/\*[\s\S]*?\*\/|\/\/.*$/gm, '');
1717
const noWhitespace = noComments.trim();
1818
return noWhitespace.length > 0;
1919
}
2020

21-
/**
22-
* Checks if an expression node is a call to `UI.Widget.widgetScoped(...)`.
23-
* @param expression The expression AST node to check.
24-
* @returns True if the expression is the specific widgetScoped call.
25-
*/
26-
function isWidgetScopedCall(expression: Expression): boolean {
27-
if (expression.type !== 'CallExpression') {
28-
return false;
29-
}
30-
const callee = expression.callee;
31-
// Checks for the direct `widgetScoped` call.
32-
const isDirectCall = callee.type === 'Identifier' && callee.name === 'widgetScoped';
33-
// Checks for the full `UI.Widget.widgetScoped` member expression chain.
34-
const isCallThroughUIWidget = callee.type === 'MemberExpression' && callee.property.type === 'Identifier' &&
35-
callee.property.name === 'widgetScoped' && callee.object.type === 'MemberExpression' &&
36-
callee.object.property.type === 'Identifier' && callee.object.property.name === 'Widget';
37-
return isDirectCall || isCallThroughUIWidget;
38-
}
39-
4021
export default createRule({
4122
name: 'no-unscoped-styles-in-views',
4223
meta: {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2025 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 type {TSESTree} from '@typescript-eslint/utils';
6+
7+
/**
8+
* Checks if an expression node is a call to `UI.Widget.widgetScoped(...)`.
9+
* @param expression The expression AST node to check.
10+
* @returns True if the expression is the specific widgetScoped call.
11+
*/
12+
export function isWidgetScopedCall(expression: TSESTree.Expression): boolean {
13+
if (expression.type !== 'CallExpression') {
14+
return false;
15+
}
16+
const callee = expression.callee;
17+
// Checks for the direct `widgetScoped` call.
18+
const isDirectCall = callee.type === 'Identifier' && callee.name === 'widgetScoped';
19+
// Checks for the full `UI.Widget.widgetScoped` member expression chain.
20+
const isCallThroughUIWidget = callee.type === 'MemberExpression' && callee.property.type === 'Identifier' &&
21+
callee.property.name === 'widgetScoped' && callee.object.type === 'MemberExpression' &&
22+
callee.object.property.type === 'Identifier' && callee.object.property.name === 'Widget';
23+
return isDirectCall || isCallThroughUIWidget;
24+
}

scripts/eslint_rules/tests/inject-checkbox-styles.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,29 @@ export class SettingCheckbox extends HTMLElement {
7171
</label>
7272
</p>\`, this.#shadow, {host: this});
7373
}
74+
}`,
75+
filename: 'front_end/ui/components/settings/SettingsCheckbox.ts',
76+
},
77+
{
78+
code: `import * as ComponentHelpers from '../../components/helpers/helpers.js';
79+
import * as Lit from '../../lit/lit.js';
80+
import * as Input from '../input/input.js';
81+
82+
83+
export class SettingCheckbox extends HTMLElement {
84+
static readonly litTagName = Lit.literal\`setting-checkbox\`;
85+
readonly #shadow = this.attachShadow({mode: 'open'});
86+
87+
#render(): void {
88+
Lit.render(
89+
Lit.html\`
90+
<style>\${UI.Widget.widgetScoped(Input.checkboxStyles)}</style>
91+
<p>
92+
<label>
93+
<input type="checkbox" />
94+
</label>
95+
</p>\`, this.#shadow, {host: this});
96+
}
7497
}`,
7598
filename: 'front_end/ui/components/settings/SettingsCheckbox.ts',
7699
},

0 commit comments

Comments
 (0)