eslint-plugin-vue-scoped-css
Version:
ESLint plugin for Scoped CSS in Vue.js
289 lines (288 loc) • 9.46 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.VueComponentContext = void 0;
exports.createVueComponentContext = createVueComponentContext;
const vue_eslint_parser_1 = require("vue-eslint-parser");
const find_vue_1 = __importDefault(require("./find-vue"));
const utils_1 = require("../../../utils/utils");
const compat_1 = require("../../../utils/compat");
const traverseNodes = vue_eslint_parser_1.AST.traverseNodes;
const UNKNOWN = Symbol("unknown");
class VueComponentContext {
constructor(node, context) {
this.properties = null;
this.node = node;
this.context = context;
}
findVueComponentProperty(name) {
const properties = this.properties ||
(this.properties = extractVueComponentProperties(this.node, this.context));
if (properties[UNKNOWN]) {
return null;
}
if (properties.data === UNKNOWN || properties.data[UNKNOWN]) {
return null;
}
if (properties.computed === UNKNOWN || properties.computed[UNKNOWN]) {
return null;
}
if (properties.data[name]) {
return properties.data[name];
}
if (properties.computed[name]) {
return properties.computed[name];
}
return null;
}
getClassesOperatedByClassList(refNames, isRoot) {
return getClassesOperatedByClassList(this.node, refNames, isRoot, this.context);
}
}
exports.VueComponentContext = VueComponentContext;
function createVueComponentContext(context) {
const node = (0, find_vue_1.default)(context);
if (!node) {
return null;
}
return new VueComponentContext(node, context);
}
function extractVueComponentProperties(vueNode, context) {
const result = {
data: {},
computed: {},
};
for (const p of vueNode.properties) {
if (p.type !== "Property") {
result[UNKNOWN] = true;
continue;
}
const keyName = getPropertyOrIdentifierName(p);
if (keyName === "data") {
result.data = extractVueComponentData(p.value, context);
}
else if (keyName === "computed") {
result.computed = extractVueComponentComputed(p.value, context);
}
}
return result;
}
function extractVueComponentData(dataNode, context) {
const dataNodes = [];
if ((dataNode.type === "ArrowFunctionExpression" &&
dataNode.body.type === "BlockStatement") ||
dataNode.type === "FunctionExpression") {
if (dataNode.body.type === "BlockStatement") {
for (const returnStatement of getReturnStatements(dataNode.body, context)) {
if (returnStatement.argument) {
dataNodes.push(returnStatement.argument);
}
}
}
else {
dataNodes.push(dataNode.body);
}
}
else if (dataNode.type === "ArrowFunctionExpression" &&
dataNode.body.type !== "BlockStatement") {
dataNodes.push(dataNode.body);
}
else if (dataNode.type === "ObjectExpression") {
dataNodes.push(dataNode);
}
else {
return UNKNOWN;
}
const data = {};
for (const dataObj of dataNodes) {
if (dataObj.type !== "ObjectExpression") {
data[UNKNOWN] = true;
continue;
}
for (const prop of dataObj.properties) {
if (prop.type === "Property") {
const keyName = getPropertyOrIdentifierName(prop);
if (keyName == null) {
data[UNKNOWN] = true;
}
else {
const values = data[keyName] || (data[keyName] = []);
values.push(prop.value);
}
}
else {
data[UNKNOWN] = true;
}
}
}
return data;
}
function extractVueComponentComputed(computedNode, context) {
if (computedNode.type !== "ObjectExpression") {
return UNKNOWN;
}
const computed = {};
for (const p of computedNode.properties) {
if (p.type !== "Property") {
computed[UNKNOWN] = true;
continue;
}
const keyName = getPropertyOrIdentifierName(p);
if (!keyName) {
computed[UNKNOWN] = true;
continue;
}
const values = computed[keyName] || (computed[keyName] = []);
const value = p.value;
let func = value;
if (value.type === "ObjectExpression") {
const get = value.properties
.filter(isProperty)
.find((prop) => getPropertyOrIdentifierName(prop) === "get");
if (get) {
func = get.value;
}
}
if ((func.type === "ArrowFunctionExpression" &&
func.body.type === "BlockStatement") ||
func.type === "FunctionExpression") {
if (func.body.type === "BlockStatement") {
const exprs = getReturnStatements(func.body, context)
.map((r) => r.argument)
.filter(utils_1.isDefined);
values.push(...exprs);
}
else {
values.push(func.body);
}
}
else if (func.type === "ArrowFunctionExpression" &&
func.body.type !== "BlockStatement") {
values.push(func.body);
}
else {
computed[UNKNOWN] = true;
}
}
return computed;
}
function getClassesOperatedByClassList(vueNode, refNames, isRoot, context) {
const results = [];
traverseNodes(vueNode, {
visitorKeys: (0, compat_1.getSourceCode)(context).visitorKeys,
enterNode(node) {
if (node.type !== "CallExpression" ||
node.callee.type !== "MemberExpression") {
return;
}
const o = node.callee.object;
if (getPropertyOrIdentifierName(o) !== "classList") {
return;
}
if (o.type === "MemberExpression" &&
getPropertyOrIdentifierName(o.object) === "$el") {
if (!isRoot) {
return;
}
}
if (refNames != null) {
const $refName = o.type === "MemberExpression" && o.object.type !== "Super"
? get$RefName(o.object)
: null;
if ($refName != null) {
if (!refNames.some((r) => r.matchString($refName))) {
return;
}
}
}
const argumentNodes = getClassesArguments(node);
results.push(...argumentNodes);
},
leaveNode() {
},
});
return results;
}
function getReturnStatements(body, context) {
const returnStatements = [];
const skipNodes = [];
traverseNodes(body, {
visitorKeys: (0, compat_1.getSourceCode)(context).visitorKeys,
enterNode(node) {
if (skipNodes.length) {
return;
}
if (node.type === "ArrowFunctionExpression" ||
node.type === "FunctionExpression" ||
node.type === "FunctionDeclaration") {
skipNodes.unshift(node);
}
else if (node.type === "ReturnStatement") {
returnStatements.push(node);
}
},
leaveNode(node) {
if (skipNodes[0] === node) {
skipNodes.shift();
}
},
});
return returnStatements;
}
function getPropertyOrIdentifierName(node) {
if (node.type === "Identifier") {
return node.name;
}
else if (node.type === "MemberExpression") {
if (node.property.type === "Identifier" && !node.computed) {
return node.property.name;
}
else if (node.property.type === "Literal" && node.computed) {
return getLiteralString(node.property);
}
}
else if (node.type === "Property") {
if (node.key.type === "Identifier" && !node.computed) {
return node.key.name;
}
else if (node.key.type === "Literal") {
return getLiteralString(node.key);
}
}
return null;
}
function get$RefName(expr) {
if (expr.type !== "MemberExpression") {
return null;
}
const { object } = expr;
const name = getPropertyOrIdentifierName(object);
if (name !== "$refs") {
return null;
}
return getPropertyOrIdentifierName(expr);
}
function getClassesArguments(node) {
const methodName = getPropertyOrIdentifierName(node.callee);
if (methodName === "add" || methodName === "remove") {
return node.arguments;
}
else if (methodName === "toggle" || methodName === "contains") {
return [node.arguments[0]];
}
else if (methodName === "replace") {
return [node.arguments[0], node.arguments[1]];
}
return [];
}
function getLiteralString(node) {
if (typeof node.value === "string") {
return node.value;
}
return `${node.value}`;
}
function isProperty(node) {
return node.type === "Property";
}