eslint-plugin-perfectionist 3.1.3 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +13 -9
- package/dist/rules/sort-array-includes.js +3 -1
- package/dist/rules/sort-array-includes.mjs +3 -1
- package/dist/rules/sort-astro-attributes.js +3 -1
- package/dist/rules/sort-astro-attributes.mjs +3 -1
- package/dist/rules/sort-classes-utils.js +99 -0
- package/dist/rules/sort-classes-utils.mjs +96 -0
- package/dist/rules/sort-classes.js +154 -77
- package/dist/rules/sort-classes.mjs +158 -77
- package/dist/rules/sort-enums.js +93 -6
- package/dist/rules/sort-enums.mjs +89 -6
- package/dist/rules/sort-exports.js +3 -1
- package/dist/rules/sort-exports.mjs +3 -1
- package/dist/rules/sort-imports.js +3 -1
- package/dist/rules/sort-imports.mjs +3 -1
- package/dist/rules/sort-interfaces.js +3 -1
- package/dist/rules/sort-interfaces.mjs +3 -1
- package/dist/rules/sort-intersection-types.js +3 -1
- package/dist/rules/sort-intersection-types.mjs +3 -1
- package/dist/rules/sort-jsx-props.js +3 -1
- package/dist/rules/sort-jsx-props.mjs +3 -1
- package/dist/rules/sort-maps.js +3 -1
- package/dist/rules/sort-maps.mjs +3 -1
- package/dist/rules/sort-named-exports.js +3 -1
- package/dist/rules/sort-named-exports.mjs +3 -1
- package/dist/rules/sort-named-imports.js +3 -1
- package/dist/rules/sort-named-imports.mjs +3 -1
- package/dist/rules/sort-object-types.js +3 -1
- package/dist/rules/sort-object-types.mjs +3 -1
- package/dist/rules/sort-objects.js +3 -1
- package/dist/rules/sort-objects.mjs +3 -1
- package/dist/rules/sort-svelte-attributes.js +3 -1
- package/dist/rules/sort-svelte-attributes.mjs +3 -1
- package/dist/rules/sort-switch-case.js +9 -4
- package/dist/rules/sort-switch-case.mjs +9 -4
- package/dist/rules/sort-union-types.js +3 -1
- package/dist/rules/sort-union-types.mjs +3 -1
- package/dist/rules/sort-variable-declarations.js +3 -1
- package/dist/rules/sort-variable-declarations.mjs +3 -1
- package/dist/rules/sort-vue-attributes.js +2 -1
- package/dist/rules/sort-vue-attributes.mjs +2 -1
- package/dist/utils/compare.js +12 -7
- package/dist/utils/compare.mjs +12 -7
- package/dist/utils/complete.js +2 -1
- package/dist/utils/complete.mjs +2 -1
- package/dist/utils/get-settings.js +30 -0
- package/dist/utils/get-settings.mjs +28 -0
- package/dist/utils/use-groups.js +2 -1
- package/dist/utils/use-groups.mjs +2 -1
- package/package.json +3 -3
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getOverloadSignatureGroups,
|
|
3
|
+
generateOfficialGroups,
|
|
4
|
+
} from './sort-classes-utils.mjs'
|
|
1
5
|
import { isPartitionComment } from '../utils/is-partition-comment.mjs'
|
|
2
6
|
import { getCommentBefore } from '../utils/get-comment-before.mjs'
|
|
3
7
|
import { createEslintRule } from '../utils/create-eslint-rule.mjs'
|
|
@@ -5,6 +9,7 @@ import { getGroupNumber } from '../utils/get-group-number.mjs'
|
|
|
5
9
|
import { getSourceCode } from '../utils/get-source-code.mjs'
|
|
6
10
|
import { toSingleLine } from '../utils/to-single-line.mjs'
|
|
7
11
|
import { rangeToDiff } from '../utils/range-to-diff.mjs'
|
|
12
|
+
import { getSettings } from '../utils/get-settings.mjs'
|
|
8
13
|
import { isPositive } from '../utils/is-positive.mjs'
|
|
9
14
|
import { useGroups } from '../utils/use-groups.mjs'
|
|
10
15
|
import { sortNodes } from '../utils/sort-nodes.mjs'
|
|
@@ -97,6 +102,8 @@ const sortClasses = createEslintRule({
|
|
|
97
102
|
},
|
|
98
103
|
],
|
|
99
104
|
messages: {
|
|
105
|
+
unexpectedClassesGroupOrder:
|
|
106
|
+
'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).',
|
|
100
107
|
unexpectedClassesOrder: 'Expected "{{right}}" to come before "{{left}}".',
|
|
101
108
|
},
|
|
102
109
|
},
|
|
@@ -107,11 +114,12 @@ const sortClasses = createEslintRule({
|
|
|
107
114
|
ignoreCase: true,
|
|
108
115
|
partitionByComment: false,
|
|
109
116
|
groups: [
|
|
117
|
+
'static-block',
|
|
110
118
|
'index-signature',
|
|
111
119
|
'static-property',
|
|
112
|
-
'protected-property',
|
|
113
|
-
'private-property',
|
|
114
|
-
'property',
|
|
120
|
+
['protected-property', 'protected-accessor-property'],
|
|
121
|
+
['private-property', 'private-accessor-property'],
|
|
122
|
+
['property', 'accessor-property'],
|
|
115
123
|
'constructor',
|
|
116
124
|
'static-method',
|
|
117
125
|
'protected-method',
|
|
@@ -126,13 +134,15 @@ const sortClasses = createEslintRule({
|
|
|
126
134
|
create: context => ({
|
|
127
135
|
ClassBody: node => {
|
|
128
136
|
if (node.body.length > 1) {
|
|
129
|
-
let
|
|
137
|
+
let settings = getSettings(context.settings)
|
|
138
|
+
let options = complete(context.options.at(0), settings, {
|
|
130
139
|
groups: [
|
|
140
|
+
'static-block',
|
|
131
141
|
'index-signature',
|
|
132
142
|
'static-property',
|
|
133
|
-
'protected-property',
|
|
134
|
-
'private-property',
|
|
135
|
-
'property',
|
|
143
|
+
['protected-property', 'protected-accessor-property'],
|
|
144
|
+
['private-property', 'private-accessor-property'],
|
|
145
|
+
['property', 'accessor-property'],
|
|
136
146
|
'constructor',
|
|
137
147
|
'static-method',
|
|
138
148
|
'protected-method',
|
|
@@ -186,9 +196,10 @@ const sortClasses = createEslintRule({
|
|
|
186
196
|
traverseNode(expression)
|
|
187
197
|
return dependencies
|
|
188
198
|
}
|
|
199
|
+
let overloadSignatureGroups = getOverloadSignatureGroups(node.body)
|
|
189
200
|
let formattedNodes = node.body.reduce(
|
|
190
201
|
(accumulator, member) => {
|
|
191
|
-
var _a
|
|
202
|
+
var _a, _b, _c, _d
|
|
192
203
|
let comment = getCommentBefore(member, sourceCode)
|
|
193
204
|
if (
|
|
194
205
|
options.partitionByComment &&
|
|
@@ -218,80 +229,126 @@ const sortClasses = createEslintRule({
|
|
|
218
229
|
name = sourceCode.text.slice(...member.key.range)
|
|
219
230
|
}
|
|
220
231
|
}
|
|
221
|
-
let
|
|
232
|
+
let isPrivateHash =
|
|
233
|
+
'key' in member && member.key.type === 'PrivateIdentifier'
|
|
222
234
|
let decorated =
|
|
223
235
|
'decorators' in member && member.decorators.length > 0
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
236
|
+
let modifiers = []
|
|
237
|
+
let selectors = []
|
|
238
|
+
if (
|
|
239
|
+
member.type === 'MethodDefinition' ||
|
|
240
|
+
member.type === 'TSAbstractMethodDefinition'
|
|
241
|
+
) {
|
|
242
|
+
if (member.static) {
|
|
243
|
+
modifiers.push('static')
|
|
227
244
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
member.accessibility === 'private' || isPrivate
|
|
231
|
-
let isStaticMethod = member.static
|
|
232
|
-
if (decorated) {
|
|
233
|
-
if (member.kind === 'get') {
|
|
234
|
-
defineGroup('decorated-get-method')
|
|
235
|
-
}
|
|
236
|
-
if (member.kind === 'set') {
|
|
237
|
-
defineGroup('decorated-set-method')
|
|
238
|
-
}
|
|
239
|
-
defineGroup('decorated-method')
|
|
245
|
+
if (member.type === 'TSAbstractMethodDefinition') {
|
|
246
|
+
modifiers.push('abstract')
|
|
240
247
|
}
|
|
241
|
-
if (
|
|
242
|
-
|
|
248
|
+
if (decorated) {
|
|
249
|
+
modifiers.push('decorated')
|
|
243
250
|
}
|
|
244
|
-
if (
|
|
245
|
-
|
|
251
|
+
if (member.override) {
|
|
252
|
+
modifiers.push('override')
|
|
246
253
|
}
|
|
247
|
-
if (
|
|
248
|
-
|
|
254
|
+
if (member.accessibility === 'protected') {
|
|
255
|
+
modifiers.push('protected')
|
|
256
|
+
} else if (member.accessibility === 'private' || isPrivateHash) {
|
|
257
|
+
modifiers.push('private')
|
|
258
|
+
} else {
|
|
259
|
+
modifiers.push('public')
|
|
249
260
|
}
|
|
250
|
-
if (
|
|
251
|
-
|
|
261
|
+
if (member.optional) {
|
|
262
|
+
modifiers.push('optional')
|
|
252
263
|
}
|
|
253
|
-
if (
|
|
254
|
-
|
|
264
|
+
if (member.kind === 'constructor') {
|
|
265
|
+
selectors.push('constructor')
|
|
255
266
|
}
|
|
256
267
|
if (member.kind === 'get') {
|
|
257
|
-
|
|
268
|
+
selectors.push('get-method')
|
|
258
269
|
}
|
|
259
270
|
if (member.kind === 'set') {
|
|
260
|
-
|
|
271
|
+
selectors.push('set-method')
|
|
261
272
|
}
|
|
262
|
-
|
|
273
|
+
selectors.push('method')
|
|
263
274
|
} else if (member.type === 'TSIndexSignature') {
|
|
264
|
-
|
|
265
|
-
|
|
275
|
+
if (member.static) {
|
|
276
|
+
modifiers.push('static')
|
|
277
|
+
}
|
|
278
|
+
if (member.readonly) {
|
|
279
|
+
modifiers.push('readonly')
|
|
280
|
+
}
|
|
281
|
+
selectors.push('index-signature')
|
|
282
|
+
} else if (member.type === 'StaticBlock') {
|
|
283
|
+
selectors.push('static-block')
|
|
284
|
+
} else if (
|
|
285
|
+
member.type === 'AccessorProperty' ||
|
|
286
|
+
member.type === 'TSAbstractAccessorProperty'
|
|
287
|
+
) {
|
|
288
|
+
if (member.static) {
|
|
289
|
+
modifiers.push('static')
|
|
290
|
+
}
|
|
291
|
+
if (member.type === 'TSAbstractAccessorProperty') {
|
|
292
|
+
modifiers.push('abstract')
|
|
293
|
+
}
|
|
266
294
|
if (decorated) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
295
|
+
modifiers.push('decorated')
|
|
296
|
+
}
|
|
297
|
+
if (member.override) {
|
|
298
|
+
modifiers.push('override')
|
|
299
|
+
}
|
|
300
|
+
if (member.accessibility === 'protected') {
|
|
301
|
+
modifiers.push('protected')
|
|
302
|
+
} else if (member.accessibility === 'private' || isPrivateHash) {
|
|
303
|
+
modifiers.push('private')
|
|
304
|
+
} else {
|
|
305
|
+
modifiers.push('public')
|
|
306
|
+
}
|
|
307
|
+
selectors.push('accessor-property')
|
|
308
|
+
} else {
|
|
309
|
+
if (member.static) {
|
|
310
|
+
modifiers.push('static')
|
|
311
|
+
}
|
|
312
|
+
if (member.declare) {
|
|
313
|
+
modifiers.push('declare')
|
|
314
|
+
}
|
|
315
|
+
if (member.type === 'TSAbstractPropertyDefinition') {
|
|
316
|
+
modifiers.push('abstract')
|
|
274
317
|
}
|
|
275
|
-
} else if (member.type === 'PropertyDefinition') {
|
|
276
318
|
if (decorated) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
319
|
+
modifiers.push('decorated')
|
|
320
|
+
}
|
|
321
|
+
if (member.override) {
|
|
322
|
+
modifiers.push('override')
|
|
323
|
+
}
|
|
324
|
+
if (member.readonly) {
|
|
325
|
+
modifiers.push('readonly')
|
|
284
326
|
}
|
|
285
327
|
if (member.accessibility === 'protected') {
|
|
286
|
-
|
|
328
|
+
modifiers.push('protected')
|
|
329
|
+
} else if (member.accessibility === 'private' || isPrivateHash) {
|
|
330
|
+
modifiers.push('private')
|
|
331
|
+
} else {
|
|
332
|
+
modifiers.push('public')
|
|
287
333
|
}
|
|
288
|
-
if (member.
|
|
289
|
-
|
|
334
|
+
if (member.optional) {
|
|
335
|
+
modifiers.push('optional')
|
|
290
336
|
}
|
|
291
|
-
if (
|
|
292
|
-
|
|
337
|
+
if (
|
|
338
|
+
((_b = member.value) == null ? void 0 : _b.type) ===
|
|
339
|
+
'ArrowFunctionExpression' ||
|
|
340
|
+
((_c = member.value) == null ? void 0 : _c.type) ===
|
|
341
|
+
'FunctionExpression'
|
|
342
|
+
) {
|
|
343
|
+
selectors.push('function-property')
|
|
293
344
|
}
|
|
294
|
-
|
|
345
|
+
selectors.push('property')
|
|
346
|
+
}
|
|
347
|
+
for (let officialGroup of generateOfficialGroups(
|
|
348
|
+
modifiers,
|
|
349
|
+
selectors,
|
|
350
|
+
)) {
|
|
351
|
+
defineGroup(officialGroup)
|
|
295
352
|
}
|
|
296
353
|
setCustomGroups(options.customGroups, name, {
|
|
297
354
|
override: true,
|
|
@@ -299,8 +356,16 @@ const sortClasses = createEslintRule({
|
|
|
299
356
|
if (member.type === 'PropertyDefinition' && member.value) {
|
|
300
357
|
dependencies = extractDependencies(member.value)
|
|
301
358
|
}
|
|
359
|
+
let overloadSignatureGroupMember =
|
|
360
|
+
(_d = overloadSignatureGroups.find(overloadSignatures =>
|
|
361
|
+
overloadSignatures.includes(member),
|
|
362
|
+
)) == null
|
|
363
|
+
? void 0
|
|
364
|
+
: _d.at(-1)
|
|
302
365
|
let value = {
|
|
303
|
-
size:
|
|
366
|
+
size: overloadSignatureGroupMember
|
|
367
|
+
? rangeToDiff(overloadSignatureGroupMember.range)
|
|
368
|
+
: rangeToDiff(member.range),
|
|
304
369
|
group: getGroup(),
|
|
305
370
|
node: member,
|
|
306
371
|
dependencies,
|
|
@@ -315,37 +380,53 @@ const sortClasses = createEslintRule({
|
|
|
315
380
|
pairwise(nodes, (left, right) => {
|
|
316
381
|
let leftNum = getGroupNumber(options.groups, left)
|
|
317
382
|
let rightNum = getGroupNumber(options.groups, right)
|
|
383
|
+
let isLeftOrRightIgnored =
|
|
384
|
+
leftNum === options.groups.length ||
|
|
385
|
+
rightNum === options.groups.length
|
|
318
386
|
if (
|
|
319
|
-
|
|
387
|
+
!isLeftOrRightIgnored &&
|
|
320
388
|
(leftNum > rightNum ||
|
|
321
389
|
(leftNum === rightNum &&
|
|
322
390
|
isPositive(compare(left, right, options))))
|
|
323
391
|
) {
|
|
324
392
|
context.report({
|
|
325
|
-
messageId:
|
|
393
|
+
messageId:
|
|
394
|
+
leftNum !== rightNum
|
|
395
|
+
? 'unexpectedClassesGroupOrder'
|
|
396
|
+
: 'unexpectedClassesOrder',
|
|
326
397
|
data: {
|
|
327
398
|
left: toSingleLine(left.name),
|
|
399
|
+
leftGroup: left.group,
|
|
328
400
|
right: toSingleLine(right.name),
|
|
401
|
+
rightGroup: right.group,
|
|
329
402
|
},
|
|
330
403
|
node: right.node,
|
|
331
404
|
fix: fixer => {
|
|
332
|
-
let
|
|
405
|
+
let nodesByNonIgnoredGroupNumber = {}
|
|
406
|
+
let ignoredNodeIndices = []
|
|
407
|
+
for (let [index, sortingNode] of nodes.entries()) {
|
|
333
408
|
let groupNum = getGroupNumber(options.groups, sortingNode)
|
|
334
|
-
if (
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
accumulator[groupNum] = sortNodes(
|
|
338
|
-
[...accumulator[groupNum], sortingNode],
|
|
339
|
-
options,
|
|
340
|
-
)
|
|
409
|
+
if (groupNum === options.groups.length) {
|
|
410
|
+
ignoredNodeIndices.push(index)
|
|
411
|
+
continue
|
|
341
412
|
}
|
|
342
|
-
|
|
343
|
-
|
|
413
|
+
nodesByNonIgnoredGroupNumber[groupNum] =
|
|
414
|
+
nodesByNonIgnoredGroupNumber[groupNum] ?? []
|
|
415
|
+
nodesByNonIgnoredGroupNumber[groupNum].push(sortingNode)
|
|
416
|
+
}
|
|
344
417
|
let sortedNodes = []
|
|
345
|
-
for (let
|
|
346
|
-
|
|
347
|
-
)) {
|
|
348
|
-
sortedNodes.push(
|
|
418
|
+
for (let groupNumber of Object.keys(
|
|
419
|
+
nodesByNonIgnoredGroupNumber,
|
|
420
|
+
).sort((a, b) => Number(a) - Number(b))) {
|
|
421
|
+
sortedNodes.push(
|
|
422
|
+
...sortNodes(
|
|
423
|
+
nodesByNonIgnoredGroupNumber[Number(groupNumber)],
|
|
424
|
+
options,
|
|
425
|
+
),
|
|
426
|
+
)
|
|
427
|
+
}
|
|
428
|
+
for (let ignoredIndex of ignoredNodeIndices) {
|
|
429
|
+
sortedNodes.splice(ignoredIndex, 0, nodes[ignoredIndex])
|
|
349
430
|
}
|
|
350
431
|
return makeFixes(fixer, nodes, sortedNodes, sourceCode, {
|
|
351
432
|
partitionComment: options.partitionByComment,
|
package/dist/rules/sort-enums.js
CHANGED
|
@@ -5,6 +5,7 @@ const getCommentBefore = require('../utils/get-comment-before.js')
|
|
|
5
5
|
const getSourceCode = require('../utils/get-source-code.js')
|
|
6
6
|
const toSingleLine = require('../utils/to-single-line.js')
|
|
7
7
|
const rangeToDiff = require('../utils/range-to-diff.js')
|
|
8
|
+
const getSettings = require('../utils/get-settings.js')
|
|
8
9
|
const isPositive = require('../utils/is-positive.js')
|
|
9
10
|
const sortNodes = require('../utils/sort-nodes.js')
|
|
10
11
|
const makeFixes = require('../utils/make-fixes.js')
|
|
@@ -39,6 +40,15 @@ const sortEnums = createEslintRule.createEslintRule({
|
|
|
39
40
|
'Controls whether sorting should be case-sensitive or not.',
|
|
40
41
|
type: 'boolean',
|
|
41
42
|
},
|
|
43
|
+
sortByValue: {
|
|
44
|
+
description: 'Compare enum values instead of names.',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
},
|
|
47
|
+
forceNumericSort: {
|
|
48
|
+
description:
|
|
49
|
+
'Will always sort numeric enums by their value regardless of the sort type specified.',
|
|
50
|
+
type: 'boolean',
|
|
51
|
+
},
|
|
42
52
|
partitionByComment: {
|
|
43
53
|
description:
|
|
44
54
|
'Allows you to use comments to separate the class members into logical groups.',
|
|
@@ -70,7 +80,9 @@ const sortEnums = createEslintRule.createEslintRule({
|
|
|
70
80
|
type: 'alphabetical',
|
|
71
81
|
order: 'asc',
|
|
72
82
|
ignoreCase: true,
|
|
83
|
+
sortByValue: false,
|
|
73
84
|
partitionByComment: false,
|
|
85
|
+
forceNumericSort: false,
|
|
74
86
|
},
|
|
75
87
|
],
|
|
76
88
|
create: context => ({
|
|
@@ -85,19 +97,46 @@ const sortEnums = createEslintRule.createEslintRule({
|
|
|
85
97
|
[]
|
|
86
98
|
)
|
|
87
99
|
}
|
|
100
|
+
let members = getMembers(node)
|
|
88
101
|
if (
|
|
89
|
-
|
|
90
|
-
|
|
102
|
+
members.length > 1 &&
|
|
103
|
+
members.every(({ initializer }) => initializer)
|
|
91
104
|
) {
|
|
92
|
-
let
|
|
105
|
+
let settings = getSettings.getSettings(context.settings)
|
|
106
|
+
let options = complete.complete(context.options.at(0), settings, {
|
|
93
107
|
partitionByComment: false,
|
|
94
108
|
type: 'alphabetical',
|
|
95
109
|
ignoreCase: true,
|
|
96
110
|
order: 'asc',
|
|
111
|
+
sortByValue: false,
|
|
112
|
+
forceNumericSort: false,
|
|
97
113
|
})
|
|
98
114
|
let sourceCode = getSourceCode.getSourceCode(context)
|
|
99
115
|
let partitionComment = options.partitionByComment
|
|
100
|
-
let
|
|
116
|
+
let extractDependencies = (expression, enumName) => {
|
|
117
|
+
let dependencies = []
|
|
118
|
+
let checkNode = nodeValue => {
|
|
119
|
+
if (
|
|
120
|
+
nodeValue.type === 'MemberExpression' &&
|
|
121
|
+
nodeValue.object.type === 'Identifier' &&
|
|
122
|
+
nodeValue.object.name === enumName &&
|
|
123
|
+
nodeValue.property.type === 'Identifier'
|
|
124
|
+
) {
|
|
125
|
+
dependencies.push(nodeValue.property.name)
|
|
126
|
+
} else if (nodeValue.type === 'Identifier') {
|
|
127
|
+
dependencies.push(nodeValue.name)
|
|
128
|
+
}
|
|
129
|
+
if ('left' in nodeValue) {
|
|
130
|
+
checkNode(nodeValue.left)
|
|
131
|
+
}
|
|
132
|
+
if ('right' in nodeValue) {
|
|
133
|
+
checkNode(nodeValue.right)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
checkNode(expression)
|
|
137
|
+
return dependencies
|
|
138
|
+
}
|
|
139
|
+
let formattedMembers = members.reduce(
|
|
101
140
|
(accumulator, member) => {
|
|
102
141
|
let comment = getCommentBefore.getCommentBefore(member, sourceCode)
|
|
103
142
|
if (
|
|
@@ -114,9 +153,17 @@ const sortEnums = createEslintRule.createEslintRule({
|
|
|
114
153
|
member.id.type === 'Literal'
|
|
115
154
|
? `${member.id.value}`
|
|
116
155
|
: `${sourceCode.text.slice(...member.id.range)}`
|
|
156
|
+
let dependencies
|
|
157
|
+
if (member.initializer) {
|
|
158
|
+
dependencies = extractDependencies(
|
|
159
|
+
member.initializer,
|
|
160
|
+
node.id.name,
|
|
161
|
+
)
|
|
162
|
+
}
|
|
117
163
|
let sortingNode = {
|
|
118
164
|
size: rangeToDiff.rangeToDiff(member.range),
|
|
119
165
|
node: member,
|
|
166
|
+
dependencies,
|
|
120
167
|
name,
|
|
121
168
|
}
|
|
122
169
|
accumulator.at(-1).push(sortingNode)
|
|
@@ -124,9 +171,49 @@ const sortEnums = createEslintRule.createEslintRule({
|
|
|
124
171
|
},
|
|
125
172
|
[[]],
|
|
126
173
|
)
|
|
174
|
+
let isNumericEnum = members.every(member => {
|
|
175
|
+
var _a
|
|
176
|
+
return (
|
|
177
|
+
((_a = member.initializer) == null ? void 0 : _a.type) ===
|
|
178
|
+
'Literal' && typeof member.initializer.value === 'number'
|
|
179
|
+
)
|
|
180
|
+
})
|
|
181
|
+
let compareOptions = {
|
|
182
|
+
// If the enum is numeric, and we sort by value, always use the `natural` sort type, which will correctly sort them.
|
|
183
|
+
type:
|
|
184
|
+
isNumericEnum && (options.forceNumericSort || options.sortByValue)
|
|
185
|
+
? 'natural'
|
|
186
|
+
: options.type,
|
|
187
|
+
order: options.order,
|
|
188
|
+
ignoreCase: options.ignoreCase,
|
|
189
|
+
// Get the enum value rather than the name if needed
|
|
190
|
+
nodeValueGetter:
|
|
191
|
+
options.sortByValue || (isNumericEnum && options.forceNumericSort)
|
|
192
|
+
? sortingNode => {
|
|
193
|
+
var _a, _b
|
|
194
|
+
if (
|
|
195
|
+
sortingNode.node.type === 'TSEnumMember' &&
|
|
196
|
+
((_a = sortingNode.node.initializer) == null
|
|
197
|
+
? void 0
|
|
198
|
+
: _a.type) === 'Literal'
|
|
199
|
+
) {
|
|
200
|
+
return (
|
|
201
|
+
((_b = sortingNode.node.initializer.value) == null
|
|
202
|
+
? void 0
|
|
203
|
+
: _b.toString()) ?? ''
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
return ''
|
|
207
|
+
}
|
|
208
|
+
: void 0,
|
|
209
|
+
}
|
|
127
210
|
for (let nodes of formattedMembers) {
|
|
128
211
|
pairwise.pairwise(nodes, (left, right) => {
|
|
129
|
-
if (
|
|
212
|
+
if (
|
|
213
|
+
isPositive.isPositive(
|
|
214
|
+
compare.compare(left, right, compareOptions),
|
|
215
|
+
)
|
|
216
|
+
) {
|
|
130
217
|
context.report({
|
|
131
218
|
messageId: 'unexpectedEnumsOrder',
|
|
132
219
|
data: {
|
|
@@ -138,7 +225,7 @@ const sortEnums = createEslintRule.createEslintRule({
|
|
|
138
225
|
makeFixes.makeFixes(
|
|
139
226
|
fixer,
|
|
140
227
|
nodes,
|
|
141
|
-
sortNodes.sortNodes(nodes,
|
|
228
|
+
sortNodes.sortNodes(nodes, compareOptions),
|
|
142
229
|
sourceCode,
|
|
143
230
|
{ partitionComment },
|
|
144
231
|
),
|
|
@@ -4,6 +4,7 @@ import { getCommentBefore } from '../utils/get-comment-before.mjs'
|
|
|
4
4
|
import { getSourceCode } from '../utils/get-source-code.mjs'
|
|
5
5
|
import { toSingleLine } from '../utils/to-single-line.mjs'
|
|
6
6
|
import { rangeToDiff } from '../utils/range-to-diff.mjs'
|
|
7
|
+
import { getSettings } from '../utils/get-settings.mjs'
|
|
7
8
|
import { isPositive } from '../utils/is-positive.mjs'
|
|
8
9
|
import { sortNodes } from '../utils/sort-nodes.mjs'
|
|
9
10
|
import { makeFixes } from '../utils/make-fixes.mjs'
|
|
@@ -38,6 +39,15 @@ const sortEnums = createEslintRule({
|
|
|
38
39
|
'Controls whether sorting should be case-sensitive or not.',
|
|
39
40
|
type: 'boolean',
|
|
40
41
|
},
|
|
42
|
+
sortByValue: {
|
|
43
|
+
description: 'Compare enum values instead of names.',
|
|
44
|
+
type: 'boolean',
|
|
45
|
+
},
|
|
46
|
+
forceNumericSort: {
|
|
47
|
+
description:
|
|
48
|
+
'Will always sort numeric enums by their value regardless of the sort type specified.',
|
|
49
|
+
type: 'boolean',
|
|
50
|
+
},
|
|
41
51
|
partitionByComment: {
|
|
42
52
|
description:
|
|
43
53
|
'Allows you to use comments to separate the class members into logical groups.',
|
|
@@ -69,7 +79,9 @@ const sortEnums = createEslintRule({
|
|
|
69
79
|
type: 'alphabetical',
|
|
70
80
|
order: 'asc',
|
|
71
81
|
ignoreCase: true,
|
|
82
|
+
sortByValue: false,
|
|
72
83
|
partitionByComment: false,
|
|
84
|
+
forceNumericSort: false,
|
|
73
85
|
},
|
|
74
86
|
],
|
|
75
87
|
create: context => ({
|
|
@@ -84,19 +96,46 @@ const sortEnums = createEslintRule({
|
|
|
84
96
|
[]
|
|
85
97
|
)
|
|
86
98
|
}
|
|
99
|
+
let members = getMembers(node)
|
|
87
100
|
if (
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
members.length > 1 &&
|
|
102
|
+
members.every(({ initializer }) => initializer)
|
|
90
103
|
) {
|
|
91
|
-
let
|
|
104
|
+
let settings = getSettings(context.settings)
|
|
105
|
+
let options = complete(context.options.at(0), settings, {
|
|
92
106
|
partitionByComment: false,
|
|
93
107
|
type: 'alphabetical',
|
|
94
108
|
ignoreCase: true,
|
|
95
109
|
order: 'asc',
|
|
110
|
+
sortByValue: false,
|
|
111
|
+
forceNumericSort: false,
|
|
96
112
|
})
|
|
97
113
|
let sourceCode = getSourceCode(context)
|
|
98
114
|
let partitionComment = options.partitionByComment
|
|
99
|
-
let
|
|
115
|
+
let extractDependencies = (expression, enumName) => {
|
|
116
|
+
let dependencies = []
|
|
117
|
+
let checkNode = nodeValue => {
|
|
118
|
+
if (
|
|
119
|
+
nodeValue.type === 'MemberExpression' &&
|
|
120
|
+
nodeValue.object.type === 'Identifier' &&
|
|
121
|
+
nodeValue.object.name === enumName &&
|
|
122
|
+
nodeValue.property.type === 'Identifier'
|
|
123
|
+
) {
|
|
124
|
+
dependencies.push(nodeValue.property.name)
|
|
125
|
+
} else if (nodeValue.type === 'Identifier') {
|
|
126
|
+
dependencies.push(nodeValue.name)
|
|
127
|
+
}
|
|
128
|
+
if ('left' in nodeValue) {
|
|
129
|
+
checkNode(nodeValue.left)
|
|
130
|
+
}
|
|
131
|
+
if ('right' in nodeValue) {
|
|
132
|
+
checkNode(nodeValue.right)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
checkNode(expression)
|
|
136
|
+
return dependencies
|
|
137
|
+
}
|
|
138
|
+
let formattedMembers = members.reduce(
|
|
100
139
|
(accumulator, member) => {
|
|
101
140
|
let comment = getCommentBefore(member, sourceCode)
|
|
102
141
|
if (
|
|
@@ -110,9 +149,17 @@ const sortEnums = createEslintRule({
|
|
|
110
149
|
member.id.type === 'Literal'
|
|
111
150
|
? `${member.id.value}`
|
|
112
151
|
: `${sourceCode.text.slice(...member.id.range)}`
|
|
152
|
+
let dependencies
|
|
153
|
+
if (member.initializer) {
|
|
154
|
+
dependencies = extractDependencies(
|
|
155
|
+
member.initializer,
|
|
156
|
+
node.id.name,
|
|
157
|
+
)
|
|
158
|
+
}
|
|
113
159
|
let sortingNode = {
|
|
114
160
|
size: rangeToDiff(member.range),
|
|
115
161
|
node: member,
|
|
162
|
+
dependencies,
|
|
116
163
|
name,
|
|
117
164
|
}
|
|
118
165
|
accumulator.at(-1).push(sortingNode)
|
|
@@ -120,9 +167,45 @@ const sortEnums = createEslintRule({
|
|
|
120
167
|
},
|
|
121
168
|
[[]],
|
|
122
169
|
)
|
|
170
|
+
let isNumericEnum = members.every(member => {
|
|
171
|
+
var _a
|
|
172
|
+
return (
|
|
173
|
+
((_a = member.initializer) == null ? void 0 : _a.type) ===
|
|
174
|
+
'Literal' && typeof member.initializer.value === 'number'
|
|
175
|
+
)
|
|
176
|
+
})
|
|
177
|
+
let compareOptions = {
|
|
178
|
+
// If the enum is numeric, and we sort by value, always use the `natural` sort type, which will correctly sort them.
|
|
179
|
+
type:
|
|
180
|
+
isNumericEnum && (options.forceNumericSort || options.sortByValue)
|
|
181
|
+
? 'natural'
|
|
182
|
+
: options.type,
|
|
183
|
+
order: options.order,
|
|
184
|
+
ignoreCase: options.ignoreCase,
|
|
185
|
+
// Get the enum value rather than the name if needed
|
|
186
|
+
nodeValueGetter:
|
|
187
|
+
options.sortByValue || (isNumericEnum && options.forceNumericSort)
|
|
188
|
+
? sortingNode => {
|
|
189
|
+
var _a, _b
|
|
190
|
+
if (
|
|
191
|
+
sortingNode.node.type === 'TSEnumMember' &&
|
|
192
|
+
((_a = sortingNode.node.initializer) == null
|
|
193
|
+
? void 0
|
|
194
|
+
: _a.type) === 'Literal'
|
|
195
|
+
) {
|
|
196
|
+
return (
|
|
197
|
+
((_b = sortingNode.node.initializer.value) == null
|
|
198
|
+
? void 0
|
|
199
|
+
: _b.toString()) ?? ''
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
return ''
|
|
203
|
+
}
|
|
204
|
+
: void 0,
|
|
205
|
+
}
|
|
123
206
|
for (let nodes of formattedMembers) {
|
|
124
207
|
pairwise(nodes, (left, right) => {
|
|
125
|
-
if (isPositive(compare(left, right,
|
|
208
|
+
if (isPositive(compare(left, right, compareOptions))) {
|
|
126
209
|
context.report({
|
|
127
210
|
messageId: 'unexpectedEnumsOrder',
|
|
128
211
|
data: {
|
|
@@ -134,7 +217,7 @@ const sortEnums = createEslintRule({
|
|
|
134
217
|
makeFixes(
|
|
135
218
|
fixer,
|
|
136
219
|
nodes,
|
|
137
|
-
sortNodes(nodes,
|
|
220
|
+
sortNodes(nodes, compareOptions),
|
|
138
221
|
sourceCode,
|
|
139
222
|
{ partitionComment },
|
|
140
223
|
),
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
const createEslintRule = require('../utils/create-eslint-rule.js')
|
|
3
3
|
const getSourceCode = require('../utils/get-source-code.js')
|
|
4
4
|
const rangeToDiff = require('../utils/range-to-diff.js')
|
|
5
|
+
const getSettings = require('../utils/get-settings.js')
|
|
5
6
|
const isPositive = require('../utils/is-positive.js')
|
|
6
7
|
const sortNodes = require('../utils/sort-nodes.js')
|
|
7
8
|
const makeFixes = require('../utils/make-fixes.js')
|
|
@@ -52,7 +53,8 @@ const sortExports = createEslintRule.createEslintRule({
|
|
|
52
53
|
},
|
|
53
54
|
],
|
|
54
55
|
create: context => {
|
|
55
|
-
let
|
|
56
|
+
let settings = getSettings.getSettings(context.settings)
|
|
57
|
+
let options = complete.complete(context.options.at(0), settings, {
|
|
56
58
|
type: 'alphabetical',
|
|
57
59
|
ignoreCase: true,
|
|
58
60
|
order: 'asc',
|