UNPKG

5.81 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 url: "https://eslint.org/docs/rules/arrow-parens"
24 },
25
26 fixable: "code",
27
28 schema: [
29 {
30 enum: ["always", "as-needed"]
31 },
32 {
33 type: "object",
34 properties: {
35 requireForBlockBody: {
36 type: "boolean"
37 }
38 },
39 additionalProperties: false
40 }
41 ],
42
43 messages: {
44 unexpectedParens: "Unexpected parentheses around single function argument.",
45 expectedParens: "Expected parentheses around arrow function argument.",
46
47 unexpectedParensInline: "Unexpected parentheses around single function argument having a body with no curly braces.",
48 expectedParensBlock: "Expected parentheses around arrow function argument having a body with curly braces."
49 }
50 },
51
52 create(context) {
53 const asNeeded = context.options[0] === "as-needed";
54 const requireForBlockBody = asNeeded && context.options[1] && context.options[1].requireForBlockBody === true;
55
56 const sourceCode = context.getSourceCode();
57
58 /**
59 * Determines whether a arrow function argument end with `)`
60 * @param {ASTNode} node The arrow function node.
61 * @returns {void}
62 */
63 function parens(node) {
64 const isAsync = node.async;
65 const firstTokenOfParam = sourceCode.getFirstToken(node, isAsync ? 1 : 0);
66
67 /**
68 * Remove the parenthesis around a parameter
69 * @param {Fixer} fixer Fixer
70 * @returns {string} fixed parameter
71 */
72 function fixParamsWithParenthesis(fixer) {
73 const paramToken = sourceCode.getTokenAfter(firstTokenOfParam);
74
75 /*
76 * ES8 allows Trailing commas in function parameter lists and calls
77 * https://github.com/eslint/eslint/issues/8834
78 */
79 const closingParenToken = sourceCode.getTokenAfter(paramToken, astUtils.isClosingParenToken);
80 const asyncToken = isAsync ? sourceCode.getTokenBefore(firstTokenOfParam) : null;
81 const shouldAddSpaceForAsync = asyncToken && (asyncToken.range[1] === firstTokenOfParam.range[0]);
82
83 return fixer.replaceTextRange([
84 firstTokenOfParam.range[0],
85 closingParenToken.range[1]
86 ], `${shouldAddSpaceForAsync ? " " : ""}${paramToken.value}`);
87 }
88
89 // "as-needed", { "requireForBlockBody": true }: x => x
90 if (
91 requireForBlockBody &&
92 node.params.length === 1 &&
93 node.params[0].type === "Identifier" &&
94 !node.params[0].typeAnnotation &&
95 node.body.type !== "BlockStatement" &&
96 !node.returnType
97 ) {
98 if (astUtils.isOpeningParenToken(firstTokenOfParam)) {
99 context.report({
100 node,
101 messageId: "unexpectedParensInline",
102 fix: fixParamsWithParenthesis
103 });
104 }
105 return;
106 }
107
108 if (
109 requireForBlockBody &&
110 node.body.type === "BlockStatement"
111 ) {
112 if (!astUtils.isOpeningParenToken(firstTokenOfParam)) {
113 context.report({
114 node,
115 messageId: "expectedParensBlock",
116 fix(fixer) {
117 return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`);
118 }
119 });
120 }
121 return;
122 }
123
124 // "as-needed": x => x
125 if (asNeeded &&
126 node.params.length === 1 &&
127 node.params[0].type === "Identifier" &&
128 !node.params[0].typeAnnotation &&
129 !node.returnType
130 ) {
131 if (astUtils.isOpeningParenToken(firstTokenOfParam)) {
132 context.report({
133 node,
134 messageId: "unexpectedParens",
135 fix: fixParamsWithParenthesis
136 });
137 }
138 return;
139 }
140
141 if (firstTokenOfParam.type === "Identifier") {
142 const after = sourceCode.getTokenAfter(firstTokenOfParam);
143
144 // (x) => x
145 if (after.value !== ")") {
146 context.report({
147 node,
148 messageId: "expectedParens",
149 fix(fixer) {
150 return fixer.replaceText(firstTokenOfParam, `(${firstTokenOfParam.value})`);
151 }
152 });
153 }
154 }
155 }
156
157 return {
158 ArrowFunctionExpression: parens
159 };
160 }
161};