core/src/plugin/loader.ts

101 lines
2.6 KiB
TypeScript

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<IPluginManifest> {
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<IPluginManifest[]> {
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);
const isDirectory = (await fs.lstat(fpath)).isDirectory();
if (!isDirectory || file.startsWith('.') || file === 'node_modules') {
continue;
}
try {
const plugin = await this.load(file);
plugins.push(plugin);
} catch (e) {
if (!ignoreErrors) {
logger.error(e);
}
}
}
return plugins;
}
}