]> git.proxmox.com Git - pve-eslint.git/blob - eslint/lib/rules/comma-spacing.js
import 8.3.0 source
[pve-eslint.git] / eslint / lib / rules / comma-spacing.js
1 /**
2 * @fileoverview Comma spacing - validates spacing before and after comma
3 * @author Vignesh Anand aka vegetableman.
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 before and after commas",
19 recommended: false,
20 url: "https://eslint.org/docs/rules/comma-spacing"
21 },
22
23 fixable: "whitespace",
24
25 schema: [
26 {
27 type: "object",
28 properties: {
29 before: {
30 type: "boolean",
31 default: false
32 },
33 after: {
34 type: "boolean",
35 default: true
36 }
37 },
38 additionalProperties: false
39 }
40 ],
41
42 messages: {
43 missing: "A space is required {{loc}} ','.",
44 unexpected: "There should be no space {{loc}} ','."
45 }
46 },
47
48 create(context) {
49
50 const sourceCode = context.getSourceCode();
51 const tokensAndComments = sourceCode.tokensAndComments;
52
53 const options = {
54 before: context.options[0] ? context.options[0].before : false,
55 after: context.options[0] ? context.options[0].after : true
56 };
57
58 //--------------------------------------------------------------------------
59 // Helpers
60 //--------------------------------------------------------------------------
61
62 // list of comma tokens to ignore for the check of leading whitespace
63 const commaTokensToIgnore = [];
64
65 /**
66 * Reports a spacing error with an appropriate message.
67 * @param {ASTNode} node The binary expression node to report.
68 * @param {string} loc Is the error "before" or "after" the comma?
69 * @param {ASTNode} otherNode The node at the left or right of `node`
70 * @returns {void}
71 * @private
72 */
73 function report(node, loc, otherNode) {
74 context.report({
75 node,
76 fix(fixer) {
77 if (options[loc]) {
78 if (loc === "before") {
79 return fixer.insertTextBefore(node, " ");
80 }
81 return fixer.insertTextAfter(node, " ");
82
83 }
84 let start, end;
85 const newText = "";
86
87 if (loc === "before") {
88 start = otherNode.range[1];
89 end = node.range[0];
90 } else {
91 start = node.range[1];
92 end = otherNode.range[0];
93 }
94
95 return fixer.replaceTextRange([start, end], newText);
96
97 },
98 messageId: options[loc] ? "missing" : "unexpected",
99 data: {
100 loc
101 }
102 });
103 }
104
105 /**
106 * Validates the spacing around a comma token.
107 * @param {Object} tokens The tokens to be validated.
108 * @param {Token} tokens.comma The token representing the comma.
109 * @param {Token} [tokens.left] The last token before the comma.
110 * @param {Token} [tokens.right] The first token after the comma.
111 * @param {Token|ASTNode} reportItem The item to use when reporting an error.
112 * @returns {void}
113 * @private
114 */
115 function validateCommaItemSpacing(tokens, reportItem) {
116 if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) &&
117 (options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma))
118 ) {
119 report(reportItem, "before", tokens.left);
120 }
121
122 if (tokens.right && astUtils.isClosingParenToken(tokens.right)) {
123 return;
124 }
125
126 if (tokens.right && !options.after && tokens.right.type === "Line") {
127 return;
128 }
129
130 if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) &&
131 (options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right))
132 ) {
133 report(reportItem, "after", tokens.right);
134 }
135 }
136
137 /**
138 * Adds null elements of the given ArrayExpression or ArrayPattern node to the ignore list.
139 * @param {ASTNode} node An ArrayExpression or ArrayPattern node.
140 * @returns {void}
141 */
142 function addNullElementsToIgnoreList(node) {
143 let previousToken = sourceCode.getFirstToken(node);
144
145 node.elements.forEach(element => {
146 let token;
147
148 if (element === null) {
149 token = sourceCode.getTokenAfter(previousToken);
150
151 if (astUtils.isCommaToken(token)) {
152 commaTokensToIgnore.push(token);
153 }
154 } else {
155 token = sourceCode.getTokenAfter(element);
156 }
157
158 previousToken = token;
159 });
160 }
161
162 //--------------------------------------------------------------------------
163 // Public
164 //--------------------------------------------------------------------------
165
166 return {
167 "Program:exit"() {
168 tokensAndComments.forEach((token, i) => {
169
170 if (!astUtils.isCommaToken(token)) {
171 return;
172 }
173
174 if (token && token.type === "JSXText") {
175 return;
176 }
177
178 const previousToken = tokensAndComments[i - 1];
179 const nextToken = tokensAndComments[i + 1];
180
181 validateCommaItemSpacing({
182 comma: token,
183 left: astUtils.isCommaToken(previousToken) || commaTokensToIgnore.includes(token) ? null : previousToken,
184 right: astUtils.isCommaToken(nextToken) ? null : nextToken
185 }, token);
186 });
187 },
188 ArrayExpression: addNullElementsToIgnoreList,
189 ArrayPattern: addNullElementsToIgnoreList
190
191 };
192
193 }
194 };