1- const { defineConfig } = require ( "eslint/config" ) ;
2- const jsdoc = require ( "eslint-plugin-jsdoc" ) ;
3- const sortKeys = require ( "eslint-plugin-sort-keys" ) ;
4- const unicorn = require ( "eslint-plugin-unicorn" ) ;
5- const tseslint = require ( "typescript-eslint" ) ;
1+ import { defineConfig } from "eslint/config" ;
2+ import perfectionist from "eslint-plugin-perfectionist" ;
3+ import { Alphabet } from "eslint-plugin-perfectionist/alphabet" ;
4+ import jsdoc from "eslint-plugin-jsdoc" ;
5+ import unicorn from "eslint-plugin-unicorn" ;
6+ import tseslint from "typescript-eslint" ;
67
78const config = {
8- files : [ "**/*.{js,jsx,ts,tsx}" ] ,
9+ files : [ "**/*.{js,jsx,mjs, ts,tsx}" ] ,
910 languageOptions : { parser : tseslint . parser } ,
1011 linterOptions : {
1112 // Individual repos may have their own additional ESLint setups that enable
@@ -19,7 +20,7 @@ const config = {
1920 plugins : {
2021 "@typescript-eslint" : tseslint . plugin ,
2122 jsdoc,
22- "sort-keys" : sortKeys ,
23+ perfectionist ,
2324 unicorn,
2425 } ,
2526 //
@@ -80,17 +81,7 @@ const config = {
8081 // "prefer-object-has-own": "error",
8182 // "prefer-object-spread": "error",
8283 "prefer-template" : "error" ,
83- // This only sorts members within an individual import statement, not import
84- // statements ("declarations") themselves. We disable that because this
85- // rule sorts in a weird way: by first member rather than by module name.
86- // The `import/order` rule provided by eslint-plugin-import does sort
87- // declarations by module name, but we forgo that too because it groups
88- // declarations based on environmental factors (e.g. node_modules, Node
89- // version) that we can't easily determine or reproduce here in a
90- // repo-agnostic way. One compromise might be to use `import/order` and
91- // simply disable its regrouping feature in favor of whatever groups are
92- // found in the source code to be formatted, but no such option exists :/
93- "sort-imports" : [ "error" , { ignoreDeclarationSort : true } ] ,
84+ // "sort-imports": "error", // Replaced by perfectionist/sort-imports and perfectionist/sort-named-imports
9485 "sort-vars" : "error" ,
9586 // "strict": "error",
9687 // "unicode-bom": "error",
@@ -132,8 +123,28 @@ const config = {
132123 // "jsdoc/tag-lines": "error",
133124 // "jsdoc/text-escaping": "error",
134125
135- // sort-keys rules. https://github.com/namnm/eslint-plugin-sort-keys
136- "sort-keys/sort-keys-fix" : [ "error" , "asc" , { natural : true } ] ,
126+ // perfectionist rules. https://perfectionist.dev/rules
127+ // "perfectionist/sort-enums": "error", // Reordering can change numeric enum values
128+ "perfectionist/sort-heritage-clauses" : "error" ,
129+ "perfectionist/sort-imports" : [
130+ "error" ,
131+ {
132+ groups : [ ] , // Don't priorize type imports above value imports
133+ newlinesBetween : "ignore" ,
134+ newlinesInside : "ignore" ,
135+ } ,
136+ ] ,
137+ "perfectionist/sort-interfaces" : "error" ,
138+ "perfectionist/sort-intersection-types" : "error" ,
139+ "perfectionist/sort-named-exports" : "error" ,
140+ "perfectionist/sort-named-imports" : [
141+ "error" ,
142+ { partitionByNewLine : false } ,
143+ ] ,
144+ "perfectionist/sort-object-types" : "error" ,
145+ "perfectionist/sort-objects" : "error" ,
146+ // "perfectionist/sort-switch-case" // TODO: Enable once it supports partitionByNewLine
147+ "perfectionist/sort-union-types" : "error" ,
137148
138149 // typescript-eslint rules. We exclude rules that require type info because
139150 // they're prohibitively slow. Get the list of autofixable rules by running
@@ -189,10 +200,9 @@ const config = {
189200 // "unicorn/new-for-builtins": "error",
190201 // "unicorn/no-array-for-each": "error", // Bug: fixer deletes comments
191202 // "unicorn/no-array-method-this-argument": "error",
192- // "unicorn/no-array-push-push": "error", // Bug: fixer deletes comments
193203 // "unicorn/no-await-expression-member": "error",
194204 "unicorn/no-console-spaces" : "error" ,
195- // "unicorn/no-for-loop": "error", // Bug: https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1802
205+ "unicorn/no-for-loop" : "error" ,
196206 // "unicorn/no-hex-escape": "error",
197207 // "unicorn/no-lonely-if": "error", // Bug: Moves comments around
198208 "unicorn/no-negated-condition" : "error" ,
@@ -249,6 +259,7 @@ const config = {
249259 "unicorn/prefer-regexp-test" : "error" ,
250260 // "unicorn/prefer-set-has": "error",
251261 "unicorn/prefer-set-size" : "error" ,
262+ // "unicorn/prefer-single-call": "error", // Bug: fixer deletes comments
252263 // "unicorn/prefer-spread": "error", // Bug: https://github.com/sindresorhus/eslint-plugin-unicorn/issues/2041
253264 // "unicorn/prefer-string-raw": "error",
254265 // "unicorn/prefer-string-replace-all": "error",
@@ -270,6 +281,22 @@ const config = {
270281
271282 /* eslint-enable */
272283 } ,
284+ settings : {
285+ perfectionist : {
286+ // By default, perfectionist sorts lowercase before uppercase. We reverse
287+ // that behavior here to match our existing pre-2026 convention, which is
288+ // also arguably more sensible from a coding perspective because it
289+ // prioritizes SCREAMING_SNAKE_CASE constants, similar to how such
290+ // constants are typically defined first in a source file
291+ alphabet : Alphabet . generateRecommendedAlphabet ( )
292+ . placeAllWithCaseBeforeAllWithOtherCase ( "uppercase" )
293+ . getCharacters ( ) ,
294+ ignoreCase : false ,
295+ order : "asc" ,
296+ partitionByNewLine : true ,
297+ type : "custom" ,
298+ } ,
299+ } ,
273300} ;
274301
275- module . exports = defineConfig ( [ config ] ) ;
302+ export default defineConfig ( [ config ] ) ;
0 commit comments