Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
arrow-parens: Allow binding patterns ([x, y]) => ... and `({x, y}) …
Browse files Browse the repository at this point in the history
…=> ...` to have parens (#1958)
  • Loading branch information
andy-hanson authored and nchen63 committed Jan 1, 2017
1 parent b7741b0 commit 7b6ac79
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 34 deletions.
61 changes: 30 additions & 31 deletions src/rules/arrowParensRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import * as ts from "typescript";

import * as Lint from "../index";
import { hasModifier } from "../language/utils";

const BAN_SINGLE_ARG_PARENS = "ban-single-arg-parens";

Expand All @@ -29,7 +28,7 @@ export class Rule extends Lint.Rules.AbstractRule {
description: "Requires parentheses around the parameters of arrow function definitions.",
rationale: "Maintains stylistic consistency with other arrow function definitions.",
optionsDescription: Lint.Utils.dedent`
if \`${BAN_SINGLE_ARG_PARENS}\` is specified, then arrow functions with one parameter
if \`${BAN_SINGLE_ARG_PARENS}\` is specified, then arrow functions with one parameter
must not have parentheses if removing them is allowed by TypeScript.`,
options: {
type: "string",
Expand Down Expand Up @@ -59,41 +58,41 @@ class ArrowParensWalker extends Lint.RuleWalker {
}

public visitArrowFunction(node: ts.FunctionLikeDeclaration) {
if (node.parameters.length === 1) {
if (node.parameters.length === 1 && node.typeParameters === undefined) {
const parameter = node.parameters[0];
const text = parameter.getText();
const firstToken = node.getFirstToken();
const lastToken = node.getChildAt(2);
const width = text.length;
const position = parameter.getStart();
let isGenerics = false;

// If firstToken is LessThanToken, it would be Generics.
if (firstToken.kind === ts.SyntaxKind.LessThanToken) {
isGenerics = true;
let openParen = node.getFirstToken();
let openParenIndex = 0;
if (openParen.kind === ts.SyntaxKind.AsyncKeyword) {
openParen = node.getChildAt(1);
openParenIndex = 1;
}

if (!isGenerics && !hasModifier(node.modifiers, ts.SyntaxKind.AsyncKeyword)) {
const hasParens = firstToken.kind === ts.SyntaxKind.OpenParenToken && lastToken.kind === ts.SyntaxKind.CloseParenToken;
if (!hasParens && !this.avoidOnSingleParameter) {
const fix = new Lint.Fix(Rule.metadata.ruleName, [new Lint.Replacement(position, width, `(${parameter.getText()})`)]);
this.addFailureAt(position, width, Rule.FAILURE_STRING_MISSING, fix);
} else if (hasParens
&& this.avoidOnSingleParameter
&& parameter.decorators == null
&& parameter.dotDotDotToken == null
&& parameter.initializer == null
&& parameter.modifiers == null
&& parameter.questionToken == null
&& parameter.type == null) {
const fix = new Lint.Fix(Rule.metadata.ruleName, [
new Lint.Replacement(lastToken.getStart(), 1, ``),
new Lint.Replacement(firstToken.getStart(), 1, ``),
]);
this.addFailureAt(position, width, Rule.FAILURE_STRING_EXISTS, fix);
}
const hasParens = openParen.kind === ts.SyntaxKind.OpenParenToken;
if (!hasParens && !this.avoidOnSingleParameter) {
const fix = new Lint.Fix(Rule.metadata.ruleName, [
this.appendText(parameter.getStart(), "("),
this.appendText(parameter.getEnd(), ")"),
]);
this.addFailureAtNode(parameter, Rule.FAILURE_STRING_MISSING, fix);
} else if (hasParens && this.avoidOnSingleParameter && isSimpleParameter(parameter)) {
// Skip over the parameter to get the closing parenthesis
const closeParen = node.getChildAt(openParenIndex + 2);
const fix = new Lint.Fix(Rule.metadata.ruleName, [
this.deleteText(openParen.getStart(), 1),
this.deleteText(closeParen.getStart(), 1),
]);
this.addFailureAtNode(parameter, Rule.FAILURE_STRING_EXISTS, fix);
}
}
super.visitArrowFunction(node);
}
}

function isSimpleParameter(parameter: ts.ParameterDeclaration): boolean {
return parameter.name.kind === ts.SyntaxKind.Identifier
&& parameter.dotDotDotToken === undefined
&& parameter.initializer === undefined
&& parameter.questionToken === undefined
&& parameter.type === undefined;
}
4 changes: 3 additions & 1 deletion test/rules/arrow-parens/ban-single-arg-parens/test.ts.fix
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// valid case
var a = ([x, y]) => {};
var aa = ({x, y}) => {};
var b = (a: number) => {};
var c = (a, b) => {};
var f = (...rest) => {};
Expand All @@ -16,10 +18,10 @@ var piyo = <T, U>(method: () => T) => {
method();
};
const validAsync = async (param: any) => {};
const validAsync = async (param) => {};

var e = (a => {})(1);
var f = ab => {};

// invalid case
var a = a => {};
const invalidAsync = async param => {};
9 changes: 7 additions & 2 deletions test/rules/arrow-parens/ban-single-arg-parens/test.ts.lint
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// valid case
var a = ([x, y]) => {};
var aa = ({x, y}) => {};
var b = (a: number) => {};
var c = (a, b) => {};
var f = (...rest) => {};
Expand All @@ -16,11 +18,14 @@ var piyo = <T, U>(method: () => T) => {
method();
};
const validAsync = async (param: any) => {};
const validAsync = async (param) => {};

var e = (a => {})(1);
var f = ab => {};

// invalid case
var a = (a) => {};
~ [Parentheses are prohibited around the parameter in this single parameter arrow function]
~ [0]
const invalidAsync = async (param) => {};
~~~~~ [0]

[0]: Parentheses are prohibited around the parameter in this single parameter arrow function

0 comments on commit 7b6ac79

Please sign in to comment.