diff --git a/rules/sort-switch-case.ts b/rules/sort-switch-case.ts index b7adde996..82a133683 100644 --- a/rules/sort-switch-case.ts +++ b/rules/sort-switch-case.ts @@ -1,4 +1,5 @@ import type { TSESTree } from '@typescript-eslint/types' +import type { TSESLint } from '@typescript-eslint/utils' import type { SortingNode } from '../typings' @@ -158,7 +159,8 @@ export default createEslintRule({ }, node: right.node, fix: fixer => { - let nodeGroups = nodes.reduce< + let additionalFixes: TSESLint.RuleFix[] = [] + let nodeGroups = structuredClone(nodes).reduce< SortingNode[][] >( ( @@ -182,10 +184,40 @@ export default createEslintRule({ let sortedNodeGroups = nodeGroups .map(group => { - let { consequent } = group.at(-1)!.node - group.at(-1)!.node.consequent = [] let sortedGroup = sortNodes(group, options) - sortedGroup.at(-1)!.node.consequent = consequent + + if (group.at(-1)!.name !== sortedGroup.at(-1)!.name) { + let firstSortedNodeConsequent = + sortedGroup.at(0)!.node.consequent + let consequentStart = firstSortedNodeConsequent + .at(0) + ?.range.at(0) + let consequentEnd = firstSortedNodeConsequent + .at(-1) + ?.range.at(1) + let lastNode = group.at(-1)!.node + if (consequentStart && consequentEnd && lastNode.test) { + lastNode.range = [ + lastNode.range.at(0)!, + lastNode.test.range.at(1)! + 1, + ] + additionalFixes.push( + ...makeFixes(fixer, group, sortedGroup, sourceCode), + fixer.removeRange([ + lastNode.range.at(1)!, + consequentEnd, + ]), + fixer.insertTextAfter( + lastNode, + sourceCode.text.slice( + lastNode.range.at(1), + consequentEnd, + ), + ), + ) + } + } + return sortedGroup }) .sort((a, b) => { @@ -205,6 +237,10 @@ export default createEslintRule({ } } + if (additionalFixes.length) { + return additionalFixes + } + return makeFixes(fixer, nodes, sortedNodes, sourceCode) }, }) diff --git a/test/sort-switch-case.test.ts b/test/sort-switch-case.test.ts index 846df182a..4423e81bf 100644 --- a/test/sort-switch-case.test.ts +++ b/test/sort-switch-case.test.ts @@ -316,6 +316,153 @@ describe(ruleName, () => { ], }, ) + + ruleTester.run( + `${ruleName}(${type}): works with single grouped case`, + rule, + { + valid: [ + { + code: dedent` + switch (x) { + case AA: + case B: + const a = 1; + break; + } + `, + options: [options], + }, + ], + invalid: [ + { + code: dedent` + switch (x) { + case B: + case AA: + const a = 1; + break; + } + `, + output: dedent` + switch (x) { + case AA: + case B: + const a = 1; + break; + } + `, + options: [options], + errors: [ + { + messageId: 'unexpectedSwitchCaseOrder', + data: { + left: 'B', + right: 'AA', + }, + }, + ], + }, + ], + }, + ) + + ruleTester.run(`${ruleName}(${type}): works with complex cases`, rule, { + valid: [ + { + code: dedent` + switch (x) { + case AAAAA: + case BBBB: + const a = 1 + break + case CCC: + break + case DD: + case E: + const b = () => { + return 2 + } + break + default: + const c = 3 + } + `, + options: [options], + }, + ], + invalid: [ + { + code: dedent` + switch (x) { + case E: + case DD: + const b = () => { + return 2 + } + break + case CCC: + break + case BBBB: + case AAAAA: + const a = 1 + break + default: + const c = 3 + } + `, + output: dedent` + switch (x) { + case DD: + case E: + const b = () => { + return 2 + } + break + case CCC: + break + case AAAAA: + case BBBB: + const a = 1 + break + default: + const c = 3 + } + `, + options: [options], + errors: [ + { + messageId: 'unexpectedSwitchCaseOrder', + data: { + left: 'E', + right: 'DD', + }, + }, + { + messageId: 'unexpectedSwitchCaseOrder', + data: { + left: 'DD', + right: 'CCC', + }, + }, + { + messageId: 'unexpectedSwitchCaseOrder', + data: { + left: 'CCC', + right: 'BBBB', + }, + }, + { + messageId: 'unexpectedSwitchCaseOrder', + data: { + left: 'BBBB', + right: 'AAAAA', + }, + }, + ], + }, + ], + }) }) describe(`${ruleName}: sorting by natural order`, () => {