| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 | /** * @fileoverview Plugins manager * @author Nicholas C. Zakas */"use strict";//------------------------------------------------------------------------------// Requirements//------------------------------------------------------------------------------const debug = require("debug")("eslint:plugins");const naming = require("../util/naming");//------------------------------------------------------------------------------// Private//------------------------------------------------------------------------------const PLUGIN_NAME_PREFIX = "eslint-plugin-";//------------------------------------------------------------------------------// Public Interface//------------------------------------------------------------------------------/** * Plugin class */class Plugins {    /**     * Creates the plugins context     * @param {Environments} envContext - env context     * @param {Rules} rulesContext - rules context     */    constructor(envContext, rulesContext) {        this._plugins = Object.create(null);        this._environments = envContext;        this._rules = rulesContext;    }    /**     * Defines a plugin with a given name rather than loading from disk.     * @param {string} pluginName The name of the plugin to load.     * @param {Object} plugin The plugin object.     * @returns {void}     */    define(pluginName, plugin) {        const pluginNamespace = naming.getNamespaceFromTerm(pluginName),            pluginNameWithoutNamespace = naming.removeNamespaceFromTerm(pluginName),            pluginNameWithoutPrefix = naming.removePrefixFromTerm(PLUGIN_NAME_PREFIX, pluginNameWithoutNamespace),            shortName = pluginNamespace + pluginNameWithoutPrefix;        // load up environments and rules        this._plugins[shortName] = plugin;        this._environments.importPlugin(plugin, shortName);        this._rules.importPlugin(plugin, shortName);    }    /**     * Gets a plugin with the given name.     * @param {string} pluginName The name of the plugin to retrieve.     * @returns {Object} The plugin or null if not loaded.     */    get(pluginName) {        return this._plugins[pluginName] || null;    }    /**     * Returns all plugins that are loaded.     * @returns {Object} The plugins cache.     */    getAll() {        return this._plugins;    }    /**     * Loads a plugin with the given name.     * @param {string} pluginName The name of the plugin to load.     * @returns {void}     * @throws {Error} If the plugin cannot be loaded.     */    load(pluginName) {        const pluginNamespace = naming.getNamespaceFromTerm(pluginName),            pluginNameWithoutNamespace = naming.removeNamespaceFromTerm(pluginName),            pluginNameWithoutPrefix = naming.removePrefixFromTerm(PLUGIN_NAME_PREFIX, pluginNameWithoutNamespace),            shortName = pluginNamespace + pluginNameWithoutPrefix,            longName = pluginNamespace + PLUGIN_NAME_PREFIX + pluginNameWithoutPrefix;        let plugin = null;        if (pluginName.match(/\s+/)) {            const whitespaceError = new Error(`Whitespace found in plugin name '${pluginName}'`);            whitespaceError.messageTemplate = "whitespace-found";            whitespaceError.messageData = {                pluginName: longName            };            throw whitespaceError;        }        if (!this._plugins[shortName]) {            try {                plugin = require(longName);            } catch (pluginLoadErr) {                try {                    // Check whether the plugin exists                    require.resolve(longName);                } catch (missingPluginErr) {                    // If the plugin can't be resolved, display the missing plugin error (usually a config or install error)                    debug(`Failed to load plugin ${longName}.`);                    missingPluginErr.message = `Failed to load plugin ${pluginName}: ${missingPluginErr.message}`;                    missingPluginErr.messageTemplate = "plugin-missing";                    missingPluginErr.messageData = {                        pluginName: longName                    };                    throw missingPluginErr;                }                // Otherwise, the plugin exists and is throwing on module load for some reason, so print the stack trace.                throw pluginLoadErr;            }            // This step is costly, so skip if debug is disabled            if (debug.enabled) {                const resolvedPath = require.resolve(longName);                let version = null;                try {                    version = require(`${longName}/package.json`).version;                } catch (e) {                    // Do nothing                }                const loadedPluginAndVersion = version                    ? `${longName}@${version}`                    : `${longName}, version unknown`;                debug(`Loaded plugin ${pluginName} (${loadedPluginAndVersion}) (from ${resolvedPath})`);            }            this.define(pluginName, plugin);        }    }    /**     * Loads all plugins from an array.     * @param {string[]} pluginNames An array of plugins names.     * @returns {void}     * @throws {Error} If a plugin cannot be loaded.     * @throws {Error} If "plugins" in config is not an array     */    loadAll(pluginNames) {        // if "plugins" in config is not an array, throw an error so user can fix their config.        if (!Array.isArray(pluginNames)) {            const pluginNotArrayMessage = "ESLint configuration error: \"plugins\" value must be an array";            debug(`${pluginNotArrayMessage}: ${JSON.stringify(pluginNames)}`);            throw new Error(pluginNotArrayMessage);        }        // load each plugin by name        pluginNames.forEach(this.load, this);    }}module.exports = Plugins;
 |