Skip to content

Commit 0086427

Browse files
authored
feat: don't sort unknown elements if unknown is not referenced in groups
1 parent 0c724e0 commit 0086427

File tree

3 files changed

+191
-36
lines changed

3 files changed

+191
-36
lines changed

docs/content/rules/sort-classes.mdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,8 @@ Elements that are not `protected` nor `private` will be matched with the `public
266266

267267

268268
##### The `unknown` group
269-
Members that don’t fit into any group entered by the user will be placed in the `unknown` group.
269+
Members that don’t fit into any group entered by the user will be placed in the `unknown` group. If the `unknown` group is not specified in `groups`,
270+
the members will remain in their original order.
270271

271272
##### Behavior when multiple groups match an element
272273

rules/sort-classes.ts

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -537,11 +537,17 @@ export default createEslintRule<Options, MESSAGE_ID>({
537537
pairwise(nodes, (left, right) => {
538538
let leftNum = getGroupNumber(options.groups, left)
539539
let rightNum = getGroupNumber(options.groups, right)
540+
// Ignore nodes belonging to `unknown` group when that group is not referenced in the
541+
// `groups` option.
542+
let isLeftOrRightIgnored =
543+
leftNum === options.groups.length ||
544+
rightNum === options.groups.length
540545

541546
if (
542-
leftNum > rightNum ||
543-
(leftNum === rightNum &&
544-
isPositive(compare(left, right, options)))
547+
!isLeftOrRightIgnored &&
548+
(leftNum > rightNum ||
549+
(leftNum === rightNum &&
550+
isPositive(compare(left, right, options))))
545551
) {
546552
context.report({
547553
messageId:
@@ -556,35 +562,36 @@ export default createEslintRule<Options, MESSAGE_ID>({
556562
},
557563
node: right.node,
558564
fix: (fixer: TSESLint.RuleFixer) => {
559-
let grouped = nodes.reduce(
560-
(
561-
accumulator: {
562-
[key: string]: SortingNode[]
563-
},
564-
sortingNode,
565-
) => {
566-
let groupNum = getGroupNumber(options.groups, sortingNode)
567-
568-
if (!(groupNum in accumulator)) {
569-
accumulator[groupNum] = [sortingNode]
570-
} else {
571-
accumulator[groupNum] = sortNodes(
572-
[...accumulator[groupNum], sortingNode],
573-
options,
574-
)
575-
}
576-
577-
return accumulator
578-
},
579-
{},
580-
)
565+
let nodesByNonIgnoredGroupNumber: {
566+
[key: number]: SortingNode[]
567+
} = {}
568+
let ignoredNodeIndices: number[] = []
569+
for (let [index, sortingNode] of nodes.entries()) {
570+
let groupNum = getGroupNumber(options.groups, sortingNode)
571+
if (groupNum === options.groups.length) {
572+
ignoredNodeIndices.push(index)
573+
continue
574+
}
575+
nodesByNonIgnoredGroupNumber[groupNum] =
576+
nodesByNonIgnoredGroupNumber[groupNum] ?? []
577+
nodesByNonIgnoredGroupNumber[groupNum].push(sortingNode)
578+
}
581579

582580
let sortedNodes: SortingNode[] = []
581+
for (let groupNumber of Object.keys(
582+
nodesByNonIgnoredGroupNumber,
583+
).sort((a, b) => Number(a) - Number(b))) {
584+
sortedNodes.push(
585+
...sortNodes(
586+
nodesByNonIgnoredGroupNumber[Number(groupNumber)],
587+
options,
588+
),
589+
)
590+
}
583591

584-
for (let group of Object.keys(grouped).sort(
585-
(a, b) => Number(a) - Number(b),
586-
)) {
587-
sortedNodes.push(...sortNodes(grouped[group], options))
592+
// Add ignored nodes at the same position as they were before linting
593+
for (let ignoredIndex of ignoredNodeIndices) {
594+
sortedNodes.splice(ignoredIndex, 0, nodes[ignoredIndex])
588595
}
589596

590597
return makeFixes(fixer, nodes, sortedNodes, sourceCode, {

test/sort-classes.test.ts

Lines changed: 153 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,7 +1650,7 @@ describe(ruleName, () => {
16501650
...options,
16511651
groups: [
16521652
['static-property', 'private-property', 'property'],
1653-
'constructor',
1653+
'index-signature',
16541654
],
16551655
},
16561656
],
@@ -1659,7 +1659,7 @@ describe(ruleName, () => {
16591659
messageId: 'unexpectedClassesGroupOrder',
16601660
data: {
16611661
left: '[k: string];',
1662-
leftGroup: 'unknown',
1662+
leftGroup: 'index-signature',
16631663
right: 'a',
16641664
rightGroup: 'static-property',
16651665
},
@@ -2736,6 +2736,55 @@ describe(ruleName, () => {
27362736
},
27372737
],
27382738
})
2739+
2740+
ruleTester.run(`${ruleName}(${type}): should ignore unknown group`, rule, {
2741+
valid: [],
2742+
invalid: [
2743+
{
2744+
code: dedent`
2745+
class Class {
2746+
2747+
public i = 'i';
2748+
private z() {}
2749+
public method3() {}
2750+
private y() {}
2751+
public method4() {}
2752+
public method1() {}
2753+
private x() {}
2754+
}
2755+
`,
2756+
output: dedent`
2757+
class Class {
2758+
2759+
private x() {}
2760+
private y() {}
2761+
public method3() {}
2762+
private z() {}
2763+
public method4() {}
2764+
public method1() {}
2765+
public i = 'i';
2766+
}
2767+
`,
2768+
options: [
2769+
{
2770+
...options,
2771+
groups: ['private-method', 'property'],
2772+
},
2773+
],
2774+
errors: [
2775+
{
2776+
messageId: 'unexpectedClassesGroupOrder',
2777+
data: {
2778+
left: 'i',
2779+
leftGroup: 'property',
2780+
right: 'z',
2781+
rightGroup: 'private-method',
2782+
},
2783+
},
2784+
],
2785+
},
2786+
],
2787+
})
27392788
})
27402789

27412790
describe(`${ruleName}: sorting by natural order`, () => {
@@ -3028,7 +3077,7 @@ describe(ruleName, () => {
30283077
...options,
30293078
groups: [
30303079
['static-property', 'private-property', 'property'],
3031-
'constructor',
3080+
'index-signature',
30323081
],
30333082
},
30343083
],
@@ -3037,7 +3086,7 @@ describe(ruleName, () => {
30373086
messageId: 'unexpectedClassesGroupOrder',
30383087
data: {
30393088
left: '[k: string];',
3040-
leftGroup: 'unknown',
3089+
leftGroup: 'index-signature',
30413090
right: 'a',
30423091
rightGroup: 'static-property',
30433092
},
@@ -4114,6 +4163,55 @@ describe(ruleName, () => {
41144163
},
41154164
],
41164165
})
4166+
4167+
ruleTester.run(`${ruleName}(${type}): should ignore unknown group`, rule, {
4168+
valid: [],
4169+
invalid: [
4170+
{
4171+
code: dedent`
4172+
class Class {
4173+
4174+
public i = 'i';
4175+
private z() {}
4176+
public method3() {}
4177+
private y() {}
4178+
public method4() {}
4179+
public method1() {}
4180+
private x() {}
4181+
}
4182+
`,
4183+
output: dedent`
4184+
class Class {
4185+
4186+
private x() {}
4187+
private y() {}
4188+
public method3() {}
4189+
private z() {}
4190+
public method4() {}
4191+
public method1() {}
4192+
public i = 'i';
4193+
}
4194+
`,
4195+
options: [
4196+
{
4197+
...options,
4198+
groups: ['private-method', 'property'],
4199+
},
4200+
],
4201+
errors: [
4202+
{
4203+
messageId: 'unexpectedClassesGroupOrder',
4204+
data: {
4205+
left: 'i',
4206+
leftGroup: 'property',
4207+
right: 'z',
4208+
rightGroup: 'private-method',
4209+
},
4210+
},
4211+
],
4212+
},
4213+
],
4214+
})
41174215
})
41184216

41194217
describe(`${ruleName}: sorting by line length`, () => {
@@ -4375,7 +4473,7 @@ describe(ruleName, () => {
43754473
...options,
43764474
groups: [
43774475
['static-property', 'private-property', 'property'],
4378-
'constructor',
4476+
'index-signature',
43794477
],
43804478
},
43814479
],
@@ -4384,7 +4482,7 @@ describe(ruleName, () => {
43844482
messageId: 'unexpectedClassesGroupOrder',
43854483
data: {
43864484
left: '[k: string];',
4387-
leftGroup: 'unknown',
4485+
leftGroup: 'index-signature',
43884486
right: 'a',
43894487
rightGroup: 'static-property',
43904488
},
@@ -4900,6 +4998,55 @@ describe(ruleName, () => {
49004998
},
49014999
],
49025000
})
5001+
5002+
ruleTester.run(`${ruleName}(${type}): should ignore unknown group`, rule, {
5003+
valid: [],
5004+
invalid: [
5005+
{
5006+
code: dedent`
5007+
class Class {
5008+
5009+
public i = 'i';
5010+
private z() {}
5011+
public method3() {}
5012+
private y() {}
5013+
public method4() {}
5014+
public method1() {}
5015+
private x() {}
5016+
}
5017+
`,
5018+
output: dedent`
5019+
class Class {
5020+
5021+
private z() {}
5022+
private y() {}
5023+
public method3() {}
5024+
private x() {}
5025+
public method4() {}
5026+
public method1() {}
5027+
public i = 'i';
5028+
}
5029+
`,
5030+
options: [
5031+
{
5032+
...options,
5033+
groups: ['private-method', 'property'],
5034+
},
5035+
],
5036+
errors: [
5037+
{
5038+
messageId: 'unexpectedClassesGroupOrder',
5039+
data: {
5040+
left: 'i',
5041+
leftGroup: 'property',
5042+
right: 'z',
5043+
rightGroup: 'private-method',
5044+
},
5045+
},
5046+
],
5047+
},
5048+
],
5049+
})
49035050
})
49045051

49055052
describe(`${ruleName}: misc`, () => {

0 commit comments

Comments
 (0)