UNPKG

5.68 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to require parens in arrow function arguments.
3 * @author Jxck
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Requirements
9//------------------------------------------------------------------------------
10
11const astUtils = require("../ast-utils");
12
13//------------------------------------------------------------------------------
14// Rule Definition
15//------------------------------------------------------------------------------
16
17module.exports = {
18 meta: {
19 docs: {
20 description: "require parentheses around arrow function arguments",
21 category: "ECMAScript 6",
22 recommended: false
23 },
24
25 fixable: "code",
26
27 schema: [
28 {
29 enum: ["always", "as-needed"]
30 },
31 {
32 type: "object",
33 properties: {
34 requireForBlockBody: {
35 type: "boolean"
36 }
37 },
38 additionalProperties: false
39 }
40 ]
41 },
42
43 create(context) {
44 const message = "Expected parentheses around arrow function argument.";
45 const asNeededMessage = "Unexpected parentheses around single function argument.";
46 const asNeeded = context.options[0] === "as-needed";
47 const requireForBlockBodyMessage = "Unexpected parentheses around single function argument having a body with no curly braces";
48 const requireForBlockBodyNoParensMessage = "Expected parentheses around arrow function argument having a body with curly braces.";
49 const requireForBlockBody = asNeeded && context.options[1] && context.options[1].requireForBlockBody === true;
50
51 const sourceCode = context.getSourceCode();
52
53 /**
54 * Determines whether a arrow function argument end with `)`
55 * @param {ASTNode} node The arrow function node.
56 * @returns {void}
57 */
58 function parens(node) {
59 const isAsync = node.async;
60 const firstTokenOfParam = sourceCode.getFirstToken(node, isAsync ? 1 : 0);
61
62 /**
63 * Remove the parenthesis around a parameter
64 * @param {Fixer} fixer Fixer
65 * @returns {string} fixed parameter
66 */
67 function fixParamsWithParenthesis(fixer) {
68 const paramToken = sourceCode.getTokenAfter(firstTokenOfParam);
69
70 // ES8 allows Trailing commas in function parameter lists and calls
71 // https://github.com/eslint/eslint/issues/8834
72 const closingParenToken = sourceCode.getTokenAfter(paramToken, astUtils.isClosingParenToken);
73 const asyncToken = isAsync ? sourceCode.getTokenBefore(firstTokenOfParam) : null;
74 const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === firstTokenOfParam.range[0]);
75
76 return fixer.replaceTextRange([
77 firstTokenOfParam.range[0],
78 closingParenToken.range[1]
79 ], `${shouldAddSpaceForAsync ? " " : ""}${paramToken.value}`);
80 }
81
82 // "as-needed", { "requireForBlockBody": true }: x => x
83 if (
84 requireForBlockBody &&
85 node.params.length === 1 &&
86 node.params[0].type === "Identifier" &&
87 !node.params[0].typeAnnotation &&
88 node.body.type !== "BlockStatement" &&
89 !node.returnType
90 ) {
91 if (astUtils.isOpeningParenToken(firstTokenOfParam)) {
92 context.report({
93 node,
94 message: requireForBlockBodyMessage,
95 fix: fixParamsWithParenthesis
96 });
97 }
98 return;
99 }
100
101 if (
102 requireForBlockBody &&
103 node.body.type === "BlockStatement"
104 ) {
105 if (!astUtils.isOpeningParenToken(firstTokenOfParam)) {
106 context.report({
107 node,
108 message: requireForBlockBodyNoParensMessage,
109 fix(fixer) {
110 return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`);
111 }
112 });
113 }
114 return;
115 }
116
117 // "as-needed": x => x
118 if (asNeeded &&
119 node.params.length === 1 &&
120 node.params[0].type === "Identifier" &&
121 !node.params[0].typeAnnotation &&
122 !node.returnType
123 ) {
124 if (astUtils.isOpeningParenToken(firstTokenOfParam)) {
125 context.report({
126 node,
127 message: asNeededMessage,
128 fix: fixParamsWithParenthesis
129 });
130 }
131 return;
132 }
133
134 if (firstTokenOfParam.type === "Identifier") {
135 const after = sourceCode.getTokenAfter(firstTokenOfParam);
136
137 // (x) => x
138 if (after.value !== ")") {
139 context.report({
140 node,
141 message,
142 fix(fixer) {
143 return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`);
144 }
145 });
146 }
147 }
148 }
149
150 return {
151 ArrowFunctionExpression: parens
152 };
153 }
154};