Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / array-element-newline.js
1 /**
2  * @fileoverview Rule to enforce line breaks after each array element
3  * @author Jan Peer Stöcklmair <https://github.com/JPeer264>
4  */
5
6 "use strict";
7
8 const astUtils = require("./utils/ast-utils");
9
10 //------------------------------------------------------------------------------
11 // Rule Definition
12 //------------------------------------------------------------------------------
13
14 module.exports = {
15     meta: {
16         type: "layout",
17
18         docs: {
19             description: "enforce line breaks after each array element",
20             category: "Stylistic Issues",
21             recommended: false,
22             url: "https://eslint.org/docs/rules/array-element-newline"
23         },
24
25         fixable: "whitespace",
26
27         schema: [
28             {
29                 oneOf: [
30                     {
31                         enum: ["always", "never", "consistent"]
32                     },
33                     {
34                         type: "object",
35                         properties: {
36                             multiline: {
37                                 type: "boolean"
38                             },
39                             minItems: {
40                                 type: ["integer", "null"],
41                                 minimum: 0
42                             }
43                         },
44                         additionalProperties: false
45                     }
46                 ]
47             }
48         ],
49
50         messages: {
51             unexpectedLineBreak: "There should be no linebreak here.",
52             missingLineBreak: "There should be a linebreak after this element."
53         }
54     },
55
56     create(context) {
57         const sourceCode = context.getSourceCode();
58
59         //----------------------------------------------------------------------
60         // Helpers
61         //----------------------------------------------------------------------
62
63         /**
64          * Normalizes a given option value.
65          * @param {string|Object|undefined} providedOption An option value to parse.
66          * @returns {{multiline: boolean, minItems: number}} Normalized option object.
67          */
68         function normalizeOptionValue(providedOption) {
69             let consistent = false;
70             let multiline = false;
71             let minItems;
72
73             const option = providedOption || "always";
74
75             if (!option || option === "always" || option.minItems === 0) {
76                 minItems = 0;
77             } else if (option === "never") {
78                 minItems = Number.POSITIVE_INFINITY;
79             } else if (option === "consistent") {
80                 consistent = true;
81                 minItems = Number.POSITIVE_INFINITY;
82             } else {
83                 multiline = Boolean(option.multiline);
84                 minItems = option.minItems || Number.POSITIVE_INFINITY;
85             }
86
87             return { consistent, multiline, minItems };
88         }
89
90         /**
91          * Normalizes a given option value.
92          * @param {string|Object|undefined} options An option value to parse.
93          * @returns {{ArrayExpression: {multiline: boolean, minItems: number}, ArrayPattern: {multiline: boolean, minItems: number}}} Normalized option object.
94          */
95         function normalizeOptions(options) {
96             const value = normalizeOptionValue(options);
97
98             return { ArrayExpression: value, ArrayPattern: value };
99         }
100
101         /**
102          * Reports that there shouldn't be a line break after the first token
103          * @param {Token} token The token to use for the report.
104          * @returns {void}
105          */
106         function reportNoLineBreak(token) {
107             const tokenBefore = sourceCode.getTokenBefore(token, { includeComments: true });
108
109             context.report({
110                 loc: {
111                     start: tokenBefore.loc.end,
112                     end: token.loc.start
113                 },
114                 messageId: "unexpectedLineBreak",
115                 fix(fixer) {
116                     if (astUtils.isCommentToken(tokenBefore)) {
117                         return null;
118                     }
119
120                     if (!astUtils.isTokenOnSameLine(tokenBefore, token)) {
121                         return fixer.replaceTextRange([tokenBefore.range[1], token.range[0]], " ");
122                     }
123
124                     /*
125                      * This will check if the comma is on the same line as the next element
126                      * Following array:
127                      * [
128                      *     1
129                      *     , 2
130                      *     , 3
131                      * ]
132                      *
133                      * will be fixed to:
134                      * [
135                      *     1, 2, 3
136                      * ]
137                      */
138                     const twoTokensBefore = sourceCode.getTokenBefore(tokenBefore, { includeComments: true });
139
140                     if (astUtils.isCommentToken(twoTokensBefore)) {
141                         return null;
142                     }
143
144                     return fixer.replaceTextRange([twoTokensBefore.range[1], tokenBefore.range[0]], "");
145
146                 }
147             });
148         }
149
150         /**
151          * Reports that there should be a line break after the first token
152          * @param {Token} token The token to use for the report.
153          * @returns {void}
154          */
155         function reportRequiredLineBreak(token) {
156             const tokenBefore = sourceCode.getTokenBefore(token, { includeComments: true });
157
158             context.report({
159                 loc: {
160                     start: tokenBefore.loc.end,
161                     end: token.loc.start
162                 },
163                 messageId: "missingLineBreak",
164                 fix(fixer) {
165                     return fixer.replaceTextRange([tokenBefore.range[1], token.range[0]], "\n");
166                 }
167             });
168         }
169
170         /**
171          * Reports a given node if it violated this rule.
172          * @param {ASTNode} node A node to check. This is an ObjectExpression node or an ObjectPattern node.
173          * @returns {void}
174          */
175         function check(node) {
176             const elements = node.elements;
177             const normalizedOptions = normalizeOptions(context.options[0]);
178             const options = normalizedOptions[node.type];
179
180             let elementBreak = false;
181
182             /*
183              * MULTILINE: true
184              * loop through every element and check
185              * if at least one element has linebreaks inside
186              * this ensures that following is not valid (due to elements are on the same line):
187              *
188              * [
189              *      1,
190              *      2,
191              *      3
192              * ]
193              */
194             if (options.multiline) {
195                 elementBreak = elements
196                     .filter(element => element !== null)
197                     .some(element => element.loc.start.line !== element.loc.end.line);
198             }
199
200             const linebreaksCount = node.elements.map((element, i) => {
201                 const previousElement = elements[i - 1];
202
203                 if (i === 0 || element === null || previousElement === null) {
204                     return false;
205                 }
206
207                 const commaToken = sourceCode.getFirstTokenBetween(previousElement, element, astUtils.isCommaToken);
208                 const lastTokenOfPreviousElement = sourceCode.getTokenBefore(commaToken);
209                 const firstTokenOfCurrentElement = sourceCode.getTokenAfter(commaToken);
210
211                 return !astUtils.isTokenOnSameLine(lastTokenOfPreviousElement, firstTokenOfCurrentElement);
212             }).filter(isBreak => isBreak === true).length;
213
214             const needsLinebreaks = (
215                 elements.length >= options.minItems ||
216                 (
217                     options.multiline &&
218                     elementBreak
219                 ) ||
220                 (
221                     options.consistent &&
222                     linebreaksCount > 0 &&
223                     linebreaksCount < node.elements.length
224                 )
225             );
226
227             elements.forEach((element, i) => {
228                 const previousElement = elements[i - 1];
229
230                 if (i === 0 || element === null || previousElement === null) {
231                     return;
232                 }
233
234                 const commaToken = sourceCode.getFirstTokenBetween(previousElement, element, astUtils.isCommaToken);
235                 const lastTokenOfPreviousElement = sourceCode.getTokenBefore(commaToken);
236                 const firstTokenOfCurrentElement = sourceCode.getTokenAfter(commaToken);
237
238                 if (needsLinebreaks) {
239                     if (astUtils.isTokenOnSameLine(lastTokenOfPreviousElement, firstTokenOfCurrentElement)) {
240                         reportRequiredLineBreak(firstTokenOfCurrentElement);
241                     }
242                 } else {
243                     if (!astUtils.isTokenOnSameLine(lastTokenOfPreviousElement, firstTokenOfCurrentElement)) {
244                         reportNoLineBreak(firstTokenOfCurrentElement);
245                     }
246                 }
247             });
248         }
249
250         //----------------------------------------------------------------------
251         // Public
252         //----------------------------------------------------------------------
253
254         return {
255             ArrayPattern: check,
256             ArrayExpression: check
257         };
258     }
259 };