Skip to content

Commit 7a19f92

Browse files
feat: support flat config (#330)
* feat: support flat config * fix: wrong parserOptions * test: add test for flat/recommended * fix: add name for debug info for eslint config inspector * 3.16.0-beta.0 * fix: work-around blocking with `fg.sync` * fix: eslint v8.x and v9 compatible * 3.16.0-beta.1 --------- Co-authored-by: francoismassart <francois.massart@gmail.com>
1 parent 4d04a96 commit 7a19f92

File tree

21 files changed

+727
-1083
lines changed

21 files changed

+727
-1083
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
/node_modules
1+
node_modules
22
.DS_Store
33
.idea

README.md

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,47 +69,53 @@ You can can the same information on your favorite command line software as well.
6969

7070
## Installation
7171

72-
### 1. Install `eslint`
72+
### 1. Install `eslint` and `eslint-plugin-tailwindcss`
7373

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

7676
```
77-
$ npm i -D eslint
77+
$ npm i -D eslint eslint-plugin-tailwindcss
78+
7879
```
7980

80-
Then, create you `.eslintrc.js` file
81+
### 2. Create Configuration file
82+
83+
#### `.eslintrc`
84+
85+
Use .eslintrc.* file to configure rules in ESLint < v9. See also: https://eslint.org/docs/latest/use/configure/.
8186

8287
```js
8388
module.exports = {
8489
root: true,
90+
extends: ["plugin:tailwindcss/recommended"],
8591
};
8692
```
8793

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

90-
```
91-
$ npm i -D eslint-plugin-tailwindcss
92-
```
9396

94-
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:
97+
#### `eslint.config.js`
98+
99+
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.
95100

96101
```js
97-
module.exports = {
98-
root: true,
99-
extends: ["plugin:tailwindcss/recommended"],
100-
};
101-
```
102+
import tailwind from "eslint-plugin-tailwindcss";
102103

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

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

107111
### 3. Configure ESLint parsers
108112

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

111115
Our recommendations:
112116

117+
#### For `.eslintrc`
118+
113119
- For `js[x]`, `react`, `ts[x]`:
114120
- Install the parser: `npm i -D @typescript-eslint/parser`
115121
- Assign it to your files in `eslintrc`:
@@ -146,6 +152,42 @@ Our recommendations:
146152

147153
> 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.
148154

155+
#### For `eslint.config.js`
156+
157+
- For `js[x]`, `ts[x]`:
158+
- Install the parser: `npm i -D @eslint/js typescript-eslint`
159+
- Assign it to your files in `eslint.config.js`:
160+
```js
161+
import js from "@eslint/js";
162+
import ts from "typescript-eslint";
163+
import tailwind from "eslint-plugin-tailwindcss";
164+
165+
export default [
166+
// add eslint built-in
167+
js.configs.recommended,
168+
// add `typescript-eslint` flat config simply
169+
// if you would like use more another configuration,
170+
// see the section: https://typescript-eslint.io/getting-started#details
171+
...ts.configs.recommended,
172+
...tailwind.configs["flat/recommended"],
173+
];
174+
```
175+
- For `vue.js`:
176+
- Install the parser: `npm i -D eslint-plugin-vue`
177+
- Assign it to your files in `eslint.config.js`:
178+
```js
179+
import vue from "eslint-plugin-vue";
180+
import tailwind from "eslint-plugin-tailwindcss";
181+
182+
export default [
183+
// add `eslint-plugin-vue` flat config simply
184+
// if you would like use more another configuration,
185+
// see the section: https://eslint.vuejs.org/user-guide/#bundle-configurations-eslint-config-js
186+
...vue.configs["flat/recommended"],
187+
...tailwind.configs["flat/recommended"],
188+
];
189+
```
190+
149191
### 4. Add a npm script
150192

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

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

219+
#### For `.eslintrc`
220+
177221
FYI, here are the `default` values:
178222

179223
```json5
@@ -201,6 +245,38 @@ FYI, here are the `default` values:
201245
}
202246
```
203247

248+
#### For `eslint.config.js`
249+
250+
```js
251+
import tailwind from "eslint-plugin-tailwindcss";
252+
253+
export default [
254+
...tailwind.configs["flat/recommended"],
255+
{
256+
settings: {
257+
tailwindcss: {
258+
// These are the default values but feel free to customize
259+
callees: ["classnames", "clsx", "ctl"],
260+
config: "tailwind.config.js", // returned from `loadConfig()` utility if not provided
261+
cssFiles: [
262+
"**/*.css",
263+
"!**/node_modules",
264+
"!**/.*",
265+
"!**/dist",
266+
"!**/build",
267+
],
268+
cssFilesRefreshRate: 5_000,
269+
removeDuplicates: true,
270+
skipClassAttribute: false,
271+
whitelist: [],
272+
tags: [], // can be set to e.g. ['tw'] for use in tw`bg-blue`
273+
classRegex: "^class(Name)?$", // can be modified to support custom attributes. E.g. "^tw$" for `twin.macro`
274+
},
275+
},
276+
}
277+
];
278+
```
279+
204280
The plugin will look for each setting in this order and stops searching as soon as it finds the settings:
205281

206282
1. In the rule option argument (rule level)

lib/config/flat-recommended.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* @fileoverview Recommended coniguration for flat style
3+
* @see https://eslint.org/docs/latest/use/configure/configuration-files-new
4+
* @author François Massart
5+
*/
6+
'use strict';
7+
8+
const rules = require('./rules');
9+
10+
module.exports = [
11+
{
12+
name: 'tailwindcss:base',
13+
plugins: {
14+
get tailwindcss() {
15+
return require('../index');
16+
},
17+
},
18+
languageOptions: {
19+
parserOptions: {
20+
ecmaFeatures: {
21+
jsx: true,
22+
},
23+
},
24+
},
25+
},
26+
{
27+
name: 'tailwindcss:rules',
28+
rules,
29+
},
30+
];

lib/config/recommended.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @fileoverview Recommended coniguration for legacy style
3+
* @see https://eslint.org/docs/latest/use/configure/configuration-files
4+
* @author François Massart
5+
*/
6+
'use strict';
7+
8+
const rules = require('./rules');
9+
10+
module.exports = {
11+
plugins: ['tailwindcss'],
12+
parserOptions: {
13+
ecmaFeatures: {
14+
jsx: true,
15+
},
16+
},
17+
rules,
18+
};

lib/config/rules.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* @fileoverview Default rules configuration
3+
* @author François Massart
4+
*/
5+
6+
module.exports = {
7+
'tailwindcss/classnames-order': 'warn',
8+
'tailwindcss/enforces-negative-arbitrary-values': 'warn',
9+
'tailwindcss/enforces-shorthand': 'warn',
10+
'tailwindcss/migration-from-tailwind-2': 'warn',
11+
'tailwindcss/no-arbitrary-value': 'off',
12+
'tailwindcss/no-custom-classname': 'warn',
13+
'tailwindcss/no-contradicting-classname': 'error',
14+
'tailwindcss/no-unnecessary-arbitrary-value': 'warn',
15+
};

lib/index.js

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,7 @@ module.exports = {
2222
'no-unnecessary-arbitrary-value': require(base + 'no-unnecessary-arbitrary-value'),
2323
},
2424
configs: {
25-
recommended: {
26-
plugins: ['tailwindcss'],
27-
parserOptions: {
28-
ecmaFeatures: {
29-
jsx: true,
30-
},
31-
},
32-
rules: {
33-
'tailwindcss/classnames-order': 'warn',
34-
'tailwindcss/enforces-negative-arbitrary-values': 'warn',
35-
'tailwindcss/enforces-shorthand': 'warn',
36-
'tailwindcss/migration-from-tailwind-2': 'warn',
37-
'tailwindcss/no-arbitrary-value': 'off',
38-
'tailwindcss/no-custom-classname': 'warn',
39-
'tailwindcss/no-contradicting-classname': 'error',
40-
'tailwindcss/no-unnecessary-arbitrary-value': 'warn',
41-
},
42-
},
25+
recommended: require('./config/recommended'),
26+
'flat/recommended': require('./config/flat-recommended'),
4327
},
4428
};

lib/util/parser.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,23 @@
66
* @returns
77
*/
88
function defineTemplateBodyVisitor(context, templateBodyVisitor, scriptVisitor) {
9-
if (context.parserServices == null || context.parserServices.defineTemplateBodyVisitor == null) {
9+
const parserServices = getParserServices(context);
10+
if (parserServices == null || parserServices.defineTemplateBodyVisitor == null) {
1011
// Default parser
1112
return scriptVisitor;
1213
}
1314

1415
// Using "vue-eslint-parser" requires this setup
1516
// @see https://eslint.org/docs/developer-guide/working-with-rules#the-context-object
16-
return context.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
17+
return parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
18+
}
19+
20+
/**
21+
* This function is API compatible with eslint v8.x and eslint v9 or later.
22+
* @see https://eslint.org/blog/2023/09/preparing-custom-rules-eslint-v9/#from-context-to-sourcecode
23+
*/
24+
function getParserServices(context) {
25+
return context.sourceCode ? context.sourceCode.parserServices : context.parserServices;
1726
}
1827

1928
module.exports = {

0 commit comments

Comments
 (0)