Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.8k
chore: applied eslint-plugin-perfectionist@4 updates#11168
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
chore: applied eslint-plugin-perfectionist@4 updates#11168
Conversation
Thanks for the PR,@JoshuaKGoldberg! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently onhttps://opencollective.com/typescript-eslint. |
netlifybot commentedMay 5, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
✅ Deploy Preview fortypescript-eslint ready!
To edit notification comments on pull requests, go to yourNetlify site configuration. |
nx-cloudbot commentedMay 5, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There are a lot here that confuse me. I'll just revert the perfectionist@4 PR. |
hugop95 commentedMay 5, 2025 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Hey@JoshuaKGoldberg 👋 I've had a quick look and I think that I see the issue:
typescript-eslint/eslint.config.mjs Lines 627 to 630 in79bb84c
I suspect that these custom groups (almost) never matched:
As an example, the proper migration for typescript-eslint/eslint.config.mjs Lines 644 to 648 in79bb84c
would be customGroups:{first:['^loc$','^name$','^node$','^type$'],fourth:['^fix$'],second:['^meta$','^messageId$','^start$'],third:['^defaultOptions$','^data$','^end$'],}, I assume that this configuration was not the original intent though, but this leads to much less autofixes (in my test: about 25 files), which are mostly:
Here is the updated eslint configuration if you wish to test it out. Let me know if something isn't clear! eslint.config.mjs//@ts-checkimporteslintCommentsPluginfrom'@eslint-community/eslint-plugin-eslint-comments/configs';import{fixupConfigRules,fixupPluginRules}from'@eslint/compat';import{FlatCompat}from'@eslint/eslintrc';importeslintfrom'@eslint/js';importtseslintInternalPluginfrom'@typescript-eslint/eslint-plugin-internal';importvitestPluginfrom'@vitest/eslint-plugin';importeslintPluginPluginfrom'eslint-plugin-eslint-plugin';importimportPluginfrom'eslint-plugin-import';importjsdocPluginfrom'eslint-plugin-jsdoc';importjsxA11yPluginfrom'eslint-plugin-jsx-a11y';importperfectionistPluginfrom'eslint-plugin-perfectionist';importreactPluginfrom'eslint-plugin-react';importreactHooksPluginfrom'eslint-plugin-react-hooks';importregexpPluginfrom'eslint-plugin-regexp';importunicornPluginfrom'eslint-plugin-unicorn';importglobalsfrom'globals';importurlfrom'node:url';importtseslintfrom'typescript-eslint';const__dirname=url.fileURLToPath(newURL('.',import.meta.url));constcompat=newFlatCompat({baseDirectory:__dirname});constrestrictNamedDeclarations={message:'Prefer a named export (e.g. `export const ...`) over an object export (e.g. `export { ... }`).',selector:'ExportNamedDeclaration[declaration=null][source=null]',};exportdefaulttseslint.config(// register all of the plugins up-front{// note - intentionally uses computed syntax to make it easy to sort the keys/* eslint-disable no-useless-computed-key */plugins:{['@typescript-eslint']:tseslint.plugin,['@typescript-eslint/internal']:tseslintInternalPlugin,['eslint-plugin']:eslintPluginPlugin,['import']:importPlugin,['jsdoc']:jsdocPlugin,//@ts-expect-error -- https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/pull/1038['jsx-a11y']:jsxA11yPlugin.flatConfigs.recommended.plugins['jsx-a11y'],['perfectionist']:perfectionistPlugin,['vitest']:vitestPlugin,// https://github.com/facebook/react/issues/28313['react']:reactPlugin,//@ts-expect-error -- Temporary types incompatibility pending flat config support// https://github.com/facebook/react/pull/30774['react-hooks']:fixupPluginRules(reactHooksPlugin),['regexp']:regexpPlugin,['unicorn']:unicornPlugin,},/* eslint-enable no-useless-computed-key */settings:{perfectionist:{order:'asc',partitionByComment:true,type:'natural',},},},{// config with just ignores is the replacement for `.eslintignore`ignores:['.nx/','.yarn/','**/node_modules/**','**/dist/**','**/fixtures/**','**/coverage/**','**/__snapshots__/**','**/.docusaurus/**','**/build/**','.nx/*','.yarn/*',// Files generated by TypeDoc'docs/packages/*/generated','packages/*/generated','docs/packages/*/generated',// Files copied as part of the build'packages/types/src/generated/**/*.ts',// Playground types downloaded from the web'packages/website/src/vendor/',// see the file header in eslint-base.test.js for more info'packages/rule-tester/tests/eslint-base/',],},// extends ...eslintCommentsPlugin.recommended,eslint.configs.recommended,tseslint.configs.strictTypeChecked,tseslint.configs.stylisticTypeChecked,jsdocPlugin.configs['flat/recommended-typescript-error'],// base config{languageOptions:{globals:{ ...globals.es2020, ...globals.node,},parserOptions:{projectService:true,tsconfigRootDir:__dirname,warnOnUnsupportedTypeScriptVersion:false,},},linterOptions:{reportUnusedDisableDirectives:'error'},rules:{//// our plugin :D//'@typescript-eslint/ban-ts-comment':['error',{minimumDescriptionLength:5,'ts-check':false,'ts-expect-error':'allow-with-description','ts-ignore':true,'ts-nocheck':true,},],'@typescript-eslint/no-confusing-void-expression':['error',{ignoreVoidReturningFunctions:true},],// TODO: enable it once we drop support for TS<5.0// https://github.com/typescript-eslint/typescript-eslint/issues/10065'@typescript-eslint/consistent-type-exports':['off',// 'error',{fixMixedExportsWithInlineTypeSpecifier:true},],'@typescript-eslint/consistent-type-imports':['error',{disallowTypeAnnotations:true,prefer:'type-imports'},],'@typescript-eslint/explicit-module-boundary-types':'error','@typescript-eslint/no-explicit-any':'error','@typescript-eslint/no-require-imports':['error',{allow:['/package\\.json$'],},],'@typescript-eslint/no-unnecessary-condition':['error',{allowConstantLoopConditions:true,checkTypePredicates:true},],'@typescript-eslint/no-unnecessary-type-conversion':'error','@typescript-eslint/no-unnecessary-type-parameters':'error','@typescript-eslint/no-unused-expressions':'error','@typescript-eslint/no-unused-vars':['error',{argsIgnorePattern:'^_',caughtErrors:'all',varsIgnorePattern:'^_',},],'@typescript-eslint/no-var-requires':'off','@typescript-eslint/prefer-literal-enum-member':['error',{allowBitwiseExpressions:true,},],'@typescript-eslint/prefer-nullish-coalescing':['error',{ignoreConditionalTests:true,ignorePrimitives:true,},],'@typescript-eslint/prefer-string-starts-ends-with':['error',{allowSingleElementEquality:'always',},],'@typescript-eslint/restrict-template-expressions':['error',{allowAny:true,allowBoolean:true,allowNullish:true,allowNumber:true,allowRegExp:true,},],'@typescript-eslint/unbound-method':'off','no-constant-condition':'off',//// Internal repo rules//'@typescript-eslint/internal/debug-namespace':'error','@typescript-eslint/internal/eqeq-nullish':'error','@typescript-eslint/internal/no-poorly-typed-ts-props':'error','@typescript-eslint/internal/no-relative-paths-to-internal-packages':'error','@typescript-eslint/internal/no-typescript-default-import':'error','@typescript-eslint/internal/prefer-ast-types-enum':'error','no-restricted-syntax':['error',restrictNamedDeclarations],//// eslint-base//curly:['error','all'],eqeqeq:['error','always',{null:'never',},],'logical-assignment-operators':'error','no-console':'error','no-else-return':['error',{allowElseIf:false,},],'no-fallthrough':['error',{commentPattern:'.*intentional fallthrough.*'},],'no-implicit-coercion':['error',{boolean:false}],'no-lonely-if':'error','no-mixed-operators':'error','no-process-exit':'error','no-unreachable-loop':'error','no-useless-call':'error','no-useless-computed-key':'error','no-useless-concat':'error','no-var':'error','no-void':['error',{allowAsStatement:true}],'object-shorthand':'error','one-var':['error','never'],'operator-assignment':'error','prefer-arrow-callback':'error','prefer-const':'error','prefer-object-has-own':'error','prefer-object-spread':'error','prefer-rest-params':'error','prefer-template':'error',radix:'error',//// eslint-plugin-eslint-comment//'@eslint-community/eslint-comments/disable-enable-pair':['error',{allowWholeFile:true},],//// eslint-plugin-import//// enforces consistent type specifier style for named imports'import/consistent-type-specifier-style':'error',// disallow non-import statements appearing before import statements'import/first':'error',// Require a newline after the last import/require in a group'import/newline-after-import':'error',// Forbid import of modules using absolute paths'import/no-absolute-path':'error',// disallow AMD require/define'import/no-amd':'error',// forbid default exports - we want to standardize on named exports so that imported names are consistent'import/no-default-export':'error',// disallow imports from duplicate paths'import/no-duplicates':'error',// Forbid the use of extraneous packages'import/no-extraneous-dependencies':['error',{devDependencies:true,optionalDependencies:false,peerDependencies:true,},],// Forbid mutable exports'import/no-mutable-exports':'error',// Prevent importing the default as if it were named'import/no-named-default':'error',// Prohibit named exports'import/no-named-export':'off',// we want everything to be a named export// Forbid a module from importing itself'import/no-self-import':'error',// Require modules with a single export to use a default export'import/prefer-default-export':'off',// we want everything to be named// enforce a sort order across the codebase'perfectionist/sort-imports':'error',//// eslint-plugin-jsdoc//// We often use@remarks or other ad-hoc tag names'jsdoc/check-tag-names':'off',// https://github.com/gajus/eslint-plugin-jsdoc/issues/1169'jsdoc/check-param-names':'off','jsdoc/informative-docs':'error',// https://github.com/gajus/eslint-plugin-jsdoc/issues/1175'jsdoc/require-jsdoc':'off','jsdoc/require-param':'off','jsdoc/require-returns':'off','jsdoc/require-yields':'off','jsdoc/tag-lines':'off','regexp/no-dupe-disjunctions':'error','regexp/no-useless-character-class':'error','regexp/no-useless-flag':'error','regexp/no-useless-lazy':'error','regexp/no-useless-non-capturing-group':'error','regexp/prefer-quantifier':'error','regexp/prefer-question-quantifier':'error','regexp/prefer-w':'error',//// eslint-plugin-unicorn//'unicorn/no-length-as-slice-end':'error','unicorn/no-lonely-if':'error','unicorn/no-single-promise-in-promise-methods':'error','unicorn/no-typeof-undefined':'error','unicorn/no-useless-spread':'error','unicorn/prefer-array-some':'error','unicorn/prefer-export-from':'error','unicorn/prefer-node-protocol':'error','unicorn/prefer-regexp-test':'error','unicorn/prefer-spread':'error','unicorn/prefer-string-replace-all':'error','unicorn/prefer-structured-clone':'error',},},{extends:[tseslint.configs.disableTypeChecked],files:['**/*.js'],rules:{// turn off other type-aware rules'@typescript-eslint/internal/no-poorly-typed-ts-props':'off',// turn off rules that don't apply to JS code'@typescript-eslint/explicit-function-return-type':'off',},},//// test file linting//// test file specific configuration{files:['packages/*/tests/**/*.{ts,tsx,cts,mts}','packages/integration-tests/tools/**/*.ts',], ...vitestPlugin.configs.env,rules:{'@typescript-eslint/no-empty-function':['error',{allow:['arrowFunctions']},],'@typescript-eslint/no-non-null-assertion':'off','@typescript-eslint/no-unsafe-assignment':'off','@typescript-eslint/no-unsafe-call':'off','@typescript-eslint/no-unsafe-member-access':'off','@typescript-eslint/no-unsafe-return':'off','vitest/no-alias-methods':'error','vitest/no-disabled-tests':'error','vitest/no-focused-tests':'error','vitest/no-identical-title':'error','vitest/no-test-prefixes':'error','vitest/no-test-return-statement':'error','vitest/prefer-describe-function-title':'error','vitest/prefer-each':'error','vitest/prefer-spy-on':'error','vitest/prefer-to-be':'error','vitest/prefer-to-contain':'error','vitest/prefer-to-have-length':'error','vitest/valid-expect':'error',},settings:{vitest:{typecheck:true}},},{files:['packages/*/tests/**/vitest-custom-matchers.d.ts'],name:'vitest-custom-matchers-declaration-files',rules:{'@typescript-eslint/no-empty-object-type':['error',{allowInterfaces:'with-single-extends'},],'@typescript-eslint/no-explicit-any':'off',},},// plugin rule tests{files:['packages/eslint-plugin-internal/tests/rules/**/*.test.{ts,tsx,cts,mts}','packages/eslint-plugin-tslint/tests/rules/**/*.test.{ts,tsx,cts,mts}','packages/eslint-plugin/tests/rules/**/*.test.{ts,tsx,cts,mts}','packages/eslint-plugin/tests/eslint-rules/**/*.test.{ts,tsx,cts,mts}',],rules:{'@typescript-eslint/internal/plugin-test-formatting':'error',},},//// tools and tests//{files:['**/tools/**/*.{ts,tsx,cts,mts}','**/tests/**/*.{ts,tsx,cts,mts}','packages/integration-tests/**/*.{ts,tsx,cts,mts}',],rules:{// allow console logs in tools and tests'no-console':'off',},},{files:['eslint.config.{js,cjs,mjs}','knip.ts','packages/*/src/index.ts','vitest.config.mts','packages/*/vitest.config.mts',],rules:{// requirement'import/no-default-export':'off',},},//// plugin source file linting//{extends:[eslintPluginPlugin.configs['flat/recommended']],files:['packages/eslint-plugin-internal/**/*.{ts,tsx,cts,mts}','packages/eslint-plugin-tslint/**/*.{ts,tsx,cts,mts}','packages/eslint-plugin/**/*.{ts,tsx,cts,mts}',],rules:{'@typescript-eslint/internal/no-typescript-estree-import':'error',},},{files:['packages/eslint-plugin-internal/src/rules/**/*.{ts,tsx,cts,mts}','packages/eslint-plugin-tslint/src/rules/**/*.{ts,tsx,cts,mts}','packages/eslint-plugin/src/configs/**/*.{ts,tsx,cts,mts}','packages/typescript-eslint/src/configs/**/*.{ts,tsx,cts,mts}','packages/core/src/configs/**/*.{ts,tsx,cts,mts}','packages/eslint-plugin/src/rules/**/*.{ts,tsx,cts,mts}',],rules:{'eslint-plugin/no-property-in-node':['error',{additionalNodeTypeFiles:['packages[\\/]types[\\/]src[\\/]generated[\\/]ast-spec.ts',],},],'eslint-plugin/require-meta-docs-description':['error',{pattern:'^(Enforce|Require|Disallow) .+[^. ]$'},],// specifically for rules - default exports makes the tooling easier'import/no-default-export':'off','no-restricted-syntax':['error',{message:"Retrieve options from create's second parameter so that defaultOptions are applied.",selector:'ExportDefaultDeclaration Property[key.name="create"] MemberExpression[object.name="context"][property.name="options"]',},restrictNamedDeclarations,],},},{files:['packages/eslint-plugin/src/rules/index.ts'],rules:{// enforce alphabetical ordering'import/order':['error',{alphabetize:{order:'asc'}}],'sort-keys':'error',},},//// generated files//{files:['packages/scope-manager/src/lib/*.{ts,tsx,cts,mts}','packages/eslint-plugin/src/configs/*.{ts,tsx,cts,mts}','packages/core/src/configs/*.{ts,tsx,cts,mts}',],rules:{'@typescript-eslint/internal/no-poorly-typed-ts-props':'off','@typescript-eslint/internal/no-typescript-default-import':'off','@typescript-eslint/internal/prefer-ast-types-enum':'off',},},//// ast spec linting//{files:['packages/ast-spec/src/**/*.{ts,tsx,cts,mts}'],rules:{// disallow ALL unused vars'@typescript-eslint/no-unused-vars':['error',{caughtErrors:'all'}],'@typescript-eslint/sort-type-constituents':'error',},},{files:['packages/ast-spec/**/*.{ts,tsx,cts,mts}'],rules:{'no-restricted-imports':['error',{message:'To prevent nx build errors, all `typescript-estree` imports should be done via `packages/ast-spec/tests/util/parsers/typescript-estree-import.ts`.',name:'@typescript-eslint/typescript-estree',},],},},//// website linting//{extends:[jsxA11yPlugin.flatConfigs.recommended,// https://github.com/facebook/react/pull/30774//@ts-expect-error -- Temporary types incompatibility pending flat config supportreactPlugin.configs.flat.recommended,// https://github.com/facebook/react/pull/30774//@ts-expect-error -- Temporary types incompatibility pending flat config supportfixupConfigRules(compat.config(reactHooksPlugin.configs.recommended)),],files:['packages/website/**/*.{ts,tsx,mts,cts,js,jsx}'],rules:{'@typescript-eslint/internal/prefer-ast-types-enum':'off','import/no-default-export':'off','react-hooks/exhaustive-deps':'warn',// TODO: enable it later'react/jsx-no-target-blank':'off','react/no-unescaped-entities':'off','react/prop-types':'off',},settings:{react:{version:'detect',},},},{files:['packages/website/src/**/*.{ts,tsx,cts,mts}'],rules:{'import/no-default-export':'off',// allow console logs in the website to help with debugging things in production'no-console':'off',},},{files:['packages/website-eslint/src/mock/**/*.js','**/*.d.{ts,tsx,cts,mts}',],rules:{// mocks and declaration files have to mirror their original package'import/no-default-export':'off',},},{files:['**/*'],ignores:['packages/eslint-plugin/src/configs/eslintrc/*','packages/eslint-plugin/src/configs/flat/*','packages/scope-manager/src/configs/*',],rules:{'@typescript-eslint/sort-type-constituents':'off','perfectionist/sort-classes':'error','perfectionist/sort-enums':'off','perfectionist/sort-objects':'error','perfectionist/sort-union-types':['error',{groups:['keyword','unknown','nullish'],type:'natural',},],},},{files:['packages/ast-spec/src/**/*.ts'],rules:{'perfectionist/sort-interfaces':['error',{customGroups:{first:['^type$'],},groups:['first','unknown'],},],},},{files:['packages/eslint-plugin/src/rules/*.ts','packages/eslint-plugin-internal/src/rules/*.ts',],rules:{'perfectionist/sort-objects':['error',{customGroups:{first:['^loc$','^name$','^node$','^type$'],fourth:['^fix$'],second:['^meta$','^messageId$','^start$'],third:['^defaultOptions$','^data$','^end$'],},groups:['first','second','third','fourth','unknown'],},],},},{files:['packages/eslint-plugin/tests/rules/*.test.ts'],rules:{'perfectionist/sort-objects':['error',{customGroups:{top:['^valid$']},groups:['top','unknown'],},],},},{files:['packages/typescript-estree/src/**/*.ts'],rules:{'perfectionist/sort-objects':['error',{customGroups:{first:['^type$'],second:['loc','range'],},groups:['first','second'],},],},},); |
@hugop95 I’m not part of the team, but I think you could create issue about this version update and add your findings there so they don’t get lost! If it’s just mostly config issue, then it should be trivial to do it. Creating new issue about it lets team to check if they want to go forward with it or not :) it may be that they won’t notice your comment here because there are so many notifications already. |
You're completely right, thank you!
|
Uh oh!
There was an error while loading.Please reload this page.
PR Checklist
main
#11169Overview
yarn lint
now is showing real reports for me locally. Hooray.💖