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.
Files changed (50) hide show
  1. package/dist/index.d.ts +13 -9
  2. package/dist/rules/sort-array-includes.js +3 -1
  3. package/dist/rules/sort-array-includes.mjs +3 -1
  4. package/dist/rules/sort-astro-attributes.js +3 -1
  5. package/dist/rules/sort-astro-attributes.mjs +3 -1
  6. package/dist/rules/sort-classes-utils.js +99 -0
  7. package/dist/rules/sort-classes-utils.mjs +96 -0
  8. package/dist/rules/sort-classes.js +154 -77
  9. package/dist/rules/sort-classes.mjs +158 -77
  10. package/dist/rules/sort-enums.js +93 -6
  11. package/dist/rules/sort-enums.mjs +89 -6
  12. package/dist/rules/sort-exports.js +3 -1
  13. package/dist/rules/sort-exports.mjs +3 -1
  14. package/dist/rules/sort-imports.js +3 -1
  15. package/dist/rules/sort-imports.mjs +3 -1
  16. package/dist/rules/sort-interfaces.js +3 -1
  17. package/dist/rules/sort-interfaces.mjs +3 -1
  18. package/dist/rules/sort-intersection-types.js +3 -1
  19. package/dist/rules/sort-intersection-types.mjs +3 -1
  20. package/dist/rules/sort-jsx-props.js +3 -1
  21. package/dist/rules/sort-jsx-props.mjs +3 -1
  22. package/dist/rules/sort-maps.js +3 -1
  23. package/dist/rules/sort-maps.mjs +3 -1
  24. package/dist/rules/sort-named-exports.js +3 -1
  25. package/dist/rules/sort-named-exports.mjs +3 -1
  26. package/dist/rules/sort-named-imports.js +3 -1
  27. package/dist/rules/sort-named-imports.mjs +3 -1
  28. package/dist/rules/sort-object-types.js +3 -1
  29. package/dist/rules/sort-object-types.mjs +3 -1
  30. package/dist/rules/sort-objects.js +3 -1
  31. package/dist/rules/sort-objects.mjs +3 -1
  32. package/dist/rules/sort-svelte-attributes.js +3 -1
  33. package/dist/rules/sort-svelte-attributes.mjs +3 -1
  34. package/dist/rules/sort-switch-case.js +9 -4
  35. package/dist/rules/sort-switch-case.mjs +9 -4
  36. package/dist/rules/sort-union-types.js +3 -1
  37. package/dist/rules/sort-union-types.mjs +3 -1
  38. package/dist/rules/sort-variable-declarations.js +3 -1
  39. package/dist/rules/sort-variable-declarations.mjs +3 -1
  40. package/dist/rules/sort-vue-attributes.js +2 -1
  41. package/dist/rules/sort-vue-attributes.mjs +2 -1
  42. package/dist/utils/compare.js +12 -7
  43. package/dist/utils/compare.mjs +12 -7
  44. package/dist/utils/complete.js +2 -1
  45. package/dist/utils/complete.mjs +2 -1
  46. package/dist/utils/get-settings.js +30 -0
  47. package/dist/utils/get-settings.mjs +28 -0
  48. package/dist/utils/use-groups.js +2 -1
  49. package/dist/utils/use-groups.mjs +2 -1
  50. 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 options = complete(context.options.at(0), {
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 isPrivate = name.startsWith('_') || name.startsWith('#')
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
- if (member.type === 'MethodDefinition') {
225
- if (member.kind === 'constructor') {
226
- defineGroup('constructor')
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
- let isProtectedMethod = member.accessibility === 'protected'
229
- let isPrivateMethod =
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 (isPrivateMethod && isStaticMethod) {
242
- defineGroup('static-private-method')
248
+ if (decorated) {
249
+ modifiers.push('decorated')
243
250
  }
244
- if (isPrivateMethod) {
245
- defineGroup('private-method')
251
+ if (member.override) {
252
+ modifiers.push('override')
246
253
  }
247
- if (isStaticMethod) {
248
- defineGroup('static-method')
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 (isProtectedMethod && isStaticMethod) {
251
- defineGroup('static-protected-method')
261
+ if (member.optional) {
262
+ modifiers.push('optional')
252
263
  }
253
- if (isProtectedMethod) {
254
- defineGroup('protected-method')
264
+ if (member.kind === 'constructor') {
265
+ selectors.push('constructor')
255
266
  }
256
267
  if (member.kind === 'get') {
257
- defineGroup('get-method')
268
+ selectors.push('get-method')
258
269
  }
259
270
  if (member.kind === 'set') {
260
- defineGroup('set-method')
271
+ selectors.push('set-method')
261
272
  }
262
- defineGroup('method')
273
+ selectors.push('method')
263
274
  } else if (member.type === 'TSIndexSignature') {
264
- defineGroup('index-signature')
265
- } else if (member.type === 'AccessorProperty') {
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
- if (member.accessibility === 'protected') {
268
- defineGroup('protected-decorated-accessor-property')
269
- }
270
- if (member.accessibility === 'private' || isPrivate) {
271
- defineGroup('private-decorated-accessor-property')
272
- }
273
- defineGroup('decorated-accessor-property')
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
- if (member.accessibility === 'protected') {
278
- defineGroup('protected-decorated-property')
279
- }
280
- if (member.accessibility === 'private' || isPrivate) {
281
- defineGroup('private-decorated-property')
282
- }
283
- defineGroup('decorated-property')
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
- defineGroup('protected-property')
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.accessibility === 'private' || isPrivate) {
289
- defineGroup('private-property')
334
+ if (member.optional) {
335
+ modifiers.push('optional')
290
336
  }
291
- if (member.static) {
292
- defineGroup('static-property')
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
- defineGroup('property')
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: rangeToDiff(member.range),
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
- left.name !== right.name &&
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: 'unexpectedClassesOrder',
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 grouped = nodes.reduce((accumulator, sortingNode) => {
405
+ let nodesByNonIgnoredGroupNumber = {}
406
+ let ignoredNodeIndices = []
407
+ for (let [index, sortingNode] of nodes.entries()) {
333
408
  let groupNum = getGroupNumber(options.groups, sortingNode)
334
- if (!(groupNum in accumulator)) {
335
- accumulator[groupNum] = [sortingNode]
336
- } else {
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
- return accumulator
343
- }, {})
413
+ nodesByNonIgnoredGroupNumber[groupNum] =
414
+ nodesByNonIgnoredGroupNumber[groupNum] ?? []
415
+ nodesByNonIgnoredGroupNumber[groupNum].push(sortingNode)
416
+ }
344
417
  let sortedNodes = []
345
- for (let group of Object.keys(grouped).sort(
346
- (a, b) => Number(a) - Number(b),
347
- )) {
348
- sortedNodes.push(...sortNodes(grouped[group], options))
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,
@@ -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
- getMembers(node).length > 1 &&
90
- getMembers(node).every(({ initializer }) => initializer)
102
+ members.length > 1 &&
103
+ members.every(({ initializer }) => initializer)
91
104
  ) {
92
- let options = complete.complete(context.options.at(0), {
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 formattedMembers = getMembers(node).reduce(
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 (isPositive.isPositive(compare.compare(left, right, options))) {
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, options),
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
- getMembers(node).length > 1 &&
89
- getMembers(node).every(({ initializer }) => initializer)
101
+ members.length > 1 &&
102
+ members.every(({ initializer }) => initializer)
90
103
  ) {
91
- let options = complete(context.options.at(0), {
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 formattedMembers = getMembers(node).reduce(
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, options))) {
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, options),
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 options = complete.complete(context.options.at(0), {
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',