.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / generator-star-spacing.js
1 /**
2  * @fileoverview Rule to check the spacing around the * in generator functions.
3  * @author Jamund Ferguson
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 const OVERRIDE_SCHEMA = {
13     oneOf: [
14         {
15             enum: ["before", "after", "both", "neither"]
16         },
17         {
18             type: "object",
19             properties: {
20                 before: { type: "boolean" },
21                 after: { type: "boolean" }
22             },
23             additionalProperties: false
24         }
25     ]
26 };
27
28 module.exports = {
29     meta: {
30         type: "layout",
31
32         docs: {
33             description: "enforce consistent spacing around `*` operators in generator functions",
34             category: "ECMAScript 6",
35             recommended: false,
36             url: "https://eslint.org/docs/rules/generator-star-spacing"
37         },
38
39         fixable: "whitespace",
40
41         schema: [
42             {
43                 oneOf: [
44                     {
45                         enum: ["before", "after", "both", "neither"]
46                     },
47                     {
48                         type: "object",
49                         properties: {
50                             before: { type: "boolean" },
51                             after: { type: "boolean" },
52                             named: OVERRIDE_SCHEMA,
53                             anonymous: OVERRIDE_SCHEMA,
54                             method: OVERRIDE_SCHEMA
55                         },
56                         additionalProperties: false
57                     }
58                 ]
59             }
60         ],
61
62         messages: {
63             missingBefore: "Missing space before *.",
64             missingAfter: "Missing space after *.",
65             unexpectedBefore: "Unexpected space before *.",
66             unexpectedAfter: "Unexpected space after *."
67         }
68     },
69
70     create(context) {
71
72         const optionDefinitions = {
73             before: { before: true, after: false },
74             after: { before: false, after: true },
75             both: { before: true, after: true },
76             neither: { before: false, after: false }
77         };
78
79         /**
80          * Returns resolved option definitions based on an option and defaults
81          * @param {any} option The option object or string value
82          * @param {Object} defaults The defaults to use if options are not present
83          * @returns {Object} the resolved object definition
84          */
85         function optionToDefinition(option, defaults) {
86             if (!option) {
87                 return defaults;
88             }
89
90             return typeof option === "string"
91                 ? optionDefinitions[option]
92                 : Object.assign({}, defaults, option);
93         }
94
95         const modes = (function(option) {
96             const defaults = optionToDefinition(option, optionDefinitions.before);
97
98             return {
99                 named: optionToDefinition(option.named, defaults),
100                 anonymous: optionToDefinition(option.anonymous, defaults),
101                 method: optionToDefinition(option.method, defaults)
102             };
103         }(context.options[0] || {}));
104
105         const sourceCode = context.getSourceCode();
106
107         /**
108          * Checks if the given token is a star token or not.
109          * @param {Token} token The token to check.
110          * @returns {boolean} `true` if the token is a star token.
111          */
112         function isStarToken(token) {
113             return token.value === "*" && token.type === "Punctuator";
114         }
115
116         /**
117          * Gets the generator star token of the given function node.
118          * @param {ASTNode} node The function node to get.
119          * @returns {Token} Found star token.
120          */
121         function getStarToken(node) {
122             return sourceCode.getFirstToken(
123                 (node.parent.method || node.parent.type === "MethodDefinition") ? node.parent : node,
124                 isStarToken
125             );
126         }
127
128         /**
129          * capitalize a given string.
130          * @param {string} str the given string.
131          * @returns {string} the capitalized string.
132          */
133         function capitalize(str) {
134             return str[0].toUpperCase() + str.slice(1);
135         }
136
137         /**
138          * Checks the spacing between two tokens before or after the star token.
139          * @param {string} kind Either "named", "anonymous", or "method"
140          * @param {string} side Either "before" or "after".
141          * @param {Token} leftToken `function` keyword token if side is "before", or
142          *     star token if side is "after".
143          * @param {Token} rightToken Star token if side is "before", or identifier
144          *     token if side is "after".
145          * @returns {void}
146          */
147         function checkSpacing(kind, side, leftToken, rightToken) {
148             if (!!(rightToken.range[0] - leftToken.range[1]) !== modes[kind][side]) {
149                 const after = leftToken.value === "*";
150                 const spaceRequired = modes[kind][side];
151                 const node = after ? leftToken : rightToken;
152                 const messageId = `${spaceRequired ? "missing" : "unexpected"}${capitalize(side)}`;
153
154                 context.report({
155                     node,
156                     messageId,
157                     fix(fixer) {
158                         if (spaceRequired) {
159                             if (after) {
160                                 return fixer.insertTextAfter(node, " ");
161                             }
162                             return fixer.insertTextBefore(node, " ");
163                         }
164                         return fixer.removeRange([leftToken.range[1], rightToken.range[0]]);
165                     }
166                 });
167             }
168         }
169
170         /**
171          * Enforces the spacing around the star if node is a generator function.
172          * @param {ASTNode} node A function expression or declaration node.
173          * @returns {void}
174          */
175         function checkFunction(node) {
176             if (!node.generator) {
177                 return;
178             }
179
180             const starToken = getStarToken(node);
181             const prevToken = sourceCode.getTokenBefore(starToken);
182             const nextToken = sourceCode.getTokenAfter(starToken);
183
184             let kind = "named";
185
186             if (node.parent.type === "MethodDefinition" || (node.parent.type === "Property" && node.parent.method)) {
187                 kind = "method";
188             } else if (!node.id) {
189                 kind = "anonymous";
190             }
191
192             // Only check before when preceded by `function`|`static` keyword
193             if (!(kind === "method" && starToken === sourceCode.getFirstToken(node.parent))) {
194                 checkSpacing(kind, "before", prevToken, starToken);
195             }
196
197             checkSpacing(kind, "after", starToken, nextToken);
198         }
199
200         return {
201             FunctionDeclaration: checkFunction,
202             FunctionExpression: checkFunction
203         };
204
205     }
206 };