eslint-plugin-perfectionist 3.2.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 (46) 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 +102 -0
  9. package/dist/rules/sort-classes-utils.mjs +105 -1
  10. package/dist/rules/sort-classes.js +263 -83
  11. package/dist/rules/sort-classes.mjs +263 -71
  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 +41 -14
  15. package/dist/rules/sort-enums.mjs +41 -10
  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-switch-case.js +6 -3
  33. package/dist/rules/sort-switch-case.mjs +6 -3
  34. package/dist/rules/sort-union-types.js +20 -0
  35. package/dist/rules/sort-union-types.mjs +20 -0
  36. package/dist/rules/sort-variable-declarations.js +8 -9
  37. package/dist/rules/sort-variable-declarations.mjs +6 -5
  38. package/dist/rules/sort-vue-attributes.js +6 -0
  39. package/dist/rules/sort-vue-attributes.mjs +6 -0
  40. package/dist/utils/compare.js +0 -6
  41. package/dist/utils/compare.mjs +0 -6
  42. package/dist/utils/sort-nodes-by-dependencies.js +30 -0
  43. package/dist/utils/sort-nodes-by-dependencies.mjs +28 -0
  44. package/dist/utils/validate-groups-configuration.js +19 -0
  45. package/dist/utils/validate-groups-configuration.mjs +17 -0
  46. package/package.json +4 -4
@@ -1,4 +1,5 @@
1
1
  'use strict'
2
+ const sortNodesByDependencies = require('../utils/sort-nodes-by-dependencies.js')
2
3
  const isPartitionComment = require('../utils/is-partition-comment.js')
3
4
  const createEslintRule = require('../utils/create-eslint-rule.js')
4
5
  const getCommentBefore = require('../utils/get-comment-before.js')
@@ -6,12 +7,10 @@ const getSourceCode = require('../utils/get-source-code.js')
6
7
  const toSingleLine = require('../utils/to-single-line.js')
7
8
  const rangeToDiff = require('../utils/range-to-diff.js')
8
9
  const getSettings = require('../utils/get-settings.js')
9
- const isPositive = require('../utils/is-positive.js')
10
10
  const sortNodes = require('../utils/sort-nodes.js')
11
11
  const makeFixes = require('../utils/make-fixes.js')
12
12
  const complete = require('../utils/complete.js')
13
13
  const pairwise = require('../utils/pairwise.js')
14
- const compare = require('../utils/compare.js')
15
14
  const sortEnums = createEslintRule.createEslintRule({
16
15
  name: 'sort-enums',
17
16
  meta: {
@@ -113,6 +112,29 @@ const sortEnums = createEslintRule.createEslintRule({
113
112
  })
114
113
  let sourceCode = getSourceCode.getSourceCode(context)
115
114
  let partitionComment = options.partitionByComment
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
+ }
116
138
  let formattedMembers = members.reduce(
117
139
  (accumulator, member) => {
118
140
  let comment = getCommentBefore.getCommentBefore(member, sourceCode)
@@ -130,9 +152,17 @@ const sortEnums = createEslintRule.createEslintRule({
130
152
  member.id.type === 'Literal'
131
153
  ? `${member.id.value}`
132
154
  : `${sourceCode.text.slice(...member.id.range)}`
155
+ let dependencies = []
156
+ if (member.initializer) {
157
+ dependencies = extractDependencies(
158
+ member.initializer,
159
+ node.id.name,
160
+ )
161
+ }
133
162
  let sortingNode = {
134
163
  size: rangeToDiff.rangeToDiff(member.range),
135
164
  node: member,
165
+ dependencies,
136
166
  name,
137
167
  }
138
168
  accumulator.at(-1).push(sortingNode)
@@ -177,12 +207,13 @@ const sortEnums = createEslintRule.createEslintRule({
177
207
  : void 0,
178
208
  }
179
209
  for (let nodes of formattedMembers) {
210
+ let sortedNodes = sortNodesByDependencies.sortNodesByDependencies(
211
+ sortNodes.sortNodes(nodes, compareOptions),
212
+ )
180
213
  pairwise.pairwise(nodes, (left, right) => {
181
- if (
182
- isPositive.isPositive(
183
- compare.compare(left, right, compareOptions),
184
- )
185
- ) {
214
+ let indexOfLeft = sortedNodes.indexOf(left)
215
+ let indexOfRight = sortedNodes.indexOf(right)
216
+ if (indexOfLeft > indexOfRight) {
186
217
  context.report({
187
218
  messageId: 'unexpectedEnumsOrder',
188
219
  data: {
@@ -191,13 +222,9 @@ const sortEnums = createEslintRule.createEslintRule({
191
222
  },
192
223
  node: right.node,
193
224
  fix: fixer =>
194
- makeFixes.makeFixes(
195
- fixer,
196
- nodes,
197
- sortNodes.sortNodes(nodes, compareOptions),
198
- sourceCode,
199
- { partitionComment },
200
- ),
225
+ makeFixes.makeFixes(fixer, nodes, sortedNodes, sourceCode, {
226
+ partitionComment,
227
+ }),
201
228
  })
202
229
  }
203
230
  })
@@ -1,3 +1,4 @@
1
+ import { sortNodesByDependencies } from '../utils/sort-nodes-by-dependencies.mjs'
1
2
  import { isPartitionComment } from '../utils/is-partition-comment.mjs'
2
3
  import { createEslintRule } from '../utils/create-eslint-rule.mjs'
3
4
  import { getCommentBefore } from '../utils/get-comment-before.mjs'
@@ -5,12 +6,10 @@ import { getSourceCode } from '../utils/get-source-code.mjs'
5
6
  import { toSingleLine } from '../utils/to-single-line.mjs'
6
7
  import { rangeToDiff } from '../utils/range-to-diff.mjs'
7
8
  import { getSettings } from '../utils/get-settings.mjs'
8
- import { isPositive } from '../utils/is-positive.mjs'
9
9
  import { sortNodes } from '../utils/sort-nodes.mjs'
10
10
  import { makeFixes } from '../utils/make-fixes.mjs'
11
11
  import { complete } from '../utils/complete.mjs'
12
12
  import { pairwise } from '../utils/pairwise.mjs'
13
- import { compare } from '../utils/compare.mjs'
14
13
  const sortEnums = createEslintRule({
15
14
  name: 'sort-enums',
16
15
  meta: {
@@ -112,6 +111,29 @@ const sortEnums = createEslintRule({
112
111
  })
113
112
  let sourceCode = getSourceCode(context)
114
113
  let partitionComment = options.partitionByComment
114
+ let extractDependencies = (expression, enumName) => {
115
+ let dependencies = []
116
+ let checkNode = nodeValue => {
117
+ if (
118
+ nodeValue.type === 'MemberExpression' &&
119
+ nodeValue.object.type === 'Identifier' &&
120
+ nodeValue.object.name === enumName &&
121
+ nodeValue.property.type === 'Identifier'
122
+ ) {
123
+ dependencies.push(nodeValue.property.name)
124
+ } else if (nodeValue.type === 'Identifier') {
125
+ dependencies.push(nodeValue.name)
126
+ }
127
+ if ('left' in nodeValue) {
128
+ checkNode(nodeValue.left)
129
+ }
130
+ if ('right' in nodeValue) {
131
+ checkNode(nodeValue.right)
132
+ }
133
+ }
134
+ checkNode(expression)
135
+ return dependencies
136
+ }
115
137
  let formattedMembers = members.reduce(
116
138
  (accumulator, member) => {
117
139
  let comment = getCommentBefore(member, sourceCode)
@@ -126,9 +148,17 @@ const sortEnums = createEslintRule({
126
148
  member.id.type === 'Literal'
127
149
  ? `${member.id.value}`
128
150
  : `${sourceCode.text.slice(...member.id.range)}`
151
+ let dependencies = []
152
+ if (member.initializer) {
153
+ dependencies = extractDependencies(
154
+ member.initializer,
155
+ node.id.name,
156
+ )
157
+ }
129
158
  let sortingNode = {
130
159
  size: rangeToDiff(member.range),
131
160
  node: member,
161
+ dependencies,
132
162
  name,
133
163
  }
134
164
  accumulator.at(-1).push(sortingNode)
@@ -173,8 +203,13 @@ const sortEnums = createEslintRule({
173
203
  : void 0,
174
204
  }
175
205
  for (let nodes of formattedMembers) {
206
+ let sortedNodes = sortNodesByDependencies(
207
+ sortNodes(nodes, compareOptions),
208
+ )
176
209
  pairwise(nodes, (left, right) => {
177
- if (isPositive(compare(left, right, compareOptions))) {
210
+ let indexOfLeft = sortedNodes.indexOf(left)
211
+ let indexOfRight = sortedNodes.indexOf(right)
212
+ if (indexOfLeft > indexOfRight) {
178
213
  context.report({
179
214
  messageId: 'unexpectedEnumsOrder',
180
215
  data: {
@@ -183,13 +218,9 @@ const sortEnums = createEslintRule({
183
218
  },
184
219
  node: right.node,
185
220
  fix: fixer =>
186
- makeFixes(
187
- fixer,
188
- nodes,
189
- sortNodes(nodes, compareOptions),
190
- sourceCode,
191
- { partitionComment },
192
- ),
221
+ makeFixes(fixer, nodes, sortedNodes, sourceCode, {
222
+ partitionComment,
223
+ }),
193
224
  })
194
225
  }
195
226
  })
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
  const node_module = require('node:module')
3
3
  const minimatch = require('minimatch')
4
+ const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
4
5
  const getCommentBefore = require('../utils/get-comment-before.js')
5
6
  const createEslintRule = require('../utils/create-eslint-rule.js')
6
7
  const getLinesBetween = require('../utils/get-lines-between.js')
@@ -202,6 +203,33 @@ const sortImports = createEslintRule.createEslintRule({
202
203
  if (!hasUnknownGroup) {
203
204
  options.groups = [...options.groups, 'unknown']
204
205
  }
206
+ validateGroupsConfiguration.validateGroupsConfiguration(
207
+ options.groups,
208
+ [
209
+ 'side-effect-style',
210
+ 'external-type',
211
+ 'internal-type',
212
+ 'builtin-type',
213
+ 'sibling-type',
214
+ 'parent-type',
215
+ 'side-effect',
216
+ 'index-type',
217
+ 'internal',
218
+ 'external',
219
+ 'sibling',
220
+ 'unknown',
221
+ 'builtin',
222
+ 'parent',
223
+ 'object',
224
+ 'index',
225
+ 'style',
226
+ 'type',
227
+ ],
228
+ [
229
+ ...Object.keys(options.customGroups.type ?? {}),
230
+ ...Object.keys(options.customGroups.value ?? {}),
231
+ ],
232
+ )
205
233
  let nodes = []
206
234
  let isSideEffectImport = node =>
207
235
  node.type === 'ImportDeclaration' &&
@@ -1,5 +1,6 @@
1
1
  import { builtinModules } from 'node:module'
2
2
  import { minimatch } from 'minimatch'
3
+ import { validateGroupsConfiguration } from '../utils/validate-groups-configuration.mjs'
3
4
  import { getCommentBefore } from '../utils/get-comment-before.mjs'
4
5
  import { createEslintRule } from '../utils/create-eslint-rule.mjs'
5
6
  import { getLinesBetween } from '../utils/get-lines-between.mjs'
@@ -201,6 +202,33 @@ const sortImports = createEslintRule({
201
202
  if (!hasUnknownGroup) {
202
203
  options.groups = [...options.groups, 'unknown']
203
204
  }
205
+ validateGroupsConfiguration(
206
+ options.groups,
207
+ [
208
+ 'side-effect-style',
209
+ 'external-type',
210
+ 'internal-type',
211
+ 'builtin-type',
212
+ 'sibling-type',
213
+ 'parent-type',
214
+ 'side-effect',
215
+ 'index-type',
216
+ 'internal',
217
+ 'external',
218
+ 'sibling',
219
+ 'unknown',
220
+ 'builtin',
221
+ 'parent',
222
+ 'object',
223
+ 'index',
224
+ 'style',
225
+ 'type',
226
+ ],
227
+ [
228
+ ...Object.keys(options.customGroups.type ?? {}),
229
+ ...Object.keys(options.customGroups.value ?? {}),
230
+ ],
231
+ )
204
232
  let nodes = []
205
233
  let isSideEffectImport = node =>
206
234
  node.type === 'ImportDeclaration' &&
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
  const minimatch = require('minimatch')
3
+ const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
3
4
  const createEslintRule = require('../utils/create-eslint-rule.js')
4
5
  const isMemberOptional = require('../utils/is-member-optional.js')
5
6
  const getLinesBetween = require('../utils/get-lines-between.js')
@@ -130,6 +131,11 @@ const sortInterfaces = createEslintRule.createEslintRule({
130
131
  order: 'asc',
131
132
  groups: [],
132
133
  })
134
+ validateGroupsConfiguration.validateGroupsConfiguration(
135
+ options.groups,
136
+ ['multiline', 'unknown'],
137
+ Object.keys(options.customGroups),
138
+ )
133
139
  let sourceCode = getSourceCode.getSourceCode(context)
134
140
  if (
135
141
  !options.ignorePattern.some(pattern =>
@@ -1,4 +1,5 @@
1
1
  import { minimatch } from 'minimatch'
2
+ import { validateGroupsConfiguration } from '../utils/validate-groups-configuration.mjs'
2
3
  import { createEslintRule } from '../utils/create-eslint-rule.mjs'
3
4
  import { isMemberOptional } from '../utils/is-member-optional.mjs'
4
5
  import { getLinesBetween } from '../utils/get-lines-between.mjs'
@@ -129,6 +130,11 @@ const sortInterfaces = createEslintRule({
129
130
  order: 'asc',
130
131
  groups: [],
131
132
  })
133
+ validateGroupsConfiguration(
134
+ options.groups,
135
+ ['multiline', 'unknown'],
136
+ Object.keys(options.customGroups),
137
+ )
132
138
  let sourceCode = getSourceCode(context)
133
139
  if (
134
140
  !options.ignorePattern.some(pattern =>
@@ -1,4 +1,5 @@
1
1
  'use strict'
2
+ const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
2
3
  const createEslintRule = require('../utils/create-eslint-rule.js')
3
4
  const getGroupNumber = require('../utils/get-group-number.js')
4
5
  const getSourceCode = require('../utils/get-source-code.js')
@@ -83,6 +84,25 @@ const sortIntersectionTypes = createEslintRule.createEslintRule({
83
84
  order: 'asc',
84
85
  groups: [],
85
86
  })
87
+ validateGroupsConfiguration.validateGroupsConfiguration(
88
+ options.groups,
89
+ [
90
+ 'intersection',
91
+ 'conditional',
92
+ 'function',
93
+ 'operator',
94
+ 'keyword',
95
+ 'literal',
96
+ 'nullish',
97
+ 'unknown',
98
+ 'import',
99
+ 'object',
100
+ 'named',
101
+ 'tuple',
102
+ 'union',
103
+ ],
104
+ [],
105
+ )
86
106
  let sourceCode = getSourceCode.getSourceCode(context)
87
107
  let nodes = node.types.map(type => {
88
108
  let { getGroup, defineGroup } = useGroups.useGroups(options.groups)
@@ -1,3 +1,4 @@
1
+ import { validateGroupsConfiguration } from '../utils/validate-groups-configuration.mjs'
1
2
  import { createEslintRule } from '../utils/create-eslint-rule.mjs'
2
3
  import { getGroupNumber } from '../utils/get-group-number.mjs'
3
4
  import { getSourceCode } from '../utils/get-source-code.mjs'
@@ -82,6 +83,25 @@ const sortIntersectionTypes = createEslintRule({
82
83
  order: 'asc',
83
84
  groups: [],
84
85
  })
86
+ validateGroupsConfiguration(
87
+ options.groups,
88
+ [
89
+ 'intersection',
90
+ 'conditional',
91
+ 'function',
92
+ 'operator',
93
+ 'keyword',
94
+ 'literal',
95
+ 'nullish',
96
+ 'unknown',
97
+ 'import',
98
+ 'object',
99
+ 'named',
100
+ 'tuple',
101
+ 'union',
102
+ ],
103
+ [],
104
+ )
85
105
  let sourceCode = getSourceCode(context)
86
106
  let nodes = node.types.map(type => {
87
107
  let { getGroup, defineGroup } = useGroups(options.groups)
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
  const minimatch = require('minimatch')
3
+ const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
3
4
  const createEslintRule = require('../utils/create-eslint-rule.js')
4
5
  const getGroupNumber = require('../utils/get-group-number.js')
5
6
  const getSourceCode = require('../utils/get-source-code.js')
@@ -113,6 +114,11 @@ const sortJsxProps = createEslintRule.createEslintRule({
113
114
  order: 'asc',
114
115
  groups: [],
115
116
  })
117
+ validateGroupsConfiguration.validateGroupsConfiguration(
118
+ options.groups,
119
+ ['multiline', 'shorthand', 'unknown'],
120
+ Object.keys(options.customGroups),
121
+ )
116
122
  let sourceCode = getSourceCode.getSourceCode(context)
117
123
  let shouldIgnore = false
118
124
  if (options.ignorePattern.length) {
@@ -1,4 +1,5 @@
1
1
  import { minimatch } from 'minimatch'
2
+ import { validateGroupsConfiguration } from '../utils/validate-groups-configuration.mjs'
2
3
  import { createEslintRule } from '../utils/create-eslint-rule.mjs'
3
4
  import { getGroupNumber } from '../utils/get-group-number.mjs'
4
5
  import { getSourceCode } from '../utils/get-source-code.mjs'
@@ -112,6 +113,11 @@ const sortJsxProps = createEslintRule({
112
113
  order: 'asc',
113
114
  groups: [],
114
115
  })
116
+ validateGroupsConfiguration(
117
+ options.groups,
118
+ ['multiline', 'shorthand', 'unknown'],
119
+ Object.keys(options.customGroups),
120
+ )
115
121
  let sourceCode = getSourceCode(context)
116
122
  let shouldIgnore = false
117
123
  if (options.ignorePattern.length) {
@@ -1,4 +1,5 @@
1
1
  'use strict'
2
+ const validateGroupsConfiguration = require('../utils/validate-groups-configuration.js')
2
3
  const createEslintRule = require('../utils/create-eslint-rule.js')
3
4
  const getLinesBetween = require('../utils/get-lines-between.js')
4
5
  const getGroupNumber = require('../utils/get-group-number.js')
@@ -118,6 +119,11 @@ const sortObjectTypes = createEslintRule.createEslintRule({
118
119
  order: 'asc',
119
120
  groups: [],
120
121
  })
122
+ validateGroupsConfiguration.validateGroupsConfiguration(
123
+ options.groups,
124
+ ['multiline', 'unknown'],
125
+ Object.keys(options.customGroups),
126
+ )
121
127
  let sourceCode = getSourceCode.getSourceCode(context)
122
128
  let formattedMembers = node.members.reduce(
123
129
  (accumulator, member) => {
@@ -1,3 +1,4 @@
1
+ import { validateGroupsConfiguration } from '../utils/validate-groups-configuration.mjs'
1
2
  import { createEslintRule } from '../utils/create-eslint-rule.mjs'
2
3
  import { getLinesBetween } from '../utils/get-lines-between.mjs'
3
4
  import { getGroupNumber } from '../utils/get-group-number.mjs'
@@ -117,6 +118,11 @@ const sortObjectTypes = createEslintRule({
117
118
  order: 'asc',
118
119
  groups: [],
119
120
  })
121
+ validateGroupsConfiguration(
122
+ options.groups,
123
+ ['multiline', 'unknown'],
124
+ Object.keys(options.customGroups),
125
+ )
120
126
  let sourceCode = getSourceCode(context)
121
127
  let formattedMembers = node.members.reduce(
122
128
  (accumulator, member) => {
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
  const minimatch = require('minimatch')
3
+ const validateGroupsConfiguration = require('../utils/validate-groups-configuration.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')
@@ -10,13 +12,11 @@ const getNodeParent = require('../utils/get-node-parent.js')
10
12
  const toSingleLine = require('../utils/to-single-line.js')
11
13
  const rangeToDiff = require('../utils/range-to-diff.js')
12
14
  const getSettings = require('../utils/get-settings.js')
13
- const isPositive = require('../utils/is-positive.js')
14
15
  const useGroups = require('../utils/use-groups.js')
15
16
  const makeFixes = require('../utils/make-fixes.js')
16
17
  const sortNodes = require('../utils/sort-nodes.js')
17
18
  const complete = require('../utils/complete.js')
18
19
  const pairwise = require('../utils/pairwise.js')
19
- const compare = require('../utils/compare.js')
20
20
  const sortObjects = createEslintRule.createEslintRule({
21
21
  name: 'sort-objects',
22
22
  meta: {
@@ -155,6 +155,11 @@ const sortObjects = createEslintRule.createEslintRule({
155
155
  order: 'asc',
156
156
  groups: [],
157
157
  })
158
+ validateGroupsConfiguration.validateGroupsConfiguration(
159
+ options.groups,
160
+ ['unknown'],
161
+ Object.keys(options.customGroups),
162
+ )
158
163
  let shouldIgnore = false
159
164
  if (options.destructureOnly) {
160
165
  shouldIgnore = node.type !== 'ObjectPattern'
@@ -327,48 +332,34 @@ const sortObjects = createEslintRule.createEslintRule({
327
332
  [[]],
328
333
  )
329
334
  for (let nodes of formatProperties(node.properties)) {
335
+ let grouped = {}
336
+ for (let currentNode of nodes) {
337
+ let groupNum = getGroupNumber.getGroupNumber(
338
+ options.groups,
339
+ currentNode,
340
+ )
341
+ if (!(groupNum in grouped)) {
342
+ grouped[groupNum] = [currentNode]
343
+ } else {
344
+ grouped[groupNum].push(currentNode)
345
+ }
346
+ }
347
+ let sortedNodes = []
348
+ for (let group of Object.keys(grouped).sort(
349
+ (a, b) => Number(a) - Number(b),
350
+ )) {
351
+ sortedNodes.push(...sortNodes.sortNodes(grouped[group], options))
352
+ }
353
+ sortedNodes =
354
+ sortNodesByDependencies.sortNodesByDependencies(sortedNodes)
330
355
  pairwise.pairwise(nodes, (left, right) => {
331
- let leftNum = getGroupNumber.getGroupNumber(options.groups, left)
332
- let rightNum = getGroupNumber.getGroupNumber(options.groups, right)
333
- if (
334
- leftNum > rightNum ||
335
- (leftNum === rightNum &&
336
- isPositive.isPositive(compare.compare(left, right, options)))
337
- ) {
338
- let fix = fixer => {
339
- let grouped = {}
340
- for (let currentNode of nodes) {
341
- let groupNum = getGroupNumber.getGroupNumber(
342
- options.groups,
343
- currentNode,
344
- )
345
- if (!(groupNum in grouped)) {
346
- grouped[groupNum] = [currentNode]
347
- } else {
348
- grouped[groupNum] = sortNodes.sortNodes(
349
- [...grouped[groupNum], currentNode],
350
- options,
351
- )
352
- }
353
- }
354
- let sortedNodes = []
355
- for (let group of Object.keys(grouped).sort(
356
- (a, b) => Number(a) - Number(b),
357
- )) {
358
- sortedNodes.push(
359
- ...sortNodes.sortNodes(grouped[group], options),
360
- )
361
- }
362
- return makeFixes.makeFixes(
363
- fixer,
364
- nodes,
365
- sortedNodes,
366
- sourceCode,
367
- {
368
- partitionComment: options.partitionByComment,
369
- },
370
- )
371
- }
356
+ let indexOfLeft = sortedNodes.indexOf(left)
357
+ let indexOfRight = sortedNodes.indexOf(right)
358
+ if (indexOfLeft > indexOfRight) {
359
+ let fix = fixer =>
360
+ makeFixes.makeFixes(fixer, nodes, sortedNodes, sourceCode, {
361
+ partitionComment: options.partitionByComment,
362
+ })
372
363
  context.report({
373
364
  messageId: 'unexpectedObjectsOrder',
374
365
  data: {
@@ -1,4 +1,6 @@
1
1
  import { minimatch } from 'minimatch'
2
+ import { validateGroupsConfiguration } from '../utils/validate-groups-configuration.mjs'
3
+ import { sortNodesByDependencies } from '../utils/sort-nodes-by-dependencies.mjs'
2
4
  import { isPartitionComment } from '../utils/is-partition-comment.mjs'
3
5
  import { getCommentBefore } from '../utils/get-comment-before.mjs'
4
6
  import { createEslintRule } from '../utils/create-eslint-rule.mjs'
@@ -9,13 +11,11 @@ import { getNodeParent } from '../utils/get-node-parent.mjs'
9
11
  import { toSingleLine } from '../utils/to-single-line.mjs'
10
12
  import { rangeToDiff } from '../utils/range-to-diff.mjs'
11
13
  import { getSettings } from '../utils/get-settings.mjs'
12
- import { isPositive } from '../utils/is-positive.mjs'
13
14
  import { useGroups } from '../utils/use-groups.mjs'
14
15
  import { makeFixes } from '../utils/make-fixes.mjs'
15
16
  import { sortNodes } from '../utils/sort-nodes.mjs'
16
17
  import { complete } from '../utils/complete.mjs'
17
18
  import { pairwise } from '../utils/pairwise.mjs'
18
- import { compare } from '../utils/compare.mjs'
19
19
  const sortObjects = createEslintRule({
20
20
  name: 'sort-objects',
21
21
  meta: {
@@ -154,6 +154,11 @@ const sortObjects = createEslintRule({
154
154
  order: 'asc',
155
155
  groups: [],
156
156
  })
157
+ validateGroupsConfiguration(
158
+ options.groups,
159
+ ['unknown'],
160
+ Object.keys(options.customGroups),
161
+ )
157
162
  let shouldIgnore = false
158
163
  if (options.destructureOnly) {
159
164
  shouldIgnore = node.type !== 'ObjectPattern'
@@ -314,37 +319,30 @@ const sortObjects = createEslintRule({
314
319
  [[]],
315
320
  )
316
321
  for (let nodes of formatProperties(node.properties)) {
322
+ let grouped = {}
323
+ for (let currentNode of nodes) {
324
+ let groupNum = getGroupNumber(options.groups, currentNode)
325
+ if (!(groupNum in grouped)) {
326
+ grouped[groupNum] = [currentNode]
327
+ } else {
328
+ grouped[groupNum].push(currentNode)
329
+ }
330
+ }
331
+ let sortedNodes = []
332
+ for (let group of Object.keys(grouped).sort(
333
+ (a, b) => Number(a) - Number(b),
334
+ )) {
335
+ sortedNodes.push(...sortNodes(grouped[group], options))
336
+ }
337
+ sortedNodes = sortNodesByDependencies(sortedNodes)
317
338
  pairwise(nodes, (left, right) => {
318
- let leftNum = getGroupNumber(options.groups, left)
319
- let rightNum = getGroupNumber(options.groups, right)
320
- if (
321
- leftNum > rightNum ||
322
- (leftNum === rightNum &&
323
- isPositive(compare(left, right, options)))
324
- ) {
325
- let fix = fixer => {
326
- let grouped = {}
327
- for (let currentNode of nodes) {
328
- let groupNum = getGroupNumber(options.groups, currentNode)
329
- if (!(groupNum in grouped)) {
330
- grouped[groupNum] = [currentNode]
331
- } else {
332
- grouped[groupNum] = sortNodes(
333
- [...grouped[groupNum], currentNode],
334
- options,
335
- )
336
- }
337
- }
338
- let sortedNodes = []
339
- for (let group of Object.keys(grouped).sort(
340
- (a, b) => Number(a) - Number(b),
341
- )) {
342
- sortedNodes.push(...sortNodes(grouped[group], options))
343
- }
344
- return makeFixes(fixer, nodes, sortedNodes, sourceCode, {
339
+ let indexOfLeft = sortedNodes.indexOf(left)
340
+ let indexOfRight = sortedNodes.indexOf(right)
341
+ if (indexOfLeft > indexOfRight) {
342
+ let fix = fixer =>
343
+ makeFixes(fixer, nodes, sortedNodes, sourceCode, {
345
344
  partitionComment: options.partitionByComment,
346
345
  })
347
- }
348
346
  context.report({
349
347
  messageId: 'unexpectedObjectsOrder',
350
348
  data: {