UNPKG

7.49 kBJavaScriptView Raw
1/**
2 * @fileoverview Disallows or enforces spaces inside computed properties.
3 * @author Jamund Ferguson
4 */
5"use strict";
6
7const astUtils = require("./utils/ast-utils");
8
9//------------------------------------------------------------------------------
10// Rule Definition
11//------------------------------------------------------------------------------
12
13module.exports = {
14 meta: {
15 type: "layout",
16
17 docs: {
18 description: "enforce consistent spacing inside computed property brackets",
19 category: "Stylistic Issues",
20 recommended: false,
21 url: "https://eslint.org/docs/rules/computed-property-spacing"
22 },
23
24 fixable: "whitespace",
25
26 schema: [
27 {
28 enum: ["always", "never"]
29 },
30 {
31 type: "object",
32 properties: {
33 enforceForClassMembers: {
34 type: "boolean",
35 default: true
36 }
37 },
38 additionalProperties: false
39 }
40 ],
41
42 messages: {
43 unexpectedSpaceBefore: "There should be no space before '{{tokenValue}}'.",
44 unexpectedSpaceAfter: "There should be no space after '{{tokenValue}}'.",
45
46 missingSpaceBefore: "A space is required before '{{tokenValue}}'.",
47 missingSpaceAfter: "A space is required after '{{tokenValue}}'."
48 }
49 },
50
51 create(context) {
52 const sourceCode = context.getSourceCode();
53 const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
54 const enforceForClassMembers = !context.options[1] || context.options[1].enforceForClassMembers;
55
56 //--------------------------------------------------------------------------
57 // Helpers
58 //--------------------------------------------------------------------------
59
60 /**
61 * Reports that there shouldn't be a space after the first token
62 * @param {ASTNode} node The node to report in the event of an error.
63 * @param {Token} token The token to use for the report.
64 * @param {Token} tokenAfter The token after `token`.
65 * @returns {void}
66 */
67 function reportNoBeginningSpace(node, token, tokenAfter) {
68 context.report({
69 node,
70 loc: { start: token.loc.end, end: tokenAfter.loc.start },
71 messageId: "unexpectedSpaceAfter",
72 data: {
73 tokenValue: token.value
74 },
75 fix(fixer) {
76 return fixer.removeRange([token.range[1], tokenAfter.range[0]]);
77 }
78 });
79 }
80
81 /**
82 * Reports that there shouldn't be a space before the last token
83 * @param {ASTNode} node The node to report in the event of an error.
84 * @param {Token} token The token to use for the report.
85 * @param {Token} tokenBefore The token before `token`.
86 * @returns {void}
87 */
88 function reportNoEndingSpace(node, token, tokenBefore) {
89 context.report({
90 node,
91 loc: { start: tokenBefore.loc.end, end: token.loc.start },
92 messageId: "unexpectedSpaceBefore",
93 data: {
94 tokenValue: token.value
95 },
96 fix(fixer) {
97 return fixer.removeRange([tokenBefore.range[1], token.range[0]]);
98 }
99 });
100 }
101
102 /**
103 * Reports that there should be a space after the first 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 reportRequiredBeginningSpace(node, token) {
109 context.report({
110 node,
111 loc: token.loc,
112 messageId: "missingSpaceAfter",
113 data: {
114 tokenValue: token.value
115 },
116 fix(fixer) {
117 return fixer.insertTextAfter(token, " ");
118 }
119 });
120 }
121
122 /**
123 * Reports that there should be a space before the last token
124 * @param {ASTNode} node The node to report in the event of an error.
125 * @param {Token} token The token to use for the report.
126 * @returns {void}
127 */
128 function reportRequiredEndingSpace(node, token) {
129 context.report({
130 node,
131 loc: token.loc,
132 messageId: "missingSpaceBefore",
133 data: {
134 tokenValue: token.value
135 },
136 fix(fixer) {
137 return fixer.insertTextBefore(token, " ");
138 }
139 });
140 }
141
142 /**
143 * Returns a function that checks the spacing of a node on the property name
144 * that was passed in.
145 * @param {string} propertyName The property on the node to check for spacing
146 * @returns {Function} A function that will check spacing on a node
147 */
148 function checkSpacing(propertyName) {
149 return function(node) {
150 if (!node.computed) {
151 return;
152 }
153
154 const property = node[propertyName];
155
156 const before = sourceCode.getTokenBefore(property, astUtils.isOpeningBracketToken),
157 first = sourceCode.getTokenAfter(before, { includeComments: true }),
158 after = sourceCode.getTokenAfter(property, astUtils.isClosingBracketToken),
159 last = sourceCode.getTokenBefore(after, { includeComments: true });
160
161 if (astUtils.isTokenOnSameLine(before, first)) {
162 if (propertyNameMustBeSpaced) {
163 if (!sourceCode.isSpaceBetweenTokens(before, first) && astUtils.isTokenOnSameLine(before, first)) {
164 reportRequiredBeginningSpace(node, before);
165 }
166 } else {
167 if (sourceCode.isSpaceBetweenTokens(before, first)) {
168 reportNoBeginningSpace(node, before, first);
169 }
170 }
171 }
172
173 if (astUtils.isTokenOnSameLine(last, after)) {
174 if (propertyNameMustBeSpaced) {
175 if (!sourceCode.isSpaceBetweenTokens(last, after) && astUtils.isTokenOnSameLine(last, after)) {
176 reportRequiredEndingSpace(node, after);
177 }
178 } else {
179 if (sourceCode.isSpaceBetweenTokens(last, after)) {
180 reportNoEndingSpace(node, after, last);
181 }
182 }
183 }
184 };
185 }
186
187
188 //--------------------------------------------------------------------------
189 // Public
190 //--------------------------------------------------------------------------
191
192 const listeners = {
193 Property: checkSpacing("key"),
194 MemberExpression: checkSpacing("property")
195 };
196
197 if (enforceForClassMembers) {
198 listeners.MethodDefinition = checkSpacing("key");
199 }
200
201 return listeners;
202
203 }
204};