eslint-plugin-perfectionist 3.1.3 → 3.2.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 +68 -0
  7. package/dist/rules/sort-classes-utils.mjs +66 -0
  8. package/dist/rules/sort-classes.js +106 -57
  9. package/dist/rules/sort-classes.mjs +106 -57
  10. package/dist/rules/sort-enums.js +62 -6
  11. package/dist/rules/sort-enums.mjs +58 -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 +3 -1
  35. package/dist/rules/sort-switch-case.mjs +3 -1
  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
package/dist/index.d.ts CHANGED
@@ -266,7 +266,7 @@ declare const _default: {
266
266
  RuleListener
267
267
  >
268
268
  'sort-classes': RuleModule<
269
- 'unexpectedClassesOrder',
269
+ 'unexpectedClassesGroupOrder' | 'unexpectedClassesOrder',
270
270
  [
271
271
  Partial<{
272
272
  customGroups: {
@@ -348,14 +348,7 @@ declare const _default: {
348
348
  >
349
349
  'sort-enums': RuleModule<
350
350
  'unexpectedEnumsOrder',
351
- [
352
- Partial<{
353
- type: 'alphabetical' | 'line-length' | 'natural'
354
- partitionByComment: string[] | boolean | string
355
- order: 'desc' | 'asc'
356
- ignoreCase: boolean
357
- }>,
358
- ],
351
+ Options,
359
352
  unknown,
360
353
  RuleListener
361
354
  >
@@ -375,5 +368,16 @@ declare const _default: {
375
368
  name: string
376
369
  }
377
370
 
371
+ declare type Options = [
372
+ Partial<{
373
+ type: 'alphabetical' | 'line-length' | 'natural'
374
+ partitionByComment: string[] | boolean | string
375
+ forceNumericSort: boolean
376
+ order: 'desc' | 'asc'
377
+ sortByValue: boolean
378
+ ignoreCase: boolean
379
+ }>,
380
+ ]
381
+
378
382
  export {}
379
383
  export = _default
@@ -4,6 +4,7 @@ const getGroupNumber = require('../utils/get-group-number.js')
4
4
  const getSourceCode = require('../utils/get-source-code.js')
5
5
  const toSingleLine = require('../utils/to-single-line.js')
6
6
  const rangeToDiff = require('../utils/range-to-diff.js')
7
+ const getSettings = require('../utils/get-settings.js')
7
8
  const isPositive = require('../utils/is-positive.js')
8
9
  const sortNodes = require('../utils/sort-nodes.js')
9
10
  const makeFixes = require('../utils/make-fixes.js')
@@ -72,8 +73,9 @@ const sortArrayIncludes = createEslintRule.createEslintRule({
72
73
  node.object.type === 'ArrayExpression'
73
74
  ? node.object.elements
74
75
  : node.object.arguments
76
+ let settings = getSettings.getSettings(context.settings)
75
77
  if (elements.length > 1) {
76
- let options = complete.complete(context.options.at(0), {
78
+ let options = complete.complete(context.options.at(0), settings, {
77
79
  groupKind: 'literals-first',
78
80
  type: 'alphabetical',
79
81
  ignoreCase: true,
@@ -3,6 +3,7 @@ import { getGroupNumber } from '../utils/get-group-number.mjs'
3
3
  import { getSourceCode } from '../utils/get-source-code.mjs'
4
4
  import { toSingleLine } from '../utils/to-single-line.mjs'
5
5
  import { rangeToDiff } from '../utils/range-to-diff.mjs'
6
+ import { getSettings } from '../utils/get-settings.mjs'
6
7
  import { isPositive } from '../utils/is-positive.mjs'
7
8
  import { sortNodes } from '../utils/sort-nodes.mjs'
8
9
  import { makeFixes } from '../utils/make-fixes.mjs'
@@ -71,8 +72,9 @@ const sortArrayIncludes = createEslintRule({
71
72
  node.object.type === 'ArrayExpression'
72
73
  ? node.object.elements
73
74
  : node.object.arguments
75
+ let settings = getSettings(context.settings)
74
76
  if (elements.length > 1) {
75
- let options = complete(context.options.at(0), {
77
+ let options = complete(context.options.at(0), settings, {
76
78
  groupKind: 'literals-first',
77
79
  type: 'alphabetical',
78
80
  ignoreCase: true,
@@ -4,6 +4,7 @@ const createEslintRule = require('../utils/create-eslint-rule.js')
4
4
  const getGroupNumber = require('../utils/get-group-number.js')
5
5
  const getSourceCode = require('../utils/get-source-code.js')
6
6
  const rangeToDiff = require('../utils/range-to-diff.js')
7
+ const getSettings = require('../utils/get-settings.js')
7
8
  const isPositive = require('../utils/is-positive.js')
8
9
  const useGroups = require('../utils/use-groups.js')
9
10
  const makeFixes = require('../utils/make-fixes.js')
@@ -100,7 +101,8 @@ const sortAstroAttributes = createEslintRule.createEslintRule({
100
101
  JSXElement: node => {
101
102
  let { attributes } = node.openingElement
102
103
  if (attributes.length > 1) {
103
- let options = complete.complete(context.options.at(0), {
104
+ let settings = getSettings.getSettings(context.settings)
105
+ let options = complete.complete(context.options.at(0), settings, {
104
106
  type: 'alphabetical',
105
107
  ignoreCase: true,
106
108
  customGroups: {},
@@ -3,6 +3,7 @@ import { createEslintRule } from '../utils/create-eslint-rule.mjs'
3
3
  import { getGroupNumber } from '../utils/get-group-number.mjs'
4
4
  import { getSourceCode } from '../utils/get-source-code.mjs'
5
5
  import { rangeToDiff } from '../utils/range-to-diff.mjs'
6
+ import { getSettings } from '../utils/get-settings.mjs'
6
7
  import { isPositive } from '../utils/is-positive.mjs'
7
8
  import { useGroups } from '../utils/use-groups.mjs'
8
9
  import { makeFixes } from '../utils/make-fixes.mjs'
@@ -99,7 +100,8 @@ const sortAstroAttributes = createEslintRule({
99
100
  JSXElement: node => {
100
101
  let { attributes } = node.openingElement
101
102
  if (attributes.length > 1) {
102
- let options = complete(context.options.at(0), {
103
+ let settings = getSettings(context.settings)
104
+ let options = complete(context.options.at(0), settings, {
103
105
  type: 'alphabetical',
104
106
  ignoreCase: true,
105
107
  customGroups: {},
@@ -0,0 +1,68 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
3
+ const cachedGroupsByModifiersAndSelectors = /* @__PURE__ */ new Map()
4
+ const generateOfficialGroups = (modifiers, selectors) => {
5
+ let modifiersAndSelectorsKey = modifiers.join('&') + '/' + selectors.join('&')
6
+ let cachedValue = cachedGroupsByModifiersAndSelectors.get(
7
+ modifiersAndSelectorsKey,
8
+ )
9
+ if (cachedValue) {
10
+ return cachedValue
11
+ }
12
+ let allModifiersCombinations = []
13
+ for (let i = modifiers.length; i > 0; i--) {
14
+ allModifiersCombinations = [
15
+ ...allModifiersCombinations,
16
+ ...getCombinations(modifiers, i),
17
+ ]
18
+ }
19
+ let allModifiersCombinationPermutations = allModifiersCombinations.flatMap(
20
+ result => getPermutations(result),
21
+ )
22
+ let returnValue = []
23
+ for (let selector of selectors) {
24
+ returnValue = [
25
+ ...returnValue,
26
+ ...allModifiersCombinationPermutations.map(
27
+ modifiersCombinationPermutation =>
28
+ [...modifiersCombinationPermutation, selector].join('-'),
29
+ ),
30
+ selector,
31
+ ]
32
+ }
33
+ cachedGroupsByModifiersAndSelectors.set(modifiersAndSelectorsKey, returnValue)
34
+ return returnValue
35
+ }
36
+ const getCombinations = (array, n) => {
37
+ let result = []
38
+ let backtrack = (start, comb) => {
39
+ if (comb.length === n) {
40
+ result.push([...comb])
41
+ return
42
+ }
43
+ for (let i = start; i < array.length; i++) {
44
+ comb.push(array[i])
45
+ backtrack(i + 1, comb)
46
+ comb.pop()
47
+ }
48
+ }
49
+ backtrack(0, [])
50
+ return result
51
+ }
52
+ const getPermutations = elements => {
53
+ let result = []
54
+ let backtrack = first => {
55
+ if (first === elements.length) {
56
+ result.push([...elements])
57
+ return
58
+ }
59
+ for (let i = first; i < elements.length; i++) {
60
+ ;[elements[first], elements[i]] = [elements[i], elements[first]]
61
+ backtrack(first + 1)
62
+ ;[elements[first], elements[i]] = [elements[i], elements[first]]
63
+ }
64
+ }
65
+ backtrack(0)
66
+ return result
67
+ }
68
+ exports.generateOfficialGroups = generateOfficialGroups
@@ -0,0 +1,66 @@
1
+ const cachedGroupsByModifiersAndSelectors = /* @__PURE__ */ new Map()
2
+ const generateOfficialGroups = (modifiers, selectors) => {
3
+ let modifiersAndSelectorsKey = modifiers.join('&') + '/' + selectors.join('&')
4
+ let cachedValue = cachedGroupsByModifiersAndSelectors.get(
5
+ modifiersAndSelectorsKey,
6
+ )
7
+ if (cachedValue) {
8
+ return cachedValue
9
+ }
10
+ let allModifiersCombinations = []
11
+ for (let i = modifiers.length; i > 0; i--) {
12
+ allModifiersCombinations = [
13
+ ...allModifiersCombinations,
14
+ ...getCombinations(modifiers, i),
15
+ ]
16
+ }
17
+ let allModifiersCombinationPermutations = allModifiersCombinations.flatMap(
18
+ result => getPermutations(result),
19
+ )
20
+ let returnValue = []
21
+ for (let selector of selectors) {
22
+ returnValue = [
23
+ ...returnValue,
24
+ ...allModifiersCombinationPermutations.map(
25
+ modifiersCombinationPermutation =>
26
+ [...modifiersCombinationPermutation, selector].join('-'),
27
+ ),
28
+ selector,
29
+ ]
30
+ }
31
+ cachedGroupsByModifiersAndSelectors.set(modifiersAndSelectorsKey, returnValue)
32
+ return returnValue
33
+ }
34
+ const getCombinations = (array, n) => {
35
+ let result = []
36
+ let backtrack = (start, comb) => {
37
+ if (comb.length === n) {
38
+ result.push([...comb])
39
+ return
40
+ }
41
+ for (let i = start; i < array.length; i++) {
42
+ comb.push(array[i])
43
+ backtrack(i + 1, comb)
44
+ comb.pop()
45
+ }
46
+ }
47
+ backtrack(0, [])
48
+ return result
49
+ }
50
+ const getPermutations = elements => {
51
+ let result = []
52
+ let backtrack = first => {
53
+ if (first === elements.length) {
54
+ result.push([...elements])
55
+ return
56
+ }
57
+ for (let i = first; i < elements.length; i++) {
58
+ ;[elements[first], elements[i]] = [elements[i], elements[first]]
59
+ backtrack(first + 1)
60
+ ;[elements[first], elements[i]] = [elements[i], elements[first]]
61
+ }
62
+ }
63
+ backtrack(0)
64
+ return result
65
+ }
66
+ export { generateOfficialGroups }
@@ -2,10 +2,12 @@
2
2
  const isPartitionComment = require('../utils/is-partition-comment.js')
3
3
  const getCommentBefore = require('../utils/get-comment-before.js')
4
4
  const createEslintRule = require('../utils/create-eslint-rule.js')
5
+ const sortClassesUtils = require('./sort-classes-utils.js')
5
6
  const getGroupNumber = require('../utils/get-group-number.js')
6
7
  const getSourceCode = require('../utils/get-source-code.js')
7
8
  const toSingleLine = require('../utils/to-single-line.js')
8
9
  const rangeToDiff = require('../utils/range-to-diff.js')
10
+ const getSettings = require('../utils/get-settings.js')
9
11
  const isPositive = require('../utils/is-positive.js')
10
12
  const useGroups = require('../utils/use-groups.js')
11
13
  const sortNodes = require('../utils/sort-nodes.js')
@@ -98,6 +100,8 @@ const sortClasses = createEslintRule.createEslintRule({
98
100
  },
99
101
  ],
100
102
  messages: {
103
+ unexpectedClassesGroupOrder:
104
+ 'Expected "{{right}}" ({{rightGroup}}) to come before "{{left}}" ({{leftGroup}}).',
101
105
  unexpectedClassesOrder: 'Expected "{{right}}" to come before "{{left}}".',
102
106
  },
103
107
  },
@@ -127,7 +131,8 @@ const sortClasses = createEslintRule.createEslintRule({
127
131
  create: context => ({
128
132
  ClassBody: node => {
129
133
  if (node.body.length > 1) {
130
- let options = complete.complete(context.options.at(0), {
134
+ let settings = getSettings.getSettings(context.settings)
135
+ let options = complete.complete(context.options.at(0), settings, {
131
136
  groups: [
132
137
  'index-signature',
133
138
  'static-property',
@@ -189,7 +194,7 @@ const sortClasses = createEslintRule.createEslintRule({
189
194
  }
190
195
  let formattedNodes = node.body.reduce(
191
196
  (accumulator, member) => {
192
- var _a
197
+ var _a, _b, _c
193
198
  let comment = getCommentBefore.getCommentBefore(member, sourceCode)
194
199
  if (
195
200
  options.partitionByComment &&
@@ -221,80 +226,119 @@ const sortClasses = createEslintRule.createEslintRule({
221
226
  name = sourceCode.text.slice(...member.key.range)
222
227
  }
223
228
  }
224
- let isPrivate = name.startsWith('_') || name.startsWith('#')
229
+ let isPrivateName = name.startsWith('#')
225
230
  let decorated =
226
231
  'decorators' in member && member.decorators.length > 0
227
- if (member.type === 'MethodDefinition') {
228
- if (member.kind === 'constructor') {
229
- defineGroup('constructor')
230
- }
231
- let isProtectedMethod = member.accessibility === 'protected'
232
- let isPrivateMethod =
233
- member.accessibility === 'private' || isPrivate
234
- let isStaticMethod = member.static
235
- if (decorated) {
236
- if (member.kind === 'get') {
237
- defineGroup('decorated-get-method')
238
- }
239
- if (member.kind === 'set') {
240
- defineGroup('decorated-set-method')
241
- }
242
- defineGroup('decorated-method')
232
+ let modifiers = []
233
+ let selectors = []
234
+ if (
235
+ member.type === 'MethodDefinition' ||
236
+ member.type === 'TSAbstractMethodDefinition'
237
+ ) {
238
+ if (member.static) {
239
+ modifiers.push('static')
243
240
  }
244
- if (isPrivateMethod && isStaticMethod) {
245
- defineGroup('static-private-method')
241
+ if (member.type === 'TSAbstractMethodDefinition') {
242
+ modifiers.push('abstract')
246
243
  }
247
- if (isPrivateMethod) {
248
- defineGroup('private-method')
244
+ if (decorated) {
245
+ modifiers.push('decorated')
249
246
  }
250
- if (isStaticMethod) {
251
- defineGroup('static-method')
247
+ if (member.override) {
248
+ modifiers.push('override')
252
249
  }
253
- if (isProtectedMethod && isStaticMethod) {
254
- defineGroup('static-protected-method')
250
+ if (member.accessibility === 'protected') {
251
+ modifiers.push('protected')
252
+ } else if (member.accessibility === 'private' || isPrivateName) {
253
+ modifiers.push('private')
254
+ } else {
255
+ modifiers.push('public')
255
256
  }
256
- if (isProtectedMethod) {
257
- defineGroup('protected-method')
257
+ if (member.kind === 'constructor') {
258
+ selectors.push('constructor')
258
259
  }
259
260
  if (member.kind === 'get') {
260
- defineGroup('get-method')
261
+ selectors.push('get-method')
261
262
  }
262
263
  if (member.kind === 'set') {
263
- defineGroup('set-method')
264
+ selectors.push('set-method')
264
265
  }
265
- defineGroup('method')
266
+ selectors.push('method')
266
267
  } else if (member.type === 'TSIndexSignature') {
267
- defineGroup('index-signature')
268
- } else if (member.type === 'AccessorProperty') {
269
- if (decorated) {
270
- if (member.accessibility === 'protected') {
271
- defineGroup('protected-decorated-accessor-property')
272
- }
273
- if (member.accessibility === 'private' || isPrivate) {
274
- defineGroup('private-decorated-accessor-property')
275
- }
276
- defineGroup('decorated-accessor-property')
268
+ if (member.static) {
269
+ modifiers.push('static')
270
+ }
271
+ if (member.readonly) {
272
+ modifiers.push('readonly')
273
+ }
274
+ selectors.push('index-signature')
275
+ } else if (member.type === 'StaticBlock') {
276
+ selectors.push('static-block')
277
+ } else if (
278
+ member.type === 'AccessorProperty' ||
279
+ member.type === 'TSAbstractAccessorProperty'
280
+ ) {
281
+ if (member.static) {
282
+ modifiers.push('static')
283
+ }
284
+ if (member.type === 'TSAbstractAccessorProperty') {
285
+ modifiers.push('abstract')
277
286
  }
278
- } else if (member.type === 'PropertyDefinition') {
279
287
  if (decorated) {
280
- if (member.accessibility === 'protected') {
281
- defineGroup('protected-decorated-property')
282
- }
283
- if (member.accessibility === 'private' || isPrivate) {
284
- defineGroup('private-decorated-property')
285
- }
286
- defineGroup('decorated-property')
288
+ modifiers.push('decorated')
287
289
  }
288
- if (member.accessibility === 'protected') {
289
- defineGroup('protected-property')
290
+ if (member.override) {
291
+ modifiers.push('override')
290
292
  }
291
- if (member.accessibility === 'private' || isPrivate) {
292
- defineGroup('private-property')
293
+ if (member.accessibility === 'protected') {
294
+ modifiers.push('protected')
295
+ } else if (member.accessibility === 'private' || isPrivateName) {
296
+ modifiers.push('private')
297
+ } else {
298
+ modifiers.push('public')
293
299
  }
300
+ selectors.push('accessor-property')
301
+ } else {
294
302
  if (member.static) {
295
- defineGroup('static-property')
303
+ modifiers.push('static')
304
+ }
305
+ if (member.declare) {
306
+ modifiers.push('declare')
307
+ }
308
+ if (member.type === 'TSAbstractPropertyDefinition') {
309
+ modifiers.push('abstract')
310
+ }
311
+ if (decorated) {
312
+ modifiers.push('decorated')
313
+ }
314
+ if (member.override) {
315
+ modifiers.push('override')
316
+ }
317
+ if (member.readonly) {
318
+ modifiers.push('readonly')
319
+ }
320
+ if (member.accessibility === 'protected') {
321
+ modifiers.push('protected')
322
+ } else if (member.accessibility === 'private' || isPrivateName) {
323
+ modifiers.push('private')
324
+ } else {
325
+ modifiers.push('public')
296
326
  }
297
- defineGroup('property')
327
+ if (
328
+ ((_b = member.value) == null ? void 0 : _b.type) ===
329
+ 'ArrowFunctionExpression' ||
330
+ ((_c = member.value) == null ? void 0 : _c.type) ===
331
+ 'FunctionExpression'
332
+ ) {
333
+ selectors.push('function-property')
334
+ }
335
+ selectors.push('property')
336
+ }
337
+ for (let officialGroup of sortClassesUtils.generateOfficialGroups(
338
+ modifiers,
339
+ selectors,
340
+ )) {
341
+ defineGroup(officialGroup)
298
342
  }
299
343
  setCustomGroups(options.customGroups, name, {
300
344
  override: true,
@@ -325,10 +369,15 @@ const sortClasses = createEslintRule.createEslintRule({
325
369
  isPositive.isPositive(compare.compare(left, right, options))))
326
370
  ) {
327
371
  context.report({
328
- messageId: 'unexpectedClassesOrder',
372
+ messageId:
373
+ leftNum !== rightNum
374
+ ? 'unexpectedClassesGroupOrder'
375
+ : 'unexpectedClassesOrder',
329
376
  data: {
330
377
  left: toSingleLine.toSingleLine(left.name),
378
+ leftGroup: left.group,
331
379
  right: toSingleLine.toSingleLine(right.name),
380
+ rightGroup: right.group,
332
381
  },
333
382
  node: right.node,
334
383
  fix: fixer => {