Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: add better TS generic support for arrow-parens (fixes #12570) #12587

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
83 changes: 48 additions & 35 deletions lib/rules/arrow-parens.js
Expand Up @@ -80,29 +80,49 @@ module.exports = {
* @returns {void}
*/
function parens(node) {
const isAsync = node.async;
const firstTokenOfParam = sourceCode.getFirstToken(node, isAsync ? 1 : 0);
const firstToken = sourceCode.getFirstToken(node);
const arrowToken = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken);
const openingParenToken = astUtils.isOpeningParenToken(firstToken)
? firstToken
: sourceCode.getFirstTokenBetween(firstToken, arrowToken, { filter: astUtils.isOpeningParenToken });
mdjermanovic marked this conversation as resolved.
Show resolved Hide resolved

/**
* Remove the parenthesis around a parameter
* @param {Fixer} fixer Fixer
* @returns {string} fixed parameter
*/
function fixParamsWithParenthesis(fixer) {
const paramToken = sourceCode.getTokenAfter(firstTokenOfParam);
function fixUnwrap(fixer) {
const firstParamToken = sourceCode.getTokenAfter(openingParenToken);

/*
* ES8 allows Trailing commas in function parameter lists and calls
* https://github.com/eslint/eslint/issues/8834
*/
const closingParenToken = sourceCode.getTokenAfter(paramToken, astUtils.isClosingParenToken);
const asyncToken = isAsync ? sourceCode.getTokenBefore(firstTokenOfParam) : null;
const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === firstTokenOfParam.range[0]);
// /*
// * ES8 allows Trailing commas in function parameter lists and calls
// * https://github.com/eslint/eslint/issues/8834
// */
const closingParenToken = sourceCode.getTokenAfter(firstParamToken, astUtils.isClosingParenToken);

const adjacentToken = sourceCode.getTokenBefore(openingParenToken);

const shouldAddSpace =
adjacentToken &&
!astUtils.canTokensBeAdjacent(adjacentToken, firstParamToken) &&
adjacentToken.range[1] === openingParenToken.range[0];

return fixer.replaceTextRange([
firstTokenOfParam.range[0],
openingParenToken.range[0],
closingParenToken.range[1]
], `${shouldAddSpaceForAsync ? " " : ""}${paramToken.value}`);
], `${shouldAddSpace ? " " : ""}${firstParamToken.value}`);
}


/**
* Adds the parenthesis around a parameter
* @param {Fixer} fixer Fixer
* @returns {string} fixed parameter
*/
function fixWrap(fixer) {
const firstParamToken = sourceCode.getFirstToken(node, node.async ? 1 : 0);

return fixer.replaceText(firstParamToken, `(${firstParamToken.value})`);
}

// "as-needed", { "requireForBlockBody": true }: x => x
Expand All @@ -114,12 +134,13 @@ module.exports = {
node.body.type !== "BlockStatement" &&
!node.returnType
) {
if (astUtils.isOpeningParenToken(firstTokenOfParam)) {
if (openingParenToken) {
context.report({
node,
messageId: "unexpectedParensInline",
loc: getLocation(node),
fix: fixParamsWithParenthesis
fix: fixUnwrap

});
}
return;
Expand All @@ -129,14 +150,12 @@ module.exports = {
requireForBlockBody &&
node.body.type === "BlockStatement"
) {
if (!astUtils.isOpeningParenToken(firstTokenOfParam)) {
if (!openingParenToken) {
context.report({
node,
messageId: "expectedParensBlock",
loc: getLocation(node),
fix(fixer) {
return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`);
}
fix: fixWrap
});
}
return;
Expand All @@ -149,31 +168,25 @@ module.exports = {
!node.params[0].typeAnnotation &&
!node.returnType
) {
if (astUtils.isOpeningParenToken(firstTokenOfParam)) {
if (openingParenToken) {
context.report({
node,
messageId: "unexpectedParens",
loc: getLocation(node),
fix: fixParamsWithParenthesis
fix: fixUnwrap
});
}
return;
}

if (firstTokenOfParam.type === "Identifier") {
const after = sourceCode.getTokenAfter(firstTokenOfParam);

// (x) => x
if (after.value !== ")") {
context.report({
node,
messageId: "expectedParens",
loc: getLocation(node),
fix(fixer) {
return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`);
}
});
}
// "always"
if (!openingParenToken) {
context.report({
node,
messageId: "expectedParens",
loc: getLocation(node),
fix: fixWrap
});
}
}

Expand Down
10 changes: 10 additions & 0 deletions lib/rules/utils/ast-utils.js
Expand Up @@ -271,6 +271,15 @@ function isArrowToken(token) {
return token.value === "=>" && token.type === "Punctuator";
}

/**
* Checks if the given token is an async token or not.
* @param {Token} token The token to check.
* @returns {boolean} `true` if the token is an async token.
*/
function isAsyncToken(token) {
return token.value === "async" && token.type === "Identifier";
}

/**
* Checks if the given token is a comma token or not.
* @param {Token} token The token to check.
Expand Down Expand Up @@ -451,6 +460,7 @@ module.exports = {
equalTokens,

isArrowToken,
isAsyncToken,
isClosingBraceToken,
isClosingBracketToken,
isClosingParenToken,
Expand Down