77 lines
3.5 KiB
JavaScript
77 lines
3.5 KiB
JavaScript
/**
|
|
* @fileoverview Rule to disallow `!important` flags.
|
|
* @author thecalamiity
|
|
* @author Yann Bertrand
|
|
*/
|
|
//-----------------------------------------------------------------------------
|
|
// Type Definitions
|
|
//-----------------------------------------------------------------------------
|
|
/**
|
|
* @import { CSSRuleDefinition } from "../types.js"
|
|
* @typedef {"unexpectedImportant" | "removeImportant"} NoImportantMessageIds
|
|
* @typedef {CSSRuleDefinition<{ RuleOptions: [], MessageIds: NoImportantMessageIds }>} NoImportantRuleDefinition
|
|
*/
|
|
//-----------------------------------------------------------------------------
|
|
// Helpers
|
|
//-----------------------------------------------------------------------------
|
|
const importantPattern = /!\s*important/iu;
|
|
const commentPattern = /\/\*[\s\S]*?\*\//gu;
|
|
const trailingWhitespacePattern = /\s*$/u;
|
|
//-----------------------------------------------------------------------------
|
|
// Rule Definition
|
|
//-----------------------------------------------------------------------------
|
|
export default /** @satisfies {NoImportantRuleDefinition} */ ({
|
|
meta: {
|
|
type: "problem",
|
|
hasSuggestions: true,
|
|
docs: {
|
|
description: "Disallow !important flags",
|
|
recommended: true,
|
|
url: "https://github.com/eslint/css/blob/main/docs/rules/no-important.md",
|
|
},
|
|
messages: {
|
|
unexpectedImportant: "Unexpected !important flag found.",
|
|
removeImportant: "Remove !important flag.",
|
|
},
|
|
},
|
|
create(context) {
|
|
const { sourceCode } = context;
|
|
return {
|
|
Declaration(node) {
|
|
if (node.important) {
|
|
const declarationText = sourceCode.getText(node);
|
|
const textWithoutComments = declarationText.replace(commentPattern,
|
|
/* eslint-disable-next-line require-unicode-regexp -- we want to replace each code unit with a space */
|
|
match => match.replace(/[^\r\n\f]/g, " "));
|
|
const importantMatch = importantPattern.exec(textWithoutComments);
|
|
const importantStartOffset = importantMatch.index;
|
|
const importantEndOffset = importantStartOffset + importantMatch[0].length;
|
|
const nodeStartOffset = node.loc.start.offset;
|
|
context.report({
|
|
loc: {
|
|
start: sourceCode.getLocFromIndex(nodeStartOffset + importantStartOffset),
|
|
end: sourceCode.getLocFromIndex(nodeStartOffset + importantEndOffset),
|
|
},
|
|
messageId: "unexpectedImportant",
|
|
suggest: [
|
|
{
|
|
messageId: "removeImportant",
|
|
fix(fixer) {
|
|
// Find any trailing whitespace before the `!important`
|
|
const whitespaceEndOffset = declarationText
|
|
.slice(0, importantStartOffset)
|
|
.search(trailingWhitespacePattern);
|
|
return fixer.removeRange([
|
|
nodeStartOffset + whitespaceEndOffset,
|
|
nodeStartOffset + importantEndOffset,
|
|
]);
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
},
|
|
};
|
|
},
|
|
});
|