cd740fd3a99057de26a670a93a2d2a987e9ba6c1
[dotfiles/.git] / rest-spread-spacing.js
1 /**
2  * @fileoverview Enforce spacing between rest and spread operators and their expressions.
3  * @author Kai Cataldo
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = {
13     meta: {
14         type: "layout",
15
16         docs: {
17             description: "enforce spacing between rest and spread operators and their expressions",
18             category: "ECMAScript 6",
19             recommended: false,
20             url: "https://eslint.org/docs/rules/rest-spread-spacing"
21         },
22
23         fixable: "whitespace",
24
25         schema: [
26             {
27                 enum: ["always", "never"]
28             }
29         ]
30     },
31
32     create(context) {
33         const sourceCode = context.getSourceCode(),
34             alwaysSpace = context.options[0] === "always";
35
36         //--------------------------------------------------------------------------
37         // Helpers
38         //--------------------------------------------------------------------------
39
40         /**
41          * Checks whitespace between rest/spread operators and their expressions
42          * @param {ASTNode} node The node to check
43          * @returns {void}
44          */
45         function checkWhiteSpace(node) {
46             const operator = sourceCode.getFirstToken(node),
47                 nextToken = sourceCode.getTokenAfter(operator),
48                 hasWhitespace = sourceCode.isSpaceBetweenTokens(operator, nextToken);
49             let type;
50
51             switch (node.type) {
52                 case "SpreadElement":
53                     type = "spread";
54                     if (node.parent.type === "ObjectExpression") {
55                         type += " property";
56                     }
57                     break;
58                 case "RestElement":
59                     type = "rest";
60                     if (node.parent.type === "ObjectPattern") {
61                         type += " property";
62                     }
63                     break;
64                 case "ExperimentalSpreadProperty":
65                     type = "spread property";
66                     break;
67                 case "ExperimentalRestProperty":
68                     type = "rest property";
69                     break;
70                 default:
71                     return;
72             }
73
74             if (alwaysSpace && !hasWhitespace) {
75                 context.report({
76                     node,
77                     loc: {
78                         line: operator.loc.end.line,
79                         column: operator.loc.end.column
80                     },
81                     message: "Expected whitespace after {{type}} operator.",
82                     data: {
83                         type
84                     },
85                     fix(fixer) {
86                         return fixer.replaceTextRange([operator.range[1], nextToken.range[0]], " ");
87                     }
88                 });
89             } else if (!alwaysSpace && hasWhitespace) {
90                 context.report({
91                     node,
92                     loc: {
93                         line: operator.loc.end.line,
94                         column: operator.loc.end.column
95                     },
96                     message: "Unexpected whitespace after {{type}} operator.",
97                     data: {
98                         type
99                     },
100                     fix(fixer) {
101                         return fixer.removeRange([operator.range[1], nextToken.range[0]]);
102                     }
103                 });
104             }
105         }
106
107         //--------------------------------------------------------------------------
108         // Public
109         //--------------------------------------------------------------------------
110
111         return {
112             SpreadElement: checkWhiteSpace,
113             RestElement: checkWhiteSpace,
114             ExperimentalSpreadProperty: checkWhiteSpace,
115             ExperimentalRestProperty: checkWhiteSpace
116         };
117     }
118 };