| 'use strict' |
| |
| const fs = require('graceful-fs') |
| const path = require('path') |
| const helper = require('./helper') |
| |
| const log = require('./logger').create('plugin') |
| |
| const IGNORED_PACKAGES = ['karma-cli', 'karma-runner.github.com'] |
| |
| function resolve (plugins, emitter) { |
| const modules = [] |
| |
| function requirePlugin (name) { |
| log.debug(`Loading plugin ${name}.`) |
| try { |
| modules.push(require(name)) |
| } catch (e) { |
| if (e.code === 'MODULE_NOT_FOUND' && e.message.includes(name)) { |
| log.error(`Cannot find plugin "${name}".\n Did you forget to install it?\n npm install ${name} --save-dev`) |
| } else { |
| log.error(`Error during loading "${name}" plugin:\n ${e.message}`) |
| } |
| emitter.emit('load_error', 'plug_in', name) |
| } |
| } |
| |
| plugins.forEach(function (plugin) { |
| if (helper.isString(plugin)) { |
| if (!plugin.includes('*')) { |
| requirePlugin(plugin) |
| return |
| } |
| const pluginDirectory = path.normalize(path.join(__dirname, '/../..')) |
| const regexp = new RegExp(`^${plugin.replace(/\*/g, '.*').replace(/\//g, '[/\\\\]')}`) |
| |
| log.debug(`Loading ${plugin} from ${pluginDirectory}`) |
| fs.readdirSync(pluginDirectory) |
| .map((e) => { |
| const modulePath = path.join(pluginDirectory, e) |
| if (e[0] === '@') { |
| return fs.readdirSync(modulePath).map((e) => path.join(modulePath, e)) |
| } |
| return modulePath |
| }) |
| .reduce((a, x) => a.concat(x), []) |
| .map((modulePath) => path.relative(pluginDirectory, modulePath)) |
| .filter((moduleName) => !IGNORED_PACKAGES.includes(moduleName) && regexp.test(moduleName)) |
| .forEach((pluginName) => requirePlugin(path.join(pluginDirectory, pluginName))) |
| } else if (helper.isObject(plugin)) { |
| log.debug(`Loading inline plugin defining ${Object.keys(plugin).join(', ')}.`) |
| modules.push(plugin) |
| } else { |
| log.error(`Invalid plugin ${plugin}`) |
| emitter.emit('load_error', 'plug_in', plugin) |
| } |
| }) |
| |
| return modules |
| } |
| |
| /** |
| Create a function to handle errors in plugin loading. |
| @param {Object} injector, the dict of dependency injection objects. |
| @return function closed over injector, which reports errors. |
| */ |
| function createInstantiatePlugin (injector) { |
| const emitter = injector.get('emitter') |
| // Cache to avoid report errors multiple times per plugin. |
| const pluginInstances = new Map() |
| return function instantiatePlugin (kind, name) { |
| if (pluginInstances.has(name)) { |
| return pluginInstances.get(name) |
| } |
| |
| let p |
| try { |
| p = injector.get(`${kind}:${name}`) |
| if (!p) { |
| log.error(`Failed to instantiate ${kind} ${name}`) |
| emitter.emit('load_error', kind, name) |
| } |
| } catch (e) { |
| if (e.message.includes(`No provider for "${kind}:${name}"`)) { |
| log.error(`Cannot load "${name}", it is not registered!\n Perhaps you are missing some plugin?`) |
| } else { |
| log.error(`Cannot load "${name}"!\n ` + e.stack) |
| } |
| emitter.emit('load_error', kind, name) |
| } |
| pluginInstances.set(name, p, `${kind}:${name}`) |
| return p |
| } |
| } |
| |
| createInstantiatePlugin.$inject = ['injector'] |
| |
| module.exports = { resolve, createInstantiatePlugin } |