110 lines
3.1 KiB
JavaScript
110 lines
3.1 KiB
JavaScript
|
'use strict';
|
||
|
const {isColonToken} = require('@eslint-community/eslint-utils');
|
||
|
const getSwitchCaseHeadLocation = require('./utils/get-switch-case-head-location.js');
|
||
|
const getIndentString = require('./utils/get-indent-string.js');
|
||
|
const {replaceNodeOrTokenAndSpacesBefore} = require('./fix/index.js');
|
||
|
|
||
|
const MESSAGE_ID_EMPTY_CLAUSE = 'switch-case-braces/empty';
|
||
|
const MESSAGE_ID_MISSING_BRACES = 'switch-case-braces/missing';
|
||
|
const MESSAGE_ID_UNNECESSARY_BRACES = 'switch-case-braces/unnecessary';
|
||
|
const messages = {
|
||
|
[MESSAGE_ID_EMPTY_CLAUSE]: 'Unexpected braces in empty case clause.',
|
||
|
[MESSAGE_ID_MISSING_BRACES]: 'Missing braces in case clause.',
|
||
|
[MESSAGE_ID_UNNECESSARY_BRACES]: 'Unnecessary braces in case clause.',
|
||
|
};
|
||
|
|
||
|
function * removeBraces(fixer, node, sourceCode) {
|
||
|
const [blockStatement] = node.consequent;
|
||
|
const openingBraceToken = sourceCode.getFirstToken(blockStatement);
|
||
|
yield * replaceNodeOrTokenAndSpacesBefore(openingBraceToken, '', fixer, sourceCode);
|
||
|
|
||
|
const closingBraceToken = sourceCode.getLastToken(blockStatement);
|
||
|
yield fixer.remove(closingBraceToken);
|
||
|
}
|
||
|
|
||
|
function * addBraces(fixer, node, sourceCode) {
|
||
|
const colonToken = sourceCode.getTokenAfter(
|
||
|
node.test || sourceCode.getFirstToken(node),
|
||
|
isColonToken,
|
||
|
);
|
||
|
yield fixer.insertTextAfter(colonToken, ' {');
|
||
|
|
||
|
const lastToken = sourceCode.getLastToken(node);
|
||
|
const indent = getIndentString(node, sourceCode);
|
||
|
yield fixer.insertTextAfter(lastToken, `\n${indent}}`);
|
||
|
}
|
||
|
|
||
|
/** @param {import('eslint').Rule.RuleContext} context */
|
||
|
const create = context => {
|
||
|
const isBracesRequired = context.options[0] !== 'avoid';
|
||
|
const sourceCode = context.getSourceCode();
|
||
|
|
||
|
return {
|
||
|
SwitchCase(node) {
|
||
|
const {consequent} = node;
|
||
|
if (consequent.length === 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (
|
||
|
consequent.length === 1
|
||
|
&& consequent[0].type === 'BlockStatement'
|
||
|
&& consequent[0].body.length === 0
|
||
|
) {
|
||
|
return {
|
||
|
node,
|
||
|
loc: sourceCode.getFirstToken(consequent[0]).loc,
|
||
|
messageId: MESSAGE_ID_EMPTY_CLAUSE,
|
||
|
fix: fixer => removeBraces(fixer, node, sourceCode),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (
|
||
|
isBracesRequired
|
||
|
&& !(
|
||
|
consequent.length === 1
|
||
|
&& consequent[0].type === 'BlockStatement'
|
||
|
)
|
||
|
) {
|
||
|
return {
|
||
|
node,
|
||
|
loc: getSwitchCaseHeadLocation(node, sourceCode),
|
||
|
messageId: MESSAGE_ID_MISSING_BRACES,
|
||
|
fix: fixer => addBraces(fixer, node, sourceCode),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (
|
||
|
!isBracesRequired
|
||
|
&& consequent.length === 1
|
||
|
&& consequent[0].type === 'BlockStatement'
|
||
|
&& consequent[0].body.every(node =>
|
||
|
node.type !== 'VariableDeclaration'
|
||
|
&& node.type !== 'FunctionDeclaration',
|
||
|
)
|
||
|
) {
|
||
|
return {
|
||
|
node,
|
||
|
loc: sourceCode.getFirstToken(consequent[0]).loc,
|
||
|
messageId: MESSAGE_ID_UNNECESSARY_BRACES,
|
||
|
fix: fixer => removeBraces(fixer, node, sourceCode),
|
||
|
};
|
||
|
}
|
||
|
},
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/** @type {import('eslint').Rule.RuleModule} */
|
||
|
module.exports = {
|
||
|
create,
|
||
|
meta: {
|
||
|
type: 'layout',
|
||
|
docs: {
|
||
|
description: 'Enforce consistent brace style for `case` clauses.',
|
||
|
},
|
||
|
fixable: 'code',
|
||
|
schema: [{enum: ['always', 'avoid']}],
|
||
|
messages,
|
||
|
},
|
||
|
};
|