@ec0lint/plugin-css
Version:
ec0lint plugin that provides rules to verify CSS definition objects
142 lines (141 loc) • 5.93 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const casing_1 = require("../utils/casing");
const regexp_1 = require("../utils/regexp");
const color_1 = require("../utils/color");
const postcss_value_parser_1 = __importDefault(require("postcss-value-parser"));
exports.default = (0, utils_1.createRule)("named-color", {
meta: {
docs: {
description: "enforce named colors",
category: "Best Practices",
recommended: false,
stylelint: "color-named",
},
fixable: "code",
schema: [
{
enum: ["always", "never"],
},
{
type: "object",
properties: {
ignoreProperties: {
type: "array",
items: {
type: "string",
},
uniqueItems: true,
minItems: 1,
},
},
additionalProperties: false,
},
],
messages: {
expected: "Expected '{{actual}}' to be '{{expected}}'.",
},
type: "suggestion",
},
create(context) {
var _a, _b;
const option = context.options[0] || "always";
const ignoreProperties = [
...((_b = (_a = context.options[1]) === null || _a === void 0 ? void 0 : _a.ignoreProperties) !== null && _b !== void 0 ? _b : []),
].map(regexp_1.toRegExp);
function ignorePropName(property) {
const name = property.getName();
if (!name) {
return false;
}
const names = [name.name];
if ((0, casing_1.isCamelCase)(name.name)) {
const kebab = (0, casing_1.kebabCase)(name.name);
names.push(kebab);
}
return ignoreProperties.some((r) => names.some((n) => r.test(n)));
}
function createVisitor(cssContext) {
return {
onProperty(property) {
if (ignorePropName(property)) {
return;
}
const value = property.getValue();
if (!value) {
return;
}
const parsedValue = value.parsed;
parsedValue.walk((node) => {
const { value: textValue, type, sourceIndex } = node;
if (type === "function" &&
textValue.toLowerCase() === "url")
return false;
const actual = postcss_value_parser_1.default.stringify(node);
let expected;
if (option === "always") {
if (type === "word") {
expected =
(0, color_1.parseHexColor)(textValue).toName() || actual;
}
else if (type === "function") {
expected = (0, color_1.parseColor)(node).toName() || actual;
}
else {
return undefined;
}
}
else if (option === "never") {
if (type !== "word" ||
/[^A-Za-z]/u.test(textValue)) {
return undefined;
}
expected = (0, color_1.parseColor)(node).toHex("RGB") || actual;
}
else {
return undefined;
}
if (expected === actual) {
return undefined;
}
const sourceCode = context.getSourceCode();
const startIndex = value.expression.range[0] +
sourceIndex +
1;
const endIndex = startIndex + actual.length;
const loc = value.directExpression
? {
start: sourceCode.getLocFromIndex(startIndex),
end: sourceCode.getLocFromIndex(endIndex),
}
: undefined;
context.report({
node: value.expression,
loc,
messageId: "expected",
data: {
actual,
expected,
},
fix(fixer) {
if (cssContext.isFixable(value.directExpression) &&
sourceCode.text.slice(startIndex, endIndex) === actual) {
return fixer.replaceTextRange([startIndex, endIndex], expected);
}
return null;
},
});
return undefined;
});
},
};
}
return (0, utils_1.defineCSSVisitor)(context, {
createVisitor,
});
},
});