Skip to content

Commit fe93423

Browse files
danilsomsikovDevtools-frontend LUCI CQ
authored andcommitted
Handle variables in the preferTemplateLiterals lint rule
Bug: 400353541 Change-Id: I47bacbb4b844e2499f138be88448171841f9b0a0 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/6353440 Commit-Queue: Philip Pfaffe <[email protected]> Reviewed-by: Philip Pfaffe <[email protected]> Auto-Submit: Danil Somsikov <[email protected]>
1 parent 34e26e6 commit fe93423

File tree

2 files changed

+70
-7
lines changed

2 files changed

+70
-7
lines changed

scripts/eslint_rules/lib/no-imperative-dom-api.js

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,31 +141,64 @@ module.exports = {
141141
const queue = [];
142142
const sourceCode = context.getSourceCode();
143143

144-
/** @type {Map<string, DomFragment>} */
144+
/** @type {Map<string|Variable, DomFragment>} */
145145
const domFragments = new Map();
146146

147147
/**
148148
* @param {Node} node
149149
* @return {DomFragment}
150150
*/
151151
function getOrCreateDomFragment(node) {
152-
const key = sourceCode.getText(node);
152+
const variable = getEnclosingVariable(node);
153+
const key = variable ?? sourceCode.getText(node);
153154

154155
let result = domFragments.get(key);
155156
if (!result) {
156157
result = new DomFragment();
157158
queue.push(result);
158159
domFragments.set(key, result);
159-
result.expression = sourceCode.getText(node);
160-
const classDeclaration = getEnclosingClassDeclaration(node);
161-
if (classDeclaration) {
162-
result.replacementLocation = classDeclaration;
160+
if (variable) {
161+
result.references = variable.references.map(r => ({node: /** @type {Node} */ (r.identifier)}));
162+
} else {
163+
result.expression = sourceCode.getText(node);
164+
const classDeclaration = getEnclosingClassDeclaration(node);
165+
if (classDeclaration) {
166+
result.replacementLocation = classDeclaration;
167+
}
163168
}
164169
}
165-
result.references.push({node});
170+
if (!variable) {
171+
result.references.push({node});
172+
}
166173
return result;
167174
}
168175

176+
/**
177+
* @param {Node} node
178+
* @return {Variable|null}
179+
*/
180+
function getEnclosingVariable(node) {
181+
if (node.type === 'Identifier') {
182+
let scope = sourceCode.getScope(node);
183+
const variableName = node.name;
184+
while (scope) {
185+
const variable = scope.variables.find(v => v.name === variableName);
186+
if (variable) {
187+
return variable;
188+
}
189+
scope = scope.upper;
190+
}
191+
}
192+
if (node.parent.type === 'VariableDeclarator') {
193+
const variables = sourceCode.getDeclaredVariables(node.parent);
194+
if (variables.length > 1) {
195+
return null; // Destructuring assignment
196+
}
197+
return variables[0];
198+
}
199+
return null;
200+
}
201+
169202
/**
170203
* @param {DomFragmentReference} reference
171204
* @param {DomFragment} domFragment

scripts/eslint_rules/tests/no-imperative-dom-api.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,36 @@ class SomeWidget extends UI.Widget.Widget {
119119
constructor() {
120120
super();
121121
}
122+
}`,
123+
errors: [{messageId: 'preferTemplateLiterals'}],
124+
},
125+
{
126+
filename: 'front_end/ui/components/component/file.ts',
127+
code: `
128+
class SomeWidget extends UI.Widget.Widget {
129+
constructor() {
130+
super();
131+
const div = document.createElement('div');
132+
div.className = 'some-class';
133+
this.contentElement.appendChild(div);
134+
}
135+
}`,
136+
output: `
137+
138+
export const DEFAULT_VIEW = (input, _output, target) => {
139+
render(html\`
140+
<div>
141+
<div class="some-class"></div>
142+
</div>\`,
143+
target, {host: input});
144+
};
145+
146+
class SomeWidget extends UI.Widget.Widget {
147+
constructor() {
148+
super();
149+
const div = document.createElement('div');
150+
div.className = 'some-class';
151+
}
122152
}`,
123153
errors: [{messageId: 'preferTemplateLiterals'}],
124154
},

0 commit comments

Comments
 (0)