.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / space-before-blocks.js
1 /**
2  * @fileoverview A rule to ensure whitespace before 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 // Helpers
16 //------------------------------------------------------------------------------
17
18 /**
19  * Checks whether the given node represents the body of a function.
20  * @param {ASTNode} node the node to check.
21  * @returns {boolean} `true` if the node is function body.
22  */
23 function isFunctionBody(node) {
24     const parent = node.parent;
25
26     return (
27         node.type === "BlockStatement" &&
28         astUtils.isFunction(parent) &&
29         parent.body === node
30     );
31 }
32
33 //------------------------------------------------------------------------------
34 // Rule Definition
35 //------------------------------------------------------------------------------
36
37 module.exports = {
38     meta: {
39         type: "layout",
40
41         docs: {
42             description: "enforce consistent spacing before blocks",
43             category: "Stylistic Issues",
44             recommended: false,
45             url: "https://eslint.org/docs/rules/space-before-blocks"
46         },
47
48         fixable: "whitespace",
49
50         schema: [
51             {
52                 oneOf: [
53                     {
54                         enum: ["always", "never"]
55                     },
56                     {
57                         type: "object",
58                         properties: {
59                             keywords: {
60                                 enum: ["always", "never", "off"]
61                             },
62                             functions: {
63                                 enum: ["always", "never", "off"]
64                             },
65                             classes: {
66                                 enum: ["always", "never", "off"]
67                             }
68                         },
69                         additionalProperties: false
70                     }
71                 ]
72             }
73         ],
74
75         messages: {
76             unexpectedSpace: "Unexpected space before opening brace.",
77             missingSpace: "Missing space before opening brace."
78         }
79     },
80
81     create(context) {
82         const config = context.options[0],
83             sourceCode = context.getSourceCode();
84         let alwaysFunctions = true,
85             alwaysKeywords = true,
86             alwaysClasses = true,
87             neverFunctions = false,
88             neverKeywords = false,
89             neverClasses = false;
90
91         if (typeof config === "object") {
92             alwaysFunctions = config.functions === "always";
93             alwaysKeywords = config.keywords === "always";
94             alwaysClasses = config.classes === "always";
95             neverFunctions = config.functions === "never";
96             neverKeywords = config.keywords === "never";
97             neverClasses = config.classes === "never";
98         } else if (config === "never") {
99             alwaysFunctions = false;
100             alwaysKeywords = false;
101             alwaysClasses = false;
102             neverFunctions = true;
103             neverKeywords = true;
104             neverClasses = true;
105         }
106
107         /**
108          * Checks whether the spacing before the given block is already controlled by another rule:
109          * - `arrow-spacing` checks spaces after `=>`.
110          * - `keyword-spacing` checks spaces after keywords in certain contexts.
111          * @param {Token} precedingToken first token before the block.
112          * @param {ASTNode|Token} node `BlockStatement` node or `{` token of a `SwitchStatement` node.
113          * @returns {boolean} `true` if requiring or disallowing spaces before the given block could produce conflicts with other rules.
114          */
115         function isConflicted(precedingToken, node) {
116             return astUtils.isArrowToken(precedingToken) ||
117                 astUtils.isKeywordToken(precedingToken) && !isFunctionBody(node);
118         }
119
120         /**
121          * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line.
122          * @param {ASTNode|Token} node The AST node of a BlockStatement.
123          * @returns {void} undefined.
124          */
125         function checkPrecedingSpace(node) {
126             const precedingToken = sourceCode.getTokenBefore(node);
127
128             if (precedingToken && !isConflicted(precedingToken, node) && astUtils.isTokenOnSameLine(precedingToken, node)) {
129                 const hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
130                 let requireSpace;
131                 let requireNoSpace;
132
133                 if (isFunctionBody(node)) {
134                     requireSpace = alwaysFunctions;
135                     requireNoSpace = neverFunctions;
136                 } else if (node.type === "ClassBody") {
137                     requireSpace = alwaysClasses;
138                     requireNoSpace = neverClasses;
139                 } else {
140                     requireSpace = alwaysKeywords;
141                     requireNoSpace = neverKeywords;
142                 }
143
144                 if (requireSpace && !hasSpace) {
145                     context.report({
146                         node,
147                         messageId: "missingSpace",
148                         fix(fixer) {
149                             return fixer.insertTextBefore(node, " ");
150                         }
151                     });
152                 } else if (requireNoSpace && hasSpace) {
153                     context.report({
154                         node,
155                         messageId: "unexpectedSpace",
156                         fix(fixer) {
157                             return fixer.removeRange([precedingToken.range[1], node.range[0]]);
158                         }
159                     });
160                 }
161             }
162         }
163
164         /**
165          * Checks if the CaseBlock of an given SwitchStatement node has a preceding space.
166          * @param {ASTNode} node The node of a SwitchStatement.
167          * @returns {void} undefined.
168          */
169         function checkSpaceBeforeCaseBlock(node) {
170             const cases = node.cases;
171             let openingBrace;
172
173             if (cases.length > 0) {
174                 openingBrace = sourceCode.getTokenBefore(cases[0]);
175             } else {
176                 openingBrace = sourceCode.getLastToken(node, 1);
177             }
178
179             checkPrecedingSpace(openingBrace);
180         }
181
182         return {
183             BlockStatement: checkPrecedingSpace,
184             ClassBody: checkPrecedingSpace,
185             SwitchStatement: checkSpaceBeforeCaseBlock
186         };
187
188     }
189 };