eslint-plugin-perfectionist 3.3.0 → 3.4.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 (44) hide show
  1. package/dist/index.d.ts +242 -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 +231 -79
  11. package/dist/rules/sort-classes.mjs +229 -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 +28 -0
  17. package/dist/rules/sort-imports.mjs +28 -0
  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 +8 -9
  35. package/dist/rules/sort-variable-declarations.mjs +6 -5
  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
@@ -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,18 @@ 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
+ }
186
295
  }
187
296
  let traverseNode = nodeValue => {
188
297
  if (Array.isArray(nodeValue)) {
@@ -198,7 +307,7 @@ const sortClasses = createEslintRule.createEslintRule({
198
307
  sortClassesUtils.getOverloadSignatureGroups(node.body)
199
308
  let formattedNodes = node.body.reduce(
200
309
  (accumulator, member) => {
201
- var _a, _b, _c, _d
310
+ var _a2, _b, _c, _d
202
311
  let comment = getCommentBefore.getCommentBefore(member, sourceCode)
203
312
  if (
204
313
  options.partitionByComment &&
@@ -219,9 +328,9 @@ const sortClasses = createEslintRule.createEslintRule({
219
328
  } else if (member.type === 'TSIndexSignature') {
220
329
  name = sourceCode.text.slice(
221
330
  member.range.at(0),
222
- ((_a = member.typeAnnotation) == null
331
+ ((_a2 = member.typeAnnotation) == null
223
332
  ? void 0
224
- : _a.range.at(0)) ?? member.range.at(1),
333
+ : _a2.range.at(0)) ?? member.range.at(1),
225
334
  )
226
335
  } else {
227
336
  if (member.key.type === 'Identifier') {
@@ -232,8 +341,21 @@ const sortClasses = createEslintRule.createEslintRule({
232
341
  }
233
342
  let isPrivateHash =
234
343
  'key' in member && member.key.type === 'PrivateIdentifier'
235
- let decorated =
236
- 'decorators' in member && member.decorators.length > 0
344
+ let decorated = false
345
+ let decorators = []
346
+ if ('decorators' in member) {
347
+ decorated = member.decorators.length > 0
348
+ for (let decorator of member.decorators) {
349
+ if (decorator.expression.type === 'Identifier') {
350
+ decorators.push(decorator.expression.name)
351
+ } else if (
352
+ decorator.expression.type === 'CallExpression' &&
353
+ decorator.expression.callee.type === 'Identifier'
354
+ ) {
355
+ decorators.push(decorator.expression.callee.name)
356
+ }
357
+ }
358
+ }
237
359
  let modifiers = []
238
360
  let selectors = []
239
361
  if (
@@ -282,6 +404,7 @@ const sortClasses = createEslintRule.createEslintRule({
282
404
  selectors.push('index-signature')
283
405
  } else if (member.type === 'StaticBlock') {
284
406
  selectors.push('static-block')
407
+ dependencies = extractDependencies(member, true)
285
408
  } else if (
286
409
  member.type === 'AccessorProperty' ||
287
410
  member.type === 'TSAbstractAccessorProperty'
@@ -335,15 +458,22 @@ const sortClasses = createEslintRule.createEslintRule({
335
458
  if (member.optional) {
336
459
  modifiers.push('optional')
337
460
  }
338
- if (
461
+ let isFunctionProperty =
339
462
  ((_b = member.value) == null ? void 0 : _b.type) ===
340
463
  'ArrowFunctionExpression' ||
341
464
  ((_c = member.value) == null ? void 0 : _c.type) ===
342
465
  'FunctionExpression'
343
- ) {
466
+ if (isFunctionProperty) {
344
467
  selectors.push('function-property')
345
468
  }
346
469
  selectors.push('property')
470
+ if (
471
+ member.type === 'PropertyDefinition' &&
472
+ member.value &&
473
+ !isFunctionProperty
474
+ ) {
475
+ dependencies = extractDependencies(member.value, member.static)
476
+ }
347
477
  }
348
478
  for (let officialGroup of sortClassesUtils.generateOfficialGroups(
349
479
  modifiers,
@@ -351,11 +481,27 @@ const sortClasses = createEslintRule.createEslintRule({
351
481
  )) {
352
482
  defineGroup(officialGroup)
353
483
  }
354
- setCustomGroups(options.customGroups, name, {
355
- override: true,
356
- })
357
- if (member.type === 'PropertyDefinition' && member.value) {
358
- dependencies = extractDependencies(member.value)
484
+ if (Array.isArray(options.customGroups)) {
485
+ for (let customGroup of options.customGroups) {
486
+ if (
487
+ sortClassesUtils.customGroupMatches({
488
+ customGroup,
489
+ elementName: name,
490
+ modifiers,
491
+ selectors,
492
+ decorators,
493
+ })
494
+ ) {
495
+ defineGroup(customGroup.groupName, true)
496
+ if (getGroup() === customGroup.groupName) {
497
+ break
498
+ }
499
+ }
500
+ }
501
+ } else {
502
+ setCustomGroups(options.customGroups, name, {
503
+ override: true,
504
+ })
359
505
  }
360
506
  let overloadSignatureGroupMember =
361
507
  (_d = overloadSignatureGroups.find(overloadSignatures =>
@@ -371,6 +517,10 @@ const sortClasses = createEslintRule.createEslintRule({
371
517
  node: member,
372
518
  dependencies,
373
519
  name,
520
+ dependencyName: getDependencyName(
521
+ name,
522
+ modifiers.includes('static'),
523
+ ),
374
524
  }
375
525
  accumulator.at(-1).push(value)
376
526
  return accumulator
@@ -378,18 +528,56 @@ const sortClasses = createEslintRule.createEslintRule({
378
528
  [[]],
379
529
  )
380
530
  for (let nodes of formattedNodes) {
531
+ let nodesByNonIgnoredGroupNumber = {}
532
+ let ignoredNodeIndices = []
533
+ for (let [index, sortingNode] of nodes.entries()) {
534
+ let groupNum = getGroupNumber.getGroupNumber(
535
+ options.groups,
536
+ sortingNode,
537
+ )
538
+ if (groupNum === options.groups.length) {
539
+ ignoredNodeIndices.push(index)
540
+ continue
541
+ }
542
+ nodesByNonIgnoredGroupNumber[groupNum] =
543
+ nodesByNonIgnoredGroupNumber[groupNum] ?? []
544
+ nodesByNonIgnoredGroupNumber[groupNum].push(sortingNode)
545
+ }
546
+ let sortedNodes = []
547
+ for (let groupNumber of Object.keys(
548
+ nodesByNonIgnoredGroupNumber,
549
+ ).sort((a, b) => Number(a) - Number(b))) {
550
+ let compareOptions = sortClassesUtils.getCompareOptions(
551
+ options,
552
+ Number(groupNumber),
553
+ )
554
+ if (!compareOptions) {
555
+ sortedNodes.push(
556
+ ...nodesByNonIgnoredGroupNumber[Number(groupNumber)],
557
+ )
558
+ } else {
559
+ sortedNodes.push(
560
+ ...sortNodes.sortNodes(
561
+ nodesByNonIgnoredGroupNumber[Number(groupNumber)],
562
+ compareOptions,
563
+ ),
564
+ )
565
+ }
566
+ }
567
+ for (let ignoredIndex of ignoredNodeIndices) {
568
+ sortedNodes.splice(ignoredIndex, 0, nodes[ignoredIndex])
569
+ }
570
+ sortedNodes =
571
+ sortNodesByDependencies.sortNodesByDependencies(sortedNodes)
381
572
  pairwise.pairwise(nodes, (left, right) => {
382
573
  let leftNum = getGroupNumber.getGroupNumber(options.groups, left)
383
574
  let rightNum = getGroupNumber.getGroupNumber(options.groups, right)
384
575
  let isLeftOrRightIgnored =
385
576
  leftNum === options.groups.length ||
386
577
  rightNum === options.groups.length
387
- if (
388
- !isLeftOrRightIgnored &&
389
- (leftNum > rightNum ||
390
- (leftNum === rightNum &&
391
- isPositive.isPositive(compare.compare(left, right, options))))
392
- ) {
578
+ let indexOfLeft = sortedNodes.indexOf(left)
579
+ let indexOfRight = sortedNodes.indexOf(right)
580
+ if (!isLeftOrRightIgnored && indexOfLeft > indexOfRight) {
393
581
  context.report({
394
582
  messageId:
395
583
  leftNum !== rightNum
@@ -402,46 +590,10 @@ const sortClasses = createEslintRule.createEslintRule({
402
590
  rightGroup: right.group,
403
591
  },
404
592
  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
- },
593
+ fix: fixer =>
594
+ makeFixes.makeFixes(fixer, nodes, sortedNodes, sourceCode, {
595
+ partitionComment: options.partitionByComment,
596
+ }),
445
597
  })
446
598
  }
447
599
  })