From 31e79399d0ad2e94bd5ad832f994d46b2bb4fa1e Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Tue, 19 Oct 2021 14:18:52 +0200 Subject: [PATCH] Fix: allow `baseConfig` to extend preloaded plugin config (fixes #15079) --- lib/cli-engine/cli-engine.js | 11 ++++++++++- lib/eslint/eslint.js | 17 ++--------------- tests/lib/eslint/eslint.js | 30 ++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/lib/cli-engine/cli-engine.js b/lib/cli-engine/cli-engine.js index aae71607d2c..7fba116c771 100644 --- a/lib/cli-engine/cli-engine.js +++ b/lib/cli-engine/cli-engine.js @@ -570,8 +570,10 @@ class CLIEngine { /** * Creates a new instance of the core CLI engine. * @param {CLIEngineOptions} providedOptions The options for this instance. + * @param {Object} [additionalData] Additional settings that are not CLIEngineOptions. + * @param {Record|null} [additionalData.preloadedPlugins] Preloaded plugins. */ - constructor(providedOptions) { + constructor(providedOptions, { preloadedPlugins } = {}) { const options = Object.assign( Object.create(null), defaultOptions, @@ -584,6 +586,13 @@ class CLIEngine { } const additionalPluginPool = new Map(); + + if (preloadedPlugins) { + for (const [id, plugin] of Object.entries(preloadedPlugins)) { + additionalPluginPool.set(id, plugin); + } + } + const cacheFilePath = getCacheFile( options.cacheLocation || options.cacheFile, options.cwd diff --git a/lib/eslint/eslint.js b/lib/eslint/eslint.js index b4a1d028db9..8886d45ab43 100644 --- a/lib/eslint/eslint.js +++ b/lib/eslint/eslint.js @@ -54,7 +54,7 @@ const { version } = require("../../package.json"); * @property {string} [ignorePath] The ignore file to use instead of .eslintignore. * @property {ConfigData} [overrideConfig] Override config object, overrides all configs used with this instance * @property {string} [overrideConfigFile] The configuration file to use. - * @property {Record} [plugins] An array of plugin implementations. + * @property {Record|null} [plugins] Preloaded plugins. This is a map-like object, keys are plugin IDs and each value is implementation. * @property {"error" | "warn" | "off"} [reportUnusedDisableDirectives] the severity to report unused eslint-disable directives. * @property {string} [resolvePluginsRelativeTo] The folder where plugins should be resolved from, defaulting to the CWD. * @property {string[]} [rulePaths] An array of directories to load custom rules from. @@ -433,26 +433,13 @@ class ESLint { */ constructor(options = {}) { const processedOptions = processOptions(options); - const cliEngine = new CLIEngine(processedOptions); + const cliEngine = new CLIEngine(processedOptions, { preloadedPlugins: options.plugins }); const { - additionalPluginPool, configArrayFactory, lastConfigArrays } = getCLIEngineInternalSlots(cliEngine); let updated = false; - /* - * Address `plugins` to add plugin implementations. - * Operate the `additionalPluginPool` internal slot directly to avoid - * using `addPlugin(id, plugin)` method that resets cache everytime. - */ - if (options.plugins) { - for (const [id, plugin] of Object.entries(options.plugins)) { - additionalPluginPool.set(id, plugin); - updated = true; - } - } - /* * Address `overrideConfig` to set override config. * Operate the `configArrayFactory` internal slot directly because this diff --git a/tests/lib/eslint/eslint.js b/tests/lib/eslint/eslint.js index 1a51a65d841..eaf4aaaaf05 100644 --- a/tests/lib/eslint/eslint.js +++ b/tests/lib/eslint/eslint.js @@ -2095,6 +2095,36 @@ describe("ESLint", () => { assert.strictEqual(results[0].messages[0].ruleId, "test/example-rule"); }); + it("should return two messages when executing with `baseConfig` that extends preloaded plugin config", async () => { + eslint = new ESLint({ + cwd: path.join(fixtureDir, ".."), + useEslintrc: false, + baseConfig: { + extends: ["plugin:test/preset"] + }, + plugins: { + test: { + rules: { + "example-rule": require("../../fixtures/rules/custom-rule") + }, + configs: { + preset: { + rules: { + "test/example-rule": 1 + }, + plugins: ["test"] + } + } + } + } + }); + const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"))]); + + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].messages.length, 2); + assert.strictEqual(results[0].messages[0].ruleId, "test/example-rule"); + }); + it("should load plugins from the `loadPluginsRelativeTo` directory, if specified", async () => { eslint = new ESLint({ resolvePluginsRelativeTo: getFixturePath("plugins"),