diff --git a/docs/content/rules/sort-objects.mdx b/docs/content/rules/sort-objects.mdx
index ec2dd2f3..29369fc6 100644
--- a/docs/content/rules/sort-objects.mdx
+++ b/docs/content/rules/sort-objects.mdx
@@ -264,11 +264,29 @@ Allows you to specify names or patterns for object types that should be ignored
You can specify their names or a regexp pattern to ignore, for example: `'^User.+'` to ignore all object types whose names begin with the word “User”.
-### destructureOnly
+### [DEPRECATED] destructureOnly
default: `false`
-Allows you to sort only objects that are part of a destructuring pattern. When set to `true`, the rule will apply sorting exclusively to destructured objects, leaving other object declarations unchanged.
+Use the [objectDeclarations](#objectdeclarations) and [destructuredObjects](#destructuredobjects) options instead.
+
+Allows you to only sort objects that are part of a destructuring pattern. When set to `true`, the rule will apply sorting exclusively to destructured objects, leaving other object declarations unchanged.
+
+### objectDeclarations
+
+default: `true`
+
+Allows you to choose whether to sort standard object declarations.
+
+### destructuredObjects
+
+
+ type: `boolean | { groups: boolean }`
+
+default: `true`
+
+Allows you to choose whether to sort destructured objects.
+The `groups` attribute allows you to specify whether to use groups to sort destructured objects.
### groups
diff --git a/rules/sort-objects.ts b/rules/sort-objects.ts
index 95448224..130a0edd 100644
--- a/rules/sort-objects.ts
+++ b/rules/sort-objects.ts
@@ -37,12 +37,14 @@ import { getSettings } from '../utils/get-settings'
import { isSortable } from '../utils/is-sortable'
import { useGroups } from '../utils/use-groups'
import { makeFixes } from '../utils/make-fixes'
+import { sortNodes } from '../utils/sort-nodes'
import { complete } from '../utils/complete'
import { pairwise } from '../utils/pairwise'
import { matches } from '../utils/matches'
type Options = [
Partial<{
+ destructuredObjects: { groups: boolean } | boolean
type: 'alphabetical' | 'line-length' | 'natural'
customGroups: Record
partitionByComment: string[] | boolean | string
@@ -51,7 +53,11 @@ type Options = [
locales: NonNullable
groups: (Group[] | Group)[]
partitionByNewLine: boolean
+ objectDeclarations: boolean
styledComponents: boolean
+ /**
+ * @deprecated for {@link `destructuredObjects`} and {@link `objectDeclarations`}
+ */
destructureOnly: boolean
ignorePattern: string[]
order: 'desc' | 'asc'
@@ -73,6 +79,8 @@ let defaultOptions: Required = {
partitionByComment: false,
newlinesBetween: 'ignore',
specialCharacters: 'keep',
+ destructuredObjects: true,
+ objectDeclarations: true,
styledComponents: true,
destructureOnly: false,
type: 'alphabetical',
@@ -87,8 +95,12 @@ let defaultOptions: Required = {
export default createEslintRule({
create: context => {
let sortObject = (
- node: TSESTree.ObjectExpression | TSESTree.ObjectPattern,
+ nodeObject: TSESTree.ObjectExpression | TSESTree.ObjectPattern,
): void => {
+ if (!isSortable(nodeObject.properties)) {
+ return
+ }
+
let settings = getSettings(context.settings)
let options = complete(context.options.at(0), settings, defaultOptions)
@@ -100,14 +112,17 @@ export default createEslintRule({
)
validateNewlinesAndPartitionConfiguration(options)
- let shouldIgnore = false
-
- if (options.destructureOnly) {
- shouldIgnore = node.type !== 'ObjectPattern'
+ let isDestructuredObject = nodeObject.type === 'ObjectPattern'
+ if (isDestructuredObject) {
+ if (!options.destructuredObjects) {
+ return
+ }
+ } else if (options.destructureOnly || !options.objectDeclarations) {
+ return
}
- if (!shouldIgnore && options.ignorePattern.length) {
- let variableParent = getNodeParent(node, [
+ if (options.ignorePattern.length) {
+ let variableParent = getNodeParent(nodeObject, [
'VariableDeclarator',
'Property',
])
@@ -126,10 +141,10 @@ export default createEslintRule({
typeof variableIdentifier === 'string' &&
checkMatch(variableIdentifier)
) {
- shouldIgnore = true
+ return
}
- let callParent = getNodeParent(node, ['CallExpression'])
+ let callParent = getNodeParent(nodeObject, ['CallExpression'])
let callIdentifier =
callParent?.type === 'CallExpression' &&
callParent.callee.type === 'Identifier'
@@ -137,12 +152,9 @@ export default createEslintRule({
: null
if (callIdentifier && checkMatch(callIdentifier)) {
- shouldIgnore = true
+ return
}
}
- if (shouldIgnore || !isSortable(node.properties)) {
- return
- }
let isStyledCallExpression = (identifier: TSESTree.Expression): boolean =>
identifier.type === 'Identifier' && identifier.name === 'styled'
@@ -163,9 +175,9 @@ export default createEslintRule({
styledNode.parent.name.name === 'style'))
if (
!options.styledComponents &&
- (isStyledComponents(node.parent) ||
- (node.parent.type === 'ArrowFunctionExpression' &&
- isStyledComponents(node.parent.parent)))
+ (isStyledComponents(nodeObject.parent) ||
+ (nodeObject.parent.type === 'ArrowFunctionExpression' &&
+ isStyledComponents(nodeObject.parent.parent)))
) {
return
}
@@ -352,14 +364,20 @@ export default createEslintRule({
},
[[]],
)
- let formattedMembers = formatProperties(node.properties)
-
+ let formattedMembers = formatProperties(nodeObject.properties)
+
+ let nodesSortingFunction =
+ isDestructuredObject &&
+ typeof options.destructuredObjects === 'object' &&
+ !options.destructuredObjects.groups
+ ? sortNodes
+ : sortNodesByGroups
let sortNodesIgnoringEslintDisabledNodes = (
ignoreEslintDisabledNodes: boolean,
): SortingNodeWithDependencies[] =>
sortNodesByDependencies(
formattedMembers.flatMap(nodes =>
- sortNodesByGroups(nodes, options, {
+ nodesSortingFunction(nodes, options, {
ignoreEslintDisabledNodes,
}),
),
@@ -460,6 +478,25 @@ export default createEslintRule({
schema: [
{
properties: {
+ destructuredObjects: {
+ oneOf: [
+ {
+ type: 'boolean',
+ },
+ {
+ properties: {
+ groups: {
+ description:
+ 'Controls whether to use groups to sort destructured objects.',
+ type: 'boolean',
+ },
+ },
+ additionalProperties: false,
+ type: 'object',
+ },
+ ],
+ description: 'Controls whether to sort destructured objects.',
+ },
ignorePattern: {
description:
'Specifies names or patterns for nodes that should be ignored by rule.',
@@ -477,6 +514,10 @@ export default createEslintRule({
description: 'Controls whether to sort only destructured objects.',
type: 'boolean',
},
+ objectDeclarations: {
+ description: 'Controls whether to sort object declarations.',
+ type: 'boolean',
+ },
styledComponents: {
description: 'Controls whether to sort styled components.',
type: 'boolean',
diff --git a/test/sort-objects.test.ts b/test/sort-objects.test.ts
index e8cf82b3..d1d48267 100644
--- a/test/sort-objects.test.ts
+++ b/test/sort-objects.test.ts
@@ -3850,7 +3850,7 @@ describe(ruleName, () => {
],
})
- ruleTester.run(`${ruleName}: allow to use for destructuring only`, rule, {
+ ruleTester.run(`${ruleName}: allow to use 'destructureOnly'`, rule, {
invalid: [
{
errors: [
@@ -3914,6 +3914,202 @@ describe(ruleName, () => {
],
})
+ ruleTester.run(`${ruleName}: allow to use 'objectDeclarations'`, rule, {
+ invalid: [
+ {
+ errors: [
+ {
+ data: {
+ right: 'b',
+ left: 'c',
+ },
+ messageId: 'unexpectedObjectsOrder',
+ },
+ {
+ data: {
+ right: 'a',
+ left: 'b',
+ },
+ messageId: 'unexpectedObjectsOrder',
+ },
+ ],
+ output: dedent`
+ let obj = {
+ c: 'c',
+ a: 'a',
+ b: 'b',
+ }
+
+ let { a, b, c } = obj
+ `,
+ code: dedent`
+ let obj = {
+ c: 'c',
+ a: 'a',
+ b: 'b',
+ }
+
+ let { c, b, a } = obj
+ `,
+ options: [
+ {
+ objectDeclarations: false,
+ },
+ ],
+ },
+ ],
+ valid: [
+ {
+ code: dedent`
+ let obj = {
+ c: 'c',
+ a: 'a',
+ b: 'b',
+ }
+
+ let { a, b, c } = obj
+ `,
+ options: [
+ {
+ objectDeclarations: false,
+ },
+ ],
+ },
+ ],
+ })
+
+ describe(`${ruleName}: allow to use 'destructuredObjects'`, () => {
+ ruleTester.run(`${ruleName}: boolean 'destructuredObjects'`, rule, {
+ invalid: [
+ {
+ errors: [
+ {
+ data: {
+ right: 'b',
+ left: 'c',
+ },
+ messageId: 'unexpectedObjectsOrder',
+ },
+ {
+ data: {
+ right: 'a',
+ left: 'b',
+ },
+ messageId: 'unexpectedObjectsOrder',
+ },
+ ],
+ output: dedent`
+ let obj = {
+ a: 'a',
+ b: 'b',
+ c: 'c',
+ }
+
+ let { c, a, b } = obj
+ `,
+ code: dedent`
+ let obj = {
+ c: 'c',
+ b: 'b',
+ a: 'a',
+ }
+
+ let { c, a, b } = obj
+ `,
+ options: [
+ {
+ destructuredObjects: false,
+ },
+ ],
+ },
+ ],
+ valid: [
+ {
+ code: dedent`
+ let obj = {
+ a: 'a',
+ b: 'b',
+ c: 'c',
+ }
+
+ let { b, c, a } = obj
+ `,
+ options: [
+ {
+ destructuredObjects: false,
+ },
+ ],
+ },
+ ],
+ })
+
+ ruleTester.run(
+ `${ruleName}: object 'destructuredObjects': 'groups' attribute`,
+ rule,
+ {
+ invalid: [
+ {
+ errors: [
+ {
+ data: {
+ leftGroup: 'unknown',
+ rightGroup: 'top',
+ right: 'c',
+ left: 'a',
+ },
+ messageId: 'unexpectedObjectsGroupOrder',
+ },
+ ],
+ options: [
+ {
+ customGroups: {
+ top: 'c',
+ },
+ destructuredObjects: { groups: true },
+ groups: ['top', 'unknown'],
+ },
+ ],
+ output: dedent`
+ let { c, a, b } = obj
+ `,
+ code: dedent`
+ let { a, c, b } = obj
+ `,
+ },
+ {
+ errors: [
+ {
+ data: {
+ rightGroup: 'unknown',
+ leftGroup: 'top',
+ right: 'b',
+ left: 'c',
+ },
+ messageId: 'unexpectedObjectsGroupOrder',
+ },
+ ],
+ options: [
+ {
+ customGroups: {
+ top: 'c',
+ },
+ destructuredObjects: { groups: false },
+ groups: ['top', 'unknown'],
+ },
+ ],
+ output: dedent`
+ let { a, b, c } = obj
+ `,
+ code: dedent`
+ let { a, c, b } = obj
+ `,
+ },
+ ],
+ valid: [],
+ },
+ )
+ })
+
ruleTester.run(`${ruleName}: works with settings`, rule, {
valid: [
{