From 5d677958bb683410ae4fba1ea5c2c4bc0782f827 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 6 Jun 2024 11:04:00 +0800 Subject: [PATCH 1/5] Migrate to flat config --- .eslintrc.cjs | 1 - browser.js | 20 ++++++++++++-------- eslint.config.js | 1 + index.js | 23 +++++++++++++---------- package.json | 16 +++++++++++----- readme.md | 34 ++++++++++++++-------------------- test/test.js | 18 ++++++++---------- 7 files changed, 59 insertions(+), 54 deletions(-) delete mode 100644 .eslintrc.cjs create mode 100644 eslint.config.js diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index e6e13eb..0000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./index'); diff --git a/browser.js b/browser.js index f70bc61..b00fe6b 100644 --- a/browser.js +++ b/browser.js @@ -1,14 +1,18 @@ -'use strict'; -const path = require('path'); -const confusingBrowserGlobals = require('confusing-browser-globals'); +import globals from 'globals'; +import confusingBrowserGlobals from 'confusing-browser-globals'; +import eslintConfigXo from './index.js'; -module.exports = { - extends: path.join(__dirname, 'index.js'), - env: { - node: false, - browser: true, +export default { + ...eslintConfigXo, + languageOptions: { + ...eslintConfigXo.languageOptions, + globals: { + ...globals.es2021, + ...globals.browser, + }, }, rules: { + ...eslintConfigXo.rules, 'no-restricted-globals': [ 'error', ...confusingBrowserGlobals, diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..0e8a9cc --- /dev/null +++ b/eslint.config.js @@ -0,0 +1 @@ +export {default} from './index.js'; diff --git a/index.js b/index.js index 1500076..e9ed2d9 100644 --- a/index.js +++ b/index.js @@ -1,18 +1,21 @@ -'use strict'; +import globals from 'globals'; -module.exports = { - parserOptions: { - ecmaVersion: 'latest', +export default { + languageOptions: { sourceType: 'module', - ecmaFeatures: { - jsx: true, + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + ...globals.es2021, + ...globals.node, }, }, - env: { - es2021: true, - node: true, + linterOptions: { + reportUnusedDisableDirectives: 'error', }, - reportUnusedDisableDirectives: true, rules: { 'comma-dangle': [ 'error', diff --git a/package.json b/package.json index 17254f1..9c7e0ca 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,11 @@ "version": "0.45.0", "description": "ESLint shareable config for XO", "license": "MIT", + "type": "module", + "exports": { + ".": "./index.js", + "./browser": "./browser.js" + }, "repository": "xojs/eslint-config-xo", "funding": "https://github.com/sponsors/sindresorhus", "author": { @@ -15,7 +20,7 @@ "node": ">=18" }, "scripts": { - "test": "eslint . && ava" + "test": "eslint && ava" }, "files": [ "index.js", @@ -50,12 +55,13 @@ "simple" ], "dependencies": { - "confusing-browser-globals": "1.0.11" + "confusing-browser-globals": "1.0.11", + "globals": "^15.3.0" }, "devDependencies": { - "ava": "^2.4.0", - "eslint": "^8.56.0", - "is-plain-obj": "^3.0.0" + "ava": "^6.1.3", + "eslint": "^9.4.0", + "is-plain-obj": "^4.1.0" }, "peerDependencies": { "eslint": ">=8.56.0" diff --git a/readme.md b/readme.md index 8c84e8a..d69b989 100644 --- a/readme.md +++ b/readme.md @@ -16,31 +16,25 @@ npm install --save-dev eslint-config-xo ## Usage -Add some ESLint config to your `package.json`: - -```json -{ - "name": "my-awesome-project", - "eslintConfig": { - "extends": "xo" - } -} -``` +Add some ESLint config to your `eslint.config.js`: -Or to `.eslintrc`: +```js +import eslintConfigXo from 'eslint-config-xo'; -```json -{ - "extends": "xo" -} +export default [ + eslintConfigXo, +]; ``` -This package also exposes [`xo/browser`](browser.js) if you're in the browser: -```json -{ - "extends": "xo/browser" -} +This package also exposes [`eslint-config-xo/browser`](browser.js) if you're in the browser: + +```js +import eslintConfigXoBrowser from 'eslint-config-xo/browser'; + +export default [ + eslintConfigXoBrowser, +]; ``` ## Use the XO CLI instead diff --git a/test/test.js b/test/test.js index be0d61b..ca597d8 100644 --- a/test/test.js +++ b/test/test.js @@ -1,12 +1,14 @@ import test from 'ava'; import isPlainObj from 'is-plain-obj'; import {ESLint} from 'eslint'; +import eslintConfigXoNode from '../index.js'; +import eslintConfigXoBrowser from '../browser.js'; const hasRule = (errors, ruleId) => errors.some(error => error.ruleId === ruleId); async function runEslint(string, config) { const eslint = new ESLint({ - useEslintrc: false, + overrideConfigFile: true, overrideConfig: config, }); @@ -16,20 +18,16 @@ async function runEslint(string, config) { } test('main', async t => { - const config = require('../index.js'); + t.true(isPlainObj(eslintConfigXoNode)); + t.true(isPlainObj(eslintConfigXoNode.rules)); - t.true(isPlainObj(config)); - t.true(isPlainObj(config.rules)); - - const errors = await runEslint('\'use strict\';\nconsole.log("unicorn")\n', config); + const errors = await runEslint('\'use strict\';\nconsole.log("unicorn")\n', eslintConfigXoNode); t.true(hasRule(errors, 'quotes'), JSON.stringify(errors)); }); test('browser', async t => { - const config = require('../browser.js'); - - t.true(isPlainObj(config)); + t.true(isPlainObj(eslintConfigXoBrowser)); - const errors = await runEslint('\'use strict\';\nprocess.exit();\n', config); + const errors = await runEslint('\'use strict\';\nprocess.exit();\n', eslintConfigXoBrowser); t.true(hasRule(errors, 'no-undef'), JSON.stringify(errors)); }); From 30d5e28a89c7783ceed895075458c9022575dcac Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 6 Jun 2024 11:06:40 +0800 Subject: [PATCH 2/5] Update matrix --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6cb6898..6e98150 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,9 +10,9 @@ jobs: fail-fast: false matrix: node-version: - - 16 - - 14 - - 12 + - 22 + - 20 + - 18 steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 From c8324a58327d3cfb9e79952b6ec93c6e3a5b2f70 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 6 Jun 2024 20:06:23 +0800 Subject: [PATCH 3/5] Export array --- browser.js | 12 ++++++++---- index.js | 4 +++- package.json | 5 ++--- readme.md | 4 ++-- test/test.js | 6 ++---- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/browser.js b/browser.js index b00fe6b..a8a1e86 100644 --- a/browser.js +++ b/browser.js @@ -2,20 +2,24 @@ import globals from 'globals'; import confusingBrowserGlobals from 'confusing-browser-globals'; import eslintConfigXo from './index.js'; -export default { - ...eslintConfigXo, +const [nodeConfig] = eslintConfigXo; + +const config = { + ...nodeConfig, languageOptions: { - ...eslintConfigXo.languageOptions, + ...nodeConfig.languageOptions, globals: { ...globals.es2021, ...globals.browser, }, }, rules: { - ...eslintConfigXo.rules, + ...nodeConfig.rules, 'no-restricted-globals': [ 'error', ...confusingBrowserGlobals, ], }, }; + +export default [config]; diff --git a/index.js b/index.js index e9ed2d9..08d236e 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,6 @@ import globals from 'globals'; -export default { +const config = { languageOptions: { sourceType: 'module', parserOptions: { @@ -674,3 +674,5 @@ export default { ], }, }; + +export default [config]; diff --git a/package.json b/package.json index 9c7e0ca..a090eb8 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "node": ">=18" }, "scripts": { - "test": "eslint && ava" + "test": "eslint . && ava" }, "files": [ "index.js", @@ -60,8 +60,7 @@ }, "devDependencies": { "ava": "^6.1.3", - "eslint": "^9.4.0", - "is-plain-obj": "^4.1.0" + "eslint": "^9.4.0" }, "peerDependencies": { "eslint": ">=8.56.0" diff --git a/readme.md b/readme.md index d69b989..0e3b710 100644 --- a/readme.md +++ b/readme.md @@ -22,7 +22,7 @@ Add some ESLint config to your `eslint.config.js`: import eslintConfigXo from 'eslint-config-xo'; export default [ - eslintConfigXo, + ...eslintConfigXo, ]; ``` @@ -33,7 +33,7 @@ This package also exposes [`eslint-config-xo/browser`](browser.js) if you're in import eslintConfigXoBrowser from 'eslint-config-xo/browser'; export default [ - eslintConfigXoBrowser, + ...eslintConfigXoBrowser, ]; ``` diff --git a/test/test.js b/test/test.js index ca597d8..57c114d 100644 --- a/test/test.js +++ b/test/test.js @@ -1,5 +1,4 @@ import test from 'ava'; -import isPlainObj from 'is-plain-obj'; import {ESLint} from 'eslint'; import eslintConfigXoNode from '../index.js'; import eslintConfigXoBrowser from '../browser.js'; @@ -18,15 +17,14 @@ async function runEslint(string, config) { } test('main', async t => { - t.true(isPlainObj(eslintConfigXoNode)); - t.true(isPlainObj(eslintConfigXoNode.rules)); + t.true(Array.isArray(eslintConfigXoNode)); const errors = await runEslint('\'use strict\';\nconsole.log("unicorn")\n', eslintConfigXoNode); t.true(hasRule(errors, 'quotes'), JSON.stringify(errors)); }); test('browser', async t => { - t.true(isPlainObj(eslintConfigXoBrowser)); + t.true(Array.isArray(eslintConfigXoBrowser)); const errors = await runEslint('\'use strict\';\nprocess.exit();\n', eslintConfigXoBrowser); t.true(hasRule(errors, 'no-undef'), JSON.stringify(errors)); From 231be9a6748e57cf257c80799b52fdb862ebabb0 Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 6 Jun 2024 20:25:35 +0800 Subject: [PATCH 4/5] Merge "space" config --- browser.js | 36 +++++++++++++++---------------- package.json | 8 +++++-- readme.md | 21 +++++++++++++++++- space-browser.js | 19 ++++++++++++++++ space.js | 19 ++++++++++++++++ test/test.js | 56 ++++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 131 insertions(+), 28 deletions(-) create mode 100644 space-browser.js create mode 100644 space.js diff --git a/browser.js b/browser.js index a8a1e86..9aa9e41 100644 --- a/browser.js +++ b/browser.js @@ -2,24 +2,24 @@ import globals from 'globals'; import confusingBrowserGlobals from 'confusing-browser-globals'; import eslintConfigXo from './index.js'; -const [nodeConfig] = eslintConfigXo; +const [config] = eslintConfigXo; -const config = { - ...nodeConfig, - languageOptions: { - ...nodeConfig.languageOptions, - globals: { - ...globals.es2021, - ...globals.browser, +export default [ + { + ...config, + languageOptions: { + ...config.languageOptions, + globals: { + ...globals.es2021, + ...globals.browser, + }, + }, + rules: { + ...config.rules, + 'no-restricted-globals': [ + 'error', + ...confusingBrowserGlobals, + ], }, }, - rules: { - ...nodeConfig.rules, - 'no-restricted-globals': [ - 'error', - ...confusingBrowserGlobals, - ], - }, -}; - -export default [config]; +]; diff --git a/package.json b/package.json index a090eb8..efa0cdd 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,9 @@ "type": "module", "exports": { ".": "./index.js", - "./browser": "./browser.js" + "./browser": "./browser.js", + "./space": "./space.js", + "./space/browser": "./space-browser.js" }, "repository": "xojs/eslint-config-xo", "funding": "https://github.com/sponsors/sindresorhus", @@ -24,7 +26,9 @@ }, "files": [ "index.js", - "browser.js" + "browser.js", + "space.js", + "space-browser.js" ], "keywords": [ "eslintconfig", diff --git a/readme.md b/readme.md index 0e3b710..5d58840 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,6 @@ export default [ ]; ``` - This package also exposes [`eslint-config-xo/browser`](browser.js) if you're in the browser: ```js @@ -37,6 +36,26 @@ export default [ ]; ``` +This package also exposes [`eslint-config-xo/space`](space.js) if you're in favor of 2-space indent: + +```js +import eslintConfigXoSpace from 'eslint-config-xo/space'; + +export default [ + ...eslintConfigXoSpace, +]; +``` + +This package also exposes [`eslint-config-xo/space`](space-browser.js) if you're in favor of 2-space indent and in browser: + +```js +import eslintConfigXoSpaceBrowser from 'eslint-config-xo/space/browser'; + +export default [ + ...eslintConfigXoSpaceBrowser, +]; +``` + ## Use the XO CLI instead XO is an ESLint wrapper with great defaults. diff --git a/space-browser.js b/space-browser.js new file mode 100644 index 0000000..551a610 --- /dev/null +++ b/space-browser.js @@ -0,0 +1,19 @@ +import eslintConfigXoBrowser from './browser.js'; + +const [config] = eslintConfigXoBrowser; + +export default [ + { + ...config, + rules: { + ...config.rules, + indent: [ + 'error', + 2, + { + SwitchCase: 1, + }, + ], + }, + }, +]; diff --git a/space.js b/space.js new file mode 100644 index 0000000..f701655 --- /dev/null +++ b/space.js @@ -0,0 +1,19 @@ +import eslintConfigXo from './index.js'; + +const [config] = eslintConfigXo; + +export default [ + { + ...config, + rules: { + ...config.rules, + indent: [ + 'error', + 2, + { + SwitchCase: 1, + }, + ], + }, + }, +]; diff --git a/test/test.js b/test/test.js index 57c114d..472130c 100644 --- a/test/test.js +++ b/test/test.js @@ -2,6 +2,8 @@ import test from 'ava'; import {ESLint} from 'eslint'; import eslintConfigXoNode from '../index.js'; import eslintConfigXoBrowser from '../browser.js'; +import eslintConfigXoSpaceNode from '../space.js'; +import eslintConfigXoSpaceBrowser from '../space-browser.js'; const hasRule = (errors, ruleId) => errors.some(error => error.ruleId === ruleId); @@ -16,16 +18,56 @@ async function runEslint(string, config) { return firstResult.messages; } -test('main', async t => { - t.true(Array.isArray(eslintConfigXoNode)); +test('node', async t => { + for (const config of [eslintConfigXoNode, eslintConfigXoSpaceNode]) { + t.true(Array.isArray(config)); - const errors = await runEslint('\'use strict\';\nconsole.log("unicorn")\n', eslintConfigXoNode); - t.true(hasRule(errors, 'quotes'), JSON.stringify(errors)); + // eslint-disable-next-line no-await-in-loop + const errors = await runEslint('\'use strict\';\nconsole.log("unicorn")\n', config); + t.true(hasRule(errors, 'quotes'), JSON.stringify(errors)); + } }); test('browser', async t => { - t.true(Array.isArray(eslintConfigXoBrowser)); + for (const config of [eslintConfigXoBrowser, eslintConfigXoSpaceBrowser]) { + t.true(Array.isArray(config)); - const errors = await runEslint('\'use strict\';\nprocess.exit();\n', eslintConfigXoBrowser); - t.true(hasRule(errors, 'no-undef'), JSON.stringify(errors)); + // eslint-disable-next-line no-await-in-loop + const errors = await runEslint('\'use strict\';\nprocess.exit();\n', config); + t.true(hasRule(errors, 'no-undef'), JSON.stringify(errors)); + } +}); + +test('space', async t => { + const fixture = ` +export function foo() { +\treturn true; +} +`.trim(); + + for (const { + expected, + config, + } of [ + { + config: eslintConfigXoSpaceNode, + expected: true, + }, + { + config: eslintConfigXoSpaceBrowser, + expected: true, + }, + { + config: eslintConfigXoNode, + expected: false, + }, + { + config: eslintConfigXoBrowser, + expected: false, + }, + ]) { + // eslint-disable-next-line no-await-in-loop + const errors = await runEslint(fixture, config); + t.is(hasRule(errors, 'indent'), expected, JSON.stringify(errors)); + } }); From ea493b809dd8ad6c3acd9be87dbf9e802b8628dc Mon Sep 17 00:00:00 2001 From: fisker Date: Thu, 6 Jun 2024 20:27:26 +0800 Subject: [PATCH 5/5] Fix --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5d58840..b8c2303 100644 --- a/readme.md +++ b/readme.md @@ -46,7 +46,7 @@ export default [ ]; ``` -This package also exposes [`eslint-config-xo/space`](space-browser.js) if you're in favor of 2-space indent and in browser: +This package also exposes [`eslint-config-xo/space/browser`](space-browser.js) if you're in favor of 2-space indent and in browser: ```js import eslintConfigXoSpaceBrowser from 'eslint-config-xo/space/browser';