.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / eslint / lib / rules / array-bracket-spacing.js
1 /**
2  * @fileoverview Disallows or enforces spaces inside of array brackets.
3  * @author Jamund Ferguson
4  */
5 "use strict";
6
7 const astUtils = require("./utils/ast-utils");
8
9 //------------------------------------------------------------------------------
10 // Rule Definition
11 //------------------------------------------------------------------------------
12
13 module.exports = {
14     meta: {
15         type: "layout",
16
17         docs: {
18             description: "enforce consistent spacing inside array brackets",
19             category: "Stylistic Issues",
20             recommended: false,
21             url: "https://eslint.org/docs/rules/array-bracket-spacing"
22         },
23
24         fixable: "whitespace",
25
26         schema: [
27             {
28                 enum: ["always", "never"]
29             },
30             {
31                 type: "object",
32                 properties: {
33                     singleValue: {
34                         type: "boolean"
35                     },
36                     objectsInArrays: {
37                         type: "boolean"
38                     },
39                     arraysInArrays: {
40                         type: "boolean"
41                     }
42                 },
43                 additionalProperties: false
44             }
45         ],
46
47         messages: {
48             unexpectedSpaceAfter: "There should be no space after '{{tokenValue}}'.",
49             unexpectedSpaceBefore: "There should be no space before '{{tokenValue}}'.",
50             missingSpaceAfter: "A space is required after '{{tokenValue}}'.",
51             missingSpaceBefore: "A space is required before '{{tokenValue}}'."
52         }
53     },
54     create(context) {
55         const spaced = context.options[0] === "always",
56             sourceCode = context.getSourceCode();
57
58         /**
59          * Determines whether an option is set, relative to the spacing option.
60          * If spaced is "always", then check whether option is set to false.
61          * If spaced is "never", then check whether option is set to true.
62          * @param {Object} option The option to exclude.
63          * @returns {boolean} Whether or not the property is excluded.
64          */
65         function isOptionSet(option) {
66             return context.options[1] ? context.options[1][option] === !spaced : false;
67         }
68
69         const options = {
70             spaced,
71             singleElementException: isOptionSet("singleValue"),
72             objectsInArraysException: isOptionSet("objectsInArrays"),
73             arraysInArraysException: isOptionSet("arraysInArrays")
74         };
75
76         //--------------------------------------------------------------------------
77         // Helpers
78         //--------------------------------------------------------------------------
79
80         /**
81          * Reports that there shouldn't be a space after the first token
82          * @param {ASTNode} node The node to report in the event of an error.
83          * @param {Token} token The token to use for the report.
84          * @returns {void}
85          */
86         function reportNoBeginningSpace(node, token) {
87             const nextToken = sourceCode.getTokenAfter(token);
88
89             context.report({
90                 node,
91                 loc: { start: token.loc.end, end: nextToken.loc.start },
92                 messageId: "unexpectedSpaceAfter",
93                 data: {
94                     tokenValue: token.value
95                 },
96                 fix(fixer) {
97                     return fixer.removeRange([token.range[1], nextToken.range[0]]);
98                 }
99             });
100         }
101
102         /**
103          * Reports that there shouldn't be a space before the last token
104          * @param {ASTNode} node The node to report in the event of an error.
105          * @param {Token} token The token to use for the report.
106          * @returns {void}
107          */
108         function reportNoEndingSpace(node, token) {
109             const previousToken = sourceCode.getTokenBefore(token);
110
111             context.report({
112                 node,
113                 loc: { start: previousToken.loc.end, end: token.loc.start },
114                 messageId: "unexpectedSpaceBefore",
115                 data: {
116                     tokenValue: token.value
117                 },
118                 fix(fixer) {
119                     return fixer.removeRange([previousToken.range[1], token.range[0]]);
120                 }
121             });
122         }
123
124         /**
125          * Reports that there should be a space after the first token
126          * @param {ASTNode} node The node to report in the event of an error.
127          * @param {Token} token The token to use for the report.
128          * @returns {void}
129          */
130         function reportRequiredBeginningSpace(node, token) {
131             context.report({
132                 node,
133                 loc: token.loc,
134                 messageId: "missingSpaceAfter",
135                 data: {
136                     tokenValue: token.value
137                 },
138                 fix(fixer) {
139                     return fixer.insertTextAfter(token, " ");
140                 }
141             });
142         }
143
144         /**
145          * Reports that there should be a space before the last token
146          * @param {ASTNode} node The node to report in the event of an error.
147          * @param {Token} token The token to use for the report.
148          * @returns {void}
149          */
150         function reportRequiredEndingSpace(node, token) {
151             context.report({
152                 node,
153                 loc: token.loc,
154                 messageId: "missingSpaceBefore",
155                 data: {
156                     tokenValue: token.value
157                 },
158                 fix(fixer) {
159                     return fixer.insertTextBefore(token, " ");
160                 }
161             });
162         }
163
164         /**
165          * Determines if a node is an object type
166          * @param {ASTNode} node The node to check.
167          * @returns {boolean} Whether or not the node is an object type.
168          */
169         function isObjectType(node) {
170             return node && (node.type === "ObjectExpression" || node.type === "ObjectPattern");
171         }
172
173         /**
174          * Determines if a node is an array type
175          * @param {ASTNode} node The node to check.
176          * @returns {boolean} Whether or not the node is an array type.
177          */
178         function isArrayType(node) {
179             return node && (node.type === "ArrayExpression" || node.type === "ArrayPattern");
180         }
181
182         /**
183          * Validates the spacing around array brackets
184          * @param {ASTNode} node The node we're checking for spacing
185          * @returns {void}
186          */
187         function validateArraySpacing(node) {
188             if (options.spaced && node.elements.length === 0) {
189                 return;
190             }
191
192             const first = sourceCode.getFirstToken(node),
193                 second = sourceCode.getFirstToken(node, 1),
194                 last = node.typeAnnotation
195                     ? sourceCode.getTokenBefore(node.typeAnnotation)
196                     : sourceCode.getLastToken(node),
197                 penultimate = sourceCode.getTokenBefore(last),
198                 firstElement = node.elements[0],
199                 lastElement = node.elements[node.elements.length - 1];
200
201             const openingBracketMustBeSpaced =
202                 options.objectsInArraysException && isObjectType(firstElement) ||
203                 options.arraysInArraysException && isArrayType(firstElement) ||
204                 options.singleElementException && node.elements.length === 1
205                     ? !options.spaced : options.spaced;
206
207             const closingBracketMustBeSpaced =
208                 options.objectsInArraysException && isObjectType(lastElement) ||
209                 options.arraysInArraysException && isArrayType(lastElement) ||
210                 options.singleElementException && node.elements.length === 1
211                     ? !options.spaced : options.spaced;
212
213             if (astUtils.isTokenOnSameLine(first, second)) {
214                 if (openingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(first, second)) {
215                     reportRequiredBeginningSpace(node, first);
216                 }
217                 if (!openingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(first, second)) {
218                     reportNoBeginningSpace(node, first);
219                 }
220             }
221
222             if (first !== penultimate && astUtils.isTokenOnSameLine(penultimate, last)) {
223                 if (closingBracketMustBeSpaced && !sourceCode.isSpaceBetweenTokens(penultimate, last)) {
224                     reportRequiredEndingSpace(node, last);
225                 }
226                 if (!closingBracketMustBeSpaced && sourceCode.isSpaceBetweenTokens(penultimate, last)) {
227                     reportNoEndingSpace(node, last);
228                 }
229             }
230         }
231
232         //--------------------------------------------------------------------------
233         // Public
234         //--------------------------------------------------------------------------
235
236         return {
237             ArrayPattern: validateArraySpacing,
238             ArrayExpression: validateArraySpacing
239         };
240     }
241 };