11import type { TSESTree } from '@typescript-eslint/types'
22
3+ import type { CompareOptions } from '../utils/compare'
34import type { SortingNode } from '../typings'
45
56import { isPartitionComment } from '../utils/is-partition-comment'
@@ -17,11 +18,13 @@ import { compare } from '../utils/compare'
1718
1819type MESSAGE_ID = 'unexpectedEnumsOrder'
1920
20- type Options = [
21+ export type Options = [
2122 Partial < {
2223 type : 'alphabetical' | 'line-length' | 'natural'
2324 partitionByComment : string [ ] | boolean | string
25+ forceNumericSort : boolean
2426 order : 'desc' | 'asc'
27+ sortByValue : boolean
2528 ignoreCase : boolean
2629 } > ,
2730]
@@ -54,6 +57,15 @@ export default createEslintRule<Options, MESSAGE_ID>({
5457 'Controls whether sorting should be case-sensitive or not.' ,
5558 type : 'boolean' ,
5659 } ,
60+ sortByValue : {
61+ description : 'Compare enum values instead of names.' ,
62+ type : 'boolean' ,
63+ } ,
64+ forceNumericSort : {
65+ description :
66+ 'Will always sort numeric enums by their value regardless of the sort type specified.' ,
67+ type : 'boolean' ,
68+ } ,
5769 partitionByComment : {
5870 description :
5971 'Allows you to use comments to separate the class members into logical groups.' ,
@@ -85,7 +97,9 @@ export default createEslintRule<Options, MESSAGE_ID>({
8597 type : 'alphabetical' ,
8698 order : 'asc' ,
8799 ignoreCase : true ,
100+ sortByValue : false ,
88101 partitionByComment : false ,
102+ forceNumericSort : false ,
89103 } ,
90104 ] ,
91105 create : context => ( {
@@ -94,21 +108,24 @@ export default createEslintRule<Options, MESSAGE_ID>({
94108 /* v8 ignore next 2 */
95109 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
96110 node . body ?. members ?? nodeValue . members ?? [ ]
111+ let members = getMembers ( node )
97112 if (
98- getMembers ( node ) . length > 1 &&
99- getMembers ( node ) . every ( ( { initializer } ) => initializer )
113+ members . length > 1 &&
114+ members . every ( ( { initializer } ) => initializer )
100115 ) {
101116 let options = complete ( context . options . at ( 0 ) , {
102117 partitionByComment : false ,
103118 type : 'alphabetical' ,
104119 ignoreCase : true ,
105120 order : 'asc' ,
121+ sortByValue : false ,
122+ forceNumericSort : false ,
106123 } as const )
107124
108125 let sourceCode = getSourceCode ( context )
109126 let partitionComment = options . partitionByComment
110127
111- let formattedMembers : SortingNode [ ] [ ] = getMembers ( node ) . reduce (
128+ let formattedMembers : SortingNode [ ] [ ] = members . reduce (
112129 ( accumulator : SortingNode [ ] [ ] , member ) => {
113130 let comment = getCommentBefore ( member , sourceCode )
114131
@@ -135,10 +152,37 @@ export default createEslintRule<Options, MESSAGE_ID>({
135152 } ,
136153 [ [ ] ] ,
137154 )
155+ let isNumericEnum = members . every (
156+ member =>
157+ member . initializer ?. type === 'Literal' &&
158+ typeof member . initializer . value === 'number' ,
159+ )
138160
161+ let compareOptions : CompareOptions = {
162+ // If the enum is numeric, and we sort by value, always use the `natural` sort type, which will correctly sort them.
163+ type :
164+ isNumericEnum && ( options . forceNumericSort || options . sortByValue )
165+ ? 'natural'
166+ : options . type ,
167+ order : options . order ,
168+ ignoreCase : options . ignoreCase ,
169+ // Get the enum value rather than the name if needed
170+ nodeValueGetter :
171+ options . sortByValue || ( isNumericEnum && options . forceNumericSort )
172+ ? sortingNode => {
173+ if (
174+ sortingNode . node . type === 'TSEnumMember' &&
175+ sortingNode . node . initializer ?. type === 'Literal'
176+ ) {
177+ return sortingNode . node . initializer . value ?. toString ( ) ?? ''
178+ }
179+ return ''
180+ }
181+ : undefined ,
182+ }
139183 for ( let nodes of formattedMembers ) {
140184 pairwise ( nodes , ( left , right ) => {
141- if ( isPositive ( compare ( left , right , options ) ) ) {
185+ if ( isPositive ( compare ( left , right , compareOptions ) ) ) {
142186 context . report ( {
143187 messageId : 'unexpectedEnumsOrder' ,
144188 data : {
@@ -150,7 +194,7 @@ export default createEslintRule<Options, MESSAGE_ID>({
150194 makeFixes (
151195 fixer ,
152196 nodes ,
153- sortNodes ( nodes , options ) ,
197+ sortNodes ( nodes , compareOptions ) ,
154198 sourceCode ,
155199 { partitionComment } ,
156200 ) ,
0 commit comments