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