Skip to content

Commit df3cd2b

Browse files
committed
revamp plugin logic & enable all enums
1 parent b0e6e34 commit df3cd2b

34 files changed

+1264
-367
lines changed

docs/rules/enum.md

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
# require enum members to be sorted (enum)
2+
3+
When declaring multiple members on an enum, some developers prefer to sort enum member names alphabetically to be able to find necessary members easier at the later time. Others feel that it adds complexity and becomes burden to maintain.
4+
5+
## Rule Details
6+
7+
This rule checks all members of an enum declaration and verifies that all keys are sorted alphabetically.
8+
9+
Examples of **incorrect** code for this rule:
10+
11+
```ts
12+
/* eslint typescript-sort-keys/enum: "error" */
13+
14+
enum U {
15+
a = 'T',
16+
c = 'T',
17+
b = 'T',
18+
}
19+
20+
// Case-sensitive by default.
21+
enum U {
22+
a = 'T',
23+
b = 'T',
24+
C = 'T',
25+
}
26+
27+
enum U {
28+
a = 'T',
29+
'c' = 'T',
30+
b = 'T',
31+
}
32+
```
33+
34+
Examples of **correct** code for this rule:
35+
36+
```ts
37+
/* eslint typescript-sort-keys/enum: "error" */
38+
39+
enum U {
40+
a = 'T',
41+
b = 'T',
42+
c = 'T',
43+
}
44+
45+
// Case-sensitive by default.
46+
enum U {
47+
C = 'T',
48+
a = 'T',
49+
b = 'T',
50+
}
51+
52+
// This rule sorts members which have an arbitrary string literal name as well.
53+
enum U {
54+
a = 'T',
55+
'b+-' = 'T',
56+
c = 'T',
57+
}
58+
```
59+
60+
## Options
61+
62+
```json
63+
{
64+
"typescript-sort-keys/enum": ["error", "asc", { "caseSensitive": true, "natural": false }]
65+
}
66+
```
67+
68+
The 1st option is `"asc"` or `"desc"`.
69+
70+
- `"asc"` (default) - enforce enum members to be in ascending order.
71+
- `"desc"` - enforce enum members to be in descending order.
72+
73+
The 2nd option is an object which has 2 properties.
74+
75+
- `caseSensitive` - if `true`, enforce enum members to be in case-sensitive order. Default is `true`.
76+
- `natural` - if `true`, enforce enum members to be in natural order. Default is `false`. Natural Order compares strings containing combination of letters and numbers in the way a human being would sort. It basically sorts numerically, instead of sorting alphabetically. So the number 10 comes after the number 3 in Natural Sorting.
77+
78+
### desc
79+
80+
Examples of **incorrect** code for the `"desc"` option:
81+
82+
```ts
83+
/* eslint typescript-sort-keys/enum: ["error", "desc"] */
84+
85+
enum U {
86+
b = 'T',
87+
c = 'T',
88+
a = 'T',
89+
}
90+
enum U {
91+
b = 'T',
92+
c = 'T',
93+
a = 'T',
94+
}
95+
96+
// Case-sensitive by default.
97+
enum U {
98+
a = 'T',
99+
B = 'T',
100+
c = 'T',
101+
}
102+
```
103+
104+
Examples of **correct** code for the `"desc"` option:
105+
106+
```ts
107+
/* eslint typescript-sort-keys/enum: ["error", "desc"] */
108+
109+
enum U {
110+
c = 'T',
111+
b = 'T',
112+
a = 'T',
113+
}
114+
enum U {
115+
c = 'T',
116+
b = 'T',
117+
a = 'T',
118+
}
119+
120+
// Case-sensitive by default.
121+
enum U {
122+
c = 'T',
123+
a = 'T',
124+
B = 'T',
125+
}
126+
```
127+
128+
### insensitive
129+
130+
Examples of **incorrect** code for the `{ caseSensitive: false }` option:
131+
132+
```ts
133+
/* eslint typescript-sort-keys/enum: ["error", "asc", { caseSensitive: false }] */
134+
135+
enum U {
136+
a = 'T',
137+
c = 'T',
138+
C = 'T',
139+
b = 'T',
140+
}
141+
enum U {
142+
a = 'T',
143+
C = 'T',
144+
c = 'T',
145+
b = 'T',
146+
}
147+
```
148+
149+
Examples of **correct** code for the `{ caseSensitive: false }` option:
150+
151+
```ts
152+
/* eslint typescript-sort-keys/enum: ["error", "asc", { caseSensitive: false }] */
153+
154+
enum U {
155+
a = 'T',
156+
b = 'T',
157+
c = 'T',
158+
C = 'T',
159+
}
160+
enum U {
161+
a = 'T',
162+
b = 'T',
163+
C = 'T',
164+
c = 'T',
165+
}
166+
```
167+
168+
### natural
169+
170+
Examples of **incorrect** code for the `{natural: true}` option:
171+
172+
```ts
173+
/* eslint typescript-sort-keys/enum: ["error", "asc", { natural: true }] */
174+
175+
enum U {
176+
a = 'T',
177+
_ = 'T',
178+
A = 'T',
179+
$ = 'T',
180+
}
181+
```
182+
183+
Examples of **correct** code for the `{natural: true}` option:
184+
185+
```ts
186+
/* eslint typescript-sort-keys/enum: ["error", "asc", { natural: true }] */
187+
188+
enum U {
189+
a = 'T',
190+
A = 'T',
191+
_ = 'T',
192+
$ = 'T',
193+
}
194+
```
195+
196+
## When Not To Use It
197+
198+
If you don't want to notify about enum members' order, then it's safe to disable this rule.

docs/rules/string-enum.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
# require string enum members to be sorted (string-enum)
1+
# Deprecation notice: This rule has been deprecated in favor of [typescript-sort-keys/enum](./enum.md). `string-enum` will continue to sort only string enums and may be removed in future updates.
22

3-
When declaring multiple members on an string enum, some developers prefer to sort enum member names alphabetically to be able to find necessary members easier at the later time. Others feel that it adds complexity and becomes burden to maintain.
3+
---
4+
5+
# require string-enum members to be sorted (string-enum)
6+
7+
When declaring multiple members on a string-enum, some developers prefer to sort string-enum member names alphabetically to be able to find necessary members easier at the later time. Others feel that it adds complexity and becomes burden to maintain.
48

59
## Rule Details
610

7-
This rule checks all members of a string enum declaration and verifies that all keys are sorted alphabetically.
11+
This rule checks all members of a string-enum declaration and verifies that all keys are sorted alphabetically.
812

913
Examples of **incorrect** code for this rule:
1014

@@ -77,13 +81,13 @@ enum U {
7781

7882
The 1st option is `"asc"` or `"desc"`.
7983

80-
- `"asc"` (default) - enforce enum members to be in ascending order.
81-
- `"desc"` - enforce enum members to be in descending order.
84+
- `"asc"` (default) - enforce string-enum members to be in ascending order.
85+
- `"desc"` - enforce string-enum members to be in descending order.
8286

8387
The 2nd option is an object which has 2 properties.
8488

85-
- `caseSensitive` - if `true`, enforce enum members to be in case-sensitive order. Default is `true`.
86-
- `natural` - if `true`, enforce enum members to be in natural order. Default is `false`. Natural Order compares strings containing combination of letters and numbers in the way a human being would sort. It basically sorts numerically, instead of sorting alphabetically. So the number 10 comes after the number 3 in Natural Sorting.
89+
- `caseSensitive` - if `true`, enforce string-enum members to be in case-sensitive order. Default is `true`.
90+
- `natural` - if `true`, enforce string-enum members to be in natural order. Default is `false`. Natural Order compares strings containing combination of letters and numbers in the way a human being would sort. It basically sorts numerically, instead of sorting alphabetically. So the number 10 comes after the number 3 in Natural Sorting.
8791

8892
### desc
8993

@@ -205,4 +209,4 @@ enum U {
205209

206210
## When Not To Use It
207211

208-
If you don't want to notify about enum members' order, then it's safe to disable this rule.
212+
If you don't want to notify about string-enum members' order, then it's safe to disable this rule.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "eslint-plugin-typescript-sort-keys",
33
"version": "3.1.0",
4-
"description": "Sort interface and string enum keys",
4+
"description": "Sort interface and enum keys",
55
"keywords": [
66
"eslint",
77
"eslintplugin",

src/common/options.ts

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,35 @@
1-
import { JSONSchema4 } from 'json-schema'
2-
3-
export enum SortingOrder {
4-
Ascending = 'asc',
5-
Descending = 'desc',
6-
}
7-
8-
export const sortingOrderOptionSchema: JSONSchema4 = {
9-
enum: [SortingOrder.Ascending, SortingOrder.Descending],
10-
}
11-
12-
export type SortingOrderOption = SortingOrder
13-
14-
interface CaseSensitiveSortingOption {
15-
readonly caseSensitive: boolean
16-
}
17-
18-
interface NaturalSortingOption {
19-
readonly natural: boolean
20-
}
21-
22-
interface RequiredFirstSortingOption {
23-
readonly requiredFirst: boolean
24-
}
25-
26-
export interface SortingParamsOptions {
27-
readonly caseSensitive: CaseSensitiveSortingOption
28-
readonly natural: NaturalSortingOption
29-
readonly requiredFirst: RequiredFirstSortingOption
1+
import {
2+
AllRuleOptions,
3+
CreateReporterArgs,
4+
SortingOrder,
5+
SortingParamsOptions,
6+
} from '../types'
7+
8+
export const defaultSortingOrder = SortingOrder.Ascending
9+
export const defaultOptions: SortingParamsOptions = {
10+
caseSensitive: true,
11+
natural: false,
12+
requiredFirst: false,
3013
}
3114

32-
export enum ErrorMessage {
33-
InterfaceInvalidOrder = `Expected interface keys to be in {{ requiredFirst }}{{ natural }}{{ insensitive }}{{ order }}ending order. '{{ thisName }}' should be before '{{ prevName }}'.`,
34-
StringEnumInvalidOrder = `Expected string enum members to be in {{ natural }}{{ insensitive }}{{ order }}ending order. '{{ thisName }}' should be before '{{ prevName }}'.`,
15+
/**
16+
* Get the options from the context
17+
*/
18+
export function getOptions(
19+
context: CreateReporterArgs<string, AllRuleOptions>['context'],
20+
) {
21+
const order = context.options[0] || defaultSortingOrder
22+
const options = context.options[1]
23+
const isAscending = order === SortingOrder.Ascending
24+
const isInsensitive = !(options?.caseSensitive ?? defaultOptions.caseSensitive)
25+
const isNatural = options?.natural ?? defaultOptions.natural
26+
const isRequiredFirst = options?.requiredFirst ?? defaultOptions.requiredFirst
27+
28+
return {
29+
isAscending,
30+
isInsensitive,
31+
isNatural,
32+
isRequiredFirst,
33+
order,
34+
}
3535
}

src/config/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const PLUGIN_NAME = 'typescript-sort-keys'

src/config/recommended.config.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { PLUGIN_NAME } from './constants'
2+
3+
export default {
4+
plugins: [PLUGIN_NAME],
5+
rules: {
6+
[`${PLUGIN_NAME}/interface`]: 'error' as const,
7+
[`${PLUGIN_NAME}/enum`]: 'error' as const,
8+
},
9+
}

src/config/recommended.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

src/config/requiredFirst.config.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Linter } from '@typescript-eslint/utils/ts-eslint'
2+
3+
import { defaultOptions, defaultSortingOrder } from '../common/options'
4+
import { PLUGIN_NAME } from './constants'
5+
import recommended from './recommended.config'
6+
7+
export default {
8+
plugins: recommended.plugins,
9+
rules: {
10+
...recommended.rules,
11+
[`${PLUGIN_NAME}/interface`]: [
12+
'error' as const,
13+
defaultSortingOrder,
14+
{ ...defaultOptions, requiredFirst: true },
15+
] as Linter.RuleEntry,
16+
},
17+
}

src/fixer.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { TSESLint } from '@typescript-eslint/utils'
2+
import { ReportFixFunction } from '@typescript-eslint/utils/ts-eslint'
3+
4+
import { AllRuleOptions, CreateReporterArgs, Node, SourceCode, TSType } from './types'
5+
import { getMemoized, memoize } from './utils/memo'
6+
import { getBodyRange, getFixedBodyText } from './utils/sourcecode'
7+
8+
export const getFixerFunction = (
9+
baseMemoKey: string,
10+
createReporterArgs: Pick<CreateReporterArgs<string, AllRuleOptions>, 'context'>,
11+
body: TSType[],
12+
sortedBody: TSType[],
13+
): ReportFixFunction =>
14+
function* (fixer: TSESLint.RuleFixer) {
15+
const sourceCode = createReporterArgs.context.getSourceCode() as SourceCode
16+
17+
const bodyRange = memoize(`bodyRange_${baseMemoKey}`, () =>
18+
getBodyRange(sourceCode, body as unknown as Node[]),
19+
)
20+
21+
const fixedBodyTextMemoKey = `fixedBodyText_${baseMemoKey}`
22+
// Replace the entire body with the sorted body
23+
const fixedBodyText =
24+
getMemoized(fixedBodyTextMemoKey) ??
25+
memoize(fixedBodyTextMemoKey, () =>
26+
getFixedBodyText(
27+
sourceCode,
28+
sortedBody as unknown as Node[],
29+
body as unknown as Node[],
30+
),
31+
)
32+
33+
yield fixer.replaceTextRange(bodyRange, fixedBodyText)
34+
}

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import recommended from './config/recommended'
1+
import recommended from './config/recommended.config'
22
import { rules } from './rules'
33

44
const config = {

0 commit comments

Comments
 (0)