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