francoismassart / eslint-plugin-tailwindcss

ESLint plugin for Tailwind CSS usage
https://www.npmjs.com/package/eslint-plugin-tailwindcss
MIT License
1.47k stars 70 forks source link

[Feature request] Support for `eslint` `v9.1.1` #335

Closed cewald closed 4 months ago

cewald commented 5 months ago

Is your feature request related to a problem? Please describe. I'm using nuxt and the latest @nuxt/eslint module which utilizes eslint version 9 and I couldn't make it work. If I import the eslint-plugin-tailwindcss index file in the new flat-config syntax e.g. an eslint.config.mjs, I'll get an error:

[Error - 13:47:05] Request textDocument/formatting failed.
  Message: Request textDocument/formatting failed with message: Config (unnamed): Key "rules": Key "classnames-order": Expected severity of "off", 0, "warn", 1, "error", or 2.
  Code: -32603 

And here the config file (eslint.config.mjs):

// @ts-check
import withNuxt from './.nuxt/eslint.config.mjs'
import pluginVue from 'eslint-plugin-vue'
import pluginTailwindCSS from 'eslint-plugin-tailwindcss'

export default withNuxt([
  ...pluginVue.configs['flat/recommended'],
  pluginTailwindCSS,
  {
    rules: {
      // ...
    }
  }
])

Describe the solution you'd like My guess is to update to the new flat-config syntax or at least describe in the documentation how to properly implement it for the new configuration syntax.

virtuallyunknown commented 5 months ago

Hey @cewald, I am not familiar with Nuxt, but I am in the process of migrating to flat config and I managed to get eslint-plugin-tailwindcss working with it in my migration testing repository.

Here is my config object for the tailwind plugin:

https://github.com/virtuallyunknown/eslint-flat-config-migration/blob/master/configs/tailwind.js

Here is my main config file:

https://github.com/virtuallyunknown/eslint-flat-config-migration/blob/master/eslint.config.js#L5

This isn't a "it works for me, so it should work for everyone" type of comment, just thought this working setup might give you a hint or idea on how to solve your issue.

https://github.com/francoismassart/eslint-plugin-tailwindcss/assets/24871108/45bb6892-36d0-42fc-8b92-33044e82f3d7

If we look at what the plugin exports, this isn't directly flat config compatible (parserOptions for example is no longer root level key, it's child property of languageOptions), but you can easily build this yourself like in my tailwind.js config file, with the plugins, languageOptions and rules keys.

Cheers.

codeflorist commented 5 months ago

using eslint v8 (which also uses the flat-config), you can do this:

// @ts-check
import { FlatCompat } from '@eslint/eslintrc'
import withNuxt from './.nuxt/eslint.config.mjs'

const compat = new FlatCompat()

export default withNuxt(
    {
        rules: {
            // ...
        }
    }, ...compat.config({
        extends: ['plugin:tailwindcss/recommended'],
        rules: {
            'tailwindcss/no-custom-classname': 'off',
            'tailwindcss/migration-from-tailwind-2': 'off',
        },
    })
)

this doesn't seem to work with v9 anymore however. i'd recomment sticking to v8 for now.

codeflorist commented 5 months ago

Regarding eslint v9 support: This comment describes the current source of incompatibility: https://github.com/eslint/eslint/issues/18405#issuecomment-2084982903 It's the usage of the deprecated context.parserServices property.

francoismassart commented 4 months ago

I made a beta version which may work with eslint v9 npm i eslint-plugin-tailwindcss@3.15.3-beta.9 -D

Can you try it ?

virtuallyunknown commented 4 months ago

Greetings @francoismassart. I installed the 3.15.3-beta.9 and it appears that every single rule is detecting errors where it should, the plugin is working as expected.

That said, I am not sure if this is intended or not, but the recommended config is still using the eslintrc format, rather than the flat config format. So for example, a config like this won't work out of the box:

import eslintPluginTailwindCss from 'eslint-plugin-tailwindcss';

export const eslintPluginTailwindCssConfig = [
    {
        ...eslintPluginTailwindCss.configs.recommended,
    }
];

For me this is not an issue because of how I configure the plugin, but I thought it might be worth mentioning anyway.

Cheers!

cewald commented 4 months ago

@francoismassart Thanks for your work!

Okay, I tested it and had a little hiccup with the different versions 3.16.0-beta.0 & 3.15.3-beta.9 but 3.15.3-beta.9 now seems to work if I use it like this:

import pluginTailwindCSS from 'eslint-plugin-tailwindcss'
import withNuxt from './.nuxt/eslint.config.mjs'

export default withNuxt([
  {
    plugins: { tailwindcss: pluginTailwindCSS },
    rules: pluginTailwindCSS.configs.recommended.rules,
  },
  // ...
])

This is the way it is intended to be, right?

francoismassart commented 4 months ago

Here is a new version to test, I need feedback from user using:

The beta version to be tested is eslint-plugin-tailwindcss@3.16.0-beta.1 which can be installed via

npm i eslint-plugin-tailwindcss@3.16.0-beta.1 -D

cewald commented 4 months ago

Thanks for the update. I've tested it with ESLint v9 + flat config and it seems to work just fine.

Here is my eslint.config.mjs:

//...
import eslintPluginTailwindCSS from 'eslint-plugin-tailwindcss'
import withNuxt from './.nuxt/eslint.config.mjs'

export default withNuxt([
  //...
  ...eslintPluginTailwindCSS.configs['flat/recommended'],
  //...
])
vladimirsiljkovic commented 4 months ago

Working fine with ESLint 8.57.0 + flat config + Nuxt + AntFu.

eslint.config.js:

import antfu from '@antfu/eslint-config'
import eslintPluginTailwindCSS from 'eslint-plugin-tailwindcss'
import withNuxt from './.nuxt/eslint.config.mjs'
//...

export default withNuxt(
  antfu(
    //...
    ...eslintPluginTailwindCSS.configs['flat/recommended'],
    {
      rules: {},
    },
  ),
)
HugoRCD commented 4 months ago

Working fine with ESLint 9.3.0 + Flat config repo link

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
import pluginTailwindcss from 'eslint-plugin-tailwindcss'
import type { Linter } from 'eslint'

export default function tailwindcss(): Linter.FlatConfig[] {
  return [
    {
      name: 'tailwindcss/rules',
      plugins: {
        tailwindcss: pluginTailwindcss
      },
      rules: {
        'tailwindcss/classnames-order': 'error',
        'tailwindcss/no-contradicting-classname': 'error',
        'tailwindcss/enforces-shorthand': 'error',
        'tailwindcss/no-custom-classname': 'off',
        'tailwindcss/no-unnecessary-arbitrary-value': 'off',
      }
    }
  ]
}
virtuallyunknown commented 4 months ago

ESLint v9 + flat config + eslint-plugin-tailwindcss@3.16.0-beta.1 all working good. Repo

francoismassart commented 4 months ago

I also tried the latest beta with ESLint 8.15.0 and the legacy config 👍

francoismassart commented 4 months ago

Latest version (3.16.0) support both flat config and ESLint 9

npm i eslint-plugin-tailwindcss@3.16.0 -D

cvhau commented 1 month ago

@francoismassart Thanks for your work!

Okay, I tested it and had a little hiccup with the different versions 3.16.0-beta.0 & 3.15.3-beta.9 but 3.15.3-beta.9 now seems to work if I use it like this:

import pluginTailwindCSS from 'eslint-plugin-tailwindcss'
import withNuxt from './.nuxt/eslint.config.mjs'

export default withNuxt([
  {
    plugins: { tailwindcss: pluginTailwindCSS },
    rules: pluginTailwindCSS.configs.recommended.rules,
  },
  // ...
])

This is the way it is intended to be, right?

Thank you! This config also work for me.