diff --git a/package-lock.json b/package-lock.json index 8522e6e..44f4733 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@types/eslint": "^9.6.1", + "flatted": "^3.3.3", "jest-worker": "^29.7.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", @@ -7417,10 +7418,10 @@ } }, "node_modules/flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "license": "ISC" }, "node_modules/for-each": { "version": "0.3.3", @@ -18959,10 +18960,9 @@ } }, "flatted": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", - "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==" }, "for-each": { "version": "0.3.3", diff --git a/package.json b/package.json index 24d05af..6d08ee7 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ }, "dependencies": { "@types/eslint": "^9.6.1", + "flatted": "^3.3.3", "jest-worker": "^29.7.0", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", diff --git a/src/getESLint.js b/src/getESLint.js index c55915d..6c852ff 100644 --- a/src/getESLint.js +++ b/src/getESLint.js @@ -6,6 +6,7 @@ const { Worker: JestWorker } = require('jest-worker'); const { setup, lintFiles } = require('./worker'); const { getESLintOptions } = require('./options'); const { jsonStringifyReplacerSortKeys } = require('./utils'); +const { stringify } = require('flatted'); /** @type {{[key: string]: any}} */ const cache = {}; @@ -115,7 +116,7 @@ async function getESLint(key, { threads, ...options }) { * @returns {string} */ function getCacheKey(key, options) { - return JSON.stringify({ key, options }, jsonStringifyReplacerSortKeys); + return stringify({ key, options }, jsonStringifyReplacerSortKeys); } module.exports = { diff --git a/src/utils.js b/src/utils.js index b9ebc36..13aa67e 100644 --- a/src/utils.js +++ b/src/utils.js @@ -104,9 +104,13 @@ const jsonStringifyReplacerSortKeys = (_, value) => { return sorted; }; - return value instanceof Object && !(value instanceof Array) - ? Object.keys(value).sort().reduce(insert, {}) - : value; + if (value instanceof Object && !(value instanceof Array)) { + let sorted = Object.keys(value).sort().reduce(insert, {}); + Object.keys(value).forEach((key) => delete value[key]); + Object.assign(value, sorted); + } + + return value; }; module.exports = { diff --git a/test/circular-plugin.test.js b/test/circular-plugin.test.js new file mode 100644 index 0000000..54b93ad --- /dev/null +++ b/test/circular-plugin.test.js @@ -0,0 +1,38 @@ +import pack from './utils/pack'; +import { ESLint } from 'eslint'; + +(ESLint && parseFloat(ESLint.version) < 9 ? describe.skip : describe)( + 'circular plugin', + () => { + it('should support plugins with circular configs', async () => { + const plugin = { + configs: {}, + rules: {}, + processors: {}, + }; + + Object.assign(plugin.configs, { + recommended: { + plugins: { + self: plugin, + }, + rules: {}, + }, + }); + + const loaderOptions = { + configType: 'flat', + overrideConfig: { + plugins: { plugin: plugin }, + }, + overrideConfigFile: true, + }; + + const compiler = pack('good', loaderOptions); + + const stats = await compiler.runAsync(); + expect(stats.hasWarnings()).toBe(false); + expect(stats.hasErrors()).toBe(false); + }); + }, +);