Skip to content

Commit

Permalink
[New] add support for Flat Config
Browse files Browse the repository at this point in the history
This change adds support for ESLint's new Flat config system.  It maintains backwards compatibility with `eslintrc`-style configs as well.

To achieve this, we're now dynamically creating flat configs on a new `flatConfigs` export.

Usage

```js
import importPlugin from 'eslint-plugin-import';
import js from '@eslint/js';
import tsParser from '@typescript-eslint/parser';

export default [
  js.configs.recommended,
  importPlugin.flatConfigs.recommended,
  importPlugin.flatConfigs.react,
  importPlugin.flatConfigs.typescript,
  {
    files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
    languageOptions: {
      parser: tsParser,
      ecmaVersion: 'latest',
      sourceType: 'module',
    },
    ignores: ['eslint.config.js'],
    rules: {
      'no-unused-vars': 'off',
      'import/no-dynamic-require': 'warn',
      'import/no-nodejs-modules': 'warn',
    },
  },
];
```
  • Loading branch information
michaelfaith authored and ljharb committed Jun 18, 2024
1 parent b340f1f commit 806e3c2
Show file tree
Hide file tree
Showing 29 changed files with 541 additions and 49 deletions.
1 change: 1 addition & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ insert_final_newline = true
indent_style = space
indent_size = 2
end_of_line = lf
quote_type = single
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ tests/files/with-syntax-error
tests/files/just-json-files/invalid.json
tests/files/typescript-d-ts/
resolvers/webpack/test/files
examples
# we want to ignore "tests/files" here, but unfortunately doing so would
# interfere with unit test and fail it for some reason.
# tests/files
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
- [`dynamic-import-chunkname`]: add `allowEmpty` option to allow empty leading comments ([#2942], thanks [@JiangWeixian])
- [`dynamic-import-chunkname`]: Allow empty chunk name when webpackMode: 'eager' is set; add suggestions to remove name in eager mode ([#3004], thanks [@amsardesai])
- [`no-unused-modules`]: Add `ignoreUnusedTypeExports` option ([#3011], thanks [@silverwind])
- add support for Flat Config ([#3018], thanks [@michaelfaith])

### Fixed
- [`no-extraneous-dependencies`]: allow wrong path ([#3012], thanks [@chabb])
Expand Down Expand Up @@ -1125,6 +1126,7 @@ for info on changes for earlier releases.

[#3036]: https://github.com/import-js/eslint-plugin-import/pull/3036
[#3033]: https://github.com/import-js/eslint-plugin-import/pull/3033
[#3018]: https://github.com/import-js/eslint-plugin-import/pull/3018
[#3012]: https://github.com/import-js/eslint-plugin-import/pull/3012
[#3011]: https://github.com/import-js/eslint-plugin-import/pull/3011
[#3004]: https://github.com/import-js/eslint-plugin-import/pull/3004
Expand Down Expand Up @@ -1874,6 +1876,7 @@ for info on changes for earlier releases.
[@meowtec]: https://github.com/meowtec
[@mgwalker]: https://github.com/mgwalker
[@mhmadhamster]: https://github.com/MhMadHamster
[@michaelfaith]: https://github.com/michaelfaith
[@MikeyBeLike]: https://github.com/MikeyBeLike
[@minervabot]: https://github.com/minervabot
[@mpint]: https://github.com/mpint
Expand Down
31 changes: 30 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ The maintainers of `eslint-plugin-import` and thousands of other packages are wo
npm install eslint-plugin-import --save-dev
```

### Config - Legacy (`.eslintrc`)

All rules are off by default. However, you may configure them manually
in your `.eslintrc.(yml|json|js)`, or extend one of the canned configs:

Expand All @@ -123,14 +125,41 @@ plugins:
- import

rules:
import/no-unresolved: [2, {commonjs: true, amd: true}]
import/no-unresolved: [2, { commonjs: true, amd: true }]
import/named: 2
import/namespace: 2
import/default: 2
import/export: 2
# etc...
```

### Config - Flat (`eslint.config.js`)

All rules are off by default. However, you may configure them manually
in your `eslint.config.(js|cjs|mjs)`, or extend one of the canned configs:

```js
import importPlugin from 'eslint-plugin-import';
import js from '@eslint/js';

export default [
js.configs.recommended,
importPlugin.flatConfigs.recommended,
{
files: ['**/*.{js,mjs,cjs}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
rules: {
'no-unused-vars': 'off',
'import/no-dynamic-require': 'warn',
'import/no-nodejs-modules': 'warn',
},
},
];
```

## TypeScript

You may use the following snippet or assemble your own config using the granular settings described below it.
Expand Down
14 changes: 14 additions & 0 deletions config/flat/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* unopinionated config. just the things that are necessarily runtime errors
* waiting to happen.
* @type {Object}
*/
module.exports = {
rules: {
'import/no-unresolved': 2,
'import/named': 2,
'import/namespace': 2,
'import/default': 2,
'import/export': 2,
},
};
19 changes: 19 additions & 0 deletions config/flat/react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Adds `.jsx` as an extension, and enables JSX parsing.
*
* Even if _you_ aren't using JSX (or .jsx) directly, if your dependencies
* define jsnext:main and have JSX internally, you may run into problems
* if you don't enable these settings at the top level.
*/
module.exports = {
settings: {
'import/extensions': ['.js', '.jsx', '.mjs', '.cjs'],
},
languageOptions: {
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
};
26 changes: 26 additions & 0 deletions config/flat/recommended.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* The basics.
* @type {Object}
*/
module.exports = {
rules: {
// analysis/correctness
'import/no-unresolved': 'error',
'import/named': 'error',
'import/namespace': 'error',
'import/default': 'error',
'import/export': 'error',

// red flags (thus, warnings)
'import/no-named-as-default': 'warn',
'import/no-named-as-default-member': 'warn',
'import/no-duplicates': 'warn',
},

// need all these for parsing dependencies (even if _your_ code doesn't need
// all of them)
languageOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
};
11 changes: 11 additions & 0 deletions config/flat/warnings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* more opinionated config.
* @type {Object}
*/
module.exports = {
rules: {
'import/no-named-as-default': 1,
'import/no-named-as-default-member': 1,
'import/no-duplicates': 1,
},
};
2 changes: 0 additions & 2 deletions config/react.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@
* if you don't enable these settings at the top level.
*/
module.exports = {

settings: {
'import/extensions': ['.js', '.jsx'],
},

parserOptions: {
ecmaFeatures: { jsx: true },
},

};
2 changes: 1 addition & 1 deletion config/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// `.ts`/`.tsx`/`.js`/`.jsx` implementation.
const typeScriptExtensions = ['.ts', '.cts', '.mts', '.tsx'];

const allExtensions = [...typeScriptExtensions, '.js', '.jsx'];
const allExtensions = [...typeScriptExtensions, '.js', '.jsx', '.mjs', '.cjs'];

module.exports = {
settings: {
Expand Down
25 changes: 25 additions & 0 deletions examples/flat/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import importPlugin from 'eslint-plugin-import';
import js from '@eslint/js';
import tsParser from '@typescript-eslint/parser';

export default [
js.configs.recommended,
importPlugin.flatConfigs.recommended,
importPlugin.flatConfigs.react,
importPlugin.flatConfigs.typescript,
{
files: ['**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}'],
languageOptions: {
parser: tsParser,
ecmaVersion: 'latest',
sourceType: 'module',
},
ignores: ['eslint.config.mjs', '**/exports-unused.ts'],
rules: {
'no-unused-vars': 'off',
'import/no-dynamic-require': 'warn',
'import/no-nodejs-modules': 'warn',
'import/no-unused-modules': ['warn', { unusedExports: true }],
},
},
];
17 changes: 17 additions & 0 deletions examples/flat/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "flat",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"lint": "cross-env ESLINT_USE_FLAT_CONFIG=true eslint src --report-unused-disable-directives"
},
"devDependencies": {
"@eslint/js": "^9.5.0",
"@types/node": "^20.14.5",
"@typescript-eslint/parser": "^7.13.1",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint-plugin-import": "file:../..",
"typescript": "^5.4.5"
}
}
12 changes: 12 additions & 0 deletions examples/flat/src/exports-unused.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type ScalarType = string | number;
export type ObjType = {
a: ScalarType;
b: ScalarType;
};

export const a = 13;
export const b = 18;

const defaultExport: ObjType = { a, b };

export default defaultExport;
12 changes: 12 additions & 0 deletions examples/flat/src/exports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type ScalarType = string | number;
export type ObjType = {
a: ScalarType;
b: ScalarType;
};

export const a = 13;
export const b = 18;

const defaultExport: ObjType = { a, b };

export default defaultExport;
7 changes: 7 additions & 0 deletions examples/flat/src/imports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//import c from './exports';
import { a, b } from './exports';
import type { ScalarType, ObjType } from './exports';

import path from 'path';
import fs from 'node:fs';
import console from 'console';
3 changes: 3 additions & 0 deletions examples/flat/src/jsx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const Components = () => {
return <></>;
};
14 changes: 14 additions & 0 deletions examples/flat/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"rootDir": "./",
"moduleResolution": "Bundler",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
24 changes: 24 additions & 0 deletions examples/legacy/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = {
root: true,
env: { es2022: true },
extends: [
'eslint:recommended',
'plugin:import/recommended',
'plugin:import/react',
'plugin:import/typescript',
],
settings: {},
ignorePatterns: ['.eslintrc.cjs', '**/exports-unused.ts'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['import'],
rules: {
'no-unused-vars': 'off',
'import/no-dynamic-require': 'warn',
'import/no-nodejs-modules': 'warn',
'import/no-unused-modules': ['warn', { unusedExports: true }],
},
};
16 changes: 16 additions & 0 deletions examples/legacy/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "legacy",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"lint": "cross-env ESLINT_USE_FLAT_CONFIG=false eslint src --ext js,jsx,ts,tsx --report-unused-disable-directives"
},
"devDependencies": {
"@types/node": "^20.14.5",
"@typescript-eslint/parser": "^7.13.1",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint-plugin-import": "file:../..",
"typescript": "^5.4.5"
}
}
12 changes: 12 additions & 0 deletions examples/legacy/src/exports-unused.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type ScalarType = string | number;
export type ObjType = {
a: ScalarType;
b: ScalarType;
};

export const a = 13;
export const b = 18;

const defaultExport: ObjType = { a, b };

export default defaultExport;
12 changes: 12 additions & 0 deletions examples/legacy/src/exports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type ScalarType = string | number;
export type ObjType = {
a: ScalarType;
b: ScalarType;
};

export const a = 13;
export const b = 18;

const defaultExport: ObjType = { a, b };

export default defaultExport;
7 changes: 7 additions & 0 deletions examples/legacy/src/imports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//import c from './exports';
import { a, b } from './exports';
import type { ScalarType, ObjType } from './exports';

import path from 'path';
import fs from 'node:fs';
import console from 'console';
3 changes: 3 additions & 0 deletions examples/legacy/src/jsx.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const Components = () => {
return <></>;
};
14 changes: 14 additions & 0 deletions examples/legacy/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["ESNext"],
"target": "ESNext",
"module": "ESNext",
"rootDir": "./",
"moduleResolution": "Bundler",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true
}
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
"test": "npm run tests-only",
"test-compiled": "npm run prepublish && BABEL_ENV=testCompiled mocha --compilers js:babel-register tests/src",
"test-all": "node --require babel-register ./scripts/testAll",
"test-examples": "npm run build && npm run test-example:legacy && npm run test-example:flat",
"test-example:legacy": "cd examples/legacy && npm install && npm run lint",
"test-example:flat": "cd examples/flat && npm install && npm run lint",
"prepublishOnly": "safe-publish-latest && npm run build",
"prepublish": "not-in-publish || npm run prepublishOnly",
"preupdate:eslint-docs": "npm run build",
Expand Down
Loading

0 comments on commit 806e3c2

Please sign in to comment.