Giter VIP home page Giter VIP logo

eslint-plugin-perfectionist's Introduction

ESLint Plugin Perfectionist

ESLint Plugin Perfectionist logo

Version GitHub license

ESLint plugin that sets rules to format your code and make it consistent.

This plugin defines rules for sorting various data, such as objects, imports, TypeScript types, enums, JSX props, Svelte attributes, etc. alphabetically, naturally, or by line length

All rules are automatically fixable. It's safe!

๐Ÿฆ„ Why

Sorting imports and properties in software development offers numerous benefits:

  • Readability: Finding declarations in a sorted, large list is a little faster. Remember that you read the code much more often than you write it.

  • Maintainability: Sorting imports and properties is considered a good practice in software development, contributing to code quality and consistency across the codebase.

  • Code Review and Collaboration: If you set rules that say you can only do things one way, then no one will have to spend time thinking about how to do it.

  • Code Uniformity: When all code looks exactly the same, it is very hard to see who wrote it, which makes achieving the lofty goal of collective code ownership easier.

  • Aesthetics: This not only provides functional benefits, but also gives the code an aesthetic appeal, visually pleasing and harmonious structure. Take your code to the beauty salon!

๐Ÿ“– Documentation

See docs.

ESLint Plugin Perfectionist usage example

๐Ÿ’ฟ Installation

You'll first need to install ESLint:

npm install --save-dev eslint

Next, install eslint-plugin-perfectionist:

npm install --save-dev eslint-plugin-perfectionist

๐Ÿš€๏ธ๏ธ๏ธ๏ธ Usage

Add eslint-plugin-perfectionist to the plugins section of the ESLint configuration file and define the list of rules you will use.

Legacy Config (.eslintrc)

{
  "plugins": [
    "perfectionist"
  ],
  "rules": {
    "perfectionist/sort-objects": [
      "error",
      {
        "type": "natural",
        "order": "asc"
      }
    ]
  }
}

Flat Config (eslint.config.js) (requires eslint >= v8.23.0)

import perfectionist from 'eslint-plugin-perfectionist'

export default [
  {
    plugins: {
      perfectionist,
    },
    rules: {
      'perfectionist/sort-objects': [
        'error',
        {
          type: 'natural',
          order: 'asc',
        },
      ],
    },
  },
]

โš™๏ธ Configs

The easiest way to use eslint-plugin-perfectionist is to use ready-made configs. Config files use all the rules of the current plugin, but you can override them.

Legacy Config (.eslintrc)

{
  "extends": [
    "plugin:perfectionist/recommended-natural"
  ]
}

Flat Config (eslint.config.js)

import perfectionistNatural from 'eslint-plugin-perfectionist/configs/recommended-natural'

export default [
  perfectionistNatural,
]

List of Configs

Name Description
recommended-alphabetical all plugin rules with alphabetical sorting in ascending order
recommended-natural all plugin rules with natural sorting in ascending order
recommended-line-length all plugin rules with sorting by line length in descending order

โœ… Rules

๐Ÿ”ง Automatically fixable by the --fix CLI option.

Name Description ๐Ÿ”ง
sort-array-includes enforce sorted arrays before include method ๐Ÿ”ง
sort-astro-attributes enforce sorted Astro attributes ๐Ÿ”ง
sort-classes enforce sorted classes ๐Ÿ”ง
sort-enums enforce sorted TypeScript enums ๐Ÿ”ง
sort-exports enforce sorted exports ๐Ÿ”ง
sort-imports enforce sorted imports ๐Ÿ”ง
sort-interfaces enforce sorted interface properties ๐Ÿ”ง
sort-jsx-props enforce sorted JSX props ๐Ÿ”ง
sort-maps enforce sorted Map elements ๐Ÿ”ง
sort-named-exports enforce sorted named exports ๐Ÿ”ง
sort-named-imports enforce sorted named imports ๐Ÿ”ง
sort-object-types enforce sorted object types ๐Ÿ”ง
sort-objects enforce sorted objects ๐Ÿ”ง
sort-svelte-attributes enforce sorted Svelte attributes ๐Ÿ”ง
sort-intersection-types enforce sorted intersection types ๐Ÿ”ง
sort-union-types enforce sorted union types ๐Ÿ”ง
sort-vue-attributes enforce sorted Vue attributes ๐Ÿ”ง

โ‰๏ธ FAQ

Can I automatically fix problems in the editor?

Yes. To do this, you need to enable autofix in ESLint when you save the file in your editor. Instructions for your editor can be found here.

Is it safety?

On the whole, yes. We are very careful to make sure that the work of the plugin does not negatively affect the work of the code. For example, the plugin takes into account spread operators in JSX and objects, comments to the code. Safety is our priority. If you encounter any problem, you can create an issue.

Why not Prettier?

I love Prettier. However, this is not his area of responsibility. Prettier is used for formatting, and ESLint is also used for styling. For example, changing the order of imports can affect how the code works (console.log calls, fetch, style loading). Prettier should not change the AST. There is a cool article about this: "The Blurry Line Between Formatting and Style" by @joshuakgoldberg.

โš ๏ธ Troubleshooting

There are rules of ESLint and other ESLint plugins that may conflict with the rules of ESLint Plugin Perfectionist. We strongly recommend that you disable rules with similar functionality.

I recommend that you read the documentation before using any rules.

Possible conflicts

perfectionist/sort-imports:

{
  "rules": {
    "import/order": "off",
    "sort-imports": "off"
  }
}

perfectionist/sort-interfaces:

{
  "rules": {
    "@typescript-eslint/adjacent-overload-signatures": "off"
  }
}

perfectionist/sort-jsx-props:

{
  "rules": {
    "react/jsx-sort-props": "off"
  }
}

perfectionist/sort-named-imports:

{
  "rules": {
    "sort-imports": "off"
  }
}

perfectionist/sort-object-types:

{
  "rules": {
    "@typescript-eslint/adjacent-overload-signatures": "off"
  }
}

perfectionist/sort-objects:

{
  "rules": {
    "sort-keys": "off"
  }
}

perfectionist/sort-union-types:

{
  "rules": {
    "@typescript-eslint/sort-type-constituents": "off"
  }
}

๐Ÿšฅ Versioning Policy

This plugin is following Semantic Versioning and ESLint's Semantic Versioning Policy.

โค๏ธ Contributing

See Contributing Guide.

๐Ÿ‘ See Also

๐Ÿ”’ License

MIT ยฉ Azat S.

eslint-plugin-perfectionist's People

Contributors

ai avatar azat-io avatar chirokas avatar deathemperor avatar hampus-stravito avatar haocheng6 avatar joshuakgoldberg avatar kid-joker avatar motss avatar renato-bohler avatar simongolms avatar sitek94 avatar stovmascript avatar tthornton3-chwy avatar wondermarin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

eslint-plugin-perfectionist's Issues

Bug: (sort-classes) The indexable type inside classes is not seen as it's own group.

Describe the bug

Like interfaces, you can declare classes as indexable. This means, you can have classes looking like this:

export default class Test {
    [key: string]: unknown
    a = 'a'
    b = 'b'
}

const t = new Test()
for (const key in t) console.log(key) // Logs 'a' then 'b', this would lead to an TypeError, if the index type notation wasn't there.

The thing is that [key: string]: unknown is seen as unknown which is why it's buried deep inside the class or down in the bottom of the class.

Code example

For example, it transform this:

export default class Test {
	[key: string]: unknown
    a = 'a'
    b = 'b'
    x(): void {}

    get y(): number {
        return 0
    }
}

to this:

export default class Test {
    a = 'a'
    b = 'b'
    x(): void {}

    get y(): number {
        return 0
    }
    [key: string]: unknown
}

Because I have the unknown group at the bottom of my config. I really don't want to move it to the top, because I don't know what else this plugin sees something as "unknown".

ESLint version

8.45.0

ESLint Plugin Perfectionist version

1.5.1

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.

Bug: a.options.at is not a function

Describe the bug

[eslint] a.options.at is not a function
Occurred while linting checkFileExtension.js:14
Rule: "perfectionist/sort-array-includes"

swears like this at all rules, except for the rules regarding types

Code example

pops up on perfectly normal lines without any problems
https://i.imgur.com/tEjtt92.png

ESLint version

v8.34.0

ESLint Plugin Perfectionist version

v1.4.0

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.

Bug: sort-object-types - Fix objects must not be overlapped in a report.

Describe the bug

New bug from v1.1.1:

Fix objects must not be overlapped in a report.
Occurred while linting /project/file-with-error.ts:10
Rule: "perfectionist/sort-object-types"
AssertionError [ERR_ASSERTION]: Fix objects must not be overlapped in a report.
    at mergeFixes (/project/node_modules/eslint/lib/linter/report-translator.js:152:9)
    at normalizeFixes (/project/node_modules/eslint/lib/linter/report-translator.js:182:16)
    at /project/node_modules/eslint/lib/linter/report-translator.js:349:49
    at Object.report (/project/node_modules/eslint/lib/linter/linter.js:1021:41)
    at /project/node_modules/eslint-plugin-perfectionist/dist/index.js:1:7540
    at I (/project/node_modules/eslint-plugin-perfectionist/dist/index.js:1:2732)
    at TSTypeLiteral (/project/node_modules/eslint-plugin-perfectionist/dist/index.js:1:7516)
    at /project/node_modules/eslint/lib/linter/timing.js:141:28
    at ruleErrorHandler (/project/node_modules/eslint/lib/linter/linter.js:1050:28)
    at /project/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/project/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/project/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
    at NodeEventGenerator.applySelectors (/project/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
    at NodeEventGenerator.enterNode (/project/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
    at CodePathAnalyzer.enterNode (/project/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:795:23)
    at /project/node_modules/eslint/lib/linter/linter.js:1085:32
    at Array.forEach (<anonymous>)
    at runRules (/project/node_modules/eslint/lib/linter/linter.js:1080:15)
    at Linter._verifyWithoutProcessors (/project/node_modules/eslint/lib/linter/linter.js:1330:31)
    at Linter._verifyWithConfigArray (/project/node_modules/eslint/lib/linter/linter.js:1706:21)
    at Linter.verify (/project/node_modules/eslint/lib/linter/linter.js:1412:65)
    at Linter.verifyAndFix (/project/node_modules/eslint/lib/linter/linter.js:1967:29)
    at verifyText (/project/node_modules/eslint/lib/cli-engine/cli-engine.js:245:48)
    at CLIEngine.executeOnFiles (/project/node_modules/eslint/lib/cli-engine/cli-engine.js:825:28)
    at ESLint.lintFiles (/project/node_modules/eslint/lib/eslint/eslint.js:551:23)

Code example

Seems like the // should just be string is the cause.

export const generateListOfChanges = ({
    arrayOfChanges,
    propNameForWhatChanged,
    formatValue = (value) => `${value}%`
}: {
    arrayOfChanges: {
        isIncreased: boolean;
        isImproved: boolean;
        change: number;
        isSame: boolean;
        [propNameForWhatChanged: string]: boolean | number | string | unknown; // should just be string
    }[];
    propNameForWhatChanged: string;
    formatValue?: (value: number) => string;
}) => {
};

ESLint version

v8.41.0

ESLint Plugin Perfectionist version

v1.1.1

Additional comments

Thanks for fixing these so quickly!

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Feature: builtin-type

What rule do you want to change?

sort-imports

Describe the problem

Config

groups: [
    ['builtin'],
    ['external', 'type'],
    ['internal', 'internal-type'],
    ['parent', 'parent-type'],
    ['sibling', 'sibling-type'],
    ['index', 'index-type'],
    'object',
    'unknown'
],

Current

http is builtin.

import path from 'path';
import express, { static as serveStatic } from 'express';
import type { Server } from 'http'; // Yikes! This is a built in like path!

Expected

import path from 'path';
import type { Server } from 'http'; // Much better!
import express, { static as serveStatic } from 'express';

Code example

I'm not sure what change is required.

https://github.com/azat-io/eslint-plugin-perfectionist/blob/main/rules/sort-imports.ts

Additional comments

Ideally we'd have something like this:

groups: [
    ['builtin', 'builtin-type'], // <--- I'm suggesting we add builtin-type.
    ['external', 'type'], // <--- Maybe type should be external-type?
    ['internal', 'internal-type'],
    ['parent', 'parent-type'],
    ['sibling', 'sibling-type'],
    ['index', 'index-type'],
    'object',
    'unknown'
],

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Feature: Consistent the order same line-length entities

What rule do you want to change?

sort-named-imports,sort-jsx-props

Describe the problem

Be enabling line-length for sort-name-imports/sort-jsx-props (and others), the same length entities can be re-order after some code manipulations.

Code example

E.g: I have
import { all, put, call, select } from "typed-redux-saga";

After remove the statement containg all and put functions, then revert the deletion, then re-import in order put then all. So the import statement becomes:
import { put, all, call, select } from "typed-redux-saga";
which is a unnecessary change.

Additional comments

Plugin version v2.1.0

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug: sort-object-types - don't fail when multiple interfaces have the same value

Describe the bug

This is a wild one.

Easier to show with a screenshot:
Screenshot 2023-06-09 at 5 19 14 PM

Code example

Code is from the answer on https://stackoverflow.com/questions/52760509/typescript-returntype-of-overloaded-function (I'm thanking my past-self for remembering to include the link to where I got this code!)

type OverloadedReturnType<T> = T extends {
    (...args: any[]): infer R;
    (...args: any[]): infer R;
    (...args: any[]): infer R;
    (...args: any[]): infer R;
}
    ? R
    : T extends { (...args: any[]): infer R; (...args: any[]): infer R; (...args: any[]): infer R }
    ? R
    : T extends { (...args: any[]): infer R; (...args: any[]): infer R }
    ? R
    : T extends (...args: any[]) => infer R
    ? R
    : any;

ESLint version

v8.41.0

ESLint Plugin Perfectionist version

v1.1.0

Additional comments

Hopefully rare, I was able to just use eslint-disable to avoid the issue.

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug: perfectionist/sort-interfaces - don't sort new

Describe the bug

If an interface describes a class, I think new has to be stay first.

Code example

Before

export interface ClassExample<T> {
    new (...args: unknown[]): T; // <-- good
    (...args: unknown[]): Partial<T>;
}

After

export interface ClassExample<T> {
    (...args: unknown[]): Partial<T>;
    new (...args: unknown[]): T; // <-- bad
}

ESLint version

v8.41.0

ESLint Plugin Perfectionist version

v1.1.0

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.

Bug: Unable to use `@/**` as internal path

Describe the bug

Hi!

First of all, thank you for this awesome plugin! I'm loving it!


I have this rule configuration

'perfectionist/sort-imports': [
      'error',
      {
        groups: [
          ['side-effect', 'object'],
          ['builtin-type', 'builtin'],
          ['type', 'external'],
          ['internal-type', 'internal'],
          [
            'parent-type',
            'parent',
            'sibling-type',
            'sibling',
            'index-type',
            'index',
          ],
          'styles',
          'unknown',
        ],
        'internal-pattern': ['~/**', '@/**'],
        'newlines-between': 'always',
        'read-tsconfig': true,
        type: 'natural',
      },
    ],

And I'm using the following setting in tsconfig.json

{
	"paths": {
      "@/public/*": ["./public/*"],
      "@/*": ["./src/*"]
    },
}

Code example

The code I want to format:

import { Box, CircularProgress, Container, Typography } from '@mui/material'
import Image from 'next/image'
import { Suspense } from 'react'

import logoDarkMode from '@/public/logo_dark_mode.png'

Expected result

import { Box, CircularProgress, Container, Typography } from '@mui/material'
import Image from 'next/image'
import { Suspense } from 'react'

import logoDarkMode from '@/public/logo_dark_mode.png'

Actual result

import logoDarkMode from '@/public/logo_dark_mode.png'
import { Box, CircularProgress, Container, Typography } from '@mui/material'
import Image from 'next/image'
import { Suspense } from 'react'

ESLint version

v8.42.0

ESLint Plugin Perfectionist version

v1.1.2

Additional comments

If I update my tsconfig.json file to use ~/ instead of @/, everything work as expected.

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug: (sort-imports) If there are comments above the import statement, automatic fixing will disrupt the layout.

Describe the bug

If there are comments above the import statement, automatic fixing will disrupt the layout.

Code example

eslint.config.js:

import ESlintPluginPerfectionist from 'eslint-plugin-perfectionist'

export default [
  {
    files: ['**/*.js', '**/*.cjs', '**/*.mjs', '**/*.jsx'],
    ignores: ['**/*.min.*', '**/dist/**', '**/build/**', '**/node_modules/**', '**/.*/**'],
    languageOptions: {
      parserOptions: {
        ecmaFeatures: {
          jsx: true
        },
        ecmaVersion: 'latest',
        sourceType: 'module'
      }
    },
    plugins: {
      'perfectionist': ESlintPluginPerfectionist
    },
    rules: {
      ...ESlintPluginPerfectionist.configs['recommended-natural'].rules
    },
  }
]

index.js:

// test
// test
import b from 'b.js'
import a from 'a.js'

result:

// test
import a from 'a.js'
// test
import b from 'b.js'

expected result:

// test
// test
import a from 'a.js'
import b from 'b.js'

ESLint version

v8.45.0

ESLint Plugin Perfectionist version

v1.5.1

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.

Bug: Respect package.json#imports

Describe the bug

Currently when using package.json's imports key to map internal files like:

"imports": {
  "#*": "./src/*"
}

The recommended-natural rules aren't placing the internal pattern where it should be.

For example it considers this to be valid:

import { type SDK } from "#config.ts";
import fs from "node:fs"

while it should be:

import fs from "node:fs"
import { type SDK } from "#config.ts";

Code example

I tried using the internal-pattern option without success, I tried both { "internal-pattern": ["#*"] } and { "internal-pattern": ["#**"] }.

ESLint version

v8.49.0

ESLint Plugin Perfectionist version

v2.0.1

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.

Bug: sort-union-types broken

Describe the bug

sort-union-types considers an inline comment as part of a union type and breaks it by sorting it

Code example

This case is ok

-    accountTypeIds?: (1 | 2 | 3 | 4 | 5 | 100)[]; // Specific Account type Ids to filter accounts. Example: 2
+    accountTypeIds?: (100 | 5 | 4 | 3 | 2 | 1)[]; // Specific Account type Ids to filter accounts. Example: 2

And here is the problem

-    accountTypeId: 1 | 2 | 3 | 4 | 5 | 100; // Account type ID. Example: 3
+    accountTypeId: 100 | // Account type ID. Example: 3 5 | 4 | 3 | 2 | 1;

ESLint version

8.21.0

ESLint Plugin Perfectionist version

1.5.0

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.

Is there a difference between `external-type` and `type`?

What rule do you want to change?

sort-imports

Describe the problem

I apologize for raising a question here because the "Discussions" section is closed.

I noticed that a new type called "external-type" has been added in the source code, which is not mentioned in the documentation. Is there any difference between "external-type" and the existing "type"? If they are the same, would it be possible to update the documentation to promote "external-type" as the primary option and gradually remove "type" in future versions? I find "type" confusing in terms of semantics.

Code example

type Group<T extends string[]> =
  | 'external-type'
  | 'internal-type'
  | 'builtin-type'
  | 'sibling-type'
  | 'parent-type'
  | 'side-effect'
  | 'index-type'
  | 'internal'
  | 'external'
  | T[number]
  | 'sibling'
  | 'unknown'
  | 'builtin'
  | 'parent'
  | 'object'
  | 'index'
  | 'style'
  | 'type'

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.

Bug: Option for Enum

What rule do you want to change?

sort-enums

Describe the problem

Currently, the sort-enums rule can break the code, if the enums don't use value

In the following code, VAL2 has an implicit value of 0, and VAL1 an implicit value of 1. So, if I sort with the fixer, VAL1 will be set first, and implicit values will be inverted

Code example

export enum Enum1 {
  VAL2, // implicit value: 0
  VAL1, // implicit value: 1
}

Additional comments

IMO, the rule must sort only enums that come with explicit values, and must avoid changing enums with implicit values

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Feature: Custom import groups

What rule do you want to change?

sort-imports

Describe the problem

We need to add the ability to define custom import groups so that we can better sort the imports by meaning.

Code example

{
  "plugins": ["perfectionist"],
  "rules": {
    "perfectionist/sort-imports": [
      "error",
      {
        "type": "natural",
        "order": "asc",
        "custom-groups": {
          "values": {
            "react": ["react", "react-*"],
            "nanostores": ["nanostores", "@nanostores/**"]
          },
          "type": {
            "react": ["react", "react-*"]          
          },
        }
        "groups": [
          "react",
          "nanostores"
        ],
        "newlines-between": "always"
      }
    ]
  }
}
import React from 'react'
import type { FC } from 'react'
import { render } from 'react-dom'

import { useStore } from '@nanostores/react'

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.

Bug: sort-classes does not follow order in groups for private instance method

Describe the bug

When given a custom sort order for sort-classes, private methods (with #) syntax are not sorted properly but rather the # seems to be interpreted as just another character.

Code example

Order set in eslint config:

"perfectionist/sort-classes": [
  "error",
  {
    "type": "natural",
    "order": "asc",
    "groups": [
      "static-property",
      "private-property",
      "property",
      "constructor",
      "method",
      "private-method",
      "static-method",
      "other"
    ]
  }
]

The following unsorted class:

class MyUnsortedClass {
  someOtherProperty

  someProperty = 1

  constructor() {}

  static #aPrivateStaticMethod () {}

  #somePrivateProperty

  #someOtherPrivateProperty = 2

  static someStaticProperty = 3

  static #someStaticPrivateProperty = 4

  aInstanceMethod () {}

  static aStaticMethod () {}

  #aPrivateInstanceMethod () {}

}

results in the following order:

class MyUnsortedClass {
  static #someStaticPrivateProperty = 4

  static someStaticProperty = 3

  #someOtherPrivateProperty = 2

  #somePrivateProperty

  someOtherProperty

  someProperty = 1

  constructor() {}

  #aPrivateInstanceMethod () {}

  aInstanceMethod () {}

  static #aPrivateStaticMethod () {}

  static aStaticMethod () {}

}

the private instance method is above the instance method despite the group having a different order.
It should be:

aInstanceMethod () {}

#aPrivateInstanceMethod () {}

ESLint version

8.48.0

ESLint Plugin Perfectionist version

1.5.1

Additional comments

it seems the # is not interpreted as "private" but rather just as a character in sorting static/regular methods and properties

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Feature: If `[type] | null | undefined`, sort first [type]

What rule do you want to change?

sort-union-types

Describe the problem

@azat-io

Currently, if sort-union-types finds [type] | null | undefined it sorts like null | [type] | undefined. It sorts alphabetically by default, but has the side-effect of not placing the [type] at the begining, when a type might be null | undefined.

Code example

this:

Promise<string | null | undefined> // which reads better

becomes

Promise<null | string | undefined>

and this:

personId?: string | null // reads much better with the `[type]` sorted at the begining

becomes

personId?: null | string

Additional comments

When finding [type] with null and/or undefined, it reads way better by sorting the [type] at the begining of the union.

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug(sort-imports): Endless newlines added between imports when semicolons are used

Describe the bug

When running ESLint with --fix on a file containing imports that end with ; and the perfectionist/sort-imports rule believes should be separated, a newline is always added before the first import's ;. This causes the fixer to continuously add more newlines before the ;.

Code example

Before:

import abc from "abc";
import def from "./def";

After:

import abc from "abc"









;
import def from "./def";

ESLint version

8.42.0

ESLint Plugin Perfectionist version

1.1.0

Additional comments

I'm using a config that just extends the recommended defaults:

module.exports = {
  extends: ["plugin:perfectionist/recommended-alphabetical"],
  parserOptions: {
    ecmaVersion: 2020,
    sourceType: "module",
  },
  plugins: ["perfectionist"],
};

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Feature: (sort-classes) Option to treat function properties as methods

What rule do you want to change?

sort-classes

Describe the problem

export class Model {
    a: string = ''
    b = () => {
        this.a = 'a'
    }
    c: string = ''
    d() {
        return this.a
    }
}

Code example

export class Model {
    a: string = ''
    c: string = ''
    d() {
        return this.a
    }
    b = () => {
        this.a = 'a'
    }
}

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.

Bug: (sort-imports) prefix-only builtin modules are defined as external modules

Describe the bug

When using the node: prefix for an builtin module, the sort-imports rule defines it as an external module.

Code example

IN CONFIG:

"perfectionist/sort-imports": [
  "error",
  {
    "type": "natural",
    "groups": [
      "builtin",
      "external",
      "internal",
      "parent",
      "sibling",
      "index",
      "side-effect"
    ]
  }
]

IN CODE:

import { writeFile } from "node:fs/promises"; // โคธ There is no space between groups.
import { createRoot } from "react-dom/client";

ESLint version

v8.48.0

ESLint Plugin Perfectionist version

v2.0.0

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.

Bug: Fix objects must not be overlapped in a report.

Describe the bug

When running this command

eslint . --ext .js,.jsx,.ts,.tsx --fix --cache

I get this error

Oops! Something went wrong! :(

ESLint: 8.41.0


AssertionError [ERR_ASSERTION]: Fix objects must not be overlapped in a report.
    at mergeFixes (PROJECT_PATH/node_modules/eslint/lib/linter/report-translator.js:152:9)
    at normalizeFixes (PROJECT_PATH/node_modules/eslint/lib/linter/report-translator.js:182:16)
    at PROJECT_PATH/node_modules/eslint/lib/linter/report-translator.js:349:49
    at Object.report (PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1021:41)
    at PROJECT_PATH/node_modules/eslint-plugin-perfectionist/dist/index.js:3:217
    at I (PROJECT_PATH/node_modules/eslint-plugin-perfectionist/dist/index.js:1:2481)
    at PROJECT_PATH/node_modules/eslint-plugin-perfectionist/dist/index.js:3:143
    at Array.forEach (<anonymous>)
    at Program:exit (PROJECT_PATH/node_modules/eslint-plugin-perfectionist/dist/index.js:3:131)
    at ruleErrorHandler (PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1050:28)
    at PROJECT_PATH/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (PROJECT_PATH/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (PROJECT_PATH/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
    at NodeEventGenerator.applySelectors (PROJECT_PATH/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
    at NodeEventGenerator.leaveNode (PROJECT_PATH/node_modules/eslint/lib/linter/node-event-generator.js:349:14)
    at CodePathAnalyzer.leaveNode (PROJECT_PATH/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:816:23)
    at PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1087:32
    at Array.forEach (<anonymous>)
    at runRules (PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1080:15)
    at Linter._verifyWithoutProcessors (PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1330:31)
    at Linter._verifyWithConfigArray (PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1706:21)
    at Linter.verify (PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1412:65)
    at Linter.verifyAndFix (PROJECT_PATH/node_modules/eslint/lib/linter/linter.js:1967:29)
    at verifyText (PROJECT_PATH/node_modules/eslint/lib/cli-engine/cli-engine.js:245:48)
    at CLIEngine.executeOnFiles (PROJECT_PATH/node_modules/eslint/lib/cli-engine/cli-engine.js:825:28)
    at ESLint.lintFiles (PROJECT_PATH/node_modules/eslint/lib/eslint/eslint.js:551:23)
    at Object.execute (PROJECT_PATH/node_modules/eslint/lib/cli.js:391:36)
    at async main (PROJECT_PATH/node_modules/eslint/bin/eslint.js:135:24)

Code example

{
  "extends": ["@callstack", "plugin:perfectionist/recommended-line-length"],
  "plugins": ["perfectionist"],

  "settings": {
    "import/parsers": {
      "@typescript-eslint/parser": [".ts", ".tsx"]
    },
    "import/resolver": {
      "typescript": {},
      "babel-module": {}
    }
  },
  "rules": {
    "perfectionist/sort-objects": [
      "error",
      {
        "type": "line-length",
        "order": "desc"
      }
    ],
    "import/newline-after-import": ["error", { "count": 1 }],
    "react-native/no-raw-text": [
      "off",
      {
        "skip": ["Heading", "Body", "Title", "Button"]
      }
    ],
    "react-native/no-color-literals": "off"
  },
  "overrides": [
    {
      "files": ["*.stories.tsx", "test/**", "*.config.js", "*.config.ts"],
      "rules": {
        "import/no-default-export": "off",
        "import/no-extraneous-dependencies": "off"
      }
    },
    {
      "files": ["test/**"],
      "env": {
        "jest": true,
        "jest/globals": true
      }
    }
  ]
}

ESLint version

v8.41.0

ESLint Plugin Perfectionist version

v1.1.0

Additional comments

{
  "devDependencies": {
    "@babel/core": "^7.20.0",
    "@callstack/eslint-config": "^13.0.2",
    "@testing-library/jest-native": "^5.4.2",
    "@testing-library/react-native": "^12.1.2",
    "@types/jest": "^29.2.1",
    "@types/lodash.debounce": "^4.0.7",
    "@types/react": "~18.0.14",
    "babel-plugin-module-resolver": "^5.0.0",
    "eslint": "^8.41.0",
    "eslint-import-resolver-babel-module": "^5.3.2",
    "eslint-import-resolver-typescript": "^3.5.5",
    "eslint-plugin-import": "^2.27.5",
    "eslint-plugin-jest": "^27.2.1",
    "eslint-plugin-perfectionist": "^1.1.0",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint_d": "^12.2.1",
    "jest": "^29.2.1",
    "jest-expo": "^48.0.2",
    "prettier": "^2.8.8",
    "typescript": "^4.9.4"
  }
}

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug: disable sorting in `side-effect`

Describe the bug

side-effect imports is unique. They change environment and canโ€™t be sorted without potencial issue.

I suggets to disable sorting for them.

Code example

import './enable-client.js'
import './add-feature-to-client.js'

ESLint version

N/A

ESLint Plugin Perfectionist version

v1.5.0

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.

Feature: The order changes for elements of the same length when new elements are added

What rule do you want to change?

sort-imports

Describe the problem

I've this config:

    "perfectionist/sort-imports": [
      "error",
      {
        "type": "line-length",
        "groups": [
          ["builtin", "external", "type", "external-type", "builtin-type", "side-effect"],
          ["internal-type", "internal"],
          ["parent", "parent-type"],
          ["sibling-type", "sibling", "index-type", "index"],
          ["style", "object", "unknown"]
        ],
      ]

On every change in the file I've a lot of changes. Would be great if you add additional subrule to keep lines with the same length in the old places.

image

Code example

Any imports with the same length

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.

Bug: does not sort in-line typings

Describe the bug

When sorting objects, seems like in-line TypeScript parameter types are not being sorted as expected.

Code example

This

image

Becomes this:

image

The arguments are sorted, but the in-line types are not.

ESLint version

v8.45.0

ESLint Plugin Perfectionist version

v.2.0.0

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.

Feature: Comments above import groups

What rule do you want to change?

sort-imports/sort-named-imports

Describe the problem

Hey, first of all - great plugin, really love what you have done here!

I understand if this is out-of-scope, so feel free to just close if this isn't something you would like to have in this plugin.

We have been sorting our imports with some eslint-plugin-import rules and manual sorting until we discovered this plugin. One of our rules is that there is a comment on top of a group describing it roughly. It makes it easier for new contributors to understand why we sort what.

I attached an example of how it currently works, I would love to be able to configure this to be done automatically in eslint-plugin-perfectionist, as it currently moves the comments we have already done by hand in-between the imports when re-ordering stuff automatically.

Code example

/**
 * built-in dependencies
 */
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { URL, fileURLToPath } from 'node:url';
import { inspect } from 'node:util';

/**
 * external dependencies
 */
import * as TOML from '@iarna/toml';
import test from 'ava';

/**
 * internal dependencies
 */
import { isNotNil } from '@internal/util/is';

/**
 * project dependencies
 */
import { parse } from './parse';

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.

Feature: sort-objects - include objects as used as function parameters

What rule do you want to change?

sort-objects

Describe the problem

const foo = (
    // The parameters are currently not sorted.
    {
        y,
        x
    }: // But the types are sorted.
    // So the params and types aren't in the same order anymore.
    { 
        x: number; 
        y: number 
    }
) => ({ x, y });

Code example

I'm guessing in https://github.com/azat-io/eslint-plugin-perfectionist/blob/main/rules/sort-objects.ts but I don't know the AST.

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.

Sort optional fields

What rule do you want to change?

Props

Describe the problem

I want to sort optional props to the bottom.

Code example

I mean that required?: boolean is supposed to be after count: number in Props type object.

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.

Feature: support Astro and/or Vue

Describe the rule

Hi, thanks for creating this awesome plug-in! I've recently incorporated it into my own opinionated ruleset here: @zeebats/eslint-config and I'm looking to release that version soon ๐Ÿš€ should be a nice drop-in for others to get an opinionated eslint-config ready to go.

I noticed while testing in an Astro ร— Vue project that for these filetypes, this plug-in doesn't work. This is of course due to what you mention in your introduction:

The plugin supports:

โ€ข JavaScript
โ€ข TypeScript
โ€ข JSX

However I think these would be nice additions! And I would like to contribute in making this a reality :-)
Could you point me in the right direction? It is my understanding that for both these filetypes there are already parsers available: Astro & Vue. So maybe it is pretty easy to hook into these?

Code example

None at this time, please let me know if you require more information

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.

Bug: sort-objects - In function parameters, don't break references to earlier params

Describe the bug

I'm sorry, this is probably an unexpected side effect of adding sort-objects to function parameters!

I think this is the only place this can occur.

// Sorting these will break the code
const fn = ({ b, a = b}) => {};
function fn({ b, a = b}) {};

Code example

Before

export const compileMonorepoDependencies = async ({
    packageJson: { dependencies },
    targetRootPath, 
    parentModulePath = targetRootPath // <-- gets the value from targetRootPath!
}: {
    packageJson: PackageJson;
    targetRootPath: string;
    parentModulePath?: string;
}) =>

After

export const compileMonorepoDependencies = async ({
    packageJson: { dependencies },
    parentModulePath = targetRootPath, // <-- Parameter 'parentModulePath' cannot reference identifier 'targetRootPath' declared after it.
    targetRootPath
}: {
    packageJson: PackageJson;
    parentModulePath?: string;
    targetRootPath: string;
}) =>

ESLint version

v

ESLint Plugin Perfectionist version

v1.1.0

Additional comments

We don't want to change the order of the two keys that depend on each other, that seems doable.

But the interface should be sorted in the same order as the object.

export const compileMonorepoDependencies = async ({
    packageJson: { dependencies },
    targetRootPath, 
    parentModulePath = targetRootPath // <-- Gets the value from targetRootPath!
}: {
    packageJson: PackageJson;
    parentModulePath?: string; // <-- Sorted alphabetically, but no longer in the same order as the object it represents.
    targetRootPath: string;
}) =>

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug: (sort-classes) Overloads are not properly sorted.

Describe the bug

It's seems like there is an error in the way you handle overloads. The top most overload is always treated as a separate function and because it has no body, TypeScript doesn't like this.

Code example

For example, it turns this:

class X {
    setBackground(color: number, hexFlag: boolean): this
    setBackground(color: Color | string | CSSColor): this
    setBackground(r: number, g: number, b: number, a?: number): this
    setBackground(color: ColorArgument, arg1?: boolean | number, arg2?: number, arg3?: number): this {
        <body>
    }
}

into this:

class X {
    setBackground(r: number, g: number, b: number, a?: number): this
    setBackground(color: CSSColor | Color | string): this
    setBackground(color: ColorArgument, arg1?: boolean | number, arg2?: number, arg3?: number): this {
        <body>
    }
    setBackground(color: number, hexFlag: boolean): this
}

ESLint version

8.45.0

ESLint Plugin Perfectionist version

1.5.0

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.

Bug: donโ€™t sort `() => โ€ฆ` type in `perfectionist/sort-interfaces`

Describe the bug

perfectionist/sort-interfaces is useful to sort keys.

But interface can also contain function arguments like in code example below.

Changing the order of these calls could break API very easy (order is very important there).

I suggest counting them all as () and donโ€™t sort between each other (sort only keys in interface).

Code example

interface Count {
  <Parameters extends Record<string, number | string>>(
    input: TranslationFunction<[Parameters], string>
  ): TranslationFunctionAlternatives<Parameters>
  <Input extends CountInput>(input: Input): TranslationFunction<
    [number],
    Input[keyof Input]
  >
}

ESLint version

v8.44

ESLint Plugin Perfectionist version

v0.9.0

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.

Feature: sort-exports

Describe the rule

Helpful for barrel files (index.ts).

Code example

Not sorted

export { readPackageJson } from './read-package-json';
export { loadDotEnv } from './load-dot-env';
export { getGitBranch } from './get-git-branch';

Sorted natural asc

export { getGitBranch } from './get-git-branch';
export { loadDotEnv } from './load-dot-env';
export { readPackageJson } from './read-package-json';

Additional comments

I'm not sure if we need the same groups support as sort-imports.

Changing export order could have side effects if the same name is exported multiple times.

export * from './util';
export * from './abc';

If they both export something with the same name then changing the order could change which one is exported. Exporting with the same name is a bad practice, so this might help find those bugs.

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug: next's 'use client' leads to 'Fix objects must not be overlapped in a report'

Describe the bug

Plugin got stuck if it finds 'use client' on top line

Code example

"use client";

import { Input } from "@/components/ui/input";
import React from "react";
import { useEffect, useState } from "react";

const EmailNameChanging = () => {...}

ESLint version

8.42.0

ESLint Plugin Perfectionist version

1.2.0

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.

Bug: `test` not working

Describe the bug

With latest main (commit 0ed298f), I am unable to run tests for the repo.

Steps to reproduce:

  1. Follow instructions in contributing.md to clone the repo and install dependencies
  2. (Optional): Modify a test so that it purposely fails
  3. Attempt to run npx pnpm test

Output is as follows:

-> % npx pnpm test

> [email protected] test /Users/adbaran/Development/GitHub/.temp/eslint-plugin-perfectionist
> pnpm run /^test:/


> [email protected] test:js /Users/adbaran/Development/GitHub/.temp/eslint-plugin-perfectionist
> eslint "**/*.{js,ts}"


> [email protected] test:types /Users/adbaran/Development/GitHub/.temp/eslint-plugin-perfectionist
> tsc --noEmit --pretty


> [email protected] test:unit /Users/adbaran/Development/GitHub/.temp/eslint-plugin-perfectionist
> vitest --run --coverage --single-thread --no-threads


 RUN  v0.32.2 /Users/adbaran/Development/GitHub/.temp/eslint-plugin-perfectionist
      Coverage enabled with v8

 % Coverage report from v8
----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files |       0 |        0 |       0 |       0 |
----------|---------|----------|---------|---------|-------------------
include: **/__tests__/**/*.?(c|m)[jt]s?(x), **/?(*.){test,spec}.?(c|m)[jt]s?(x)
exclude:  **/node_modules/**, **/dist/**, **/cypress/**, **/.{idea,git,cache,output,temp}/**, **/{karma,rollup,webpack,vite,vitest,jest,ava,babel,nyc,cypress,tsup,build}.config.*
watch exclude:  **/node_modules/**, **/dist/**

No test files found, exiting with code 1
โ€‰ELIFECYCLEโ€‰ Command failed with exit code 1.
โ€‰ELIFECYCLEโ€‰ Test failed. See above for more details.

Code example

N/A

ESLint version

N/A

ESLint Plugin Perfectionist version

N/A

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.

Feature: allow to disable perfectionist for some objects

Describe the rule

First,perfectionist makes your code cleaner! Thanks.

Context

  • I'm using zod to validate my form and some schema are quite long
  • perfectionist throws me a lot of errors because my schema isn't well sorted
  • However, I do not want my schema to be sorted. For example, I want:
    • longitude to stay close to latitude
    • support_email close to support_phone
    • author close to title...

Code example

What about having like eslint the ability to disable perfectionist for some files or objects like this: // eslint-disable-perfectionist-next-line

I've found nothing in Docs.

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.

Feature: Ignore quotes of strings when comparing them

What rule do you want to change?

sort-array-includes

Describe the problem

Currently the sort-array-includes rule doesn't ignore the surrounding quotes of string literals when comparing them. This will produce unexpected errors in some cases.

Code example

  • index.js
function isValid(name) {
  return ['Burger King', "McDonald's", 'Subway'].includes(name);
}
  • .eslintrc.json
{
  "plugins": ["perfectionist"],
  "rules": {
    "perfectionist/sort-array-includes": ["error"],
    "quotes": ["error", "single", { "avoidEscape": true }]
  }
}

Additional comments

Current behavior:

2:40 error Expected "'Subway'" to come before ""McDonald's"" perfectionist/sort-array-includes

Expected behavior: The sort-array-includes rule should not complain about the code snippet above.

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Sort keys by type

Describe the problem

I want to sort object properties by its type

Code example

I have the following type object:

type MyObject = {
  updatedAt: Date
  count: number
  createdAt: Date
}

I want to colocate properties by type, so Date will be next to each other:

type MyObject = {
  count: number
  createdAt: Date
  updatedAt: Date
}

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.

Feature: add side-effect imports category for grouping

What rule do you want to change?

sort-imports

Describe the problem

Side effect imports like:

import from './set-production-env.js'

should be above all others import. And fo-course there should not be auto-srto for these type of imports.

Can we add another category to grouping? If we already support it (and have no option to configure, which is fine) letโ€™s add an example to docs.

Code example

import from './set-production-env.js'

Additional comments

Maybe we need another logic for .css imports

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Bug: (sort-imports) side-effect imports with an internal pattern are defined as internal modules

Describe the bug

If a side-effect import starts with an internal pattern, then it will be defined as an internal module and not a side-effect.

Code example

IN CONFIG:

"perfectionist/sort-imports": [
  "error",
  {
    "type": "line-length",
    "order": "desc",
    "internal-pattern": ["@/**"],
    "groups": [
      "builtin",
      "external",
      "internal",
      "parent",
      "sibling",
      "index",
      "side-effect"
    ]
  }
],

IN CODE:

import { App } from "@/components/app"; // โคธ There is no space between groups.
import "@/styles/globals.css";

ESLint version

v8.49.0

ESLint Plugin Perfectionist version

v2.1.0

Additional comments

Starting from the idea of the plugin, I think that the current behavior is not quite correct, because there is a group for side-effect imports and therefore something like this is not very aesthetically?

import { EvenLongerNameComponent } from "@/components";
import { LongNameComponent } from "@/components";
import { AnotherComponent } from "@/components";
import { Component } from "@/components";
import "@/styles/globals.css";
import { s } from "@/css";

import "./styles.css";
import "./base.css";

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Feature: Add the 'always-on-top' option

What rule do you want to change?

sort-interfaces, sort-object-types

Describe the problem

interface ButtonProps {
  children?: string | number
  className?: string
  onClick?: () => void
  onChange?: () => void
  size: 's' | 'm' | 'l'
  type?: 'submit' | 'button'
  variant?: 'solid' | 'outline' | 'text'
}

type Props = {
  children?: string | number
  className?: string
  onClick?: () => void
  onChange?: () => void
  size: 's' | 'm' | 'l'
  type?: 'submit' | 'button'
  variant?: 'solid' | 'outline' | 'text'
}
{
  "plugins": ["perfectionist"],
  "rules": {
    "perfectionist/sort-interfaces": [
      "error",
      {
        "type": "natural",
        "order": "asc",
        "always-on-top": ["on*"]
      }
    ],
   "perfectionist/sort-object-types": [
      "error",
      {
        "type": "natural",
        "order": "asc",
        "always-on-top": ["on*"]
      }
    ]
  }
}

Expected Result:

interface ButtonProps {
  onClick?: () => void
  onChange?: () => void
  children?: string | number
  className?: string
  size: 's' | 'm' | 'l'
  type?: 'submit' | 'button'
  variant?: 'solid' | 'outline' | 'text'
}

type Props = {
  onClick?: () => void
  onChange?: () => void
  children?: string | number
  className?: string
  size: 's' | 'm' | 'l'
  type?: 'submit' | 'button'
  variant?: 'solid' | 'outline' | 'text'
}

Code example

...

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.

Feature: Don't sort styles in react components

What rule do you want to change?

perfectionist/sort-objects

Describe the problem

Rule perfectionist/sort-objects breaks styles when sorting objects passed to styled components.

After sorting borderWidth will be after borderBottom which will rewrite it. Sorting should be smart enough to understand stuff like that (like style lint) or be disabled for styled components (or at least have an option for that).

image

Code example

export default styled('div')(() => ({
    borderRadius: 0,
    borderWidth: 0,
    border: 0,
    borderBottom: hasBorder && `1px solid ${theme.palette.divider}`,
}));

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.

Release: v2.0.0

  • Add rule for sorting Astro attributes (#36)
  • Add rule for sorting Svelte attributes (#26)
  • Add rule for sorting Vue attributes (#55)
  • Rename sort-map-elements rule to sort-maps (#34)
  • Move from callback, multiline and shorthand options to groups option in sort-jsx-props rule (#40)
  • Remove read-tsconfig feature in sort-imports rule (#35)
  • Support require in sort-imports rule (#38)
  • Move to typescript-eslint v6 (#37)
  • Add option for disabling sorting in styled-components in sort-objects rule (#44)
  • Add groups option in sort-interfaces rule (#60)
  • Add groups option in sort-object-types rule (#63)
  • Move from always-on-top option to groups option in sort-objects rule (#43)

Feature: Allow sorting with commented areas

What rule do you want to change?

sort-objects

Describe the problem

Sometimes, there are properties that I would intentionally want to sort within specific delineated areas. For example, in https://github.com/JoshuaKGoldberg/template-typescript-node-package/pull/528/files#r1228571350, it was noted that I intentionally use comments to indicate areas of rules in my ESLint configs.

But, perfectionist/sort-objects is sorting them alphabetically as my lint config asked it to. It'd be nice to have an option I can enable to sort within commented areas.

This feels like something that shouldn't be on by default. I think I'd only want it in specific files/areas, such as an ESLint config. Actually, I'm not sure... maybe this would be reasonable to turn on by default? Using // (non-JSDoc) comments to indicate specific areas is a reasonable practice...

Code example

{
    // First: these off-by-default rules are intentionally enabled
    "very-awesome-rule": "error",

    // Second: these on-by-default rules are intentionally disabled
    "not-as-awesome-rule": "off",
    "also-keep-in-this-area": "off",
}

After auto-fixing, that config gets turned into:

export default {
    "also-keep-in-this-area": "off",

    // Second: these on-by-default rules are intentionally disabled
    "not-as-awesome-rule": "off",
    // First: these off-by-default rules are intentionally enabled
    "very-awesome-rule": "error",
}

Additional comments

I checked the options in https://eslint-plugin-perfectionist.azat.io/rules/sort-objects#%F0%9F%94%A7-options and didn't see anything that looked related to this request.

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Feature: (Sort exports by path)

Describe the rule

Sort "export * from '...'" structures by path

Code example

I have the following index file:

export * from "./useSomething2";
export * from "./useSomething3";
export * from "./useSomething1";

I want to be able to change the export order along the path:

export * from "./useSomething1";
export * from "./useSomething2";
export * from "./useSomething3";

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.

Feature: (sort-exports) Support sorting exports of `const` / `function` / `interface` / `type` and other similar exports.

What rule do you want to change?

sort-exports

Describe the problem

Same as https://github.com/jrdrg/eslint-plugin-sort-exports

I think eslint-plugin-sort-exports is great, and I have been using it all along. However, it has a fatal flaw: if the exported variables depend on another variable, sorting them may result in accessing undefined variables. Currently, I can only disable it using // eslint-disable-next-line sort-exports/sort-exports (even if referenced within an exported function or an arrow function defined with export const, there won't be any issues because of variable hoisting). It would be great if it could be optimized and fixed based on this!

Code example

Input

export const z = { x: 0 };

// line comment
export const a = () => {
  return b;
};

// Due to the dependency on constant `z`, `b` should be placed after `z`.
export const b = z.x;

export enum E {};

export type B = '';

/** block comment */
export interface C {};

Output

If the sortExportKindFirst option is set to type, then the export interface and export type need to be placed at the top for separate sorting, with other export statements placed below them for separate sorting. I think this should be the default value because it is more in line with the intuitive definition of React components.

Note: The comment above the export statement should be sorted together with it.

export type B = '';

/** block comment */
export interface C {}

export enum E {}

// line comment
export const a = () => {
  return b;
};

export const z = { x: 0 };

// Due to the dependency on constant `z`, `b` should be placed after `z`.
export const b = z.x;

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.

Run on save with VSCode

Hello! Is it possible to fix all rules on file save, I can't find anything in your docs about it so I am just creating an issue here, sorry for that.

Feature: (sort-switch-case) Would you consider sorting the `case` blocks in a `switch` statement?

Describe the rule

Can you add a sort-switch-case rule? It will sort the case statements, their order does not affect the execution result, but it can improve readability, reduce code merge conflicts, and eliminate the need to worry about their order when writing code.

Code example

Input

switch (type) {
  case 'save': {
    break;
  }

  case 'edit': {
    break;
  }

  default:
  case 'close': {
    break;
  }
}

Output

switch (type) {
  default:
  case 'close': {
    break;
  }

  case 'edit': {
    break;
  }

  case 'save': {
    break;
  }
}

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.

Feature: (sort-classes) Distinguish between normal methods and getters and setters

What rule do you want to change?

sort-classes

Describe the problem

I like the idea of this rule to sort all of my methods, but, at least with the natural config, get and set methods are buried between them. It's much more readable to put all of them in an extra group.

Code example

This:

class A {
    x() {}
    b() {}
    get z() {}
    get c() {}
    set c() {}
}

Turns into:

class A {
    b() {}
    get c() {}
    set c() {}
    x() {}
    get z() {}
}

But I really prefer instead this:

class A {
    b() {}
    x() {}
    get c() {}
    set c() {}
    get z() {}
}

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.

Feature: (sort-classes) split static property/method group into static and static-private

What rule do you want to change?

sort-classes

Describe the problem

Thank you for fixing #62.

tl;dr

Now that private and public methods are properly differentiated I'd suggest splitting the current static methods and static properties into static public and static private.

reasoning

One might ask why? Simple: to align the behaviour of the static property and method groups with the other property and method groups as described below.

details

Current groups behave differently for instance public/private:

  • instance properties:
    • private-property for _/#/private properties
    • property for public properties (or all properties if private/static is not used)
  • instance methods:
    • private-method for privates
    • methods for publics (or all methods if private/static is not used)

versus static public/private:

  • static properties:
    • static-property for both private and public
  • static methods:
    • static-method both private and public

The supposed change would align the behaviour of static and instance groups for methods and properties:

  • static properties:
    • static-private-property for privates
    • static-property for publics (or all static properties if static private is not used)
  • static methods:
    • static-private-method for privates
    • static-method for publics (or all static methods if static private is not used)

Code example

this would allow configs like this:

"perfectionist/sort-classes": [
      "error",
      {
        "type": "natural",
        "order": "asc",
        "groups": [
          "static-property",
          "static-private-property",
          "property",
          "private-property",
          "constructor",
          "method",
          "private-method",
          "static-method",
          "static-private-method",
          "other"
        ]
      }
    ],

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.

Docs: Deprioritize sorting by line length in the README.md

Describe the bug

Right now, in the README.md, there are a few references to sorting by line length (rather than alphabetical / natural). It's cool that that's an option, but in my experience most folks will want an alphabetical/natural sorting order - and many could find a seemingly arbitrary order such as max line length off-putting.

Links:

Code example

n/a

ESLint version

v8.42.0

ESLint Plugin Perfectionist version

v1.1.0

Additional comments

We chatted on Discord - just filing an issue for tracking. ๐Ÿ™‚

Validations

  • Read the docs.
  • Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.