Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / arrow-body-style.js
1 /**
2  * @fileoverview Rule to require braces in arrow function body.
3  * @author Alberto Rodríguez
4  */
5 "use strict";
6
7 //------------------------------------------------------------------------------
8 // Requirements
9 //------------------------------------------------------------------------------
10
11 const astUtils = require("./utils/ast-utils");
12
13 //------------------------------------------------------------------------------
14 // Rule Definition
15 //------------------------------------------------------------------------------
16
17 module.exports = {
18     meta: {
19         type: "suggestion",
20
21         docs: {
22             description: "require braces around arrow function bodies",
23             category: "ECMAScript 6",
24             recommended: false,
25             url: "https://eslint.org/docs/rules/arrow-body-style"
26         },
27
28         schema: {
29             anyOf: [
30                 {
31                     type: "array",
32                     items: [
33                         {
34                             enum: ["always", "never"]
35                         }
36                     ],
37                     minItems: 0,
38                     maxItems: 1
39                 },
40                 {
41                     type: "array",
42                     items: [
43                         {
44                             enum: ["as-needed"]
45                         },
46                         {
47                             type: "object",
48                             properties: {
49                                 requireReturnForObjectLiteral: { type: "boolean" }
50                             },
51                             additionalProperties: false
52                         }
53                     ],
54                     minItems: 0,
55                     maxItems: 2
56                 }
57             ]
58         },
59
60         fixable: "code",
61
62         messages: {
63             unexpectedOtherBlock: "Unexpected block statement surrounding arrow body.",
64             unexpectedEmptyBlock: "Unexpected block statement surrounding arrow body; put a value of `undefined` immediately after the `=>`.",
65             unexpectedObjectBlock: "Unexpected block statement surrounding arrow body; parenthesize the returned value and move it immediately after the `=>`.",
66             unexpectedSingleBlock: "Unexpected block statement surrounding arrow body; move the returned value immediately after the `=>`.",
67             expectedBlock: "Expected block statement surrounding arrow body."
68         }
69     },
70
71     create(context) {
72         const options = context.options;
73         const always = options[0] === "always";
74         const asNeeded = !options[0] || options[0] === "as-needed";
75         const never = options[0] === "never";
76         const requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
77         const sourceCode = context.getSourceCode();
78
79         /**
80          * Checks whether the given node has ASI problem or not.
81          * @param {Token} token The token to check.
82          * @returns {boolean} `true` if it changes semantics if `;` or `}` followed by the token are removed.
83          */
84         function hasASIProblem(token) {
85             return token && token.type === "Punctuator" && /^[([/`+-]/u.test(token.value);
86         }
87
88         /**
89          * Gets the closing parenthesis which is the pair of the given opening parenthesis.
90          * @param {Token} token The opening parenthesis token to get.
91          * @returns {Token} The found closing parenthesis token.
92          */
93         function findClosingParen(token) {
94             let node = sourceCode.getNodeByRangeIndex(token.range[1]);
95
96             while (!astUtils.isParenthesised(sourceCode, node)) {
97                 node = node.parent;
98             }
99             return sourceCode.getTokenAfter(node);
100         }
101
102         /**
103          * Determines whether a arrow function body needs braces
104          * @param {ASTNode} node The arrow function node.
105          * @returns {void}
106          */
107         function validate(node) {
108             const arrowBody = node.body;
109
110             if (arrowBody.type === "BlockStatement") {
111                 const blockBody = arrowBody.body;
112
113                 if (blockBody.length !== 1 && !never) {
114                     return;
115                 }
116
117                 if (asNeeded && requireReturnForObjectLiteral && blockBody[0].type === "ReturnStatement" &&
118                     blockBody[0].argument && blockBody[0].argument.type === "ObjectExpression") {
119                     return;
120                 }
121
122                 if (never || asNeeded && blockBody[0].type === "ReturnStatement") {
123                     let messageId;
124
125                     if (blockBody.length === 0) {
126                         messageId = "unexpectedEmptyBlock";
127                     } else if (blockBody.length > 1) {
128                         messageId = "unexpectedOtherBlock";
129                     } else if (blockBody[0].argument === null) {
130                         messageId = "unexpectedSingleBlock";
131                     } else if (astUtils.isOpeningBraceToken(sourceCode.getFirstToken(blockBody[0], { skip: 1 }))) {
132                         messageId = "unexpectedObjectBlock";
133                     } else {
134                         messageId = "unexpectedSingleBlock";
135                     }
136
137                     context.report({
138                         node,
139                         loc: arrowBody.loc.start,
140                         messageId,
141                         fix(fixer) {
142                             const fixes = [];
143
144                             if (blockBody.length !== 1 ||
145                                 blockBody[0].type !== "ReturnStatement" ||
146                                 !blockBody[0].argument ||
147                                 hasASIProblem(sourceCode.getTokenAfter(arrowBody))
148                             ) {
149                                 return fixes;
150                             }
151
152                             const openingBrace = sourceCode.getFirstToken(arrowBody);
153                             const closingBrace = sourceCode.getLastToken(arrowBody);
154                             const firstValueToken = sourceCode.getFirstToken(blockBody[0], 1);
155                             const lastValueToken = sourceCode.getLastToken(blockBody[0]);
156                             const commentsExist =
157                                 sourceCode.commentsExistBetween(openingBrace, firstValueToken) ||
158                                 sourceCode.commentsExistBetween(lastValueToken, closingBrace);
159
160                             /*
161                              * Remove tokens around the return value.
162                              * If comments don't exist, remove extra spaces as well.
163                              */
164                             if (commentsExist) {
165                                 fixes.push(
166                                     fixer.remove(openingBrace),
167                                     fixer.remove(closingBrace),
168                                     fixer.remove(sourceCode.getTokenAfter(openingBrace)) // return keyword
169                                 );
170                             } else {
171                                 fixes.push(
172                                     fixer.removeRange([openingBrace.range[0], firstValueToken.range[0]]),
173                                     fixer.removeRange([lastValueToken.range[1], closingBrace.range[1]])
174                                 );
175                             }
176
177                             /*
178                              * If the first token of the reutrn value is `{` or the return value is a sequence expression,
179                              * enclose the return value by parentheses to avoid syntax error.
180                              */
181                             if (astUtils.isOpeningBraceToken(firstValueToken) || blockBody[0].argument.type === "SequenceExpression") {
182                                 fixes.push(
183                                     fixer.insertTextBefore(firstValueToken, "("),
184                                     fixer.insertTextAfter(lastValueToken, ")")
185                                 );
186                             }
187
188                             /*
189                              * If the last token of the return statement is semicolon, remove it.
190                              * Non-block arrow body is an expression, not a statement.
191                              */
192                             if (astUtils.isSemicolonToken(lastValueToken)) {
193                                 fixes.push(fixer.remove(lastValueToken));
194                             }
195
196                             return fixes;
197                         }
198                     });
199                 }
200             } else {
201                 if (always || (asNeeded && requireReturnForObjectLiteral && arrowBody.type === "ObjectExpression")) {
202                     context.report({
203                         node,
204                         loc: arrowBody.loc.start,
205                         messageId: "expectedBlock",
206                         fix(fixer) {
207                             const fixes = [];
208                             const arrowToken = sourceCode.getTokenBefore(arrowBody, astUtils.isArrowToken);
209                             const firstBodyToken = sourceCode.getTokenAfter(arrowToken);
210                             const lastBodyToken = sourceCode.getLastToken(node);
211                             const isParenthesisedObjectLiteral =
212                                 astUtils.isOpeningParenToken(firstBodyToken) &&
213                                 astUtils.isOpeningBraceToken(sourceCode.getTokenAfter(firstBodyToken));
214
215                             // Wrap the value by a block and a return statement.
216                             fixes.push(
217                                 fixer.insertTextBefore(firstBodyToken, "{return "),
218                                 fixer.insertTextAfter(lastBodyToken, "}")
219                             );
220
221                             // If the value is object literal, remove parentheses which were forced by syntax.
222                             if (isParenthesisedObjectLiteral) {
223                                 fixes.push(
224                                     fixer.remove(firstBodyToken),
225                                     fixer.remove(findClosingParen(firstBodyToken))
226                                 );
227                             }
228
229                             return fixes;
230                         }
231                     });
232                 }
233             }
234         }
235
236         return {
237             "ArrowFunctionExpression:exit": validate
238         };
239     }
240 };