1 | /**
|
---|
2 | * @fileoverview Rule to enforce spacing before and after keywords.
|
---|
3 | * @author Toru Nagashima
|
---|
4 | * @deprecated in ESLint v8.53.0
|
---|
5 | */
|
---|
6 |
|
---|
7 | "use strict";
|
---|
8 |
|
---|
9 | //------------------------------------------------------------------------------
|
---|
10 | // Requirements
|
---|
11 | //------------------------------------------------------------------------------
|
---|
12 |
|
---|
13 | const astUtils = require("./utils/ast-utils"),
|
---|
14 | keywords = require("./utils/keywords");
|
---|
15 |
|
---|
16 | //------------------------------------------------------------------------------
|
---|
17 | // Constants
|
---|
18 | //------------------------------------------------------------------------------
|
---|
19 |
|
---|
20 | const PREV_TOKEN = /^[)\]}>]$/u;
|
---|
21 | const NEXT_TOKEN = /^(?:[([{<~!]|\+\+?|--?)$/u;
|
---|
22 | const PREV_TOKEN_M = /^[)\]}>*]$/u;
|
---|
23 | const NEXT_TOKEN_M = /^[{*]$/u;
|
---|
24 | const TEMPLATE_OPEN_PAREN = /\$\{$/u;
|
---|
25 | const TEMPLATE_CLOSE_PAREN = /^\}/u;
|
---|
26 | const CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template|PrivateIdentifier)$/u;
|
---|
27 | const KEYS = keywords.concat(["as", "async", "await", "from", "get", "let", "of", "set", "yield"]);
|
---|
28 |
|
---|
29 | // check duplications.
|
---|
30 | (function() {
|
---|
31 | KEYS.sort();
|
---|
32 | for (let i = 1; i < KEYS.length; ++i) {
|
---|
33 | if (KEYS[i] === KEYS[i - 1]) {
|
---|
34 | throw new Error(`Duplication was found in the keyword list: ${KEYS[i]}`);
|
---|
35 | }
|
---|
36 | }
|
---|
37 | }());
|
---|
38 |
|
---|
39 | //------------------------------------------------------------------------------
|
---|
40 | // Helpers
|
---|
41 | //------------------------------------------------------------------------------
|
---|
42 |
|
---|
43 | /**
|
---|
44 | * Checks whether or not a given token is a "Template" token ends with "${".
|
---|
45 | * @param {Token} token A token to check.
|
---|
46 | * @returns {boolean} `true` if the token is a "Template" token ends with "${".
|
---|
47 | */
|
---|
48 | function isOpenParenOfTemplate(token) {
|
---|
49 | return token.type === "Template" && TEMPLATE_OPEN_PAREN.test(token.value);
|
---|
50 | }
|
---|
51 |
|
---|
52 | /**
|
---|
53 | * Checks whether or not a given token is a "Template" token starts with "}".
|
---|
54 | * @param {Token} token A token to check.
|
---|
55 | * @returns {boolean} `true` if the token is a "Template" token starts with "}".
|
---|
56 | */
|
---|
57 | function isCloseParenOfTemplate(token) {
|
---|
58 | return token.type === "Template" && TEMPLATE_CLOSE_PAREN.test(token.value);
|
---|
59 | }
|
---|
60 |
|
---|
61 | //------------------------------------------------------------------------------
|
---|
62 | // Rule Definition
|
---|
63 | //------------------------------------------------------------------------------
|
---|
64 |
|
---|
65 | /** @type {import('../shared/types').Rule} */
|
---|
66 | module.exports = {
|
---|
67 | meta: {
|
---|
68 | deprecated: true,
|
---|
69 | replacedBy: [],
|
---|
70 | type: "layout",
|
---|
71 |
|
---|
72 | docs: {
|
---|
73 | description: "Enforce consistent spacing before and after keywords",
|
---|
74 | recommended: false,
|
---|
75 | url: "https://eslint.org/docs/latest/rules/keyword-spacing"
|
---|
76 | },
|
---|
77 |
|
---|
78 | fixable: "whitespace",
|
---|
79 |
|
---|
80 | schema: [
|
---|
81 | {
|
---|
82 | type: "object",
|
---|
83 | properties: {
|
---|
84 | before: { type: "boolean", default: true },
|
---|
85 | after: { type: "boolean", default: true },
|
---|
86 | overrides: {
|
---|
87 | type: "object",
|
---|
88 | properties: KEYS.reduce((retv, key) => {
|
---|
89 | retv[key] = {
|
---|
90 | type: "object",
|
---|
91 | properties: {
|
---|
92 | before: { type: "boolean" },
|
---|
93 | after: { type: "boolean" }
|
---|
94 | },
|
---|
95 | additionalProperties: false
|
---|
96 | };
|
---|
97 | return retv;
|
---|
98 | }, {}),
|
---|
99 | additionalProperties: false
|
---|
100 | }
|
---|
101 | },
|
---|
102 | additionalProperties: false
|
---|
103 | }
|
---|
104 | ],
|
---|
105 | messages: {
|
---|
106 | expectedBefore: "Expected space(s) before \"{{value}}\".",
|
---|
107 | expectedAfter: "Expected space(s) after \"{{value}}\".",
|
---|
108 | unexpectedBefore: "Unexpected space(s) before \"{{value}}\".",
|
---|
109 | unexpectedAfter: "Unexpected space(s) after \"{{value}}\"."
|
---|
110 | }
|
---|
111 | },
|
---|
112 |
|
---|
113 | create(context) {
|
---|
114 | const sourceCode = context.sourceCode;
|
---|
115 |
|
---|
116 | const tokensToIgnore = new WeakSet();
|
---|
117 |
|
---|
118 | /**
|
---|
119 | * Reports a given token if there are not space(s) before the token.
|
---|
120 | * @param {Token} token A token to report.
|
---|
121 | * @param {RegExp} pattern A pattern of the previous token to check.
|
---|
122 | * @returns {void}
|
---|
123 | */
|
---|
124 | function expectSpaceBefore(token, pattern) {
|
---|
125 | const prevToken = sourceCode.getTokenBefore(token);
|
---|
126 |
|
---|
127 | if (prevToken &&
|
---|
128 | (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
|
---|
129 | !isOpenParenOfTemplate(prevToken) &&
|
---|
130 | !tokensToIgnore.has(prevToken) &&
|
---|
131 | astUtils.isTokenOnSameLine(prevToken, token) &&
|
---|
132 | !sourceCode.isSpaceBetweenTokens(prevToken, token)
|
---|
133 | ) {
|
---|
134 | context.report({
|
---|
135 | loc: token.loc,
|
---|
136 | messageId: "expectedBefore",
|
---|
137 | data: token,
|
---|
138 | fix(fixer) {
|
---|
139 | return fixer.insertTextBefore(token, " ");
|
---|
140 | }
|
---|
141 | });
|
---|
142 | }
|
---|
143 | }
|
---|
144 |
|
---|
145 | /**
|
---|
146 | * Reports a given token if there are space(s) before the token.
|
---|
147 | * @param {Token} token A token to report.
|
---|
148 | * @param {RegExp} pattern A pattern of the previous token to check.
|
---|
149 | * @returns {void}
|
---|
150 | */
|
---|
151 | function unexpectSpaceBefore(token, pattern) {
|
---|
152 | const prevToken = sourceCode.getTokenBefore(token);
|
---|
153 |
|
---|
154 | if (prevToken &&
|
---|
155 | (CHECK_TYPE.test(prevToken.type) || pattern.test(prevToken.value)) &&
|
---|
156 | !isOpenParenOfTemplate(prevToken) &&
|
---|
157 | !tokensToIgnore.has(prevToken) &&
|
---|
158 | astUtils.isTokenOnSameLine(prevToken, token) &&
|
---|
159 | sourceCode.isSpaceBetweenTokens(prevToken, token)
|
---|
160 | ) {
|
---|
161 | context.report({
|
---|
162 | loc: { start: prevToken.loc.end, end: token.loc.start },
|
---|
163 | messageId: "unexpectedBefore",
|
---|
164 | data: token,
|
---|
165 | fix(fixer) {
|
---|
166 | return fixer.removeRange([prevToken.range[1], token.range[0]]);
|
---|
167 | }
|
---|
168 | });
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | /**
|
---|
173 | * Reports a given token if there are not space(s) after the token.
|
---|
174 | * @param {Token} token A token to report.
|
---|
175 | * @param {RegExp} pattern A pattern of the next token to check.
|
---|
176 | * @returns {void}
|
---|
177 | */
|
---|
178 | function expectSpaceAfter(token, pattern) {
|
---|
179 | const nextToken = sourceCode.getTokenAfter(token);
|
---|
180 |
|
---|
181 | if (nextToken &&
|
---|
182 | (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
|
---|
183 | !isCloseParenOfTemplate(nextToken) &&
|
---|
184 | !tokensToIgnore.has(nextToken) &&
|
---|
185 | astUtils.isTokenOnSameLine(token, nextToken) &&
|
---|
186 | !sourceCode.isSpaceBetweenTokens(token, nextToken)
|
---|
187 | ) {
|
---|
188 | context.report({
|
---|
189 | loc: token.loc,
|
---|
190 | messageId: "expectedAfter",
|
---|
191 | data: token,
|
---|
192 | fix(fixer) {
|
---|
193 | return fixer.insertTextAfter(token, " ");
|
---|
194 | }
|
---|
195 | });
|
---|
196 | }
|
---|
197 | }
|
---|
198 |
|
---|
199 | /**
|
---|
200 | * Reports a given token if there are space(s) after the token.
|
---|
201 | * @param {Token} token A token to report.
|
---|
202 | * @param {RegExp} pattern A pattern of the next token to check.
|
---|
203 | * @returns {void}
|
---|
204 | */
|
---|
205 | function unexpectSpaceAfter(token, pattern) {
|
---|
206 | const nextToken = sourceCode.getTokenAfter(token);
|
---|
207 |
|
---|
208 | if (nextToken &&
|
---|
209 | (CHECK_TYPE.test(nextToken.type) || pattern.test(nextToken.value)) &&
|
---|
210 | !isCloseParenOfTemplate(nextToken) &&
|
---|
211 | !tokensToIgnore.has(nextToken) &&
|
---|
212 | astUtils.isTokenOnSameLine(token, nextToken) &&
|
---|
213 | sourceCode.isSpaceBetweenTokens(token, nextToken)
|
---|
214 | ) {
|
---|
215 |
|
---|
216 | context.report({
|
---|
217 | loc: { start: token.loc.end, end: nextToken.loc.start },
|
---|
218 | messageId: "unexpectedAfter",
|
---|
219 | data: token,
|
---|
220 | fix(fixer) {
|
---|
221 | return fixer.removeRange([token.range[1], nextToken.range[0]]);
|
---|
222 | }
|
---|
223 | });
|
---|
224 | }
|
---|
225 | }
|
---|
226 |
|
---|
227 | /**
|
---|
228 | * Parses the option object and determines check methods for each keyword.
|
---|
229 | * @param {Object|undefined} options The option object to parse.
|
---|
230 | * @returns {Object} - Normalized option object.
|
---|
231 | * Keys are keywords (there are for every keyword).
|
---|
232 | * Values are instances of `{"before": function, "after": function}`.
|
---|
233 | */
|
---|
234 | function parseOptions(options = {}) {
|
---|
235 | const before = options.before !== false;
|
---|
236 | const after = options.after !== false;
|
---|
237 | const defaultValue = {
|
---|
238 | before: before ? expectSpaceBefore : unexpectSpaceBefore,
|
---|
239 | after: after ? expectSpaceAfter : unexpectSpaceAfter
|
---|
240 | };
|
---|
241 | const overrides = (options && options.overrides) || {};
|
---|
242 | const retv = Object.create(null);
|
---|
243 |
|
---|
244 | for (let i = 0; i < KEYS.length; ++i) {
|
---|
245 | const key = KEYS[i];
|
---|
246 | const override = overrides[key];
|
---|
247 |
|
---|
248 | if (override) {
|
---|
249 | const thisBefore = ("before" in override) ? override.before : before;
|
---|
250 | const thisAfter = ("after" in override) ? override.after : after;
|
---|
251 |
|
---|
252 | retv[key] = {
|
---|
253 | before: thisBefore ? expectSpaceBefore : unexpectSpaceBefore,
|
---|
254 | after: thisAfter ? expectSpaceAfter : unexpectSpaceAfter
|
---|
255 | };
|
---|
256 | } else {
|
---|
257 | retv[key] = defaultValue;
|
---|
258 | }
|
---|
259 | }
|
---|
260 |
|
---|
261 | return retv;
|
---|
262 | }
|
---|
263 |
|
---|
264 | const checkMethodMap = parseOptions(context.options[0]);
|
---|
265 |
|
---|
266 | /**
|
---|
267 | * Reports a given token if usage of spacing followed by the token is
|
---|
268 | * invalid.
|
---|
269 | * @param {Token} token A token to report.
|
---|
270 | * @param {RegExp} [pattern] Optional. A pattern of the previous
|
---|
271 | * token to check.
|
---|
272 | * @returns {void}
|
---|
273 | */
|
---|
274 | function checkSpacingBefore(token, pattern) {
|
---|
275 | checkMethodMap[token.value].before(token, pattern || PREV_TOKEN);
|
---|
276 | }
|
---|
277 |
|
---|
278 | /**
|
---|
279 | * Reports a given token if usage of spacing preceded by the token is
|
---|
280 | * invalid.
|
---|
281 | * @param {Token} token A token to report.
|
---|
282 | * @param {RegExp} [pattern] Optional. A pattern of the next
|
---|
283 | * token to check.
|
---|
284 | * @returns {void}
|
---|
285 | */
|
---|
286 | function checkSpacingAfter(token, pattern) {
|
---|
287 | checkMethodMap[token.value].after(token, pattern || NEXT_TOKEN);
|
---|
288 | }
|
---|
289 |
|
---|
290 | /**
|
---|
291 | * Reports a given token if usage of spacing around the token is invalid.
|
---|
292 | * @param {Token} token A token to report.
|
---|
293 | * @returns {void}
|
---|
294 | */
|
---|
295 | function checkSpacingAround(token) {
|
---|
296 | checkSpacingBefore(token);
|
---|
297 | checkSpacingAfter(token);
|
---|
298 | }
|
---|
299 |
|
---|
300 | /**
|
---|
301 | * Reports the first token of a given node if the first token is a keyword
|
---|
302 | * and usage of spacing around the token is invalid.
|
---|
303 | * @param {ASTNode|null} node A node to report.
|
---|
304 | * @returns {void}
|
---|
305 | */
|
---|
306 | function checkSpacingAroundFirstToken(node) {
|
---|
307 | const firstToken = node && sourceCode.getFirstToken(node);
|
---|
308 |
|
---|
309 | if (firstToken && firstToken.type === "Keyword") {
|
---|
310 | checkSpacingAround(firstToken);
|
---|
311 | }
|
---|
312 | }
|
---|
313 |
|
---|
314 | /**
|
---|
315 | * Reports the first token of a given node if the first token is a keyword
|
---|
316 | * and usage of spacing followed by the token is invalid.
|
---|
317 | *
|
---|
318 | * This is used for unary operators (e.g. `typeof`), `function`, and `super`.
|
---|
319 | * Other rules are handling usage of spacing preceded by those keywords.
|
---|
320 | * @param {ASTNode|null} node A node to report.
|
---|
321 | * @returns {void}
|
---|
322 | */
|
---|
323 | function checkSpacingBeforeFirstToken(node) {
|
---|
324 | const firstToken = node && sourceCode.getFirstToken(node);
|
---|
325 |
|
---|
326 | if (firstToken && firstToken.type === "Keyword") {
|
---|
327 | checkSpacingBefore(firstToken);
|
---|
328 | }
|
---|
329 | }
|
---|
330 |
|
---|
331 | /**
|
---|
332 | * Reports the previous token of a given node if the token is a keyword and
|
---|
333 | * usage of spacing around the token is invalid.
|
---|
334 | * @param {ASTNode|null} node A node to report.
|
---|
335 | * @returns {void}
|
---|
336 | */
|
---|
337 | function checkSpacingAroundTokenBefore(node) {
|
---|
338 | if (node) {
|
---|
339 | const token = sourceCode.getTokenBefore(node, astUtils.isKeywordToken);
|
---|
340 |
|
---|
341 | checkSpacingAround(token);
|
---|
342 | }
|
---|
343 | }
|
---|
344 |
|
---|
345 | /**
|
---|
346 | * Reports `async` or `function` keywords of a given node if usage of
|
---|
347 | * spacing around those keywords is invalid.
|
---|
348 | * @param {ASTNode} node A node to report.
|
---|
349 | * @returns {void}
|
---|
350 | */
|
---|
351 | function checkSpacingForFunction(node) {
|
---|
352 | const firstToken = node && sourceCode.getFirstToken(node);
|
---|
353 |
|
---|
354 | if (firstToken &&
|
---|
355 | ((firstToken.type === "Keyword" && firstToken.value === "function") ||
|
---|
356 | firstToken.value === "async")
|
---|
357 | ) {
|
---|
358 | checkSpacingBefore(firstToken);
|
---|
359 | }
|
---|
360 | }
|
---|
361 |
|
---|
362 | /**
|
---|
363 | * Reports `class` and `extends` keywords of a given node if usage of
|
---|
364 | * spacing around those keywords is invalid.
|
---|
365 | * @param {ASTNode} node A node to report.
|
---|
366 | * @returns {void}
|
---|
367 | */
|
---|
368 | function checkSpacingForClass(node) {
|
---|
369 | checkSpacingAroundFirstToken(node);
|
---|
370 | checkSpacingAroundTokenBefore(node.superClass);
|
---|
371 | }
|
---|
372 |
|
---|
373 | /**
|
---|
374 | * Reports `if` and `else` keywords of a given node if usage of spacing
|
---|
375 | * around those keywords is invalid.
|
---|
376 | * @param {ASTNode} node A node to report.
|
---|
377 | * @returns {void}
|
---|
378 | */
|
---|
379 | function checkSpacingForIfStatement(node) {
|
---|
380 | checkSpacingAroundFirstToken(node);
|
---|
381 | checkSpacingAroundTokenBefore(node.alternate);
|
---|
382 | }
|
---|
383 |
|
---|
384 | /**
|
---|
385 | * Reports `try`, `catch`, and `finally` keywords of a given node if usage
|
---|
386 | * of spacing around those keywords is invalid.
|
---|
387 | * @param {ASTNode} node A node to report.
|
---|
388 | * @returns {void}
|
---|
389 | */
|
---|
390 | function checkSpacingForTryStatement(node) {
|
---|
391 | checkSpacingAroundFirstToken(node);
|
---|
392 | checkSpacingAroundFirstToken(node.handler);
|
---|
393 | checkSpacingAroundTokenBefore(node.finalizer);
|
---|
394 | }
|
---|
395 |
|
---|
396 | /**
|
---|
397 | * Reports `do` and `while` keywords of a given node if usage of spacing
|
---|
398 | * around those keywords is invalid.
|
---|
399 | * @param {ASTNode} node A node to report.
|
---|
400 | * @returns {void}
|
---|
401 | */
|
---|
402 | function checkSpacingForDoWhileStatement(node) {
|
---|
403 | checkSpacingAroundFirstToken(node);
|
---|
404 | checkSpacingAroundTokenBefore(node.test);
|
---|
405 | }
|
---|
406 |
|
---|
407 | /**
|
---|
408 | * Reports `for` and `in` keywords of a given node if usage of spacing
|
---|
409 | * around those keywords is invalid.
|
---|
410 | * @param {ASTNode} node A node to report.
|
---|
411 | * @returns {void}
|
---|
412 | */
|
---|
413 | function checkSpacingForForInStatement(node) {
|
---|
414 | checkSpacingAroundFirstToken(node);
|
---|
415 |
|
---|
416 | const inToken = sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken);
|
---|
417 | const previousToken = sourceCode.getTokenBefore(inToken);
|
---|
418 |
|
---|
419 | if (previousToken.type !== "PrivateIdentifier") {
|
---|
420 | checkSpacingBefore(inToken);
|
---|
421 | }
|
---|
422 |
|
---|
423 | checkSpacingAfter(inToken);
|
---|
424 | }
|
---|
425 |
|
---|
426 | /**
|
---|
427 | * Reports `for` and `of` keywords of a given node if usage of spacing
|
---|
428 | * around those keywords is invalid.
|
---|
429 | * @param {ASTNode} node A node to report.
|
---|
430 | * @returns {void}
|
---|
431 | */
|
---|
432 | function checkSpacingForForOfStatement(node) {
|
---|
433 | if (node.await) {
|
---|
434 | checkSpacingBefore(sourceCode.getFirstToken(node, 0));
|
---|
435 | checkSpacingAfter(sourceCode.getFirstToken(node, 1));
|
---|
436 | } else {
|
---|
437 | checkSpacingAroundFirstToken(node);
|
---|
438 | }
|
---|
439 |
|
---|
440 | const ofToken = sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken);
|
---|
441 | const previousToken = sourceCode.getTokenBefore(ofToken);
|
---|
442 |
|
---|
443 | if (previousToken.type !== "PrivateIdentifier") {
|
---|
444 | checkSpacingBefore(ofToken);
|
---|
445 | }
|
---|
446 |
|
---|
447 | checkSpacingAfter(ofToken);
|
---|
448 | }
|
---|
449 |
|
---|
450 | /**
|
---|
451 | * Reports `import`, `export`, `as`, and `from` keywords of a given node if
|
---|
452 | * usage of spacing around those keywords is invalid.
|
---|
453 | *
|
---|
454 | * This rule handles the `*` token in module declarations.
|
---|
455 | *
|
---|
456 | * import*as A from "./a"; /*error Expected space(s) after "import".
|
---|
457 | * error Expected space(s) before "as".
|
---|
458 | * @param {ASTNode} node A node to report.
|
---|
459 | * @returns {void}
|
---|
460 | */
|
---|
461 | function checkSpacingForModuleDeclaration(node) {
|
---|
462 | const firstToken = sourceCode.getFirstToken(node);
|
---|
463 |
|
---|
464 | checkSpacingBefore(firstToken, PREV_TOKEN_M);
|
---|
465 | checkSpacingAfter(firstToken, NEXT_TOKEN_M);
|
---|
466 |
|
---|
467 | if (node.type === "ExportDefaultDeclaration") {
|
---|
468 | checkSpacingAround(sourceCode.getTokenAfter(firstToken));
|
---|
469 | }
|
---|
470 |
|
---|
471 | if (node.type === "ExportAllDeclaration" && node.exported) {
|
---|
472 | const asToken = sourceCode.getTokenBefore(node.exported);
|
---|
473 |
|
---|
474 | checkSpacingBefore(asToken, PREV_TOKEN_M);
|
---|
475 | checkSpacingAfter(asToken, NEXT_TOKEN_M);
|
---|
476 | }
|
---|
477 |
|
---|
478 | if (node.source) {
|
---|
479 | const fromToken = sourceCode.getTokenBefore(node.source);
|
---|
480 |
|
---|
481 | checkSpacingBefore(fromToken, PREV_TOKEN_M);
|
---|
482 | checkSpacingAfter(fromToken, NEXT_TOKEN_M);
|
---|
483 | }
|
---|
484 | }
|
---|
485 |
|
---|
486 | /**
|
---|
487 | * Reports `as` keyword of a given node if usage of spacing around this
|
---|
488 | * keyword is invalid.
|
---|
489 | * @param {ASTNode} node An `ImportSpecifier` node to check.
|
---|
490 | * @returns {void}
|
---|
491 | */
|
---|
492 | function checkSpacingForImportSpecifier(node) {
|
---|
493 | if (node.imported.range[0] !== node.local.range[0]) {
|
---|
494 | const asToken = sourceCode.getTokenBefore(node.local);
|
---|
495 |
|
---|
496 | checkSpacingBefore(asToken, PREV_TOKEN_M);
|
---|
497 | }
|
---|
498 | }
|
---|
499 |
|
---|
500 | /**
|
---|
501 | * Reports `as` keyword of a given node if usage of spacing around this
|
---|
502 | * keyword is invalid.
|
---|
503 | * @param {ASTNode} node An `ExportSpecifier` node to check.
|
---|
504 | * @returns {void}
|
---|
505 | */
|
---|
506 | function checkSpacingForExportSpecifier(node) {
|
---|
507 | if (node.local.range[0] !== node.exported.range[0]) {
|
---|
508 | const asToken = sourceCode.getTokenBefore(node.exported);
|
---|
509 |
|
---|
510 | checkSpacingBefore(asToken, PREV_TOKEN_M);
|
---|
511 | checkSpacingAfter(asToken, NEXT_TOKEN_M);
|
---|
512 | }
|
---|
513 | }
|
---|
514 |
|
---|
515 | /**
|
---|
516 | * Reports `as` keyword of a given node if usage of spacing around this
|
---|
517 | * keyword is invalid.
|
---|
518 | * @param {ASTNode} node A node to report.
|
---|
519 | * @returns {void}
|
---|
520 | */
|
---|
521 | function checkSpacingForImportNamespaceSpecifier(node) {
|
---|
522 | const asToken = sourceCode.getFirstToken(node, 1);
|
---|
523 |
|
---|
524 | checkSpacingBefore(asToken, PREV_TOKEN_M);
|
---|
525 | }
|
---|
526 |
|
---|
527 | /**
|
---|
528 | * Reports `static`, `get`, and `set` keywords of a given node if usage of
|
---|
529 | * spacing around those keywords is invalid.
|
---|
530 | * @param {ASTNode} node A node to report.
|
---|
531 | * @throws {Error} If unable to find token get, set, or async beside method name.
|
---|
532 | * @returns {void}
|
---|
533 | */
|
---|
534 | function checkSpacingForProperty(node) {
|
---|
535 | if (node.static) {
|
---|
536 | checkSpacingAroundFirstToken(node);
|
---|
537 | }
|
---|
538 | if (node.kind === "get" ||
|
---|
539 | node.kind === "set" ||
|
---|
540 | (
|
---|
541 | (node.method || node.type === "MethodDefinition") &&
|
---|
542 | node.value.async
|
---|
543 | )
|
---|
544 | ) {
|
---|
545 | const token = sourceCode.getTokenBefore(
|
---|
546 | node.key,
|
---|
547 | tok => {
|
---|
548 | switch (tok.value) {
|
---|
549 | case "get":
|
---|
550 | case "set":
|
---|
551 | case "async":
|
---|
552 | return true;
|
---|
553 | default:
|
---|
554 | return false;
|
---|
555 | }
|
---|
556 | }
|
---|
557 | );
|
---|
558 |
|
---|
559 | if (!token) {
|
---|
560 | throw new Error("Failed to find token get, set, or async beside method name");
|
---|
561 | }
|
---|
562 |
|
---|
563 |
|
---|
564 | checkSpacingAround(token);
|
---|
565 | }
|
---|
566 | }
|
---|
567 |
|
---|
568 | /**
|
---|
569 | * Reports `await` keyword of a given node if usage of spacing before
|
---|
570 | * this keyword is invalid.
|
---|
571 | * @param {ASTNode} node A node to report.
|
---|
572 | * @returns {void}
|
---|
573 | */
|
---|
574 | function checkSpacingForAwaitExpression(node) {
|
---|
575 | checkSpacingBefore(sourceCode.getFirstToken(node));
|
---|
576 | }
|
---|
577 |
|
---|
578 | return {
|
---|
579 |
|
---|
580 | // Statements
|
---|
581 | DebuggerStatement: checkSpacingAroundFirstToken,
|
---|
582 | WithStatement: checkSpacingAroundFirstToken,
|
---|
583 |
|
---|
584 | // Statements - Control flow
|
---|
585 | BreakStatement: checkSpacingAroundFirstToken,
|
---|
586 | ContinueStatement: checkSpacingAroundFirstToken,
|
---|
587 | ReturnStatement: checkSpacingAroundFirstToken,
|
---|
588 | ThrowStatement: checkSpacingAroundFirstToken,
|
---|
589 | TryStatement: checkSpacingForTryStatement,
|
---|
590 |
|
---|
591 | // Statements - Choice
|
---|
592 | IfStatement: checkSpacingForIfStatement,
|
---|
593 | SwitchStatement: checkSpacingAroundFirstToken,
|
---|
594 | SwitchCase: checkSpacingAroundFirstToken,
|
---|
595 |
|
---|
596 | // Statements - Loops
|
---|
597 | DoWhileStatement: checkSpacingForDoWhileStatement,
|
---|
598 | ForInStatement: checkSpacingForForInStatement,
|
---|
599 | ForOfStatement: checkSpacingForForOfStatement,
|
---|
600 | ForStatement: checkSpacingAroundFirstToken,
|
---|
601 | WhileStatement: checkSpacingAroundFirstToken,
|
---|
602 |
|
---|
603 | // Statements - Declarations
|
---|
604 | ClassDeclaration: checkSpacingForClass,
|
---|
605 | ExportNamedDeclaration: checkSpacingForModuleDeclaration,
|
---|
606 | ExportDefaultDeclaration: checkSpacingForModuleDeclaration,
|
---|
607 | ExportAllDeclaration: checkSpacingForModuleDeclaration,
|
---|
608 | FunctionDeclaration: checkSpacingForFunction,
|
---|
609 | ImportDeclaration: checkSpacingForModuleDeclaration,
|
---|
610 | VariableDeclaration: checkSpacingAroundFirstToken,
|
---|
611 |
|
---|
612 | // Expressions
|
---|
613 | ArrowFunctionExpression: checkSpacingForFunction,
|
---|
614 | AwaitExpression: checkSpacingForAwaitExpression,
|
---|
615 | ClassExpression: checkSpacingForClass,
|
---|
616 | FunctionExpression: checkSpacingForFunction,
|
---|
617 | NewExpression: checkSpacingBeforeFirstToken,
|
---|
618 | Super: checkSpacingBeforeFirstToken,
|
---|
619 | ThisExpression: checkSpacingBeforeFirstToken,
|
---|
620 | UnaryExpression: checkSpacingBeforeFirstToken,
|
---|
621 | YieldExpression: checkSpacingBeforeFirstToken,
|
---|
622 |
|
---|
623 | // Others
|
---|
624 | ImportSpecifier: checkSpacingForImportSpecifier,
|
---|
625 | ExportSpecifier: checkSpacingForExportSpecifier,
|
---|
626 | ImportNamespaceSpecifier: checkSpacingForImportNamespaceSpecifier,
|
---|
627 | MethodDefinition: checkSpacingForProperty,
|
---|
628 | PropertyDefinition: checkSpacingForProperty,
|
---|
629 | StaticBlock: checkSpacingAroundFirstToken,
|
---|
630 | Property: checkSpacingForProperty,
|
---|
631 |
|
---|
632 | // To avoid conflicts with `space-infix-ops`, e.g. `a > this.b`
|
---|
633 | "BinaryExpression[operator='>']"(node) {
|
---|
634 | const operatorToken = sourceCode.getTokenBefore(node.right, astUtils.isNotOpeningParenToken);
|
---|
635 |
|
---|
636 | tokensToIgnore.add(operatorToken);
|
---|
637 | }
|
---|
638 | };
|
---|
639 | }
|
---|
640 | };
|
---|