From 65711f984ad18975610ea54d288ff5728b09382e Mon Sep 17 00:00:00 2001 From: jjangga0214 Date: Thu, 21 Dec 2023 02:56:01 +0900 Subject: [PATCH] Support ESLint's new config system (#1886) Co-authored-by: Sindre Sorhus Co-authored-by: fisker --- .eslint-doc-generatorrc.js | 2 +- configs/all.js | 11 +- configs/flat-config-base.js | 20 +++ configs/legacy-config-base.js | 10 ++ configs/recommended.js | 240 ++++++++++++++++------------------ index.js | 27 +++- package.json | 6 +- readme.md | 150 ++++++++++++++++++++- scripts/create-rule.mjs | 17 +-- test/package.mjs | 37 +++++- 10 files changed, 364 insertions(+), 156 deletions(-) create mode 100644 configs/flat-config-base.js create mode 100644 configs/legacy-config-base.js diff --git a/.eslint-doc-generatorrc.js b/.eslint-doc-generatorrc.js index cafa0a8c90..0f1f832fab 100644 --- a/.eslint-doc-generatorrc.js +++ b/.eslint-doc-generatorrc.js @@ -2,7 +2,7 @@ /** @type {import('eslint-doc-generator').GenerateOptions} */ const config = { - ignoreConfig: ['all'], + ignoreConfig: ['all', 'flat/all', 'flat/recommended'], ignoreDeprecatedRules: true, ruleDocTitleFormat: 'desc', ruleListColumns: [ diff --git a/configs/all.js b/configs/all.js index d1ab5d77c3..743845a378 100644 --- a/configs/all.js +++ b/configs/all.js @@ -1,9 +1,6 @@ 'use strict'; -const {rules, ...baseConfigs} = require('./recommended.js'); +const recommended = require('./recommended.js'); -module.exports = { - ...baseConfigs, - rules: Object.fromEntries(Object.entries(rules).map( - ([ruleId, severity]) => [ruleId, ruleId.startsWith('unicorn/') ? 'error' : severity], - )), -}; +module.exports = Object.fromEntries(Object.entries(recommended).map( + ([ruleId, severity]) => [ruleId, ruleId.startsWith('unicorn/') ? 'error' : severity], +)); diff --git a/configs/flat-config-base.js b/configs/flat-config-base.js new file mode 100644 index 0000000000..4325e66d1e --- /dev/null +++ b/configs/flat-config-base.js @@ -0,0 +1,20 @@ +'use strict'; +const eslintrc = require('@eslint/eslintrc'); +const legacyConfigBase = require('./legacy-config-base.js'); + +const { + parserOptions: { + ecmaVersion, + sourceType, + }, +} = legacyConfigBase; + +const {globals} = eslintrc.Legacy.environments.get('es2024'); + +module.exports = { + languageOptions: { + ecmaVersion, + sourceType, + globals, + }, +}; diff --git a/configs/legacy-config-base.js b/configs/legacy-config-base.js new file mode 100644 index 0000000000..6a828fcb01 --- /dev/null +++ b/configs/legacy-config-base.js @@ -0,0 +1,10 @@ +'use strict'; +module.exports = { + env: { + es2024: true, + }, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + }, +}; diff --git a/configs/recommended.js b/configs/recommended.js index ecbedcd90c..42ea8e9730 100644 --- a/configs/recommended.js +++ b/configs/recommended.js @@ -1,129 +1,117 @@ 'use strict'; module.exports = { - env: { - es2024: true, - }, - parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - }, - plugins: [ - 'unicorn', - ], - rules: { - 'unicorn/better-regex': 'error', - 'unicorn/catch-error-name': 'error', - 'unicorn/consistent-destructuring': 'error', - 'unicorn/consistent-function-scoping': 'error', - 'unicorn/custom-error-definition': 'off', - 'unicorn/empty-brace-spaces': 'error', - 'unicorn/error-message': 'error', - 'unicorn/escape-case': 'error', - 'unicorn/expiring-todo-comments': 'error', - 'unicorn/explicit-length-check': 'error', - 'unicorn/filename-case': 'error', - 'unicorn/import-style': 'error', - 'unicorn/new-for-builtins': 'error', - 'unicorn/no-abusive-eslint-disable': 'error', - 'unicorn/no-array-callback-reference': 'error', - 'unicorn/no-array-for-each': 'error', - 'unicorn/no-array-method-this-argument': 'error', - 'unicorn/no-array-push-push': 'error', - 'unicorn/no-array-reduce': 'error', - 'unicorn/no-await-expression-member': 'error', - 'unicorn/no-console-spaces': 'error', - 'unicorn/no-document-cookie': 'error', - 'unicorn/no-empty-file': 'error', - 'unicorn/no-for-loop': 'error', - 'unicorn/no-hex-escape': 'error', - 'unicorn/no-instanceof-array': 'error', - 'unicorn/no-invalid-remove-event-listener': 'error', - 'unicorn/no-keyword-prefix': 'off', - 'unicorn/no-lonely-if': 'error', - 'no-negated-condition': 'off', - 'unicorn/no-negated-condition': 'error', - 'no-nested-ternary': 'off', - 'unicorn/no-nested-ternary': 'error', - 'unicorn/no-new-array': 'error', - 'unicorn/no-new-buffer': 'error', - 'unicorn/no-null': 'error', - 'unicorn/no-object-as-default-parameter': 'error', - 'unicorn/no-process-exit': 'error', - 'unicorn/no-static-only-class': 'error', - 'unicorn/no-thenable': 'error', - 'unicorn/no-this-assignment': 'error', - 'unicorn/no-typeof-undefined': 'error', - 'unicorn/no-unnecessary-await': 'error', - 'unicorn/no-unnecessary-polyfills': 'error', - 'unicorn/no-unreadable-array-destructuring': 'error', - 'unicorn/no-unreadable-iife': 'error', - 'unicorn/no-unused-properties': 'off', - 'unicorn/no-useless-fallback-in-spread': 'error', - 'unicorn/no-useless-length-check': 'error', - 'unicorn/no-useless-promise-resolve-reject': 'error', - 'unicorn/no-useless-spread': 'error', - 'unicorn/no-useless-switch-case': 'error', - 'unicorn/no-useless-undefined': 'error', - 'unicorn/no-zero-fractions': 'error', - 'unicorn/number-literal-case': 'error', - 'unicorn/numeric-separators-style': 'error', - 'unicorn/prefer-add-event-listener': 'error', - 'unicorn/prefer-array-find': 'error', - 'unicorn/prefer-array-flat': 'error', - 'unicorn/prefer-array-flat-map': 'error', - 'unicorn/prefer-array-index-of': 'error', - 'unicorn/prefer-array-some': 'error', - 'unicorn/prefer-at': 'error', - 'unicorn/prefer-blob-reading-methods': 'error', - 'unicorn/prefer-code-point': 'error', - 'unicorn/prefer-date-now': 'error', - 'unicorn/prefer-default-parameters': 'error', - 'unicorn/prefer-dom-node-append': 'error', - 'unicorn/prefer-dom-node-dataset': 'error', - 'unicorn/prefer-dom-node-remove': 'error', - 'unicorn/prefer-dom-node-text-content': 'error', - 'unicorn/prefer-event-target': 'error', - 'unicorn/prefer-export-from': 'error', - 'unicorn/prefer-includes': 'error', - 'unicorn/prefer-json-parse-buffer': 'off', - 'unicorn/prefer-keyboard-event-key': 'error', - 'unicorn/prefer-logical-operator-over-ternary': 'error', - 'unicorn/prefer-math-trunc': 'error', - 'unicorn/prefer-modern-dom-apis': 'error', - 'unicorn/prefer-modern-math-apis': 'error', - 'unicorn/prefer-module': 'error', - 'unicorn/prefer-native-coercion-functions': 'error', - 'unicorn/prefer-negative-index': 'error', - 'unicorn/prefer-node-protocol': 'error', - 'unicorn/prefer-number-properties': 'error', - 'unicorn/prefer-object-from-entries': 'error', - 'unicorn/prefer-optional-catch-binding': 'error', - 'unicorn/prefer-prototype-methods': 'error', - 'unicorn/prefer-query-selector': 'error', - 'unicorn/prefer-reflect-apply': 'error', - 'unicorn/prefer-regexp-test': 'error', - 'unicorn/prefer-set-has': 'error', - 'unicorn/prefer-set-size': 'error', - 'unicorn/prefer-spread': 'error', - 'unicorn/prefer-string-replace-all': 'error', - 'unicorn/prefer-string-slice': 'error', - 'unicorn/prefer-string-starts-ends-with': 'error', - 'unicorn/prefer-string-trim-start-end': 'error', - 'unicorn/prefer-switch': 'error', - 'unicorn/prefer-ternary': 'error', - 'unicorn/prefer-top-level-await': 'error', - 'unicorn/prefer-type-error': 'error', - 'unicorn/prevent-abbreviations': 'error', - 'unicorn/relative-url-style': 'error', - 'unicorn/require-array-join-separator': 'error', - 'unicorn/require-number-to-fixed-digits-argument': 'error', - // Turned off because we can't distinguish `widow.postMessage` and `{Worker,MessagePort,Client,BroadcastChannel}#postMessage()` - // See #1396 - 'unicorn/require-post-message-target-origin': 'off', - 'unicorn/string-content': 'off', - 'unicorn/switch-case-braces': 'error', - 'unicorn/template-indent': 'error', - 'unicorn/text-encoding-identifier-case': 'error', - 'unicorn/throw-new-error': 'error', - }, + 'unicorn/better-regex': 'error', + 'unicorn/catch-error-name': 'error', + 'unicorn/consistent-destructuring': 'error', + 'unicorn/consistent-function-scoping': 'error', + 'unicorn/custom-error-definition': 'off', + 'unicorn/empty-brace-spaces': 'error', + 'unicorn/error-message': 'error', + 'unicorn/escape-case': 'error', + 'unicorn/expiring-todo-comments': 'error', + 'unicorn/explicit-length-check': 'error', + 'unicorn/filename-case': 'error', + 'unicorn/import-style': 'error', + 'unicorn/new-for-builtins': 'error', + 'unicorn/no-abusive-eslint-disable': 'error', + 'unicorn/no-array-callback-reference': 'error', + 'unicorn/no-array-for-each': 'error', + 'unicorn/no-array-method-this-argument': 'error', + 'unicorn/no-array-push-push': 'error', + 'unicorn/no-array-reduce': 'error', + 'unicorn/no-await-expression-member': 'error', + 'unicorn/no-console-spaces': 'error', + 'unicorn/no-document-cookie': 'error', + 'unicorn/no-empty-file': 'error', + 'unicorn/no-for-loop': 'error', + 'unicorn/no-hex-escape': 'error', + 'unicorn/no-instanceof-array': 'error', + 'unicorn/no-invalid-remove-event-listener': 'error', + 'unicorn/no-keyword-prefix': 'off', + 'unicorn/no-lonely-if': 'error', + 'no-negated-condition': 'off', + 'unicorn/no-negated-condition': 'error', + 'no-nested-ternary': 'off', + 'unicorn/no-nested-ternary': 'error', + 'unicorn/no-new-array': 'error', + 'unicorn/no-new-buffer': 'error', + 'unicorn/no-null': 'error', + 'unicorn/no-object-as-default-parameter': 'error', + 'unicorn/no-process-exit': 'error', + 'unicorn/no-static-only-class': 'error', + 'unicorn/no-thenable': 'error', + 'unicorn/no-this-assignment': 'error', + 'unicorn/no-typeof-undefined': 'error', + 'unicorn/no-unnecessary-await': 'error', + 'unicorn/no-unnecessary-polyfills': 'error', + 'unicorn/no-unreadable-array-destructuring': 'error', + 'unicorn/no-unreadable-iife': 'error', + 'unicorn/no-unused-properties': 'off', + 'unicorn/no-useless-fallback-in-spread': 'error', + 'unicorn/no-useless-length-check': 'error', + 'unicorn/no-useless-promise-resolve-reject': 'error', + 'unicorn/no-useless-spread': 'error', + 'unicorn/no-useless-switch-case': 'error', + 'unicorn/no-useless-undefined': 'error', + 'unicorn/no-zero-fractions': 'error', + 'unicorn/number-literal-case': 'error', + 'unicorn/numeric-separators-style': 'error', + 'unicorn/prefer-add-event-listener': 'error', + 'unicorn/prefer-array-find': 'error', + 'unicorn/prefer-array-flat': 'error', + 'unicorn/prefer-array-flat-map': 'error', + 'unicorn/prefer-array-index-of': 'error', + 'unicorn/prefer-array-some': 'error', + 'unicorn/prefer-at': 'error', + 'unicorn/prefer-blob-reading-methods': 'error', + 'unicorn/prefer-code-point': 'error', + 'unicorn/prefer-date-now': 'error', + 'unicorn/prefer-default-parameters': 'error', + 'unicorn/prefer-dom-node-append': 'error', + 'unicorn/prefer-dom-node-dataset': 'error', + 'unicorn/prefer-dom-node-remove': 'error', + 'unicorn/prefer-dom-node-text-content': 'error', + 'unicorn/prefer-event-target': 'error', + 'unicorn/prefer-export-from': 'error', + 'unicorn/prefer-includes': 'error', + 'unicorn/prefer-json-parse-buffer': 'off', + 'unicorn/prefer-keyboard-event-key': 'error', + 'unicorn/prefer-logical-operator-over-ternary': 'error', + 'unicorn/prefer-math-trunc': 'error', + 'unicorn/prefer-modern-dom-apis': 'error', + 'unicorn/prefer-modern-math-apis': 'error', + 'unicorn/prefer-module': 'error', + 'unicorn/prefer-native-coercion-functions': 'error', + 'unicorn/prefer-negative-index': 'error', + 'unicorn/prefer-node-protocol': 'error', + 'unicorn/prefer-number-properties': 'error', + 'unicorn/prefer-object-from-entries': 'error', + 'unicorn/prefer-optional-catch-binding': 'error', + 'unicorn/prefer-prototype-methods': 'error', + 'unicorn/prefer-query-selector': 'error', + 'unicorn/prefer-reflect-apply': 'error', + 'unicorn/prefer-regexp-test': 'error', + 'unicorn/prefer-set-has': 'error', + 'unicorn/prefer-set-size': 'error', + 'unicorn/prefer-spread': 'error', + 'unicorn/prefer-string-replace-all': 'error', + 'unicorn/prefer-string-slice': 'error', + 'unicorn/prefer-string-starts-ends-with': 'error', + 'unicorn/prefer-string-trim-start-end': 'error', + 'unicorn/prefer-switch': 'error', + 'unicorn/prefer-ternary': 'error', + 'unicorn/prefer-top-level-await': 'error', + 'unicorn/prefer-type-error': 'error', + 'unicorn/prevent-abbreviations': 'error', + 'unicorn/relative-url-style': 'error', + 'unicorn/require-array-join-separator': 'error', + 'unicorn/require-number-to-fixed-digits-argument': 'error', + // Turned off because we can't distinguish `widow.postMessage` and `{Worker,MessagePort,Client,BroadcastChannel}#postMessage()` + // See #1396 + 'unicorn/require-post-message-target-origin': 'off', + 'unicorn/string-content': 'off', + 'unicorn/switch-case-braces': 'error', + 'unicorn/template-indent': 'error', + 'unicorn/text-encoding-identifier-case': 'error', + 'unicorn/throw-new-error': 'error', }; diff --git a/index.js b/index.js index 83a2943b61..ed98665e25 100644 --- a/index.js +++ b/index.js @@ -1,8 +1,10 @@ 'use strict'; const createDeprecatedRules = require('./rules/utils/create-deprecated-rules.js'); const {loadRules} = require('./rules/utils/rule.js'); -const recommendedConfig = require('./configs/recommended.js'); -const allRulesEnabledConfig = require('./configs/all.js'); +const legacyConfigBase = require('./configs/legacy-config-base.js'); +const flatConfigBase = require('./configs/flat-config-base.js'); +const recommendedRules = require('./configs/recommended.js'); +const allRules = require('./configs/all.js'); const {name, version} = require('./package.json'); const deprecatedRules = createDeprecatedRules({ @@ -26,7 +28,13 @@ const deprecatedRules = createDeprecatedRules({ 'regex-shorthand': 'unicorn/better-regex', }); -module.exports = { +const createConfig = (rules, isLegacyConfig = false) => ({ + ...(isLegacyConfig ? legacyConfigBase : flatConfigBase), + plugins: isLegacyConfig ? ['unicorn'] : {unicorn}, + rules, +}); + +const unicorn = { meta: { name, version, @@ -35,8 +43,13 @@ module.exports = { ...loadRules(), ...deprecatedRules, }, - configs: { - recommended: recommendedConfig, - all: allRulesEnabledConfig, - }, }; + +const configs = { + recommended: createConfig(recommendedRules, /* isLegacyConfig */ true), + all: createConfig(allRules, /* isLegacyConfig */ true), + 'flat/recommended': createConfig(recommendedRules), + 'flat/all': createConfig(allRules), +}; + +module.exports = {...unicorn, configs}; diff --git a/package.json b/package.json index 0c33239ed8..11bd5e1acf 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "email": "sindresorhus@gmail.com", "url": "https://sindresorhus.com" }, + "main": "index.js", "engines": { "node": ">=16" }, @@ -18,12 +19,12 @@ "fix": "run-p --continue-on-error fix:*", "fix:eslint-docs": "eslint-doc-generator", "fix:js": "npm run lint:js -- --fix", - "fix:md": "npm run lint:md -- --fix", + "fix:markdown": "npm run lint:markdown -- --fix", "integration": "node ./test/integration/test.mjs", "lint": "run-p --continue-on-error lint:*", "lint:eslint-docs": "npm run fix:eslint-docs -- --check", "lint:js": "xo", - "lint:md": "markdownlint \"**/*.md\"", + "lint:markdown": "markdownlint \"**/*.md\"", "lint:package-json": "npmPkgJsonLint .", "run-rules-on-codebase": "node ./test/run-rules-on-codebase/lint.mjs", "bundle-lodash": "echo \"export {defaultsDeep, camelCase, kebabCase, snakeCase, upperFirst, lowerFirst} from 'lodash-es';\" | npx esbuild --bundle --outfile=rules/utils/lodash.js --format=cjs", @@ -49,6 +50,7 @@ "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "@eslint-community/eslint-utils": "^4.4.0", + "@eslint/eslintrc": "^2.1.4", "ci-info": "^4.0.0", "clean-regexp": "^1.0.0", "core-js-compat": "^3.34.0", diff --git a/readme.md b/readme.md index b3de1d0f95..080dfa6d6d 100644 --- a/readme.md +++ b/readme.md @@ -15,9 +15,68 @@ You might want to check out [XO](https://github.com/xojs/xo), which includes thi npm install --save-dev eslint eslint-plugin-unicorn ``` -## Usage +## Usage (`eslint.config.js`) -Use a [preset config](#preset-configs) or configure each rule in `package.json`. +**Requires ESLint `>=8.23.0`.** + +Use a [preset config](#preset-configs-eslintconfigjs) or configure each rule in `eslint.config.js`. + +If you don't use the preset, ensure you use the same `languageOptions` config as below. + +### ES Module (Recommended) + +```js +import eslintPluginUnicorn from 'eslint-plugin-unicorn'; +import * as eslintrc from '@eslint/eslintrc'; + +export default [ + { + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: eslintrc.Legacy.environments.get('es2024'), + }, + plugins: { + unicorn: eslintPluginUnicorn, + }, + rules: { + 'unicorn/better-regex': 'error', + 'unicorn/…': 'error', + }, + }, + // … +]; +``` + +### CommonJS + +```js +'use strict'; +const eslintPluginUnicorn = require('eslint-plugin-unicorn'); +const eslintrc = require('@eslint/eslintrc'); + +module.exports = [ + { + languageOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + globals: eslintrc.Legacy.environments.get('es2024'), + }, + plugins: { + unicorn: eslintPluginUnicorn, + }, + rules: { + 'unicorn/better-regex': 'error', + 'unicorn/…': 'error', + }, + }, + // … +]; +``` + +## Usage (legacy: `.eslintrc.*` or `package.json`) + +Use a [preset config](#preset-configs-eslintrc-or-packagejson) or configure each rule in `package.json`. If you don't use the preset, ensure you use the same `env` and `parserOptions` config as below. @@ -172,7 +231,87 @@ If you don't use the preset, ensure you use the same `env` and `parserOptions` c See [docs/deprecated-rules.md](docs/deprecated-rules.md) -## Preset configs +## Preset configs (`eslint.config.js`) + +See the [ESLint docs](https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new) for more information about extending config files. + +**Note**: Preset configs will also enable the correct [language options](https://eslint.org/docs/latest/use/configure/configuration-files-new#configuring-language-options). + +### Recommended config + +This plugin exports a [`recommended` config](configs/recommended.js) that enforces good practices. + +#### ES Module (Recommended) + +```js +import eslintPluginUnicorn from 'eslint-plugin-unicorn'; + +export default [ + // … + eslintPluginUnicorn.config['flat/recommended'], + { + rules: { + 'unicorn/better-regex': 'warn', + }, + }, +]; +``` + +#### CommonJS + +```js +'use strict'; +const eslintPluginUnicorn = require('eslint-plugin-unicorn'); + +module.exports = [ + // … + eslintPluginUnicorn.config['flat/recommended'], + { + rules: { + 'unicorn/better-regex': 'warn', + }, + }, +]; +``` + +### All config + +This plugin exports an [`all` config](configs/all.js) that makes use of all rules (except for deprecated ones). + +#### ES Module (Recommended) + +```js +import eslintPluginUnicorn from 'eslint-plugin-unicorn'; + +export default [ + // … + eslintPluginUnicorn.config['flat/all'], + { + rules: { + 'unicorn/better-regex': 'warn', + }, + }, +]; +``` + +#### CommonJS + +```js +'use strict'; +const eslintPluginUnicorn = require('eslint-plugin-unicorn'); + +module.exports = [ + // … + eslintPluginUnicorn.config['flat/all'], + { + rules: { + 'unicorn/better-regex': 'warn', + }, + }, +]; +``` + +## Preset configs (`.eslintrc.*` or `package.json`) See the [ESLint docs](https://eslint.org/docs/user-guide/configuring/configuration-files#extending-configuration-files) for more information about extending config files. @@ -186,7 +325,10 @@ This plugin exports a [`recommended` config](configs/recommended.js) that enforc { "name": "my-awesome-project", "eslintConfig": { - "extends": "plugin:unicorn/recommended" + "extends": "plugin:unicorn/recommended", + "rules": { + "unicorn/better-regex": "warn" + } } } ``` diff --git a/scripts/create-rule.mjs b/scripts/create-rule.mjs index 976e0c1297..e04b8e590c 100644 --- a/scripts/create-rule.mjs +++ b/scripts/create-rule.mjs @@ -36,21 +36,22 @@ function renderTemplate({source, target, data}) { } function updateRecommended(id) { - const RULE_START = '\n\trules: {\n'; - const RULE_END = '\n\t}'; - const RULE_INDENT = '\t'.repeat(2); - let ruleContent = `${RULE_INDENT}'unicorn/${id}': 'error',`; - + const RULE_INDENT = '\t'; const file = path.join(ROOT, 'configs/recommended.js'); const content = fs.readFileSync(file, 'utf8'); - const [before, rest] = content.split(RULE_START); - const [rules, after] = rest.split(RULE_END); + const {before, rules, after} = content.match(/(?.*?{\n)(?.*?)(?\n};\s*)/s)?.groups ?? {}; + if (!rules) { + throw new Error('Unexpected content in “configs/recommended.js”.'); + } const lines = rules.split('\n'); + if (!lines.every(line => line.startsWith(RULE_INDENT))) { throw new Error('Unexpected content in “configs/recommended.js”.'); } + let ruleContent = `${RULE_INDENT}'unicorn/${id}': 'error',`; + const unicornRuleLines = lines.filter(line => line.startsWith(`${RULE_INDENT}'unicorn/`)); let insertIndex; if (ruleContent.localeCompare(unicornRuleLines[0]) === -1) { @@ -68,7 +69,7 @@ function updateRecommended(id) { lines.splice(insertIndex, 0, ruleContent); - const updated = `${before}${RULE_START}${lines.join('\n')}${RULE_END}${after}`; + const updated = `${before}${lines.join('\n')}${after}`; fs.writeFileSync(file, updated); } diff --git a/test/package.mjs b/test/package.mjs index 6163453c51..f4989a5957 100644 --- a/test/package.mjs +++ b/test/package.mjs @@ -1,5 +1,6 @@ import fs, {promises as fsAsync} from 'node:fs'; import path from 'node:path'; +import process from 'node:process'; import test from 'ava'; import {ESLint} from 'eslint'; import * as eslintrc from '@eslint/eslintrc'; @@ -75,7 +76,7 @@ test('Every rule is defined in index file in alphabetical order', t => { test('validate configuration', async t => { const results = await Promise.all( - Object.entries(eslintPluginUnicorn.configs).map(async ([name, config]) => { + Object.entries(eslintPluginUnicorn.configs).filter(([name]) => !name.startsWith('flat/')).map(async ([name, config]) => { const eslint = new ESLint({ baseConfig: config, useEslintrc: false, @@ -215,3 +216,37 @@ test('Plugin should have metadata', t => { t.is(typeof eslintPluginUnicorn.meta.name, 'string'); t.is(typeof eslintPluginUnicorn.meta.version, 'string'); }); + +function getCompactConfig(config) { + const compat = new eslintrc.FlatCompat({ + baseDirectory: process.cwd(), + resolvePluginsRelativeTo: process.cwd(), + }); + + const result = {plugins: undefined}; + + for (const part of compat.config(config)) { + for (const [key, value] of Object.entries(part)) { + if (key === 'languageOptions') { + result[key] = {...result[key], ...value}; + } else if (key === 'plugins') { + result[key] = undefined; + } else { + result[key] = value; + } + } + } + + return result; +} + +test('flat configs', t => { + t.deepEqual( + getCompactConfig(eslintPluginUnicorn.configs.recommended), + {...eslintPluginUnicorn.configs['flat/recommended'], plugins: undefined}, + ); + t.deepEqual( + getCompactConfig(eslintPluginUnicorn.configs.all), + {...eslintPluginUnicorn.configs['flat/all'], plugins: undefined}, + ); +});