UNPKG

eslint-flat-config-airbnb

Version:

A mostly reasonable approach to JavaScript and React using Airbnb's ESLint config, updated for ESLint 9+

339 lines (300 loc) 10.8 kB
# eslint-flat-config-airbnb A mostly reasonable approach to JavaScript and React using Airbnb's ESLint config, updated for ESLint 9+ This fork of the [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) updates the rules and configurations to support ESLint 9.0+ while maintaining the core principles of clean, consistent, and modern JavaScript code. ## Why this fork? - The original [guide](https://github.com/airbnb/javascript) is widely adopted but does not yet support ESLint 9.0+. - This version ensures compatibility with the latest ESLint rules and best practices. - Updates may include deprecations, rule refinements, and modern JavaScript features. ## Installation & Usage To use this updated guide in your project: ``` npm install --save-dev eslint-flat-config-airbnb ``` We export multiple ESLint configurations for your usage. Extend it in your eslint.config.mjs (or *.js, *.cjs, *.ts, *.mts, *cts). ### eslint-flat-config-airbnb Our default export contains all of our ESLint and React rules. It requires `eslint`. ``` // eslint.config.mjs import globals from 'globals'; import tseslint from 'typescript-eslint'; import airbnb from 'eslint-flat-config-airbnb'; import stylistic from '@stylistic/eslint-plugin'; export default [ { ignores: ['node_modules', 'build', 'dist'], }, { files: ['src/**/*.{js,mjs,cjs,ts}'], }, ...tseslint.configs.recommended, ...airbnb, { languageOptions: { globals: globals.node, }, plugins: { '@stylistic': stylistic, }, settings: { 'import/resolver': { node: { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, }, { rules: { 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], '@stylistic/template-curly-spacing': ['error', 'always'], '@stylistic/object-curly-spacing': ['error', 'always'], '@stylistic/computed-property-spacing': ['error', 'always'], 'no-use-before-define': ['error', { functions: false }], 'prefer-const': 1, complexity: ['error', { max: 15 }], }, }, ]; ``` ### base Our `base` export contains all ESLint rules, including ECMAScript6+. `base` also exports these configs - `bestPractices`, `errors`, `es6`, `node`, `strict`, `style`, `imports`, `variables` which are javasScript objects. ``` // eslint.config.mjs import globals from 'globals'; import { base } from 'eslint-flat-config-airbnb'; import stylistic from '@stylistic/eslint-plugin'; export default [ { ignores: ['node_modules', 'build', 'dist'], }, ...base, { languageOptions: { globals: globals.node, }, plugins: { '@stylistic': stylistic, }, rules: { 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], '@stylistic/template-curly-spacing': ['error', 'always'], } }, ]; ``` #### importing sub-rules from base ``` // eslint.config.mjs import globals from 'globals'; import { style } from 'eslint-flat-config-airbnb/base'; import stylistic from '@stylistic/eslint-plugin'; export default [ { ignores: ['node_modules', 'build', 'dist'], }, style, { languageOptions: { globals: globals.node, }, plugins: { '@stylistic': stylistic, }, rules: { 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], '@stylistic/template-curly-spacing': ['error', 'always'], } }, ]; ``` ### react Our `react` export contains all React rules. `react` also exports these configs - `reactA11y`, `reactHooks`, `reactCore` which are javasScript objects. ``` // eslint.config.mjs import globals from 'globals'; import { react } from 'eslint-flat-config-airbnb'; import stylistic from '@stylistic/eslint-plugin'; export default [ { ignores: ['node_modules', 'build', 'dist'], }, ...react, { languageOptions: { globals: globals.node, }, plugins: { '@stylistic': stylistic, }, rules: { 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], '@stylistic/template-curly-spacing': ['error', 'always'], } }, ]; ``` #### importing sub-rules from react ``` // eslint.config.mjs import globals from 'globals'; import { reactCore } from 'eslint-flat-config-airbnb/react'; import stylistic from '@stylistic/eslint-plugin'; export default [ { ignores: ['node_modules', 'build', 'dist'], }, reactCore, { languageOptions: { globals: globals.node, }, plugins: { '@stylistic': stylistic, }, rules: { 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], '@stylistic/template-curly-spacing': ['error', 'always'], } }, ]; ``` #### Custom eslint.config.mjs used across nodejs repo's ``` import globals from 'globals'; import { base } from 'eslint-flat-config-airbnb'; import stylistic from '@stylistic/eslint-plugin'; export default [ { ignores: ['node_modules', 'build', 'dist'], }, { files: ['src/**/*.{js,mjs,cjs,ts}'], }, ...base, { languageOptions: { globals: globals.node, }, plugins: { '@stylistic': stylistic, }, settings: { 'import/resolver': { node: { extensions: ['.js', '.jsx', '.ts', '.tsx'], }, }, }, }, { rules: { 'import/no-extraneous-dependencies': ['error'], 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], '@stylistic/indent': ['error', 4], '@stylistic/template-curly-spacing': ['error', 'always'], '@stylistic/computed-property-spacing': ['error', 'always'], 'no-use-before-define': ['error', { functions: false }], 'prefer-const': 1, '@stylistic/max-len': ['error', { code: 200 }], complexity: ['error', { max: 15 }], }, }, { files: ['eslint.config.mjs'], rules: { 'import/no-extraneous-dependencies': 'off', }, }, ]; ``` ## Troubleshoot Guide **Q1:** Can you use flat config for projects using commonjs (i.e., using ```module.exports```)?<br> **Ans:** Yes. Change file format to ```.mjs``` and use ES6 import and export statements in ```eslint.config.mjs```. **Q2:** Getting warning: ```Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.```<br> **Ans:** If you are not using react package in your project, you can use ```base``` rules instead as described in [above](#base) section. **Q3:** Getting error: ```ReferenceError: stylistic is not defined``` or for any other eslint plugin instead of ```stylistic```.<br> **Ans:** It is likely because there are some rule(s) defined in ```rules``` object in ```eslint.config.mjs``` and its corresponding package is not imported and added in ```plugins``` separately in the file even though it is installed with ```eslint-flat-config-airbnb``` package. **Q4:** Getting error: ```ConfigError: Config (unnamed): Key "plugins": Cannot redefine plugin "import".``` or for any other eslint plugin instead of ```import```.<br> **Ans:** Flat config doesn't support multiple declaration of ```plugins``` keyword. If there are mutiple packages which are importing with ```plugins``` keyword, remove them until atmost one declaration is present in config namespace. ``` // eslint.config.mjs import globals from 'globals'; import { base } from 'eslint-flat-config-airbnb'; import stylistic from '@stylistic/eslint-plugin'; import importPlugin from 'eslint-plugin-import'; // eslint-disable-next-line no-unused-vars const { plugins, ...importConfigWithoutPlugin } = importPlugin.flatConfigs.recommended; export default [ { ignores: ['node_modules', 'build', 'dist'], }, ...base, importConfigWithoutPlugin, { languageOptions: { globals: globals.node, }, plugins: { '@stylistic': stylistic, }, rules: { 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], '@stylistic/template-curly-spacing': ['error', 'always'], } }, ]; ``` **OR** ``` // eslint.config.mjs /* eslint-disable no-unused-vars */ import globals from 'globals'; import { bestPractices, errors, es6, node, strict, style, imports, variables } from 'eslint-flat-config-airbnb/base'; import stylistic from '@stylistic/eslint-plugin'; import importPlugin from 'eslint-plugin-import'; import nodePlugin from 'eslint-plugin-n'; const { plugins, ...importConfigWithoutPlugin } = importPlugin.flatConfigs.recommended; const { plugins: bestPracticesPlugins, ...bestPracticesConfigWithoutPlugin } = bestPractices; const { plugins: errorsPlugins, ...errorsConfigWithoutPlugin } = errors; const { plugins: es6Plugins, ...es6ConfigWithoutPlugin } = es6; const { plugins: nodePlugins, ...nodeConfigWithoutPlugin } = node; const { plugins: stylePlugins, ...styleConfigWithoutPlugin } = style; const { plugins: importsPlugins, ...importsConfigWithoutPlugin } = imports; export default [ { ignores: ['node_modules', 'build', 'dist'], }, importConfigWithoutPlugin, bestPracticesConfigWithoutPlugin, errorsConfigWithoutPlugin, es6ConfigWithoutPlugin, nodeConfigWithoutPlugin, styleConfigWithoutPlugin, importsConfigWithoutPlugin, strict, variables, { languageOptions: { parserOptions: { // set correct parser ecmaVersion: 'latest', sourceType: 'module', }, }, }, { languageOptions: { globals: globals.node, }, plugins: { // re-import plugins separately '@stylistic': stylistic, // for bestPracticesConfigWithoutPlugin, errorsConfigWithoutPlugin, es6ConfigWithoutPlugin, styleConfigWithoutPlugin import: importPlugin, // for importConfigWithoutPlugin, importsConfigWithoutPlugin n: nodePlugin, // nodeConfigWithoutPlugin }, rules: { 'no-underscore-dangle': ['error', { allow: ['_id', '__dirname', '__type'] }], } }, ]; ```