@creedengo/eslint-plugin
Version:
JavaScript linter of creedengo project
95 lines (86 loc) • 3.21 kB
JavaScript
/*
* creedengo JavaScript plugin - Provides rules to reduce the environmental footprint of your JavaScript programs
* Copyright © 2023 Green Code Initiative (https://green-code-initiative.org)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
;
/** @type {import("eslint").Rule.RuleModule} */
module.exports = {
meta: {
type: "suggestion",
docs: {
description: "Disallow multiple style changes at once",
category: "eco-design",
recommended: "warn",
},
messages: {
UseClassInstead:
"There are more than two style assignments for '{{elementName}}'. Use a class instead.",
},
schema: [],
},
create: function (context) {
const isNodeUseStyleProperty = (node) =>
node?.object?.property?.name === "style";
const getNodeFullName = (node) => {
let names = [];
do {
names.unshift(node.name ?? node.property.name);
node = node.object;
} while (node);
return names.join(".");
};
return {
AssignmentExpression(node) {
// Check if there is a literal assignation on a style property
if (
node.right.type === "Literal" &&
isNodeUseStyleProperty(node.left)
) {
const domElementName = getNodeFullName(node.left.object.object);
const currentRangestart = node.left.object.object.range[0];
/**
* Store parent AST to check if there is more
* than one assignation on the style of the same domElement
*/
const currentScopeASTBody =
context.getScope().block.body.length != null
? context.getScope().block.body
: context.getScope().block.body.body;
const filtered = currentScopeASTBody.filter(
(e) =>
e.type === "ExpressionStatement" &&
e.expression.type === "AssignmentExpression" &&
isNodeUseStyleProperty(e.expression.left) &&
getNodeFullName(e.expression.left.object.object) ===
domElementName,
);
// De-duplication, prevents multiple alerts for each line involved
const isCurrentNodeTheFirstAssignation =
filtered.length > 1 &&
currentRangestart <=
filtered[0].expression.left.object.object.range[0];
if (isCurrentNodeTheFirstAssignation) {
context.report({
node,
messageId: "UseClassInstead",
data: { elementName: domElementName },
});
}
}
},
};
},
};