Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / padded-blocks.js
1 /**
2  * @fileoverview A rule to ensure blank lines within blocks.
3  * @author Mathias Schreck <https://github.com/lo1tuma>
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Requirements
10 //------------------------------------------------------------------------------
11
12 const astUtils = require("./utils/ast-utils");
13
14 //------------------------------------------------------------------------------
15 // Rule Definition
16 //------------------------------------------------------------------------------
17
18 module.exports = {
19     meta: {
20         type: "layout",
21
22         docs: {
23             description: "require or disallow padding within blocks",
24             category: "Stylistic Issues",
25             recommended: false,
26             url: "https://eslint.org/docs/rules/padded-blocks"
27         },
28
29         fixable: "whitespace",
30
31         schema: [
32             {
33                 oneOf: [
34                     {
35                         enum: ["always", "never"]
36                     },
37                     {
38                         type: "object",
39                         properties: {
40                             blocks: {
41                                 enum: ["always", "never"]
42                             },
43                             switches: {
44                                 enum: ["always", "never"]
45                             },
46                             classes: {
47                                 enum: ["always", "never"]
48                             }
49                         },
50                         additionalProperties: false,
51                         minProperties: 1
52                     }
53                 ]
54             },
55             {
56                 type: "object",
57                 properties: {
58                     allowSingleLineBlocks: {
59                         type: "boolean"
60                     }
61                 }
62             }
63         ]
64     },
65
66     create(context) {
67         const options = {};
68         const typeOptions = context.options[0] || "always";
69         const exceptOptions = context.options[1] || {};
70
71         if (typeof typeOptions === "string") {
72             const shouldHavePadding = typeOptions === "always";
73
74             options.blocks = shouldHavePadding;
75             options.switches = shouldHavePadding;
76             options.classes = shouldHavePadding;
77         } else {
78             if (Object.prototype.hasOwnProperty.call(typeOptions, "blocks")) {
79                 options.blocks = typeOptions.blocks === "always";
80             }
81             if (Object.prototype.hasOwnProperty.call(typeOptions, "switches")) {
82                 options.switches = typeOptions.switches === "always";
83             }
84             if (Object.prototype.hasOwnProperty.call(typeOptions, "classes")) {
85                 options.classes = typeOptions.classes === "always";
86             }
87         }
88
89         if (Object.prototype.hasOwnProperty.call(exceptOptions, "allowSingleLineBlocks")) {
90             options.allowSingleLineBlocks = exceptOptions.allowSingleLineBlocks === true;
91         }
92
93         const ALWAYS_MESSAGE = "Block must be padded by blank lines.",
94             NEVER_MESSAGE = "Block must not be padded by blank lines.";
95
96         const sourceCode = context.getSourceCode();
97
98         /**
99          * Gets the open brace token from a given node.
100          * @param {ASTNode} node A BlockStatement or SwitchStatement node from which to get the open brace.
101          * @returns {Token} The token of the open brace.
102          */
103         function getOpenBrace(node) {
104             if (node.type === "SwitchStatement") {
105                 return sourceCode.getTokenBefore(node.cases[0]);
106             }
107             return sourceCode.getFirstToken(node);
108         }
109
110         /**
111          * Checks if the given parameter is a comment node
112          * @param {ASTNode|Token} node An AST node or token
113          * @returns {boolean} True if node is a comment
114          */
115         function isComment(node) {
116             return node.type === "Line" || node.type === "Block";
117         }
118
119         /**
120          * Checks if there is padding between two tokens
121          * @param {Token} first The first token
122          * @param {Token} second The second token
123          * @returns {boolean} True if there is at least a line between the tokens
124          */
125         function isPaddingBetweenTokens(first, second) {
126             return second.loc.start.line - first.loc.end.line >= 2;
127         }
128
129
130         /**
131          * Checks if the given token has a blank line after it.
132          * @param {Token} token The token to check.
133          * @returns {boolean} Whether or not the token is followed by a blank line.
134          */
135         function getFirstBlockToken(token) {
136             let prev,
137                 first = token;
138
139             do {
140                 prev = first;
141                 first = sourceCode.getTokenAfter(first, { includeComments: true });
142             } while (isComment(first) && first.loc.start.line === prev.loc.end.line);
143
144             return first;
145         }
146
147         /**
148          * Checks if the given token is preceeded by a blank line.
149          * @param {Token} token The token to check
150          * @returns {boolean} Whether or not the token is preceeded by a blank line
151          */
152         function getLastBlockToken(token) {
153             let last = token,
154                 next;
155
156             do {
157                 next = last;
158                 last = sourceCode.getTokenBefore(last, { includeComments: true });
159             } while (isComment(last) && last.loc.end.line === next.loc.start.line);
160
161             return last;
162         }
163
164         /**
165          * Checks if a node should be padded, according to the rule config.
166          * @param {ASTNode} node The AST node to check.
167          * @returns {boolean} True if the node should be padded, false otherwise.
168          */
169         function requirePaddingFor(node) {
170             switch (node.type) {
171                 case "BlockStatement":
172                     return options.blocks;
173                 case "SwitchStatement":
174                     return options.switches;
175                 case "ClassBody":
176                     return options.classes;
177
178                 /* istanbul ignore next */
179                 default:
180                     throw new Error("unreachable");
181             }
182         }
183
184         /**
185          * Checks the given BlockStatement node to be padded if the block is not empty.
186          * @param {ASTNode} node The AST node of a BlockStatement.
187          * @returns {void} undefined.
188          */
189         function checkPadding(node) {
190             const openBrace = getOpenBrace(node),
191                 firstBlockToken = getFirstBlockToken(openBrace),
192                 tokenBeforeFirst = sourceCode.getTokenBefore(firstBlockToken, { includeComments: true }),
193                 closeBrace = sourceCode.getLastToken(node),
194                 lastBlockToken = getLastBlockToken(closeBrace),
195                 tokenAfterLast = sourceCode.getTokenAfter(lastBlockToken, { includeComments: true }),
196                 blockHasTopPadding = isPaddingBetweenTokens(tokenBeforeFirst, firstBlockToken),
197                 blockHasBottomPadding = isPaddingBetweenTokens(lastBlockToken, tokenAfterLast);
198
199             if (options.allowSingleLineBlocks && astUtils.isTokenOnSameLine(tokenBeforeFirst, tokenAfterLast)) {
200                 return;
201             }
202
203             if (requirePaddingFor(node)) {
204                 if (!blockHasTopPadding) {
205                     context.report({
206                         node,
207                         loc: { line: tokenBeforeFirst.loc.start.line, column: tokenBeforeFirst.loc.start.column },
208                         fix(fixer) {
209                             return fixer.insertTextAfter(tokenBeforeFirst, "\n");
210                         },
211                         message: ALWAYS_MESSAGE
212                     });
213                 }
214                 if (!blockHasBottomPadding) {
215                     context.report({
216                         node,
217                         loc: { line: tokenAfterLast.loc.end.line, column: tokenAfterLast.loc.end.column - 1 },
218                         fix(fixer) {
219                             return fixer.insertTextBefore(tokenAfterLast, "\n");
220                         },
221                         message: ALWAYS_MESSAGE
222                     });
223                 }
224             } else {
225                 if (blockHasTopPadding) {
226
227                     context.report({
228                         node,
229                         loc: { line: tokenBeforeFirst.loc.start.line, column: tokenBeforeFirst.loc.start.column },
230                         fix(fixer) {
231                             return fixer.replaceTextRange([tokenBeforeFirst.range[1], firstBlockToken.range[0] - firstBlockToken.loc.start.column], "\n");
232                         },
233                         message: NEVER_MESSAGE
234                     });
235                 }
236
237                 if (blockHasBottomPadding) {
238
239                     context.report({
240                         node,
241                         loc: { line: tokenAfterLast.loc.end.line, column: tokenAfterLast.loc.end.column - 1 },
242                         message: NEVER_MESSAGE,
243                         fix(fixer) {
244                             return fixer.replaceTextRange([lastBlockToken.range[1], tokenAfterLast.range[0] - tokenAfterLast.loc.start.column], "\n");
245                         }
246                     });
247                 }
248             }
249         }
250
251         const rule = {};
252
253         if (Object.prototype.hasOwnProperty.call(options, "switches")) {
254             rule.SwitchStatement = function(node) {
255                 if (node.cases.length === 0) {
256                     return;
257                 }
258                 checkPadding(node);
259             };
260         }
261
262         if (Object.prototype.hasOwnProperty.call(options, "blocks")) {
263             rule.BlockStatement = function(node) {
264                 if (node.body.length === 0) {
265                     return;
266                 }
267                 checkPadding(node);
268             };
269         }
270
271         if (Object.prototype.hasOwnProperty.call(options, "classes")) {
272             rule.ClassBody = function(node) {
273                 if (node.body.length === 0) {
274                     return;
275                 }
276                 checkPadding(node);
277             };
278         }
279
280         return rule;
281     }
282 };