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/.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 diff --git a/browser.js b/browser.js index f70bc61..9aa9e41 100644 --- a/browser.js +++ b/browser.js @@ -1,17 +1,25 @@ -'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, - }, - rules: { - 'no-restricted-globals': [ - 'error', - ...confusingBrowserGlobals, - ], +const [config] = eslintConfigXo; + +export default [ + { + ...config, + languageOptions: { + ...config.languageOptions, + globals: { + ...globals.es2021, + ...globals.browser, + }, + }, + rules: { + ...config.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 ff43688..8b16c4f 100644 --- a/index.js +++ b/index.js @@ -1,18 +1,21 @@ -'use strict'; +import globals from 'globals'; -module.exports = { - parserOptions: { - ecmaVersion: 'latest', +const config = { + 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', @@ -693,3 +696,5 @@ module.exports = { ], }, }; + +export default [config]; diff --git a/package.json b/package.json index 17254f1..efa0cdd 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,13 @@ "version": "0.45.0", "description": "ESLint shareable config for XO", "license": "MIT", + "type": "module", + "exports": { + ".": "./index.js", + "./browser": "./browser.js", + "./space": "./space.js", + "./space/browser": "./space-browser.js" + }, "repository": "xojs/eslint-config-xo", "funding": "https://github.com/sponsors/sindresorhus", "author": { @@ -19,7 +26,9 @@ }, "files": [ "index.js", - "browser.js" + "browser.js", + "space.js", + "space-browser.js" ], "keywords": [ "eslintconfig", @@ -50,12 +59,12 @@ "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" }, "peerDependencies": { "eslint": ">=8.56.0" diff --git a/readme.md b/readme.md index 8c84e8a..b8c2303 100644 --- a/readme.md +++ b/readme.md @@ -16,31 +16,44 @@ 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`: + +```js +import eslintConfigXo from 'eslint-config-xo'; + +export default [ + ...eslintConfigXo, +]; +``` + +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, +]; ``` -Or to `.eslintrc`: +This package also exposes [`eslint-config-xo/space`](space.js) if you're in favor of 2-space indent: -```json -{ - "extends": "xo" -} +```js +import eslintConfigXoSpace from 'eslint-config-xo/space'; + +export default [ + ...eslintConfigXoSpace, +]; ``` -This package also exposes [`xo/browser`](browser.js) if you're in the 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'; -```json -{ - "extends": "xo/browser" -} +export default [ + ...eslintConfigXoSpaceBrowser, +]; ``` ## Use the XO CLI instead 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 be0d61b..472130c 100644 --- a/test/test.js +++ b/test/test.js @@ -1,12 +1,15 @@ import test from 'ava'; -import isPlainObj from 'is-plain-obj'; 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); async function runEslint(string, config) { const eslint = new ESLint({ - useEslintrc: false, + overrideConfigFile: true, overrideConfig: config, }); @@ -15,21 +18,56 @@ async function runEslint(string, config) { return firstResult.messages; } -test('main', async t => { - const config = require('../index.js'); +test('node', async t => { + for (const config of [eslintConfigXoNode, eslintConfigXoSpaceNode]) { + t.true(Array.isArray(config)); - t.true(isPlainObj(config)); - t.true(isPlainObj(config.rules)); - - const errors = await runEslint('\'use strict\';\nconsole.log("unicorn")\n', config); - 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 => { - const config = require('../browser.js'); + for (const config of [eslintConfigXoBrowser, eslintConfigXoSpaceBrowser]) { + t.true(Array.isArray(config)); + + // 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)); + } +}); - t.true(isPlainObj(config)); +test('space', async t => { + const fixture = ` +export function foo() { +\treturn true; +} +`.trim(); - const errors = await runEslint('\'use strict\';\nprocess.exit();\n', config); - t.true(hasRule(errors, 'no-undef'), JSON.stringify(errors)); + 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)); + } });