UNPKG

eslint-plugin-vue-scoped-css

Version:
128 lines (127 loc) 4.98 kB
"use strict"; const template_1 = require("../styles/template"); const context_1 = require("../styles/context"); const style_1 = require("../styles/context/style"); const compat_1 = require("../utils/compat"); module.exports = { meta: { docs: { description: "disallow `@keyframes` which don't use in Scoped CSS", categories: ["vue2-recommended", "vue3-recommended"], default: "warn", url: "https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/no-unused-keyframes.html", }, fixable: null, messages: { unused: "The @keyframes `{{params}}` is unused.", }, schema: [ { type: "object", properties: { checkUnscoped: { type: "boolean", }, }, additionalProperties: false, }, ], type: "suggestion", }, create(context) { var _a; const checkUnscoped = Boolean((_a = context.options[0]) === null || _a === void 0 ? void 0 : _a.checkUnscoped); const styles = (0, context_1.getStyleContexts)(context) .filter(style_1.isValidStyleContext) .filter((style) => style.scoped || checkUnscoped); if (!styles.length) { return {}; } const reporter = (0, context_1.getCommentDirectivesReporter)(context); const sourceCode = (0, compat_1.getSourceCode)(context); function report(node) { const paramsStartIndex = node.range[0] + node.identifier.length + node.name.length + (node.node.raws.afterName || "").length; const paramsEndIndex = paramsStartIndex + node.rawParamsText.length; reporter.report({ node, loc: { start: sourceCode.getLocFromIndex(paramsStartIndex), end: sourceCode.getLocFromIndex(paramsEndIndex), }, messageId: "unused", data: { params: node.paramsText }, }); } function extract(style) { const keyframes = []; const animationNames = []; const animations = []; style.traverseNodes({ enterNode(node) { if (node.type === "VCSSAtRule") { if (/-?keyframes$/u.test(node.name) && node.identifier === "@") { keyframes.push({ params: template_1.Template.ofParams(node), node, }); } } else if (node.type === "VCSSDeclarationProperty") { if (/^(?:-\w+-)?animation-name$/u.test(node.property)) { animationNames.push(node); } if (/^(?:-\w+-)?animation$/u.test(node.property)) { animations.push(node); } } }, }); return { keyframes, animationNames, animations, }; } function verify(style) { const { keyframes, animationNames, animations } = extract(style); for (const decl of animationNames) { for (const v of decl.value.split(",").map((s) => s.trim())) { const value = template_1.Template.ofDeclValue(v, decl.lang); for (let index = keyframes.length - 1; index >= 0; index--) { const { params } = keyframes[index]; if (value.match(params)) { keyframes.splice(index, 1); } } } } for (const decl of animations) { for (const v of decl.value.split(",").map((s) => s.trim())) { const vals = v.trim().split(/\s+/u); for (const val of vals) { const value = template_1.Template.ofDeclValue(val, decl.lang); for (let index = keyframes.length - 1; index >= 0; index--) { const { params } = keyframes[index]; if (value.match(params)) { keyframes.splice(index, 1); } } } } } for (const { node } of keyframes) { report(node); } } return { "Program:exit"() { for (const style of styles) { verify(style); } }, }; }, };