diff --git a/README.md b/README.md index 9368b1c2..c40c8a5d 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,14 @@ module.exports = { }; ``` +**eslint.config.js** +```js +const algolia = require('eslint-config-algolia/flat/base'); +module.exports = [ + ...algolia, +]; +``` + **package.json** ```json { @@ -86,6 +94,16 @@ module.exports = { }; ``` +**eslint.config.js** +```js +const algolia = require('eslint-config-algolia/flat/base'); +const algoliaJest = require('eslint-config-algolia/flat/jest'); +module.exports = [ + ...algolia, + ...algoliaJest, +]; +``` + **package.json** ```json { @@ -111,6 +129,16 @@ module.exports = { }; ``` +**eslint.config.js** +```js +const algolia = require('eslint-config-algolia/flat/base'); +const algoliaReact = require('eslint-config-algolia/flat/react'); +module.exports = [ + ...algolia, + ...algoliaReact, +]; +``` + **package.json** ```json { @@ -122,7 +150,7 @@ module.exports = { } ``` -### Flow +### Flow (deprecated) **terminal** ```sh @@ -136,7 +164,7 @@ module.exports = { }; ``` -### Flow with React +### Flow with React (deprecated) **terminal** ```sh @@ -171,7 +199,7 @@ yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript - **.eslintrc.js** ```js module.exports = { - extends: ['algolia', 'algolia/typescript'] + extends: ['algolia', 'algolia/typescript'], parserOptions: { project: '', @@ -179,6 +207,23 @@ module.exports = { }; ``` +**eslint.config.js** +```js +const algolia = require('eslint-config-algolia/flat/base'); +const algoliaTypescript = require('eslint-config-algolia/flat/typescript'); +module.exports = [ + ...algolia, + ...algoliaTypescript, + { + languageOptions: { + parserOptions: { + project: '', + }, + }, + }, +]; +``` + **package.json** ```json { @@ -207,6 +252,18 @@ module.exports = { ``` **Note**: Be sure to put the `algolia/typescript` configuration last so the parser is properly set for TypeScript files. +**eslint.config.js** +```js +const algolia = require('eslint-config-algolia/flat/base'); +const algoliaReact = require('eslint-config-algolia/flat/react'); +const algoliaTypescript = require('eslint-config-algolia/flat/typescript'); +module.exports = [ + ...algolia, + ...algoliaReact, + ...algoliaTypescript, +]; +``` + **package.json** ```json { @@ -233,6 +290,16 @@ module.exports = { }; ``` +**eslint.config.js** +```js +const algolia = require('eslint-config-algolia/flat/base'); +const algoliaVue = require('eslint-config-algolia/flat/vue'); +module.exports = [ + ...algolia, + ...algoliaVue, +]; +``` + **package.json** ```json { @@ -275,10 +342,23 @@ module.exports = { extends: 'algolia', rules: { 'import/no-commonjs': 'off' - } + }, }; ``` +**eslint.config.js** +```js +const algolia = require('eslint-config-algolia/flat/base'); +module.exports = [ + ...algolia, + { + rules: { + 'import/no-commonjs': 'off' + } + }, +]; +``` + ## Existing codebase setup If you have a lot of files already written and wants to now use diff --git a/packages/eslint-config-algolia/.eslintrc.js b/packages/eslint-config-algolia/.eslintrc.js deleted file mode 100644 index 85ad0105..00000000 --- a/packages/eslint-config-algolia/.eslintrc.js +++ /dev/null @@ -1,4 +0,0 @@ -// eslint-disable-next-line import/no-commonjs -module.exports = { - extends: './base.js', -}; diff --git a/packages/eslint-config-algolia/eslint.config.js b/packages/eslint-config-algolia/eslint.config.js new file mode 100644 index 00000000..31c7b989 --- /dev/null +++ b/packages/eslint-config-algolia/eslint.config.js @@ -0,0 +1,4 @@ +/* eslint-disable import/no-commonjs */ +const base = require('./flat/base'); + +module.exports = [...base]; diff --git a/packages/eslint-config-algolia/flat/base.js b/packages/eslint-config-algolia/flat/base.js new file mode 100644 index 00000000..aa99f0f1 --- /dev/null +++ b/packages/eslint-config-algolia/flat/base.js @@ -0,0 +1,61 @@ +/* eslint-disable import/no-commonjs */ +const eslintJs = require('@eslint/js'); +const commentsPlugin = require('@eslint-community/eslint-plugin-eslint-comments'); +const stylisticPlugin = require('@stylistic/eslint-plugin'); +const importPlugin = require('eslint-plugin-import'); +const jsdocPlugin = require('eslint-plugin-jsdoc'); +const eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended'); +const reactHooksPlugin = require('eslint-plugin-react-hooks'); +const globals = require('globals'); + +const rules = require('../rules/base'); + +// Remove legacy properties +delete rules.overrides; + +module.exports = [ + eslintJs.configs.recommended, + rules, + // prettier is set after to override our own rules + eslintPluginPrettierRecommended, + { + plugins: { + '@stylistic': stylisticPlugin, + '@eslint-community/eslint-comments': commentsPlugin, + import: importPlugin, + jsdoc: jsdocPlugin, + 'react-hooks': reactHooksPlugin, + }, + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + ecmaVersion: 'latest', + sourceType: 'module', + parserOptions: { + ecmaFeatures: { + experimentalObjectRestSpread: true, + impliedStrict: true, + }, + }, + }, + settings: { + 'import/extensions': ['.js', '.jsx', '.ts', '.tsx'], + + 'import/resolver': { + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + }, + }, + }, + }, + // Mixed codebase issues + { + // enable the rule specifically for TypeScript files + files: ['*.ts', '*.tsx'], + rules: { + 'jsdoc/no-types': ['error'], + }, + }, +]; diff --git a/packages/eslint-config-algolia/flat/jest.js b/packages/eslint-config-algolia/flat/jest.js new file mode 100644 index 00000000..f364ffeb --- /dev/null +++ b/packages/eslint-config-algolia/flat/jest.js @@ -0,0 +1,18 @@ +/* eslint-disable import/no-commonjs */ +const jestPlugin = require('eslint-plugin-jest'); +const globals = require('globals'); + +const jestRules = require('../rules/jest'); + +module.exports = [ + jestRules, + { + ...jestPlugin.configs['flat/recommended'], + ...jestPlugin.configs['flat/style'], + languageOptions: { + globals: { + ...globals.jest, + }, + }, + }, +]; diff --git a/packages/eslint-config-algolia/flat/react.js b/packages/eslint-config-algolia/flat/react.js new file mode 100644 index 00000000..728f9c14 --- /dev/null +++ b/packages/eslint-config-algolia/flat/react.js @@ -0,0 +1,28 @@ +/* eslint-disable import/no-commonjs */ +const babelParser = require('@babel/eslint-parser'); +const jsxA11yPlugin = require('eslint-plugin-jsx-a11y'); +const reactPlugin = require('eslint-plugin-react'); +const reactHooksPlugin = require('eslint-plugin-react-hooks'); + +const rules = require('../rules/react'); + +module.exports = [ + reactPlugin.configs.flat.recommended, + { + plugins: { + 'react-hooks': reactHooksPlugin, + 'jsx-a11y': jsxA11yPlugin, + }, + + languageOptions: { + parser: babelParser, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + requireConfigFile: false, + }, + }, + }, + rules, +]; diff --git a/packages/eslint-config-algolia/flat/typescript.js b/packages/eslint-config-algolia/flat/typescript.js new file mode 100644 index 00000000..bbae6460 --- /dev/null +++ b/packages/eslint-config-algolia/flat/typescript.js @@ -0,0 +1,48 @@ +/* eslint-disable import/no-commonjs */ +const typescriptPlugin = require('@typescript-eslint/eslint-plugin'); +const parser = require('@typescript-eslint/parser'); +const importPlugin = require('eslint-plugin-import'); + +const rules = require('../rules/typescript'); + +// Remove legacy properties +delete rules.plugins; +delete rules.overrides; + +module.exports = [ + rules, + { + plugins: { + '@typescript-eslint': typescriptPlugin, + import: importPlugin, + }, + languageOptions: { + parser, + parserOptions: { + ecmaFeatures: { + impliedStrict: true, + jsx: true, + }, + ecmaVersion: 2018, + sourceType: 'module', + requireConfigFile: false, + }, + }, + }, + // Mixed codebase issues + { + // enable the rule specifically for TypeScript files + files: ['*.ts', '*.tsx'], + rules: { + '@typescript-eslint/explicit-function-return-type': [ + 'error', + { + allowHigherOrderFunctions: true, + allowTypedFunctionExpressions: true, + // allowExpressions: true, + }, + ], + '@typescript-eslint/explicit-member-accessibility': ['error', { accessibility: 'no-public' }], + }, + }, +]; diff --git a/packages/eslint-config-algolia/flat/vue.js b/packages/eslint-config-algolia/flat/vue.js new file mode 100644 index 00000000..778308fb --- /dev/null +++ b/packages/eslint-config-algolia/flat/vue.js @@ -0,0 +1,40 @@ +// We don't extends from the `base` preset because the Vue plugin needs +// to use the parser under `parserOptions`. By doing this we broke the import +// plugin in the `react` preset. For now we just recreate the same configuration +// until all the plugins behave the same. + +/* eslint-disable import/no-commonjs */ +const babelParser = require('@babel/eslint-parser'); +const importPlugin = require('eslint-plugin-import'); +const vuePlugin = require('eslint-plugin-vue'); +const globals = require('globals'); + +const rules = require('../rules/vue'); + +module.exports.flat = [ + ...vuePlugin.configs['flat/recommended'], + rules, + { + plugins: { + import: importPlugin, + }, + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + }, + ecmaVersion: 2018, + sourceType: 'module', + parser: babelParser, // allows both flowtype and static class properties + parserOptions: { + ecmaFeatures: { + impliedStrict: true, + jsx: true, + }, + }, + }, + settings: { + 'import/extensions': ['.js'], + }, + }, +]; diff --git a/packages/eslint-config-algolia/package.json b/packages/eslint-config-algolia/package.json index a9f9c695..20bd41f0 100644 --- a/packages/eslint-config-algolia/package.json +++ b/packages/eslint-config-algolia/package.json @@ -27,6 +27,7 @@ "@babel/core": "7.25.2", "@babel/eslint-parser": "7.25.1", "@eslint-community/eslint-plugin-eslint-comments": "4.4.0", + "@eslint/js": "9.11.1", "@stylistic/eslint-plugin": "2.7.2", "eslint": "8.57.0", "eslint-config-prettier": "8.10.0", @@ -37,6 +38,7 @@ "eslint-plugin-prettier": "5.2.1", "eslint-plugin-react": "7.35.0", "eslint-plugin-react-hooks": "4.6.2", + "globals": "15.10.0", "prettier": "3.3.3" }, "peerDependencies": { diff --git a/packages/test/eslint.config.js b/packages/test/eslint.config.js new file mode 100644 index 00000000..4d79afbc --- /dev/null +++ b/packages/test/eslint.config.js @@ -0,0 +1,23 @@ +/* eslint-disable import/no-commonjs, @typescript-eslint/no-var-requires */ +const algolia = require('eslint-config-algolia/flat/base'); +const algoliaJest = require('eslint-config-algolia/flat/jest'); +const algoliaReact = require('eslint-config-algolia/flat/react'); +const algoliaTypescript = require('eslint-config-algolia/flat/typescript'); + +module.exports = [ + ...algolia, + ...algoliaReact, + ...algoliaTypescript, + ...algoliaJest, + { + rules: { + // Re-enable when this is released: https://github.com/import-js/eslint-plugin-import/commit/186f248357437ef46889f3eab7fda8e6030ba874 + 'import/no-named-as-default': 'off', + }, + languageOptions: { + parserOptions: { + project: 'tsconfig.json', + }, + }, + }, +]; diff --git a/packages/test/package.json b/packages/test/package.json index 1d71bcc0..beff03ea 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -4,6 +4,7 @@ "main": "index.js", "scripts": { "lint": "eslint .", + "lint:legacy": "ESLINT_USE_FLAT_CONFIG=false eslint .", "lint:fix": "eslint . --fix" }, "author": "Algolia (https://github.com/algolia/)", diff --git a/packages/test/tsconfig.json b/packages/test/tsconfig.json index 35cbec46..4305b393 100644 --- a/packages/test/tsconfig.json +++ b/packages/test/tsconfig.json @@ -45,6 +45,7 @@ "include": [ "index.js", "src/*", - ".eslintrc.js" + ".eslintrc.js", + "eslint.config.js" ], } diff --git a/scripts/test.sh b/scripts/test.sh index 73b5db70..2800eda5 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -4,3 +4,4 @@ set -e # exit when error cd packages/test yarn lint +yarn lint:legacy diff --git a/yarn.lock b/yarn.lock index 171c7502..11add3e5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -503,6 +503,13 @@ __metadata: languageName: node linkType: hard +"@eslint/js@npm:9.11.1": + version: 9.11.1 + resolution: "@eslint/js@npm:9.11.1" + checksum: 10c0/22916ef7b09c6f60c62635d897c66e1e3e38d90b5a5cf5e62769033472ecbcfb6ec7c886090a4b32fe65d6ce371da54384e46c26a899e38184dfc152c6152f7b + languageName: node + linkType: hard + "@humanwhocodes/config-array@npm:^0.11.14": version: 0.11.14 resolution: "@humanwhocodes/config-array@npm:0.11.14" @@ -2682,12 +2689,12 @@ __metadata: "eslint-config-algolia@file:../eslint-config-algolia::locator=test%40workspace%3Apackages%2Ftest": version: 23.1.7 - resolution: "eslint-config-algolia@file:../eslint-config-algolia#../eslint-config-algolia::hash=1b945a&locator=test%40workspace%3Apackages%2Ftest" + resolution: "eslint-config-algolia@file:../eslint-config-algolia#../eslint-config-algolia::hash=7517c7&locator=test%40workspace%3Apackages%2Ftest" peerDependencies: "@stylistic/eslint-plugin": ^2.6.4 eslint: ^5.16.0 || ^6.8.0 || ^7.2.0 || ^8.0.0 prettier: ^3.0.0 - checksum: 10c0/803e65bc961c7c7489d401759e387d442bc60f13fdbe1231210642ad81b2b81ae5a5e099f2e554f80a39a1bd8dad7966b20ec47c7d4e5055ec56c117670550a3 + checksum: 10c0/4d4ebce9aadd7033ae5c45903c0f1ab4d2555714e807cd4fe3ff398404a4634b52e2d44408bf1e50fc43e8b5d20d9ede53dd6f21a61f7c2794fe1d90fa5f4a1e languageName: node linkType: hard @@ -2698,6 +2705,7 @@ __metadata: "@babel/core": "npm:7.25.2" "@babel/eslint-parser": "npm:7.25.1" "@eslint-community/eslint-plugin-eslint-comments": "npm:4.4.0" + "@eslint/js": "npm:9.11.1" "@stylistic/eslint-plugin": "npm:2.7.2" eslint: "npm:8.57.0" eslint-config-prettier: "npm:8.10.0" @@ -2708,6 +2716,7 @@ __metadata: eslint-plugin-prettier: "npm:5.2.1" eslint-plugin-react: "npm:7.35.0" eslint-plugin-react-hooks: "npm:4.6.2" + globals: "npm:15.10.0" prettier: "npm:3.3.3" peerDependencies: "@stylistic/eslint-plugin": ^2.6.4 @@ -3461,6 +3470,13 @@ __metadata: languageName: node linkType: hard +"globals@npm:15.10.0": + version: 15.10.0 + resolution: "globals@npm:15.10.0" + checksum: 10c0/fef8f320e88f01f1492fef1b04b056908e1f6726eeaffe3bca03247237300c2d86e71585ee641b62ba71460a6eaff0d6ca7fca284e61bd1b3f833c7ad68b160a + languageName: node + linkType: hard + "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0"