const never = options[0] === "never";
const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
const sourceCode = context.getSourceCode();
+ let funcInfo = null;
/**
* Checks whether the given node has ASI problem or not.
}
/**
- * Gets the closing parenthesis which is the pair of the given opening parenthesis.
- * @param {Token} token The opening parenthesis token to get.
+ * Gets the closing parenthesis by the given node.
+ * @param {ASTNode} node first node after an opening parenthesis.
* @returns {Token} The found closing parenthesis token.
*/
- function findClosingParen(token) {
- let node = sourceCode.getNodeByRangeIndex(token.range[1]);
+ function findClosingParen(node) {
+ let nodeToCheck = node;
- while (!astUtils.isParenthesised(sourceCode, node)) {
- node = node.parent;
+ while (!astUtils.isParenthesised(sourceCode, nodeToCheck)) {
+ nodeToCheck = nodeToCheck.parent;
}
- return sourceCode.getTokenAfter(node);
+ return sourceCode.getTokenAfter(nodeToCheck);
+ }
+
+ /**
+ * Check whether the node is inside of a for loop's init
+ * @param {ASTNode} node node is inside for loop
+ * @returns {boolean} `true` if the node is inside of a for loop, else `false`
+ */
+ function isInsideForLoopInitializer(node) {
+ if (node && node.parent) {
+ if (node.parent.type === "ForStatement" && node.parent.init === node) {
+ return true;
+ }
+ return isInsideForLoopInitializer(node.parent);
+ }
+ return false;
}
/**
context.report({
node,
- loc: arrowBody.loc.start,
+ loc: arrowBody.loc,
messageId,
fix(fixer) {
const fixes = [];
}
/*
- * If the first token of the reutrn value is `{` or the return value is a sequence expression,
+ * If the first token of the return value is `{` or the return value is a sequence expression,
* enclose the return value by parentheses to avoid syntax error.
*/
- if (astUtils.isOpeningBraceToken(firstValueToken) || blockBody[0].argument.type === "SequenceExpression") {
- fixes.push(
- fixer.insertTextBefore(firstValueToken, "("),
- fixer.insertTextAfter(lastValueToken, ")")
- );
+ if (astUtils.isOpeningBraceToken(firstValueToken) || blockBody[0].argument.type === "SequenceExpression" || (funcInfo.hasInOperator && isInsideForLoopInitializer(node))) {
+ if (!astUtils.isParenthesised(sourceCode, blockBody[0].argument)) {
+ fixes.push(
+ fixer.insertTextBefore(firstValueToken, "("),
+ fixer.insertTextAfter(lastValueToken, ")")
+ );
+ }
}
/*
if (always || (asNeeded && requireReturnForObjectLiteral && arrowBody.type === "ObjectExpression")) {
context.report({
node,
- loc: arrowBody.loc.start,
+ loc: arrowBody.loc,
messageId: "expectedBlock",
fix(fixer) {
const fixes = [];
const arrowToken = sourceCode.getTokenBefore(arrowBody, astUtils.isArrowToken);
- const firstBodyToken = sourceCode.getTokenAfter(arrowToken);
- const lastBodyToken = sourceCode.getLastToken(node);
- const isParenthesisedObjectLiteral =
- astUtils.isOpeningParenToken(firstBodyToken) &&
- astUtils.isOpeningBraceToken(sourceCode.getTokenAfter(firstBodyToken));
-
- // Wrap the value by a block and a return statement.
- fixes.push(
- fixer.insertTextBefore(firstBodyToken, "{return "),
- fixer.insertTextAfter(lastBodyToken, "}")
- );
+ const [firstTokenAfterArrow, secondTokenAfterArrow] = sourceCode.getTokensAfter(arrowToken, { count: 2 });
+ const lastToken = sourceCode.getLastToken(node);
+
+ let parenthesisedObjectLiteral = null;
+
+ if (
+ astUtils.isOpeningParenToken(firstTokenAfterArrow) &&
+ astUtils.isOpeningBraceToken(secondTokenAfterArrow)
+ ) {
+ const braceNode = sourceCode.getNodeByRangeIndex(secondTokenAfterArrow.range[0]);
+
+ if (braceNode.type === "ObjectExpression") {
+ parenthesisedObjectLiteral = braceNode;
+ }
+ }
// If the value is object literal, remove parentheses which were forced by syntax.
- if (isParenthesisedObjectLiteral) {
- fixes.push(
- fixer.remove(firstBodyToken),
- fixer.remove(findClosingParen(firstBodyToken))
- );
+ if (parenthesisedObjectLiteral) {
+ const openingParenToken = firstTokenAfterArrow;
+ const openingBraceToken = secondTokenAfterArrow;
+
+ if (astUtils.isTokenOnSameLine(openingParenToken, openingBraceToken)) {
+ fixes.push(fixer.replaceText(openingParenToken, "{return "));
+ } else {
+
+ // Avoid ASI
+ fixes.push(
+ fixer.replaceText(openingParenToken, "{"),
+ fixer.insertTextBefore(openingBraceToken, "return ")
+ );
+ }
+
+ // Closing paren for the object doesn't have to be lastToken, e.g.: () => ({}).foo()
+ fixes.push(fixer.remove(findClosingParen(parenthesisedObjectLiteral)));
+ fixes.push(fixer.insertTextAfter(lastToken, "}"));
+
+ } else {
+ fixes.push(fixer.insertTextBefore(firstTokenAfterArrow, "{return "));
+ fixes.push(fixer.insertTextAfter(lastToken, "}"));
}
return fixes;
}
return {
- "ArrowFunctionExpression:exit": validate
+ "BinaryExpression[operator='in']"() {
+ let info = funcInfo;
+
+ while (info) {
+ info.hasInOperator = true;
+ info = info.upper;
+ }
+ },
+ ArrowFunctionExpression() {
+ funcInfo = {
+ upper: funcInfo,
+ hasInOperator: false
+ };
+ },
+ "ArrowFunctionExpression:exit"(node) {
+ validate(node);
+ funcInfo = funcInfo.upper;
+ }
};
}
};