Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support flat config #330

Merged
merged 9 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/node_modules
node_modules
.DS_Store
.idea
106 changes: 91 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,47 +69,53 @@ You can can the same information on your favorite command line software as well.

## Installation

### 1. Install `eslint`
### 1. Install `eslint` and `eslint-plugin-tailwindcss`

You'll first need to install [ESLint](http://eslint.org):

```
$ npm i -D eslint
$ npm i -D eslint eslint-plugin-tailwindcss

```

Then, create you `.eslintrc.js` file
### 2. Create Configuration file

#### `.eslintrc`

Use .eslintrc.* file to configure rules in ESLint < v9. See also: https://eslint.org/docs/latest/use/configure/.

```js
module.exports = {
root: true,
extends: ["plugin:tailwindcss/recommended"],
};
```

### 2. Install `eslint-plugin-tailwindcss`
If you would like to know about configuration, Learn more in [ESLint docs](https://eslint.org/docs/latest/use/configure/configuration-files)

```
$ npm i -D eslint-plugin-tailwindcss
```

Edit your `.eslintrc` file to use our [`recommended` preset](https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/lib/index.js#L24) to get reasonable defaults:
#### `eslint.config.js`

Use `eslint.config.js` file to configure rules. This is the default in ESLint v9, but can be used starting from ESLint v8.57.0. See also: https://eslint.org/docs/latest/use/configure/configuration-files-new.

```js
module.exports = {
root: true,
extends: ["plugin:tailwindcss/recommended"],
};
```
import tailwind from "eslint-plugin-tailwindcss";

> If you do not use our preset you will need to specify individual rules and add extra configuration...
export default [
...tailwind.configs["flat/recommended"],
];
```

Learn more about [Configuring Rules in ESLint](https://eslint.org/docs/user-guide/configuring/rules).
If you would like to know about configuration, Learn more in [ESLint docs](https://eslint.org/docs/latest/use/configure/configuration-files-new)

### 3. Configure ESLint parsers

Depending on the languages you are using in your project you must tell which parser will analyze your source files.

Our recommendations:

#### For `.eslintrc`

- For `js[x]`, `react`, `ts[x]`:
- Install the parser: `npm i -D @typescript-eslint/parser`
- Assign it to your files in `eslintrc`:
Expand Down Expand Up @@ -146,6 +152,42 @@ Our recommendations:

> We removed the default parsers which were added to `v3.8.2` because it created negative impact on dependencies resolution, bundle size increase and possible conflicts with existing configurations.

#### For `eslint.config.js`

- For `js[x]`, `ts[x]`:
- Install the parser: `npm i -D @eslint/js typescript-eslint`
- Assign it to your files in `eslint.config.js`:
```js
import js from "@eslint/js";
import ts from "typescript-eslint";
import tailwind from "eslint-plugin-tailwindcss";

export default [
// add eslint built-in
js.configs.recommended,
// add `typescript-eslint` flat config simply
// if you would like use more another configuration,
// see the section: https://typescript-eslint.io/getting-started#details
...ts.configs.recommended,
...tailwind.configs["flat/recommended"],
];
```
- For `vue.js`:
- Install the parser: `npm i -D eslint-plugin-vue`
- Assign it to your files in `eslint.config.js`:
```js
import vue from "eslint-plugin-vue";
import tailwind from "eslint-plugin-tailwindcss";

export default [
// add `eslint-plugin-vue` flat config simply
// if you would like use more another configuration,
// see the section: https://eslint.vuejs.org/user-guide/#bundle-configurations-eslint-config-js
...vue.configs["flat/recommended"],
...tailwind.configs["flat/recommended"],
];
```

### 4. Add a npm script

In your `package.json` add one or more script(s) to run eslint targeting your source files:
Expand Down Expand Up @@ -174,6 +216,8 @@ You should define the [shared settings](https://eslint.org/docs/user-guide/confi

All these settings already have nice default values that are explained in the documentation.

#### For `.eslintrc`

FYI, here are the `default` values:

```json5
Expand Down Expand Up @@ -201,6 +245,38 @@ FYI, here are the `default` values:
}
```

#### For `eslint.config.js`

```js
import tailwind from "eslint-plugin-tailwindcss";

export default [
...tailwind.configs["flat/recommended"],
{
settings: {
tailwindcss: {
// These are the default values but feel free to customize
callees: ["classnames", "clsx", "ctl"],
config: "tailwind.config.js", // returned from `loadConfig()` utility if not provided
cssFiles: [
"**/*.css",
"!**/node_modules",
"!**/.*",
"!**/dist",
"!**/build",
],
cssFilesRefreshRate: 5_000,
removeDuplicates: true,
skipClassAttribute: false,
whitelist: [],
tags: [], // can be set to e.g. ['tw'] for use in tw`bg-blue`
classRegex: "^class(Name)?$", // can be modified to support custom attributes. E.g. "^tw$" for `twin.macro`
},
},
}
];
```

The plugin will look for each setting in this order and stops searching as soon as it finds the settings:

1. In the rule option argument (rule level)
Expand Down
30 changes: 30 additions & 0 deletions lib/config/flat-recommended.js
Copy link
Contributor Author

@kazupon kazupon Mar 27, 2024

Choose a reason for hiding this comment

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

for flat config, ecmaFeatures option is not added. Because the parser options should be specified by the user. especially, jsx: true should be supported by plugins like eslint-plugin-react, as mentioned in the eslint documentation.
https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options

BTW, ecmaFeatures for flat config built-in on the plugin side will cause eslint to output an error as shown below, so we cannot set them built-in:

Error: Key "languageOptions": Unexpected key "ecmaFeatures" found.
    at ObjectSchema.validate (/path/to/oss/tailwind/eslint-plugin-tailwindcss/tests/integrations/flat-config/node_modules/@humanwhocodes/object-schema/src/object-schema.js:287:23)
    at /path/to/oss/tailwind/eslint-plugin-tailwindcss/tests/integrations/flat-config/node_modules/@humanwhocodes/object-schema/src/object-schema.js:239:18
    at Array.reduce (<anonymous>)
    at ObjectSchema.merge (/path/to/oss/tailwind/eslint-plugin-tailwindcss/tests/integrations/flat-config/node_modules/@humanwhocodes/object-schema/src/object-schema.js:237:24)
    at /path/to/oss/tailwind/eslint-plugin-tailwindcss/tests/integrations/flat-config/node_modules/@humanwhocodes/config-array/api.js:935:42
    at Array.reduce (<anonymous>)
    at FlatConfigArray.getConfig (/path/to/oss/tailwind/eslint-plugin-tailwindcss/tests/integrations/flat-config/node_modules/@humanwhocodes/config-array/api.js:934:39)
    at FlatConfigArray.isFileIgnored (/path/to/oss/tailwind/eslint-plugin-tailwindcss/tests/integrations/flat-config/node_modules/@humanwhocodes/config-array/api.js:962:15)
    at /path/to/oss/tailwind/eslint-plugin-tailwindcss/tests/integrations/flat-config/node_modules/eslint/lib/eslint/eslint-helpers.js:504:38
    at Array.forEach (<anonymous>)

Copy link

Choose a reason for hiding this comment

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

Aren’t ecmaFeatures supported in languageOptions.parserOptions?

  {
+   languageOptions: {
+     parserOptions: {
+       ecmaFeatures: {
+         jsx: true,
+       },
+     },
+   },
    plugins: {
      get tailwindcss() {
        return require('../index');
      },
    },
  },

ref: https://eslint.org/docs/latest/use/configure/configuration-files-new#configuration-objects

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks!
oh, I've apparently mis-read the config docs, and I found that it is possible with flat config.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @fileoverview Recommended coniguration for flat style
* @see https://eslint.org/docs/latest/use/configure/configuration-files-new
* @author François Massart
*/
'use strict';

const rules = require('./rules');

module.exports = [
{
name: 'tailwindcss:base',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

about name, see the here

We can check flat config with eslint config inspector
image

plugins: {
get tailwindcss() {
return require('../index');
},
},
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
},
{
name: 'tailwindcss:rules',
rules,
},
];
18 changes: 18 additions & 0 deletions lib/config/recommended.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* @fileoverview Recommended coniguration for legacy style
* @see https://eslint.org/docs/latest/use/configure/configuration-files
* @author François Massart
*/
'use strict';

const rules = require('./rules');

module.exports = {
plugins: ['tailwindcss'],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
rules,
};
15 changes: 15 additions & 0 deletions lib/config/rules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @fileoverview Default rules configuration
* @author François Massart
*/

module.exports = {
'tailwindcss/classnames-order': 'warn',
'tailwindcss/enforces-negative-arbitrary-values': 'warn',
'tailwindcss/enforces-shorthand': 'warn',
'tailwindcss/migration-from-tailwind-2': 'warn',
'tailwindcss/no-arbitrary-value': 'off',
'tailwindcss/no-custom-classname': 'warn',
'tailwindcss/no-contradicting-classname': 'error',
'tailwindcss/no-unnecessary-arbitrary-value': 'warn',
};
20 changes: 2 additions & 18 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,7 @@ module.exports = {
'no-unnecessary-arbitrary-value': require(base + 'no-unnecessary-arbitrary-value'),
},
configs: {
recommended: {
plugins: ['tailwindcss'],
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
rules: {
'tailwindcss/classnames-order': 'warn',
'tailwindcss/enforces-negative-arbitrary-values': 'warn',
'tailwindcss/enforces-shorthand': 'warn',
'tailwindcss/migration-from-tailwind-2': 'warn',
'tailwindcss/no-arbitrary-value': 'off',
'tailwindcss/no-custom-classname': 'warn',
'tailwindcss/no-contradicting-classname': 'error',
'tailwindcss/no-unnecessary-arbitrary-value': 'warn',
},
},
recommended: require('./config/recommended'),
'flat/recommended': require('./config/flat-recommended'),
},
};
Loading