Skip to content

Conversation

@schoero
Copy link
Owner

@schoero schoero commented Nov 21, 2025

Fixes the predefined configs to correctly expose the plugin in the config.

This simplifies the setup as it its now possible to just add a config to eslint.config.js without requiring to specify the plugin explicitly:

// eslint.config.js

import eslintPluginBetterTailwindcss from "eslint-plugin-better-tailwindcss";

export default [
  eslintPluginBetterTailwindcss.configs.recommended
]

Parsers and languageOptions still need to be configured explicitly.

Legacy configs using the old plugin format are now exposed using the legacy- prefix as it is recommended by ESLint

The following configs are now exposed:

  • recommended
  • recommended-warn
  • recommended-error
  • stylistic
  • stylistic-warn
  • stylistic-error
  • correctness
  • correctness-warn
  • correctness-error
  • legacy-recommended
  • legacy-recommended-warn
  • legacy-recommended-error
  • legacy-stylistic
  • legacy-stylistic-warn
  • legacy-stylistic-error
  • legacy-correctness
  • legacy-correctness-warn
  • legacy-correctness-error

fixes: #148
closes: #152

@schoero schoero requested a review from Copilot November 21, 2025 10:36
Copilot finished reviewing on behalf of schoero November 21, 2025 10:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR refactors the plugin's configuration structure to properly support ESLint's flat config format while maintaining backward compatibility with the legacy .eslintrc format. The main improvement is that configs now include the plugin itself, eliminating the need for users to manually specify it in their configuration.

Key changes:

  • Modified config structure to include the plugin object in flat configs and plugin names array in legacy configs
  • Added legacy- prefix to all configs intended for .eslintrc format
  • Updated all documentation and test files to demonstrate the new simplified setup

Reviewed Changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/configs/config.ts Core config structure refactored to generate both flat and legacy config variants with proper plugin inclusion
tests/e2e/esm/eslint.config.js Updated to use simplified flat config syntax with spread operator
tests/e2e/commonjs/eslint.config.js Updated to use simplified flat config syntax with spread operator
tests/e2e/eslintrc/.eslintrc.json New test file for legacy config with legacy-stylistic-warn config
tests/e2e/eslintrc/test.test.ts New E2E test to verify legacy config compatibility
tests/e2e/eslintrc/test.html New test HTML file for legacy config testing
tests/e2e/eslintrc/package.json Package configuration for commonjs module type
docs/parsers/*.md All parser documentation updated to show new config usage patterns with flat and legacy examples
README.md Added explanation of legacy- prefix for old config format

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@schoero
Copy link
Owner Author

schoero commented Nov 21, 2025

May I request a review from you @kachkaev for this PR? You seem to be quite knowledgeable in this topic.

Copy link

@kachkaev kachkaev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks for working on this @schoero! I left a couple of random thoughts, but all looks great to me overall! I like that you use a mix of warnings and errors by default, that's the way to go!

files: ["**/*.{ts,tsx,cts,mts}"],

languageOptions: {
parser: eslintParserTypeScript,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the latest typescript-eslint docs, the parser is added slightly differently:

import tseslint from 'typescript-eslint';

...
    {
      languageOptions: {
        parser: tseslint.parser,
        ...
    },

It is only necessary to install typescript-eslint dependency. I haven't used legacy eslintrc config so haven't checked the latest recommended settings for it. There may be a change there too.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the package. The legacy config is still using the old package: https://typescript-eslint.io/getting-started/legacy-eslint-setup.

},
rules: getRulesFunction()
}
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth checking the type of the output (I haven't cloned the repo locally so haven't done it myself). In some plugins, pluginFooBar.configs.recommended returns Config | undefined so needs ?? {} which is inconvenient. Example: user code.

Looking at your implementation, typings may be derived correctly, it's just something worth paying extra attention to.

"better-tailwindcss/enforce-consistent-line-wrapping": ["warn", { printWidth: 100 }]
},
// enable all recommended rules
...eslintPluginBetterTailwindcss.configs.recommended,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my experience, most configs contain a single flat config object, so they don't need to be spread (...). typescript-eslint (and a few others) export an array which requires a few more symbols on the consumer end but is more future-proof. I am comfortable both ways, even prefer if ... was a bit more prevelant. If you think that a single flat config object will be always enough, you can consider removing ... and returning {..} instead of [{..}]. Otherwise, it's just a matter of taste.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for this in-depth review!

Now that I look at the ESLint docs again, I see that they brought back the extends field in the flat config format. It is also the recommended way for plugin configs.

I think the cleanest approach would be this one:

// eslint.config.js
import eslintPluginBetterTailwindcss from "eslint-plugin-better-tailwindcss";
import eslintParserVue from "vue-eslint-parser";
import { defineConfig } from "eslint/config";

export default defineConfig({
  // enable all recommended rules
  extends: [
    eslintPluginBetterTailwindcss.configs.recommended
  ],

  // if needed, override rules to configure them individually
  // rules: {
  //   "better-tailwindcss/enforce-consistent-line-wrapping": ["warn", { printWidth: 100 }]
  // },

  settings: {
    "better-tailwindcss": {
      // tailwindcss 4: the path to the entry file of the css based tailwind config (eg: `src/global.css`)
      entryPoint: "src/global.css",
      // tailwindcss 3: the path to the tailwind config file (eg: `tailwind.config.js`)
      tailwindConfig: "tailwind.config.js"
    }
  },

  files: ["**/*.vue"],

  languageOptions: {
    parser: eslintParserVue
  }

});

That way

  • the plugin is only loaded for the desired files
  • no spread syntax is needed to merge the recommended config
  • rules can still be overwritten in the same object
  • the plugin settings and parsers can also be configured in the same object

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I did not know about it. Cool!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants