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

Question: any options to sort the objects like expected? #436

Open
2 tasks done
ntnyq opened this issue Jan 1, 2025 · 7 comments · May be fixed by #438
Open
2 tasks done

Question: any options to sort the objects like expected? #436

ntnyq opened this issue Jan 1, 2025 · 7 comments · May be fixed by #438
Labels
bug Something isn't working

Comments

@ntnyq
Copy link

ntnyq commented Jan 1, 2025

Describe the bug

Currently, both property baz and bar matches the group method and sorts alphabetically inside group.
However bar also matches the group multiline. As the docs said:

The order of items in the groups option determines how groups are ordered.

It seems the first matched group owns a higher priority in sorting.

Except using partitionBy* or customGroups, is there any options to sort the objects like the expected result?

Code example

ESLint config

// @ts-check

import { config, configs } from 'typescript-eslint'
import pluginPerfectionist from 'eslint-plugin-perfectionist'

export default config(
  {
    extends: configs.recommended,
  },
  {
    plugins: {
      perfectionist: pluginPerfectionist,
    },
    rules: {
      'perfectionist/sort-objects': [
        'error',
        {
          groups: ['unknown', 'method', 'multiline'],
          order: 'asc',
          type: 'alphabetical',
        },
      ],
    },
  },
)

Output

export const foobar = {
  // groups: unknown
  foo: 'foo',
  // groups: method, multiline
  bar() {
    console.log('This is bar')
  },
  // groups: method
  baz: () => ({ baz: 'baz' }),
}

Expected

export const foobar = {
  // groups: unknown
  foo: 'foo',
  // groups: method
  baz: () => ({ baz: 'baz' }),
  // groups: method, multiline
  bar() {
    console.log('This is bar')
  },
}

ESLint version

Latest

ESLint Plugin Perfectionist version

Latest

Additional comments

No response

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
@ntnyq ntnyq added the bug Something isn't working label Jan 1, 2025
@ntnyq
Copy link
Author

ntnyq commented Jan 1, 2025

This is not a real bug, nor a new rule proposal or a rule change request.

But the repo doesn't have discussion page setup, so I posted it using bug template.

Feel free to close or move it.

@hugop95
Copy link
Contributor

hugop95 commented Jan 1, 2025

Hi @ntnyq

sort-objects currently does not support the array-based customGroups API with selectors/modifiers that can be found in sort-classes or sort-modules. Once this will be implemented, it will be possible to precisely define custom groups that can resolve your issue.

@ntnyq
Copy link
Author

ntnyq commented Jan 2, 2025

Thanks for your reply.

I'll leave this issue open to track it.

@ambethia
Copy link

ambethia commented Jan 3, 2025

@hugop95 When this is array-based customGroups is implemented for sort-objects, would this let me sort only the properties that are matched in my group, and leave unknown properties unsorted?

For example, I'm using panda CSS, and I have objects like:

const styles = sva({
  base: {
    container: {
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'center',
    },
    cta: {
      display: 'none',
      md: {
        display: 'initial',
      },
    },
    nav: {
      display: 'flex',
      gap: '4',
    },
    root: {
      paddingBlock: '4',
      background: 'slate.900',
    },
  },
  slots: ['root', 'container', 'nav', 'cta'],
})

I know can limit my rule with callingFunctionNamePattern, e.g. (css|cva|sva), but it sorts all of the objects at every level.

I would really like to leave the keys for base, and slot unsorted. But sort the css properties according to the custom group rules I've generated. I'm not sure if this is possible right now. What I'd like so see is:

const styles = sva({
  slots: ['root', 'container', 'nav', 'cta'],
  base: {
    root: {
      paddingBlock: '4',
      background: 'slate.900',
    },
    container: {
      display: 'flex',
      justifyContent: 'space-between',
      alignItems: 'center',
    },
    nav: {
      display: 'flex',
      gap: '4',
    },
    cta: {
      display: 'none',
      md: {
        display: 'initial',
      },
    },
  },
})

By convention I like to have the properties under base match the order in slots, which I write in the order they appear in the markup. I'm happy to order these keys myself, and have perfectionist ignore them, but I also want the nested CSS properties to get sorted.

@hugop95
Copy link
Contributor

hugop95 commented Jan 3, 2025

@ambethia

When this is array-based customGroups is implemented for sort-objects, would this let me sort only the properties that are matched in my group, and leave unknown properties unsorted?

This is already possible with the current customGroups API, as it seems that you are only looking to match keys by their names.

{
  "perfectionist/sort-objects": [
    "error",
    {
      "useConfigurationIf": { // Make `slots` go before `base`
        "callingFunctionNamePattern": "sva" // Make sure to update the plugin to v4.6.0 to get the latest fix for this: https://github.com/azat-io/eslint-plugin-perfectionist/pull/437
      },
      "groups": [
        "slots",
        "base"
      ],
      "customGroups": {
        "slots": "slots",
        "base": "base"
      }
    },
    {
      "useConfigurationIf": { // Order the `base` object keys
        "allNamesMatchPattern": "^root|container|nav|cta$"
      },
      "groups": [
        "root",
        "container",
        "nav",
        "cta"
      ],
      "customGroups": {
        "root": "root",
        "container": "container",
        "nav": "nav",
        "cta": "cta"
      }
    }
  ]
}

Explanation:

Based on your expected results, I see they are two things that need to be enforced:

  • Make slots go before base.
    • This can already be done today with useConfigurationIf.callingFunctionNamePattern: '^sva$' for example.
  • Order the base object keys: 'root' > 'container' > 'nav'> 'cta'
    • You can't match this object with a specific configuration using useConfigurationIf.callingFunctionNamePattern because the base object is a nested one and not directly called by a function.
    • But you can match this object with a specific configuration using useConfigurationIf.allNamesMatchPattern: '^root|container|nav|cta$', assuming that those keys always appear in such objects.
      • If not, it could be interesting to add a useConfigurationIf.parentObjectKeyNamePattern (placeholder name) option to match base objects.

The array-based customGroups API will be able to do the same thing as well.

@hugop95 hugop95 linked a pull request Jan 3, 2025 that will close this issue
1 task
@ntnyq
Copy link
Author

ntnyq commented Jan 5, 2025

Hi @hugop95

I checked the sort-object-types docs about customGroups and found that it seems all customGroups options are based on the property type or property name.

Is it possible to custom a group based on the property value?

There is an use case:

export const foobar = {
  // single-line property
  bar: 'bar is very very very very very very very very very very very very  very very very very very very very very very  very very very very very very very very very  very very very very very very very very very very very very very very very  long',
  // single-line property
  foo: 'foo',
}

I wish to define foo and bar as two custom groups.

@hugop95
Copy link
Contributor

hugop95 commented Jan 5, 2025

Hi @ntnyq
Similarly to sort-classes, elementValuePattern can be implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants