UNPKG

eslint-plugin-vue-scoped-css

Version:
185 lines (184 loc) 7.87 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; const lodash_1 = __importDefault(require("lodash")); const context_1 = require("../styles/context"); const compat_1 = require("../utils/compat"); const styleTypesAttrs = ["scoped", "module"]; module.exports = { meta: { docs: { description: "enforce the `<style>` tags to be plain or have the `scoped` or `module` attribute", categories: ["vue2-recommended", "vue3-recommended"], default: "warn", url: "https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/enforce-style-type.html", suggestion: true, }, fixable: null, messages: { add: "Add attribute `{{ attribute }}`.", remove: "Remove attribute `{{ attribute }}`.", removeMultiple: "Remove attributes {{ attributes }}.", change: "Change `{{ fromAttribute }}` to `{{ toAttribute }}` attribute.", forbiddenStyle: "`{{ attribute }}` attribute is forbidden.", forbiddenPlain: "Missing attribute {{ attributes }}.", forbiddenScopedModule: "Cannot use both `scoped` and `module` attributes.", }, schema: [ { type: "object", properties: { allows: { type: "array", minItems: 1, uniqueItems: true, items: { type: "string", enum: ["plain", "scoped", "module"], }, }, }, additionalProperties: false, }, ], type: "suggestion", hasSuggestions: true, }, create(context) { var _a, _b, _c, _d; const styles = (0, context_1.getStyleContexts)(context).filter(context_1.isValidStyleContext); if (!styles.length) { return {}; } const reporter = (0, context_1.getCommentDirectivesReporter)(context); const sourceCode = (0, compat_1.getSourceCode)(context); const tokenStore = (_b = (_a = sourceCode.parserServices).getTemplateBodyTokenStore) === null || _b === void 0 ? void 0 : _b.call(_a); const { options } = context; const allows = (_d = (_c = options[0]) === null || _c === void 0 ? void 0 : _c.allows) !== null && _d !== void 0 ? _d : ["scoped"]; const singleAllow = allows.length === 1 && allows[0]; function removeAttr(fixer, node) { const { attributes } = node.parent; const prevToken = tokenStore.getTokenBefore(node); const nextToken = tokenStore.getTokenAfter(node); return [ fixer.removeRange([ prevToken.range[1], attributes.length === 1 ? nextToken.range[0] : node.range[1], ]), ]; } function reportForbiddenStyle(node, attribute) { const forbiddenAttr = node.startTag.attributes.find((attr) => attr.key.name === attribute); const forbiddenAttrName = forbiddenAttr.key.name; reporter.report({ node: forbiddenAttr, messageId: "forbiddenStyle", data: { attribute, }, suggest: [ singleAllow && singleAllow !== "plain" ? { messageId: "change", data: { fromAttribute: forbiddenAttrName, toAttribute: singleAllow, }, fix(fixer) { return fixer.replaceText(forbiddenAttr, singleAllow); }, } : { messageId: "remove", data: { attribute: forbiddenAttrName, }, fix(fixer) { return removeAttr(fixer, forbiddenAttr); }, }, ], }); } function reportForbiddenPlain(node) { reporter.report({ node: node.startTag, messageId: "forbiddenPlain", data: { attributes: allows.map((allow) => `\`${allow}\``).join(" or "), }, suggest: singleAllow ? [ { messageId: "add", data: { attribute: singleAllow, }, fix(fixer) { const close = tokenStore.getLastToken(node.startTag); return (close && fixer.insertTextBefore(close, ` ${singleAllow}`)); }, }, ] : undefined, }); } function reportForbiddenScopedModule(node) { const forbiddenAttrs = node.startTag.attributes.filter((attr) => styleTypesAttrs.includes(attr.key.name) && !allows.includes(attr.key.name)); reporter.report({ node: node.startTag, messageId: "forbiddenScopedModule", suggest: forbiddenAttrs.length ? [ forbiddenAttrs.length === 1 ? { messageId: "remove", data: { attribute: forbiddenAttrs[0].key.name.toString(), }, fix(fixer) { return removeAttr(fixer, forbiddenAttrs[0]); }, } : { messageId: "removeMultiple", data: { attributes: forbiddenAttrs .map((attr) => `\`${attr.key.name}\``) .join(", "), }, fix(fixer) { return lodash_1.default.flatMap(forbiddenAttrs, (attr) => removeAttr(fixer, attr)); }, }, ] : undefined, }); } return { "Program:exit"() { for (const style of styles) { if (style.scoped && style.module) { reportForbiddenScopedModule(style.styleElement); } else if (style.scoped) { if (!allows.includes("scoped")) { reportForbiddenStyle(style.styleElement, "scoped"); } } else if (style.module) { if (!allows.includes("module")) { reportForbiddenStyle(style.styleElement, "module"); } } else { if (!allows.includes("plain")) { reportForbiddenPlain(style.styleElement); } } } }, }; }, };