1/** 2 * @fileoverview Rule to enforce spacing around colons of switch statements. 3 * @author Toru Nagashima 4 */ 5 6"use strict"; 7 8//------------------------------------------------------------------------------ 9// Requirements 10//------------------------------------------------------------------------------ 11 12const astUtils = require("./utils/ast-utils"); 13 14//------------------------------------------------------------------------------ 15// Rule Definition 16//------------------------------------------------------------------------------ 17 18module.exports = { 19 meta: { 20 type: "layout", 21 22 docs: { 23 description: "enforce spacing around colons of switch statements", 24 category: "Stylistic Issues", 25 recommended: false, 26 url: "https://eslint.org/docs/rules/switch-colon-spacing" 27 }, 28 29 schema: [ 30 { 31 type: "object", 32 properties: { 33 before: { type: "boolean", default: false }, 34 after: { type: "boolean", default: true } 35 }, 36 additionalProperties: false 37 } 38 ], 39 fixable: "whitespace", 40 messages: { 41 expectedBefore: "Expected space(s) before this colon.", 42 expectedAfter: "Expected space(s) after this colon.", 43 unexpectedBefore: "Unexpected space(s) before this colon.", 44 unexpectedAfter: "Unexpected space(s) after this colon." 45 } 46 }, 47 48 create(context) { 49 const sourceCode = context.getSourceCode(); 50 const options = context.options[0] || {}; 51 const beforeSpacing = options.before === true; // false by default 52 const afterSpacing = options.after !== false; // true by default 53 54 /** 55 * Get the colon token of the given SwitchCase node. 56 * @param {ASTNode} node The SwitchCase node to get. 57 * @returns {Token} The colon token of the node. 58 */ 59 function getColonToken(node) { 60 if (node.test) { 61 return sourceCode.getTokenAfter(node.test, astUtils.isColonToken); 62 } 63 return sourceCode.getFirstToken(node, 1); 64 } 65 66 /** 67 * Check whether the spacing between the given 2 tokens is valid or not. 68 * @param {Token} left The left token to check. 69 * @param {Token} right The right token to check. 70 * @param {boolean} expected The expected spacing to check. `true` if there should be a space. 71 * @returns {boolean} `true` if the spacing between the tokens is valid. 72 */ 73 function isValidSpacing(left, right, expected) { 74 return ( 75 astUtils.isClosingBraceToken(right) || 76 !astUtils.isTokenOnSameLine(left, right) || 77 sourceCode.isSpaceBetweenTokens(left, right) === expected 78 ); 79 } 80 81 /** 82 * Check whether comments exist between the given 2 tokens. 83 * @param {Token} left The left token to check. 84 * @param {Token} right The right token to check. 85 * @returns {boolean} `true` if comments exist between the given 2 tokens. 86 */ 87 function commentsExistBetween(left, right) { 88 return sourceCode.getFirstTokenBetween( 89 left, 90 right, 91 { 92 includeComments: true, 93 filter: astUtils.isCommentToken 94 } 95 ) !== null; 96 } 97 98 /** 99 * Fix the spacing between the given 2 tokens. 100 * @param {RuleFixer} fixer The fixer to fix. 101 * @param {Token} left The left token of fix range. 102 * @param {Token} right The right token of fix range. 103 * @param {boolean} spacing The spacing style. `true` if there should be a space. 104 * @returns {Fix|null} The fix object. 105 */ 106 function fix(fixer, left, right, spacing) { 107 if (commentsExistBetween(left, right)) { 108 return null; 109 } 110 if (spacing) { 111 return fixer.insertTextAfter(left, " "); 112 } 113 return fixer.removeRange([left.range[1], right.range[0]]); 114 } 115 116 return { 117 SwitchCase(node) { 118 const colonToken = getColonToken(node); 119 const beforeToken = sourceCode.getTokenBefore(colonToken); 120 const afterToken = sourceCode.getTokenAfter(colonToken); 121 122 if (!isValidSpacing(beforeToken, colonToken, beforeSpacing)) { 123 context.report({ 124 node, 125 loc: colonToken.loc, 126 messageId: beforeSpacing ? "expectedBefore" : "unexpectedBefore", 127 fix: fixer => fix(fixer, beforeToken, colonToken, beforeSpacing) 128 }); 129 } 130 if (!isValidSpacing(colonToken, afterToken, afterSpacing)) { 131 context.report({ 132 node, 133 loc: colonToken.loc, 134 messageId: afterSpacing ? "expectedAfter" : "unexpectedAfter", 135 fix: fixer => fix(fixer, colonToken, afterToken, afterSpacing) 136 }); 137 } 138 } 139 }; 140 } 141}; 142