/** * @fileoverview Rule to enforce spacing around colons of switch statements. * @author Toru Nagashima */ "use strict"; //------------------------------------------------------------------------------ // Requirements //------------------------------------------------------------------------------ const astUtils = require("../ast-utils"); //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ module.exports = { meta: { docs: { description: "enforce spacing around colons of switch statements", category: "Stylistic Issues", recommended: false }, schema: [ { type: "object", properties: { before: { type: "boolean" }, after: { type: "boolean" } }, additionalProperties: false } ], fixable: "whitespace" }, create(context) { const sourceCode = context.getSourceCode(); const options = context.options[0] || {}; const beforeSpacing = options.before === true; // false by default const afterSpacing = options.after !== false; // true by default /** * Get the colon token of the given SwitchCase node. * @param {ASTNode} node The SwitchCase node to get. * @returns {Token} The colon token of the node. */ function getColonToken(node) { if (node.test) { return sourceCode.getTokenAfter(node.test, astUtils.isColonToken); } return sourceCode.getFirstToken(node, 1); } /** * Check whether the spacing between the given 2 tokens is valid or not. * @param {Token} left The left token to check. * @param {Token} right The right token to check. * @param {boolean} expected The expected spacing to check. `true` if there should be a space. * @returns {boolean} `true` if the spacing between the tokens is valid. */ function isValidSpacing(left, right, expected) { return ( astUtils.isClosingBraceToken(right) || !astUtils.isTokenOnSameLine(left, right) || sourceCode.isSpaceBetweenTokens(left, right) === expected ); } /** * Check whether comments exist between the given 2 tokens. * @param {Token} left The left token to check. * @param {Token} right The right token to check. * @returns {boolean} `true` if comments exist between the given 2 tokens. */ function commentsExistBetween(left, right) { return sourceCode.getFirstTokenBetween( left, right, { includeComments: true, filter: astUtils.isCommentToken } ) !== null; } /** * Fix the spacing between the given 2 tokens. * @param {RuleFixer} fixer The fixer to fix. * @param {Token} left The left token of fix range. * @param {Token} right The right token of fix range. * @param {boolean} spacing The spacing style. `true` if there should be a space. * @returns {Fix|null} The fix object. */ function fix(fixer, left, right, spacing) { if (commentsExistBetween(left, right)) { return null; } if (spacing) { return fixer.insertTextAfter(left, " "); } return fixer.removeRange([left.range[1], right.range[0]]); } return { SwitchCase(node) { const colonToken = getColonToken(node); const beforeToken = sourceCode.getTokenBefore(colonToken); const afterToken = sourceCode.getTokenAfter(colonToken); if (!isValidSpacing(beforeToken, colonToken, beforeSpacing)) { context.report({ node, loc: colonToken.loc, message: "{{verb}} space(s) before this colon.", data: { verb: beforeSpacing ? "Expected" : "Unexpected" }, fix: fixer => fix(fixer, beforeToken, colonToken, beforeSpacing) }); } if (!isValidSpacing(colonToken, afterToken, afterSpacing)) { context.report({ node, loc: colonToken.loc, message: "{{verb}} space(s) after this colon.", data: { verb: afterSpacing ? "Expected" : "Unexpected" }, fix: fixer => fix(fixer, colonToken, afterToken, afterSpacing) }); } } }; } };