source: imaps-frontend/node_modules/eslint/lib/rules/keyword-spacing.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 23.7 KB
Line 
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
13const astUtils = require("./utils/ast-utils"),
14 keywords = require("./utils/keywords");
15
16//------------------------------------------------------------------------------
17// Constants
18//------------------------------------------------------------------------------
19
20const PREV_TOKEN = /^[)\]}>]$/u;
21const NEXT_TOKEN = /^(?:[([{<~!]|\+\+?|--?)$/u;
22const PREV_TOKEN_M = /^[)\]}>*]$/u;
23const NEXT_TOKEN_M = /^[{*]$/u;
24const TEMPLATE_OPEN_PAREN = /\$\{$/u;
25const TEMPLATE_CLOSE_PAREN = /^\}/u;
26const CHECK_TYPE = /^(?:JSXElement|RegularExpression|String|Template|PrivateIdentifier)$/u;
27const 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 */
48function 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 */
57function 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} */
66module.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};
Note: See TracBrowser for help on using the repository browser.