eslint-plugin-vue
Version:
Official ESLint plugin for Vue.js
171 lines (168 loc) • 5.9 kB
JavaScript
'use strict';
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.js');
const require_index = require('../utils/index.js');
const require_index$1 = require('../utils/style-variables/index.js');
//#region lib/rules/no-extra-parens.js
/**
* @author Yosuke Ota
*/
var require_no_extra_parens = /* @__PURE__ */ require_rolldown_runtime.__commonJSMin(((exports, module) => {
const { isParenthesized } = require("@eslint-community/eslint-utils");
const { wrapStylisticOrCoreRule } = require_index.default;
const { getStyleVariablesContext } = require_index$1.default;
module.exports = wrapStylisticOrCoreRule("no-extra-parens", {
skipDynamicArguments: true,
applyDocument: true,
create: createForVueSyntax
});
/**
* Check whether the given token is a left parenthesis.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is a left parenthesis.
*/
function isLeftParen(token) {
return token.type === "Punctuator" && token.value === "(";
}
/**
* Check whether the given token is a right parenthesis.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is a right parenthesis.
*/
function isRightParen(token) {
return token.type === "Punctuator" && token.value === ")";
}
/**
* Check whether the given token is a left brace.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is a left brace.
*/
function isLeftBrace(token) {
return token.type === "Punctuator" && token.value === "{";
}
/**
* Check whether the given token is a right brace.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is a right brace.
*/
function isRightBrace(token) {
return token.type === "Punctuator" && token.value === "}";
}
/**
* Check whether the given token is a left bracket.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is a left bracket.
*/
function isLeftBracket(token) {
return token.type === "Punctuator" && token.value === "[";
}
/**
* Check whether the given token is a right bracket.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is a right bracket.
*/
function isRightBracket(token) {
return token.type === "Punctuator" && token.value === "]";
}
/**
* Determines if a given expression node is an IIFE
* @param {Expression} node The node to check
* @returns {node is CallExpression & { callee: FunctionExpression } } `true` if the given node is an IIFE
*/
function isIIFE(node) {
return node.type === "CallExpression" && node.callee.type === "FunctionExpression";
}
/**
* @param {RuleContext} context - The rule context.
* @returns {TemplateListener} AST event handlers.
*/
function createForVueSyntax(context) {
const sourceCode = context.sourceCode;
if (!sourceCode.parserServices.getTemplateBodyTokenStore) return {};
const tokenStore = sourceCode.parserServices.getTemplateBodyTokenStore();
/**
* Checks if the given node turns into a filter when unwraped.
* @param {Expression} expression node to evaluate
* @returns {boolean} `true` if the given node turns into a filter when unwraped.
*/
function isUnwrapChangeToFilter(expression) {
let parenStack = null;
for (const token of tokenStore.getTokens(expression)) {
if (parenStack) {
if (parenStack.isUpToken(token)) {
parenStack = parenStack.upper;
continue;
}
} else if (token.value === "|") return true;
if (isLeftParen(token)) parenStack = {
isUpToken: isRightParen,
upper: parenStack
};
else if (isLeftBracket(token)) parenStack = {
isUpToken: isRightBracket,
upper: parenStack
};
else if (isLeftBrace(token)) parenStack = {
isUpToken: isRightBrace,
upper: parenStack
};
}
return false;
}
/**
* Checks if the given node is CSS v-bind() without quote.
* @param {VExpressionContainer} node
* @param {Expression} expression
*/
function isStyleVariableWithoutQuote(node, expression) {
const styleVars = getStyleVariablesContext(context);
if (!styleVars || !styleVars.vBinds.includes(node)) return false;
const vBindToken = tokenStore.getFirstToken(node);
return tokenStore.getTokensBetween(vBindToken, expression).every(isLeftParen);
}
/**
* @param {VExpressionContainer & { expression: Expression | VFilterSequenceExpression | null }} node
*/
function verify(node) {
if (!node.expression) return;
const expression = node.expression.type === "VFilterSequenceExpression" ? node.expression.expression : node.expression;
if (!isParenthesized(expression, tokenStore)) return;
if (!isParenthesized(2, expression, tokenStore)) {
if (isIIFE(expression) && !isParenthesized(expression.callee, tokenStore)) return;
if (isUnwrapChangeToFilter(expression)) return;
if (isStyleVariableWithoutQuote(node, expression)) return;
}
report(expression);
}
/**
* Report the node
* @param {Expression} node node to evaluate
* @returns {void}
* @private
*/
function report(node) {
const sourceCode$1 = context.sourceCode;
const leftParenToken = tokenStore.getTokenBefore(node);
const rightParenToken = tokenStore.getTokenAfter(node);
context.report({
node,
loc: leftParenToken.loc,
messageId: "unexpected",
fix(fixer) {
const parenthesizedSource = sourceCode$1.text.slice(leftParenToken.range[1], rightParenToken.range[0]);
return fixer.replaceTextRange([leftParenToken.range[0], rightParenToken.range[1]], parenthesizedSource);
}
});
}
return {
"VAttribute[directive=true][key.name.name='bind'] > VExpressionContainer": verify,
"VElement > VExpressionContainer": verify
};
}
}));
//#endregion
Object.defineProperty(exports, 'default', {
enumerable: true,
get: function () {
return require_no_extra_parens();
}
});