From 50630e7b63c2f0c9fb480d9b3dc7a6f7bed49977 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 8 Sep 2022 14:07:06 -0700 Subject: [PATCH] fix: Plugins should always use the same reference When loading a plugin the first time, we should create a normalized plugin object and then cache it to use later so every reference to the same plugin is represented by the same normalized plugin reference. Refs eslint/eslint#16277 Closes #89 Closes #90 --- lib/config-array-factory.js | 18 ++++++++++++- tests/lib/config-array-factory.js | 43 +++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/lib/config-array-factory.js b/lib/config-array-factory.js index 9553d1fd..99851e15 100644 --- a/lib/config-array-factory.js +++ b/lib/config-array-factory.js @@ -129,6 +129,9 @@ const configFilenames = [ /** @type {WeakMap} */ const internalSlotsMap = new WeakMap(); +/** @type {WeakMap} */ +const normalizedPlugins = new WeakMap(); + /** * Check if a given string is a file path. * @param {string} nameOrPath A module name or file path. @@ -405,12 +408,25 @@ function createContext( * @returns {Plugin} The normalized plugin. */ function normalizePlugin(plugin) { - return { + + // first check the cache + let normalizedPlugin = normalizedPlugins.get(plugin); + + if (normalizedPlugin) { + return normalizedPlugin; + } + + normalizedPlugin = { configs: plugin.configs || {}, environments: plugin.environments || {}, processors: plugin.processors || {}, rules: plugin.rules || {} }; + + // save the reference for later + normalizedPlugins.set(plugin, normalizedPlugin); + + return normalizedPlugin; } //------------------------------------------------------------------------------ diff --git a/tests/lib/config-array-factory.js b/tests/lib/config-array-factory.js index efabbfc7..6b991381 100644 --- a/tests/lib/config-array-factory.js +++ b/tests/lib/config-array-factory.js @@ -2967,6 +2967,49 @@ env: }); }); + it("should represent the same plugin with the same object reference", async () => { + const teardown = createCustomTeardown({ + cwd: tempDir, + files: { + "node_modules/eslint-plugin-test/index.js": ` + module.exports = { + environments: { + bar: { globals: { bar: true } } + } + } + `, + "plugins/.eslintrc.yml": ` +plugins: + - test +rules: + test/foo: 2 +env: + test/bar: true + ` + } + }); + + cleanup = teardown.cleanup; + + await teardown.prepare(); + const factory = new ConfigArrayFactory({ cwd: teardown.getPath() }); + + const filePath = "plugins/.eslintrc.yml"; + const config1 = factory + .loadFile(filePath) + .extractConfig(filePath); + + const config2 = factory + .loadFile(filePath) + .extractConfig(filePath); + + const first = config1.plugins.test.definition; + const second = config2.plugins.test.definition; + + assert.strictEqual(first, second); + }); + + it("should load two separate configs from a plugin", async () => { const teardown = createCustomTeardown({ cwd: tempDir,