eslint-plugin-perfectionist 3.3.0 → 3.5.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 (45) hide show
  1. package/dist/index.d.ts +243 -21
  2. package/dist/index.js +3 -1
  3. package/dist/index.mjs +2 -0
  4. package/dist/rules/sort-array-includes.js +108 -107
  5. package/dist/rules/sort-array-includes.mjs +100 -100
  6. package/dist/rules/sort-astro-attributes.js +6 -0
  7. package/dist/rules/sort-astro-attributes.mjs +6 -0
  8. package/dist/rules/sort-classes-utils.js +71 -0
  9. package/dist/rules/sort-classes-utils.mjs +75 -1
  10. package/dist/rules/sort-classes.js +234 -79
  11. package/dist/rules/sort-classes.mjs +232 -69
  12. package/dist/rules/sort-classes.types.js +71 -0
  13. package/dist/rules/sort-classes.types.mjs +71 -0
  14. package/dist/rules/sort-enums.js +11 -15
  15. package/dist/rules/sort-enums.mjs +11 -11
  16. package/dist/rules/sort-imports.js +46 -5
  17. package/dist/rules/sort-imports.mjs +46 -5
  18. package/dist/rules/sort-interfaces.js +6 -0
  19. package/dist/rules/sort-interfaces.mjs +6 -0
  20. package/dist/rules/sort-intersection-types.js +20 -0
  21. package/dist/rules/sort-intersection-types.mjs +20 -0
  22. package/dist/rules/sort-jsx-props.js +6 -0
  23. package/dist/rules/sort-jsx-props.mjs +6 -0
  24. package/dist/rules/sort-object-types.js +6 -0
  25. package/dist/rules/sort-object-types.mjs +6 -0
  26. package/dist/rules/sort-objects.js +34 -43
  27. package/dist/rules/sort-objects.mjs +28 -30
  28. package/dist/rules/sort-sets.js +48 -0
  29. package/dist/rules/sort-sets.mjs +47 -0
  30. package/dist/rules/sort-svelte-attributes.js +6 -0
  31. package/dist/rules/sort-svelte-attributes.mjs +6 -0
  32. package/dist/rules/sort-union-types.js +20 -0
  33. package/dist/rules/sort-union-types.mjs +20 -0
  34. package/dist/rules/sort-variable-declarations.js +43 -14
  35. package/dist/rules/sort-variable-declarations.mjs +41 -10
  36. package/dist/rules/sort-vue-attributes.js +6 -0
  37. package/dist/rules/sort-vue-attributes.mjs +6 -0
  38. package/dist/utils/compare.js +0 -6
  39. package/dist/utils/compare.mjs +0 -6
  40. package/dist/utils/sort-nodes-by-dependencies.js +30 -0
  41. package/dist/utils/sort-nodes-by-dependencies.mjs +28 -0
  42. package/dist/utils/validate-groups-configuration.js +19 -0
  43. package/dist/utils/validate-groups-configuration.mjs +17 -0
  44. package/package.json +4 -4
  45. package/readme.md +1 -0
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
  const sortClassesUtils = require('./sort-classes-utils.js')
3
+ const sortClasses_types = require('./sort-classes.types.js')
4
+ const sortNodesByDependencies = require('../utils/sort-nodes-by-dependencies.js')
3
5
  const isPartitionComment = require('../utils/is-partition-comment.js')
4
6
  const getCommentBefore = require('../utils/get-comment-before.js')
5
7
  const createEslintRule = require('../utils/create-eslint-rule.js')
@@ -8,13 +10,11 @@ const getSourceCode = require('../utils/get-source-code.js')
8
10
  const toSingleLine = require('../utils/to-single-line.js')
9
11
  const rangeToDiff = require('../utils/range-to-diff.js')
10
12
  const getSettings = require('../utils/get-settings.js')
11
- const isPositive = require('../utils/is-positive.js')
12
13
  const useGroups = require('../utils/use-groups.js')
13
14
  const sortNodes = require('../utils/sort-nodes.js')
14
15
  const makeFixes = require('../utils/make-fixes.js')
15
16
  const complete = require('../utils/complete.js')
16
17
  const pairwise = require('../utils/pairwise.js')
17
- const compare = require('../utils/compare.js')
18
18
  const sortClasses = createEslintRule.createEslintRule({
19
19
  name: 'sort-classes',
20
20
  meta: {
@@ -80,20 +80,62 @@ const sortClasses = createEslintRule.createEslintRule({
80
80
  },
81
81
  customGroups: {
82
82
  description: 'Specifies custom groups.',
83
- type: 'object',
84
- additionalProperties: {
85
- oneOf: [
86
- {
87
- type: 'string',
83
+ oneOf: [
84
+ {
85
+ type: 'object',
86
+ additionalProperties: {
87
+ oneOf: [
88
+ {
89
+ type: 'string',
90
+ },
91
+ {
92
+ type: 'array',
93
+ items: {
94
+ type: 'string',
95
+ },
96
+ },
97
+ ],
88
98
  },
89
- {
90
- type: 'array',
91
- items: {
92
- type: 'string',
93
- },
99
+ },
100
+ {
101
+ type: 'array',
102
+ items: {
103
+ description: 'Advanced custom groups.',
104
+ oneOf: [
105
+ {
106
+ description: 'Custom group block.',
107
+ type: 'object',
108
+ additionalProperties: false,
109
+ properties: {
110
+ ...sortClasses_types.customGroupNameJsonSchema,
111
+ ...sortClasses_types.customGroupSortJsonSchema,
112
+ anyOf: {
113
+ type: 'array',
114
+ items: {
115
+ description: 'Custom group.',
116
+ type: 'object',
117
+ additionalProperties: false,
118
+ properties: {
119
+ ...sortClasses_types.singleCustomGroupJsonSchema,
120
+ },
121
+ },
122
+ },
123
+ },
124
+ },
125
+ {
126
+ description: 'Custom group.',
127
+ type: 'object',
128
+ additionalProperties: false,
129
+ properties: {
130
+ ...sortClasses_types.customGroupNameJsonSchema,
131
+ ...sortClasses_types.customGroupSortJsonSchema,
132
+ ...sortClasses_types.singleCustomGroupJsonSchema,
133
+ },
134
+ },
135
+ ],
94
136
  },
95
- ],
96
- },
137
+ },
138
+ ],
97
139
  },
98
140
  },
99
141
  additionalProperties: false,
@@ -112,9 +154,9 @@ const sortClasses = createEslintRule.createEslintRule({
112
154
  ignoreCase: true,
113
155
  partitionByComment: false,
114
156
  groups: [
115
- 'static-block',
116
157
  'index-signature',
117
158
  'static-property',
159
+ 'static-block',
118
160
  ['protected-property', 'protected-accessor-property'],
119
161
  ['private-property', 'private-accessor-property'],
120
162
  ['property', 'accessor-property'],
@@ -126,18 +168,19 @@ const sortClasses = createEslintRule.createEslintRule({
126
168
  ['get-method', 'set-method'],
127
169
  'unknown',
128
170
  ],
129
- customGroups: {},
171
+ customGroups: [],
130
172
  },
131
173
  ],
132
174
  create: context => ({
133
175
  ClassBody: node => {
176
+ var _a
134
177
  if (node.body.length > 1) {
135
178
  let settings = getSettings.getSettings(context.settings)
136
179
  let options = complete.complete(context.options.at(0), settings, {
137
180
  groups: [
138
- 'static-block',
139
181
  'index-signature',
140
182
  'static-property',
183
+ 'static-block',
141
184
  ['protected-property', 'protected-accessor-property'],
142
185
  ['private-property', 'private-accessor-property'],
143
186
  ['property', 'accessor-property'],
@@ -152,19 +195,76 @@ const sortClasses = createEslintRule.createEslintRule({
152
195
  partitionByComment: false,
153
196
  type: 'alphabetical',
154
197
  ignoreCase: true,
155
- customGroups: {},
198
+ customGroups: [],
156
199
  order: 'asc',
157
200
  })
158
201
  let sourceCode = getSourceCode.getSourceCode(context)
159
- let extractDependencies = expression => {
202
+ let className = (_a = node.parent.id) == null ? void 0 : _a.name
203
+ let getDependencyName = (nodeName, isStatic) =>
204
+ `${isStatic ? 'static ' : ''}${nodeName}`
205
+ let classMethodsDependencyNames = new Set(
206
+ node.body
207
+ .map(member => {
208
+ if (
209
+ (member.type === 'MethodDefinition' ||
210
+ member.type === 'TSAbstractMethodDefinition') &&
211
+ 'name' in member.key
212
+ ) {
213
+ return getDependencyName(member.key.name, member.static)
214
+ }
215
+ return null
216
+ })
217
+ .filter(m => m !== null),
218
+ )
219
+ let extractDependencies = (expression, isMemberStatic) => {
160
220
  let dependencies = []
161
221
  let checkNode = nodeValue => {
222
+ if (
223
+ nodeValue.type === 'ArrowFunctionExpression' ||
224
+ nodeValue.type === 'FunctionExpression'
225
+ ) {
226
+ return
227
+ }
162
228
  if (
163
229
  nodeValue.type === 'MemberExpression' &&
164
- nodeValue.object.type === 'ThisExpression' &&
230
+ (nodeValue.object.type === 'ThisExpression' ||
231
+ (nodeValue.object.type === 'Identifier' &&
232
+ nodeValue.object.name === className)) &&
165
233
  nodeValue.property.type === 'Identifier'
166
234
  ) {
167
- dependencies.push(nodeValue.property.name)
235
+ let isStaticDependency =
236
+ isMemberStatic || nodeValue.object.type === 'Identifier'
237
+ let dependencyName = getDependencyName(
238
+ nodeValue.property.name,
239
+ isStaticDependency,
240
+ )
241
+ if (!classMethodsDependencyNames.has(dependencyName)) {
242
+ dependencies.push(dependencyName)
243
+ }
244
+ }
245
+ if (nodeValue.type === 'Property') {
246
+ traverseNode(nodeValue.key)
247
+ traverseNode(nodeValue.value)
248
+ }
249
+ if (nodeValue.type === 'ConditionalExpression') {
250
+ traverseNode(nodeValue.test)
251
+ traverseNode(nodeValue.consequent)
252
+ traverseNode(nodeValue.alternate)
253
+ }
254
+ if (
255
+ 'expression' in nodeValue &&
256
+ typeof nodeValue.expression !== 'boolean'
257
+ ) {
258
+ traverseNode(nodeValue.expression)
259
+ }
260
+ if ('object' in nodeValue) {
261
+ traverseNode(nodeValue.object)
262
+ }
263
+ if ('callee' in nodeValue) {
264
+ traverseNode(nodeValue.callee)
265
+ }
266
+ if ('init' in nodeValue && nodeValue.init) {
267
+ traverseNode(nodeValue.init)
168
268
  }
169
269
  if ('body' in nodeValue && nodeValue.body) {
170
270
  traverseNode(nodeValue.body)
@@ -180,9 +280,21 @@ const sortClasses = createEslintRule.createEslintRule({
180
280
  .filter(currentNode => currentNode !== null)
181
281
  .forEach(traverseNode)
182
282
  }
283
+ if ('argument' in nodeValue && nodeValue.argument) {
284
+ traverseNode(nodeValue.argument)
285
+ }
183
286
  if ('arguments' in nodeValue) {
184
287
  nodeValue.arguments.forEach(traverseNode)
185
288
  }
289
+ if ('declarations' in nodeValue) {
290
+ nodeValue.declarations.forEach(traverseNode)
291
+ }
292
+ if ('properties' in nodeValue) {
293
+ nodeValue.properties.forEach(traverseNode)
294
+ }
295
+ if ('expressions' in nodeValue) {
296
+ nodeValue.expressions.forEach(traverseNode)
297
+ }
186
298
  }
187
299
  let traverseNode = nodeValue => {
188
300
  if (Array.isArray(nodeValue)) {
@@ -198,7 +310,7 @@ const sortClasses = createEslintRule.createEslintRule({
198
310
  sortClassesUtils.getOverloadSignatureGroups(node.body)
199
311
  let formattedNodes = node.body.reduce(
200
312
  (accumulator, member) => {
201
- var _a, _b, _c, _d
313
+ var _a2, _b, _c, _d
202
314
  let comment = getCommentBefore.getCommentBefore(member, sourceCode)
203
315
  if (
204
316
  options.partitionByComment &&
@@ -219,9 +331,9 @@ const sortClasses = createEslintRule.createEslintRule({
219
331
  } else if (member.type === 'TSIndexSignature') {
220
332
  name = sourceCode.text.slice(
221
333
  member.range.at(0),
222
- ((_a = member.typeAnnotation) == null
334
+ ((_a2 = member.typeAnnotation) == null
223
335
  ? void 0
224
- : _a.range.at(0)) ?? member.range.at(1),
336
+ : _a2.range.at(0)) ?? member.range.at(1),
225
337
  )
226
338
  } else {
227
339
  if (member.key.type === 'Identifier') {
@@ -232,8 +344,21 @@ const sortClasses = createEslintRule.createEslintRule({
232
344
  }
233
345
  let isPrivateHash =
234
346
  'key' in member && member.key.type === 'PrivateIdentifier'
235
- let decorated =
236
- 'decorators' in member && member.decorators.length > 0
347
+ let decorated = false
348
+ let decorators = []
349
+ if ('decorators' in member) {
350
+ decorated = member.decorators.length > 0
351
+ for (let decorator of member.decorators) {
352
+ if (decorator.expression.type === 'Identifier') {
353
+ decorators.push(decorator.expression.name)
354
+ } else if (
355
+ decorator.expression.type === 'CallExpression' &&
356
+ decorator.expression.callee.type === 'Identifier'
357
+ ) {
358
+ decorators.push(decorator.expression.callee.name)
359
+ }
360
+ }
361
+ }
237
362
  let modifiers = []
238
363
  let selectors = []
239
364
  if (
@@ -282,6 +407,7 @@ const sortClasses = createEslintRule.createEslintRule({
282
407
  selectors.push('index-signature')
283
408
  } else if (member.type === 'StaticBlock') {
284
409
  selectors.push('static-block')
410
+ dependencies = extractDependencies(member, true)
285
411
  } else if (
286
412
  member.type === 'AccessorProperty' ||
287
413
  member.type === 'TSAbstractAccessorProperty'
@@ -335,15 +461,22 @@ const sortClasses = createEslintRule.createEslintRule({
335
461
  if (member.optional) {
336
462
  modifiers.push('optional')
337
463
  }
338
- if (
464
+ let isFunctionProperty =
339
465
  ((_b = member.value) == null ? void 0 : _b.type) ===
340
466
  'ArrowFunctionExpression' ||
341
467
  ((_c = member.value) == null ? void 0 : _c.type) ===
342
468
  'FunctionExpression'
343
- ) {
469
+ if (isFunctionProperty) {
344
470
  selectors.push('function-property')
345
471
  }
346
472
  selectors.push('property')
473
+ if (
474
+ member.type === 'PropertyDefinition' &&
475
+ member.value &&
476
+ !isFunctionProperty
477
+ ) {
478
+ dependencies = extractDependencies(member.value, member.static)
479
+ }
347
480
  }
348
481
  for (let officialGroup of sortClassesUtils.generateOfficialGroups(
349
482
  modifiers,
@@ -351,11 +484,27 @@ const sortClasses = createEslintRule.createEslintRule({
351
484
  )) {
352
485
  defineGroup(officialGroup)
353
486
  }
354
- setCustomGroups(options.customGroups, name, {
355
- override: true,
356
- })
357
- if (member.type === 'PropertyDefinition' && member.value) {
358
- dependencies = extractDependencies(member.value)
487
+ if (Array.isArray(options.customGroups)) {
488
+ for (let customGroup of options.customGroups) {
489
+ if (
490
+ sortClassesUtils.customGroupMatches({
491
+ customGroup,
492
+ elementName: name,
493
+ modifiers,
494
+ selectors,
495
+ decorators,
496
+ })
497
+ ) {
498
+ defineGroup(customGroup.groupName, true)
499
+ if (getGroup() === customGroup.groupName) {
500
+ break
501
+ }
502
+ }
503
+ }
504
+ } else {
505
+ setCustomGroups(options.customGroups, name, {
506
+ override: true,
507
+ })
359
508
  }
360
509
  let overloadSignatureGroupMember =
361
510
  (_d = overloadSignatureGroups.find(overloadSignatures =>
@@ -371,6 +520,10 @@ const sortClasses = createEslintRule.createEslintRule({
371
520
  node: member,
372
521
  dependencies,
373
522
  name,
523
+ dependencyName: getDependencyName(
524
+ name,
525
+ modifiers.includes('static'),
526
+ ),
374
527
  }
375
528
  accumulator.at(-1).push(value)
376
529
  return accumulator
@@ -378,18 +531,56 @@ const sortClasses = createEslintRule.createEslintRule({
378
531
  [[]],
379
532
  )
380
533
  for (let nodes of formattedNodes) {
534
+ let nodesByNonIgnoredGroupNumber = {}
535
+ let ignoredNodeIndices = []
536
+ for (let [index, sortingNode] of nodes.entries()) {
537
+ let groupNum = getGroupNumber.getGroupNumber(
538
+ options.groups,
539
+ sortingNode,
540
+ )
541
+ if (groupNum === options.groups.length) {
542
+ ignoredNodeIndices.push(index)
543
+ continue
544
+ }
545
+ nodesByNonIgnoredGroupNumber[groupNum] =
546
+ nodesByNonIgnoredGroupNumber[groupNum] ?? []
547
+ nodesByNonIgnoredGroupNumber[groupNum].push(sortingNode)
548
+ }
549
+ let sortedNodes = []
550
+ for (let groupNumber of Object.keys(
551
+ nodesByNonIgnoredGroupNumber,
552
+ ).sort((a, b) => Number(a) - Number(b))) {
553
+ let compareOptions = sortClassesUtils.getCompareOptions(
554
+ options,
555
+ Number(groupNumber),
556
+ )
557
+ if (!compareOptions) {
558
+ sortedNodes.push(
559
+ ...nodesByNonIgnoredGroupNumber[Number(groupNumber)],
560
+ )
561
+ } else {
562
+ sortedNodes.push(
563
+ ...sortNodes.sortNodes(
564
+ nodesByNonIgnoredGroupNumber[Number(groupNumber)],
565
+ compareOptions,
566
+ ),
567
+ )
568
+ }
569
+ }
570
+ for (let ignoredIndex of ignoredNodeIndices) {
571
+ sortedNodes.splice(ignoredIndex, 0, nodes[ignoredIndex])
572
+ }
573
+ sortedNodes =
574
+ sortNodesByDependencies.sortNodesByDependencies(sortedNodes)
381
575
  pairwise.pairwise(nodes, (left, right) => {
382
576
  let leftNum = getGroupNumber.getGroupNumber(options.groups, left)
383
577
  let rightNum = getGroupNumber.getGroupNumber(options.groups, right)
384
578
  let isLeftOrRightIgnored =
385
579
  leftNum === options.groups.length ||
386
580
  rightNum === options.groups.length
387
- if (
388
- !isLeftOrRightIgnored &&
389
- (leftNum > rightNum ||
390
- (leftNum === rightNum &&
391
- isPositive.isPositive(compare.compare(left, right, options))))
392
- ) {
581
+ let indexOfLeft = sortedNodes.indexOf(left)
582
+ let indexOfRight = sortedNodes.indexOf(right)
583
+ if (!isLeftOrRightIgnored && indexOfLeft > indexOfRight) {
393
584
  context.report({
394
585
  messageId:
395
586
  leftNum !== rightNum
@@ -402,46 +593,10 @@ const sortClasses = createEslintRule.createEslintRule({
402
593
  rightGroup: right.group,
403
594
  },
404
595
  node: right.node,
405
- fix: fixer => {
406
- let nodesByNonIgnoredGroupNumber = {}
407
- let ignoredNodeIndices = []
408
- for (let [index, sortingNode] of nodes.entries()) {
409
- let groupNum = getGroupNumber.getGroupNumber(
410
- options.groups,
411
- sortingNode,
412
- )
413
- if (groupNum === options.groups.length) {
414
- ignoredNodeIndices.push(index)
415
- continue
416
- }
417
- nodesByNonIgnoredGroupNumber[groupNum] =
418
- nodesByNonIgnoredGroupNumber[groupNum] ?? []
419
- nodesByNonIgnoredGroupNumber[groupNum].push(sortingNode)
420
- }
421
- let sortedNodes = []
422
- for (let groupNumber of Object.keys(
423
- nodesByNonIgnoredGroupNumber,
424
- ).sort((a, b) => Number(a) - Number(b))) {
425
- sortedNodes.push(
426
- ...sortNodes.sortNodes(
427
- nodesByNonIgnoredGroupNumber[Number(groupNumber)],
428
- options,
429
- ),
430
- )
431
- }
432
- for (let ignoredIndex of ignoredNodeIndices) {
433
- sortedNodes.splice(ignoredIndex, 0, nodes[ignoredIndex])
434
- }
435
- return makeFixes.makeFixes(
436
- fixer,
437
- nodes,
438
- sortedNodes,
439
- sourceCode,
440
- {
441
- partitionComment: options.partitionByComment,
442
- },
443
- )
444
- },
596
+ fix: fixer =>
597
+ makeFixes.makeFixes(fixer, nodes, sortedNodes, sourceCode, {
598
+ partitionComment: options.partitionByComment,
599
+ }),
445
600
  })
446
601
  }
447
602
  })