eslint-plugin-vue-scoped-css
Version:
ESLint plugin for Scoped CSS in Vue.js
96 lines (95 loc) • 3.69 kB
JavaScript
;
const context_1 = require("../styles/context");
const selectors_1 = require("../styles/utils/selectors");
const css_nodes_1 = require("../styles/utils/css-nodes");
const compat_1 = require("../utils/compat");
module.exports = {
meta: {
docs: {
description: "require selector argument to be passed to `::v-deep()`",
categories: ["vue3-recommended"],
default: "warn",
url: "https://future-architect.github.io/eslint-plugin-vue-scoped-css/rules/require-v-deep-argument.html",
},
fixable: "code",
messages: {
missingArguments: "Need to pass argument to the `::v-deep` pseudo-element.",
},
schema: [],
type: "suggestion",
},
create(context) {
const styles = (0, context_1.getStyleContexts)(context)
.filter(context_1.isValidStyleContext)
.filter((style) => style.scoped);
if (!styles.length) {
return {};
}
const reporter = (0, context_1.getCommentDirectivesReporter)(context);
function findHasSelectorsNode(node) {
if ((0, css_nodes_1.hasSelectorNodes)(node.parent)) {
return node.parent;
}
if ((0, css_nodes_1.isVCSSAtRule)(node.parent)) {
return null;
}
return findHasSelectorsNode(node.parent);
}
function report(node) {
reporter.report({
node,
loc: node.loc,
messageId: "missingArguments",
fix(fixer) {
if (!(0, selectors_1.isVDeepPseudoV2)(node)) {
return null;
}
const nodes = node.parent.nodes;
const selectorIndex = nodes.indexOf(node);
const nextNode = nodes[selectorIndex + 1];
if (!nextNode) {
return null;
}
const betweenRange = [
node.range[0] + node.value.length,
nextNode.range[0],
];
if ((0, compat_1.getSourceCode)(context)
.text.slice(...betweenRange)
.trim()) {
return null;
}
const ruleNode = findHasSelectorsNode(node);
if (!(ruleNode === null || ruleNode === void 0 ? void 0 : ruleNode.nodes.every((n) => (0, css_nodes_1.isVCSSDeclarationProperty)(n) || (0, css_nodes_1.isVCSSComment)(n)))) {
return null;
}
const last = nodes[nodes.length - 1];
return [
fixer.removeRange(betweenRange),
fixer.insertTextAfterRange(betweenRange, "("),
fixer.insertTextAfterRange(last.range, ")"),
];
},
});
}
function verify(style) {
style.traverseSelectorNodes({
enterNode(node) {
if ((0, selectors_1.isVDeepPseudoV2)(node)) {
report(node);
}
else if ((0, selectors_1.isVDeepPseudo)(node) && (0, selectors_1.isPseudoEmptyArguments)(node)) {
report(node);
}
},
});
}
return {
"Program:exit"() {
for (const style of styles) {
verify(style);
}
},
};
},
};