Skip to content

Commit

Permalink
feat: support flat config (#330)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
kazupon and francoismassart authored May 22, 2024
1 parent 4d04a96 commit 7a19f92
Show file tree
Hide file tree
Showing 21 changed files with 727 additions and 1,083 deletions.
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
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',
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'),
},
};
13 changes: 11 additions & 2 deletions lib/util/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@
* @returns
*/
function defineTemplateBodyVisitor(context, templateBodyVisitor, scriptVisitor) {
if (context.parserServices == null || context.parserServices.defineTemplateBodyVisitor == null) {
const parserServices = getParserServices(context);
if (parserServices == null || parserServices.defineTemplateBodyVisitor == null) {
// Default parser
return scriptVisitor;
}

// Using "vue-eslint-parser" requires this setup
// @see https://eslint.org/docs/developer-guide/working-with-rules#the-context-object
return context.parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
return parserServices.defineTemplateBodyVisitor(templateBodyVisitor, scriptVisitor);
}

/**
* This function is API compatible with eslint v8.x and eslint v9 or later.
* @see https://eslint.org/blog/2023/09/preparing-custom-rules-eslint-v9/#from-context-to-sourcecode
*/
function getParserServices(context) {
return context.sourceCode ? context.sourceCode.parserServices : context.parserServices;
}

module.exports = {
Expand Down
Loading

0 comments on commit 7a19f92

Please sign in to comment.