Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: trying to enforce a specific order within custom groups leads to complicated config #419

Open
2 tasks done
stormwarning opened this issue Dec 13, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@stormwarning
Copy link

stormwarning commented Dec 13, 2024

What rule do you want to change?

sort-classes

Describe the problem

I'm using perfectionist/sort-classes as a replacement for react/sort-comp which is autofixable, but I'm also trying to follow Airbnb's class order, which leads to a very verbose config for the rule...

Code example

{
	type: 'natural',
	ignoreCase: false,
	groups: [
		'static-property',
		'static-method',
		'property',

		// React properties
		'displayName',
		'propTypes',
		'contextTypes',
		'childContextTypes',
		'mixins',
		'statics',
		'defaultProps',

		'constructor',

		// React lifecycle methods
		'getDefaultProps',
		'getInitialState',
		'state',
		'getChildContext',
		'getDerivedStateFromProps',
		'componentWillMount',
		'UNSAFE_componentWillMount',
		'componentDidMount',
		'componentWillReceiveProps',
		'UNSAFE_componentWillReceiveProps',
		'shouldComponentUpdate',
		'componentWillUpdate',
		'UNSAFE_componentWillUpdate',
		'getSnapshotBeforeUpdate',
		'componentDidUpdate',
		'componentDidCatch',
		'componentWillUnmount',

		'handlers',
		'callbacks',
		['get-method', 'set-method'],
		'get-set-methods',
		'method',
		'unknown',
		'render-methods',
		'main-render',
	],
	customGroups: [
		// React properties.
		{
			groupName: 'displayName',
			elementNamePattern: 'displayName',
		},
		{
			groupName: 'propTypes',
			elementNamePattern: 'propTypes',
		},
		{
			groupName: 'contextTypes',
			elementNamePattern: 'contextTypes',
		},
		{
			groupName: 'childContextTypes',
			elementNamePattern: 'childContextTypes',
		},
		{
			groupName: 'mixins',
			elementNamePattern: 'mixins',
		},
		{
			groupName: 'statics',
			elementNamePattern: 'statics',
		},
		{
			groupName: 'defaultProps',
			elementNamePattern: 'defaultProps',
		},

		// React lifecycle methods.
		{
			groupName: 'getDefaultProps',
			elementNamePattern: 'getDefaultProps',
		},
		{
			groupName: 'getInitialState',
			elementNamePattern: 'getInitialState',
		},
		{
			groupName: 'state',
			elementNamePattern: 'state',
		},
		{
			groupName: 'getChildContext',
			elementNamePattern: 'getChildContext',
		},
		{
			groupName: 'getDerivedStateFromProps',
			elementNamePattern: 'getDerivedStateFromProps',
		},
		{
			groupName: 'componentWillMount',
			elementNamePattern: 'componentWillMount',
		},
		{
			groupName: 'UNSAFE_componentWillMount',
			elementNamePattern: 'UNSAFE_componentWillMount',
		},
		{
			groupName: 'componentDidMount',
			elementNamePattern: 'componentDidMount',
		},
		{
			groupName: 'componentWillReceiveProps',
			elementNamePattern: 'componentWillReceiveProps',
		},
		{
			groupName: 'UNSAFE_componentWillReceiveProps',
			elementNamePattern: 'UNSAFE_componentWillReceiveProps',
		},
		{
			groupName: 'shouldComponentUpdate',
			elementNamePattern: 'shouldComponentUpdate',
		},
		{
			groupName: 'componentWillUpdate',
			elementNamePattern: 'componentWillUpdate',
		},
		{
			groupName: 'UNSAFE_componentWillUpdate',
			elementNamePattern: 'UNSAFE_componentWillUpdate',
		},
		{
			groupName: 'getSnapshotBeforeUpdate',
			elementNamePattern: 'getSnapshotBeforeUpdate',
		},
		{
			groupName: 'componentDidUpdate',
			elementNamePattern: 'componentDidUpdate',
		},
		{
			groupName: 'componentDidCatch',
			elementNamePattern: 'componentDidCatch',
		},
		{
			groupName: 'componentWillUnmount',
			elementNamePattern: 'componentWillUnmount',
		},

		{
			groupName: 'handlers',
			elementNamePattern: /^handle.+$/.source,
		},
		{
			groupName: 'callbacks',
			elementNamePattern: /^on.+$/.source,
		},
		{
			groupName: 'get-set-methods',
			elementNamePattern:
				/^(get|set)(?!(InitialState$|DefaultProps$|ChildContext$)).+$/
					.source,
		},

		// Separate groups so that the main `render` comes last.
		{
			groupName: 'render-methods',
			elementNamePattern: /^render.+$/.source,
		},
		{
			groupName: 'main-render',
			elementNamePattern: 'render',
		},
	],
},

Additional comments

Is there any way to configure a specific order within custom groups that I'm missing?

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
@stormwarning stormwarning added the enhancement New feature or request label Dec 13, 2024
@hugop95
Copy link
Contributor

hugop95 commented Dec 13, 2024

Hi @stormwarning

Could you please give a code example including:

  • The initial state or currently sorted state.
  • What you expect to happen instead.

This will help us better understand what feature you are looking for.

@stormwarning
Copy link
Author

Oh, the config I'm using works, it's just not ideal for this case.

Ideally, I could define a single react-lifecycle custom group and define the exact order within it; something like

{
  groupName: 'react-lifecycle',
  elements: [
    'componentWillMount',
    'componentDidMount',
    // etc...
  ],
}

Where elements (or what have you) is a list of patterns. Items matching would be in this group and the order of the group would be the order of the elements array itself.

@stormwarning
Copy link
Author

Class components aren't used as much in React these days, so I understand if this isn't something to work on right away, I just wanted to point it out and see if there was a better way to configure this that I've missed

@OlivierZal
Copy link
Contributor

@hugop95, I think #408 (comment) would address the need

@hugop95
Copy link
Contributor

hugop95 commented Dec 13, 2024

@OlivierZal @stormwarning

I'm actually not sure if this falls under the same need as what we discussed in #408: if I understand correctly:

  • The config works and sorts with the expected order.
  • But it's verbose.

Ideally, I could define a single react-lifecycle custom group and define the exact order within it

What is the objective behind this? Let's consider that you have

{
  groupName: 'react-lifecycle',
  elements: [
    "componentWillMount",
    "componentDidMount",
    // etc...
  ],
}

and

{
  groupName: 'other-stuff',
  elements: [
    "otherStuff1",
    "otherStuff2",
    // etc...
  ],
}

I assume you would want your groups to look like

groups: [
 "react-lifecycle",
 "other-stuff"
]

Is this better than doing

groups: [
 "componentWillMount",
 "componentDidMount",
 "otherStuff1",
 "otherStuff2",
]

?

Can you confirm that this is solely for convenience (and not a missing feature) purpose?

elements (or what have you) is a list of patterns. Items matching would be in this group and the order of the group would be the order of the elements array itself.

This is regrouping two things in one:

  • The order of groups (the order of the elements array).
  • What each group matches (each elements member).

I see two potential issues:

  • It's opinionated: choosing to match by element pattern is common, but is only one of all the filters that are offered.
  • customGroups order matters: the first custom group that matches is the one that will be used. Following your architecture, the following configuration can not explicitly tell where some elements would go:
[
	"component",
    "comp.*",
    "com.*",
]

Where should component go? (it matches the 3 members of the array).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants