import * as fs from 'fs-extra'; import * as path from 'path'; import { IEnvironment } from '../types/environment'; import { IPluginManifest } from './plugin'; import { logger } from '../core'; /** * Plugin manifest loader */ export class PluginMetaLoader { constructor(private env: IEnvironment) {} /** * Load a plugin manifest by plugin name. * @param name Plugin name * @returns Plugin manifest */ public async load(name: string): Promise { if (name === 'squeebot') { throw new Error('Illegal name.'); } const fullpath = path.join(this.env.pluginsPath, name); const metapath = path.join(fullpath, 'plugin.json'); if (!await fs.pathExists(metapath)) { throw new Error('Not a plugin directory.'); } // Read the metadata const json = await fs.readJson(metapath); // Mandatory fields if (!json.name) { throw new Error('Plugin metadata does not specify a name, for some reason'); } if (json.name === 'squeebot' || !(/^[a-zA-Z0-9_\-]+$/.test(json.name))) { throw new Error('Illegal name.'); } if (!json.version) { throw new Error('Plugin metadata does not specify a version, for some reason'); } // Ensure main file exists if (!json.main) { json.main = 'plugin.js'; } const mainfile = path.resolve(fullpath, json.main); if (!await fs.pathExists(mainfile)) { throw new Error('Plugin does not have a main file or it is misconfigured.'); } json.fullPath = fullpath; json.main = mainfile; if (!json.dependencies) { json.dependencies = []; } if (!json.npmDependencies) { json.npmDependencies = []; } return json; } /** * Load all plugin manifests from files. * @param ignoreErrors Ignore loading errors instead of throwing them * @returns List of plugin manifests ready to be loaded */ public async loadAll(ignoreErrors = false): Promise { const dirlist = await fs.readdir(this.env.pluginsPath); const plugins: IPluginManifest[] = []; for (const file of dirlist) { // Ignore hidden files and non-directories const fpath = path.join(this.env.pluginsPath, file); if (file.indexOf('.') === 0 || file === 'node_modules' || !(await fs.lstat(fpath)).isDirectory()) { continue; } try { const plugin = await this.load(file); plugins.push(plugin); } catch (e) { if (ignoreErrors) { continue; } logger.error(e); } } return plugins; } }