mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-10-07 12:33:47 +08:00
This CL introduces (but does not enable) an ESLint rule to check that if a Lit component renders a checkbox, that it also imports and adopts the common `Input.checkboxStyles` into the component's shadow root. We can also roll this rule out to the text inputs too, but I wanted to start with just one and see how it goes. I will follow up this CL with a CL to enable this rule. Bug: 1316297 Change-Id: Ibed7109d5948c8be3f4c9d376738290137e444ff Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/3586906 Reviewed-by: Johan Bay <jobay@chromium.org> Commit-Queue: Jack Franklin <jacktfranklin@chromium.org> Auto-Submit: Jack Franklin <jacktfranklin@chromium.org>
122 lines
3.9 KiB
JavaScript
122 lines
3.9 KiB
JavaScript
// Copyright 2020 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
'use strict';
|
|
|
|
const {isLitHtmlTemplateCall} = require('./utils.js');
|
|
const path = require('path');
|
|
|
|
const FRONT_END_DIRECTORY = path.join(__dirname, '..', '..', '..', 'front_end');
|
|
|
|
// NOTE: the actual file is input.ts, but for the sake of importing we want
|
|
// input.js as that's what the import statement would reference.
|
|
const COMMON_INPUT_STYLES = path.join(FRONT_END_DIRECTORY, 'ui', 'components', 'input', 'input.js');
|
|
|
|
module.exports = {
|
|
meta: {
|
|
type: 'problem',
|
|
|
|
docs: {
|
|
description: 'Ensure common checkbox styles are imported in Lit components',
|
|
category: 'Possible Errors',
|
|
},
|
|
fixable: 'code',
|
|
messages: {
|
|
missingCheckboxStylesImport:
|
|
'When rendering a checkbox, ensure the common checkbox styles are imported from components/input/input.ts.',
|
|
missingCheckboxStylesAdoption:
|
|
'When rendering a checkbox, ensure the common checkbox styles are adopted into the component shadow root.',
|
|
},
|
|
schema: [] // no options
|
|
},
|
|
create: function(context) {
|
|
let foundInputStylesImport = false;
|
|
let inputStylesImportedName = null;
|
|
let adoptedStyleSheetsCallNode = null;
|
|
const litCheckboxElements = new Set();
|
|
return {
|
|
TaggedTemplateExpression(node) {
|
|
if (!isLitHtmlTemplateCall(node)) {
|
|
return;
|
|
}
|
|
|
|
const litNodesContainingCheckbox = node.quasi.quasis.filter(element => {
|
|
return element.value.raw.includes('type="checkbox"');
|
|
});
|
|
for (const node of litNodesContainingCheckbox) {
|
|
// We store the node so we can use it as the basis for the ESLint error later.
|
|
litCheckboxElements.add(node);
|
|
}
|
|
},
|
|
|
|
ImportDeclaration(node) {
|
|
if (foundInputStylesImport) {
|
|
return;
|
|
}
|
|
|
|
// Get the absolute path , so we can compare it to COMMON_INPUT_STYLES;
|
|
const fullImportPath = path.resolve(context.getFilename(), node.source.value);
|
|
foundInputStylesImport = fullImportPath === COMMON_INPUT_STYLES;
|
|
if (foundInputStylesImport) {
|
|
inputStylesImportedName = node.specifiers[0].local.name;
|
|
}
|
|
},
|
|
|
|
'AssignmentExpression[left.type="MemberExpression"][left.property.name="adoptedStyleSheets"]'(node) {
|
|
adoptedStyleSheetsCallNode = node;
|
|
},
|
|
|
|
'Program:exit'() {
|
|
if (litCheckboxElements.size === 0) {
|
|
// No checkboxes to check, so we are done.
|
|
return;
|
|
}
|
|
if (!foundInputStylesImport) {
|
|
for (const checkbox of litCheckboxElements) {
|
|
context.report({
|
|
node: checkbox,
|
|
messageId: 'missingCheckboxStylesImport',
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!adoptedStyleSheetsCallNode) {
|
|
for (const checkbox of litCheckboxElements) {
|
|
context.report({
|
|
node: checkbox,
|
|
messageId: 'missingCheckboxStylesAdoption',
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
|
|
const inputCheckboxStylesAdoptionReference = adoptedStyleSheetsCallNode.right.elements.find(elem => {
|
|
// Ensure we find [Input.checkboxStyles] in the adopted stylesheets.
|
|
if (elem.type !== 'MemberExpression') {
|
|
return false;
|
|
}
|
|
|
|
// Check that if we imported the styles as `Input`, that the reference here matches.
|
|
if (elem.object.name !== inputStylesImportedName) {
|
|
return false;
|
|
}
|
|
|
|
if (elem.property.name !== 'checkboxStyles') {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
|
|
if (!inputCheckboxStylesAdoptionReference) {
|
|
context.report({
|
|
node: adoptedStyleSheetsCallNode,
|
|
messageId: 'missingCheckboxStylesAdoption',
|
|
});
|
|
}
|
|
}
|
|
};
|
|
}
|
|
};
|