diff --git a/lib/eslint/eslint.js b/lib/eslint/eslint.js index b4a28b2905d..196ce8d7bd5 100644 --- a/lib/eslint/eslint.js +++ b/lib/eslint/eslint.js @@ -80,10 +80,22 @@ const { CLIEngine } = require("../cli-engine"); * @property {(results: LintResult[]) => string} format The main formatter method. */ +/** + * Private properties for the `ESLint` instance. + * @typedef {Object} LinterInternalSlots + * @property {CLIEngine} cliEngine The wrapped CLIEngine instance. + */ + //------------------------------------------------------------------------------ // Helpers //------------------------------------------------------------------------------ +/** + * The map with which to store private properties. + * @type {WeakMap} + */ +const internalSlotsMap = new WeakMap(); + /** * Normalizes an array of plugins to their respective IDs. * @param {string[]|PluginElement[]} plugins An array of plugins to normalize. @@ -283,17 +295,22 @@ class ESLint { * @param {ESLintOptions} options The options for this instance. */ constructor(options) { - this._cliEngine = new CLIEngine(processOptions(options)); + const cliEngine = new CLIEngine(processOptions(options)); if (options.plugins.length) { for (const plugin of options.plugins) { - if (typeof plugin === "object" && plugin !== null) { - this._cliEngine.addPlugin(plugin.id, plugin.definition); + if (typeof plugin === "object" && !Array.isArray(plugin) && plugin !== null) { + cliEngine.addPlugin(plugin.id, plugin.definition); } else if (typeof plugin !== "string") { throw new Error("Invalid plugin. Plugins must be specified as a string (e.g., \"eslint-plugin-example\") or as an object (e.g., { id: string; definition: Object })."); } } } + + // Initialize private properties. + internalSlotsMap.set(this, { + cliEngine + }); } /** @@ -338,7 +355,9 @@ class ESLint { * @returns {Promise} The results of linting the file patterns given. */ async lintFiles(patterns) { - return processCLIEngineLintReport(this._cliEngine.executeOnFiles(patterns)); + const { cliEngine } = internalSlotsMap.get(this); + + return processCLIEngineLintReport(cliEngine.executeOnFiles(patterns)); } /** @@ -350,7 +369,9 @@ class ESLint { * @returns {Promise} The results of linting the string of code given. */ async lintText(code, { filePath = null, warnIgnored = false }) { - return processCLIEngineLintReport(this._cliEngine.executeOnText(code, filePath, warnIgnored)); + const { cliEngine } = internalSlotsMap.get(this); + + return processCLIEngineLintReport(cliEngine.executeOnText(code, filePath, warnIgnored)); } /** @@ -361,7 +382,8 @@ class ESLint { * @returns {Promise} A promise resolving to the formatter object or null if not found. */ async loadFormatter(name) { - const formatter = this._cliEngine.getFormatter(name); + const { cliEngine } = internalSlotsMap.get(this); + const formatter = cliEngine.getFormatter(name); if (formatter === null) { return null; @@ -382,7 +404,7 @@ class ESLint { return formatter(results, { get rulesMeta() { if (!rulesMeta) { - rulesMeta = createRulesMeta(this._cliEngine.getRules()); + rulesMeta = createRulesMeta(cliEngine.getRules()); } return rulesMeta; @@ -400,7 +422,9 @@ class ESLint { * @returns {Promise} A configuration object for the file. */ async calculateConfigForFile(filePath) { - return this._cliEngine.getConfigForFile(filePath); + const { cliEngine } = internalSlotsMap.get(this); + + return cliEngine.getConfigForFile(filePath); } /** @@ -409,7 +433,9 @@ class ESLint { * @returns {boolean} Whether or not the given path is ignored. */ async isPathIgnored(filePath) { - return this._cliEngine.isPathIgnored(filePath); + const { cliEngine } = internalSlotsMap.get(this); + + return cliEngine.isPathIgnored(filePath); } }