eslint-plugin-vue-scoped-css
Version:
ESLint plugin for Scoped CSS in Vue.js
179 lines (178 loc) • 6.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.StyleContextImpl = void 0;
exports.isValidStyleContext = isValidStyleContext;
exports.createStyleContexts = createStyleContexts;
const parser_1 = require("../../parser");
const css_nodes_1 = require("../../utils/css-nodes");
const compat_1 = require("../../../utils/compat");
function getInvalidEOFError(context, style) {
const node = (0, compat_1.getSourceCode)(context).ast;
const body = node.templateBody;
let errors = body === null || body === void 0 ? void 0 : body.errors;
let inDocumentFragment = false;
if (errors == null) {
const sourceCode = (0, compat_1.getSourceCode)(context);
if (!sourceCode.parserServices.getDocumentFragment) {
return null;
}
const df = sourceCode.parserServices.getDocumentFragment();
inDocumentFragment = true;
errors = df === null || df === void 0 ? void 0 : df.errors;
if (errors == null) {
return null;
}
}
const error = errors.find((err) => typeof err.code === "string" &&
err.code.startsWith("eof-") &&
style.range[0] <= err.index &&
err.index < style.range[1]) ||
errors.find((err) => typeof err.code === "string" && err.code.startsWith("eof-"));
if (!error) {
return null;
}
return {
error,
inDocumentFragment,
};
}
function getStyleElements(context) {
let document = null;
const sourceCode = (0, compat_1.getSourceCode)(context);
if (sourceCode.parserServices.getDocumentFragment) {
document = sourceCode.parserServices.getDocumentFragment();
}
else {
const { ast } = sourceCode;
const templateBody = ast.templateBody;
if (templateBody) {
document = templateBody.parent;
}
}
if (document) {
return document.children
.filter(isVElement)
.filter((element) => element.name === "style");
}
return [];
}
function isScoped(style) {
const { startTag } = style;
return startTag.attributes.some((attr) => attr.key.name === "scoped");
}
function isCssModule(style) {
const { startTag } = style;
return startTag.attributes.some((attr) => attr.key.name === "module");
}
function getLang(style) {
var _a;
const { startTag } = style;
const lang = startTag.attributes.find((attr) => attr.key.name === "lang") || null;
return ((lang === null || lang === void 0 ? void 0 : lang.type) === "VAttribute" &&
((_a = lang.value) === null || _a === void 0 ? void 0 : _a.type) === "VLiteral" &&
lang.value.value);
}
function isValidStyleContext(context) {
return !context.invalid;
}
class StyleContextImpl {
constructor(style, context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
this.styleElement = style;
this.sourceCode = sourceCode;
const { startTag, endTag } = style;
this.invalid = null;
const eof = getInvalidEOFError(context, style);
if (eof) {
this.invalid = {
message: eof.error.message,
needReport: eof.inDocumentFragment,
loc: { line: eof.error.lineNumber, column: eof.error.column },
};
}
else if (endTag == null && !startTag.selfClosing) {
this.invalid = {
message: "Missing end tag",
needReport: true,
loc: startTag.loc.end,
};
}
this.scoped = Boolean(style && isScoped(style));
this.module = Boolean(style && isCssModule(style));
this.lang = ((style && getLang(style)) || "css").toLowerCase();
if (!this.invalid) {
this.cssText = endTag
? sourceCode.text.slice(startTag.range[1], endTag.range[0])
: "";
this.cssNode = (0, parser_1.parse)(sourceCode, startTag.loc.end, this.cssText, this.lang);
}
else {
this.cssText = null;
this.cssNode = null;
}
}
traverseNodes(visitor) {
if (this.cssNode) {
traverseNodes(this.cssNode, visitor);
}
}
traverseSelectorNodes(visitor) {
this.traverseNodes({
enterNode(node) {
if ((0, css_nodes_1.hasSelectorNodes)(node)) {
for (const sel of node.selectors) {
traverseSelectorNodes(sel, visitor);
}
}
},
});
}
}
exports.StyleContextImpl = StyleContextImpl;
function traverseNodes(node, visitor) {
var _a;
visitor.break = false;
visitor.enterNode(node);
if (visitor.exit || visitor.break) {
return;
}
if ((0, css_nodes_1.isVCSSContainerNode)(node)) {
for (const child of node.nodes) {
traverseNodes(child, visitor);
if (visitor.break) {
break;
}
if (visitor.exit) {
return;
}
}
}
(_a = visitor.leaveNode) === null || _a === void 0 ? void 0 : _a.call(visitor, node);
}
function traverseSelectorNodes(node, visitor) {
var _a;
visitor.break = false;
visitor.enterNode(node);
if (visitor.exit || visitor.break) {
return;
}
if (node.type === "VCSSSelector" || node.type === "VCSSSelectorPseudo") {
for (const child of node.nodes) {
traverseSelectorNodes(child, visitor);
if (visitor.break) {
break;
}
if (visitor.exit) {
return;
}
}
}
(_a = visitor.leaveNode) === null || _a === void 0 ? void 0 : _a.call(visitor, node);
}
function createStyleContexts(context) {
const styles = getStyleElements(context);
return styles.map((style) => new StyleContextImpl(style, context));
}
function isVElement(node) {
return (node === null || node === void 0 ? void 0 : node.type) === "VElement";
}