.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / semi-spacing.js
1 /**
2  * @fileoverview Validates spacing before and after semicolon
3  * @author Mathias Schreck
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 consistent spacing before and after semicolons",
20             category: "Stylistic Issues",
21             recommended: false,
22             url: "https://eslint.org/docs/rules/semi-spacing"
23         },
24
25         fixable: "whitespace",
26
27         schema: [
28             {
29                 type: "object",
30                 properties: {
31                     before: {
32                         type: "boolean",
33                         default: false
34                     },
35                     after: {
36                         type: "boolean",
37                         default: true
38                     }
39                 },
40                 additionalProperties: false
41             }
42         ],
43
44         messages: {
45             unexpectedWhitespaceBefore: "Unexpected whitespace before semicolon.",
46             unexpectedWhitespaceAfter: "Unexpected whitespace after semicolon.",
47             missingWhitespaceBefore: "Missing whitespace before semicolon.",
48             missingWhitespaceAfter: "Missing whitespace after semicolon."
49         }
50     },
51
52     create(context) {
53
54         const config = context.options[0],
55             sourceCode = context.getSourceCode();
56         let requireSpaceBefore = false,
57             requireSpaceAfter = true;
58
59         if (typeof config === "object") {
60             requireSpaceBefore = config.before;
61             requireSpaceAfter = config.after;
62         }
63
64         /**
65          * Checks if a given token has leading whitespace.
66          * @param {Object} token The token to check.
67          * @returns {boolean} True if the given token has leading space, false if not.
68          */
69         function hasLeadingSpace(token) {
70             const tokenBefore = sourceCode.getTokenBefore(token);
71
72             return tokenBefore && astUtils.isTokenOnSameLine(tokenBefore, token) && sourceCode.isSpaceBetweenTokens(tokenBefore, token);
73         }
74
75         /**
76          * Checks if a given token has trailing whitespace.
77          * @param {Object} token The token to check.
78          * @returns {boolean} True if the given token has trailing space, false if not.
79          */
80         function hasTrailingSpace(token) {
81             const tokenAfter = sourceCode.getTokenAfter(token);
82
83             return tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter) && sourceCode.isSpaceBetweenTokens(token, tokenAfter);
84         }
85
86         /**
87          * Checks if the given token is the last token in its line.
88          * @param {Token} token The token to check.
89          * @returns {boolean} Whether or not the token is the last in its line.
90          */
91         function isLastTokenInCurrentLine(token) {
92             const tokenAfter = sourceCode.getTokenAfter(token);
93
94             return !(tokenAfter && astUtils.isTokenOnSameLine(token, tokenAfter));
95         }
96
97         /**
98          * Checks if the given token is the first token in its line
99          * @param {Token} token The token to check.
100          * @returns {boolean} Whether or not the token is the first in its line.
101          */
102         function isFirstTokenInCurrentLine(token) {
103             const tokenBefore = sourceCode.getTokenBefore(token);
104
105             return !(tokenBefore && astUtils.isTokenOnSameLine(token, tokenBefore));
106         }
107
108         /**
109          * Checks if the next token of a given token is a closing parenthesis.
110          * @param {Token} token The token to check.
111          * @returns {boolean} Whether or not the next token of a given token is a closing parenthesis.
112          */
113         function isBeforeClosingParen(token) {
114             const nextToken = sourceCode.getTokenAfter(token);
115
116             return (nextToken && astUtils.isClosingBraceToken(nextToken) || astUtils.isClosingParenToken(nextToken));
117         }
118
119         /**
120          * Report location example :
121          *
122          * for unexpected space `before`
123          *
124          * var a = 'b'   ;
125          *            ^^^
126          *
127          * for unexpected space `after`
128          *
129          * var a = 'b';  c = 10;
130          *             ^^
131          *
132          * Reports if the given token has invalid spacing.
133          * @param {Token} token The semicolon token to check.
134          * @param {ASTNode} node The corresponding node of the token.
135          * @returns {void}
136          */
137         function checkSemicolonSpacing(token, node) {
138             if (astUtils.isSemicolonToken(token)) {
139                 if (hasLeadingSpace(token)) {
140                     if (!requireSpaceBefore) {
141                         const tokenBefore = sourceCode.getTokenBefore(token);
142                         const loc = {
143                             start: tokenBefore.loc.end,
144                             end: token.loc.start
145                         };
146
147                         context.report({
148                             node,
149                             loc,
150                             messageId: "unexpectedWhitespaceBefore",
151                             fix(fixer) {
152
153                                 return fixer.removeRange([tokenBefore.range[1], token.range[0]]);
154                             }
155                         });
156                     }
157                 } else {
158                     if (requireSpaceBefore) {
159                         const loc = token.loc;
160
161                         context.report({
162                             node,
163                             loc,
164                             messageId: "missingWhitespaceBefore",
165                             fix(fixer) {
166                                 return fixer.insertTextBefore(token, " ");
167                             }
168                         });
169                     }
170                 }
171
172                 if (!isFirstTokenInCurrentLine(token) && !isLastTokenInCurrentLine(token) && !isBeforeClosingParen(token)) {
173                     if (hasTrailingSpace(token)) {
174                         if (!requireSpaceAfter) {
175                             const tokenAfter = sourceCode.getTokenAfter(token);
176                             const loc = {
177                                 start: token.loc.end,
178                                 end: tokenAfter.loc.start
179                             };
180
181                             context.report({
182                                 node,
183                                 loc,
184                                 messageId: "unexpectedWhitespaceAfter",
185                                 fix(fixer) {
186
187                                     return fixer.removeRange([token.range[1], tokenAfter.range[0]]);
188                                 }
189                             });
190                         }
191                     } else {
192                         if (requireSpaceAfter) {
193                             const loc = token.loc;
194
195                             context.report({
196                                 node,
197                                 loc,
198                                 messageId: "missingWhitespaceAfter",
199                                 fix(fixer) {
200                                     return fixer.insertTextAfter(token, " ");
201                                 }
202                             });
203                         }
204                     }
205                 }
206             }
207         }
208
209         /**
210          * Checks the spacing of the semicolon with the assumption that the last token is the semicolon.
211          * @param {ASTNode} node The node to check.
212          * @returns {void}
213          */
214         function checkNode(node) {
215             const token = sourceCode.getLastToken(node);
216
217             checkSemicolonSpacing(token, node);
218         }
219
220         return {
221             VariableDeclaration: checkNode,
222             ExpressionStatement: checkNode,
223             BreakStatement: checkNode,
224             ContinueStatement: checkNode,
225             DebuggerStatement: checkNode,
226             DoWhileStatement: checkNode,
227             ReturnStatement: checkNode,
228             ThrowStatement: checkNode,
229             ImportDeclaration: checkNode,
230             ExportNamedDeclaration: checkNode,
231             ExportAllDeclaration: checkNode,
232             ExportDefaultDeclaration: checkNode,
233             ForStatement(node) {
234                 if (node.init) {
235                     checkSemicolonSpacing(sourceCode.getTokenAfter(node.init), node);
236                 }
237
238                 if (node.test) {
239                     checkSemicolonSpacing(sourceCode.getTokenAfter(node.test), node);
240                 }
241             }
242         };
243     }
244 };