UNPKG

@ec0lint/plugin-css

Version:

ec0lint plugin that provides rules to verify CSS definition objects

142 lines (141 loc) 5.93 kB
"use strict"; 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, }); }, });