import { Event } from './Event'; import { EventCallableRegsitry } from './EventCallableRegsitry'; import { IPlugin } from './interfaces/IPlugin'; import dependencyValid from './utils/dependencyValid'; export class PluginStore { private functionArray: Map; private pluginMap: Map; private _eventCallableRegistry: EventCallableRegsitry = new EventCallableRegsitry(); constructor() { this.functionArray = new Map(); this.pluginMap = new Map(); } install(plugin: IPlugin) { const pluginNameAndVer = plugin.getPluginName(); const [pluginName] = pluginNameAndVer.split('@'); const pluginDependencies = plugin.getDependencies() || []; let installationErrors: string[] = []; pluginDependencies.forEach((dep: string) => { const [depName, depVersion] = dep.split('@'); const installedNameAndVer = this.getInstalledPluginNameWithVersion( depName ); const [, installedVersion] = installedNameAndVer ? installedNameAndVer.split('@') : [null, '']; if (!installedNameAndVer) { installationErrors.push( `Error installing ${pluginNameAndVer}. Could not find dependency ${dep}.` ); } else if (!dependencyValid(installedVersion, depVersion)) { installationErrors.push( `Error installing ${pluginNameAndVer}.\n${installedNameAndVer} doesn't satisfy the required dependency ${dep}.` ); } }); if (installationErrors.length === 0) { this.pluginMap.set(pluginName, plugin); plugin.init(this); plugin.activate(); } else { installationErrors.forEach(err => { console.error(err); }); } } getInstalledPluginNameWithVersion(name: string) { const plugin = this.pluginMap.get(name); if (!plugin) { return null; } return plugin.getPluginName(); } addFunction(key: string, fn: any) { this.functionArray.set(key, fn); } executeFunction(key: string, ...args: any): any { let fn = this.functionArray.get(key); if (fn) { return fn(...args); } console.error('No function added for the key ' + key + '.'); } removeFunction(key: string): void { this.functionArray.delete(key); } uninstall(key: string) { let plugin = this.pluginMap.get(key); if (plugin) { plugin.deactivate(); this.pluginMap.delete(key); } } addEventListener( name: string, callback: (event: EventType) => void ) { this._eventCallableRegistry.addEventListener(name, callback); } removeEventListener( name: string, callback: (event: EventType) => void ) { this._eventCallableRegistry.removeEventListener(name, callback); } dispatchEvent(event: EventType) { // @ts-ignore this._eventCallableRegistry.dispatchEvent(event); } }