Files
factorio-clusterio/packages/lib/src/plugin_loader.ts
T
Hornwitser 7314dc99c8 Fix code style errors
Remove extra whitespace, use more consistent spacing, add missing
semicolons, using dangling commas, break up long lines, consistent
multiline operator placement, add missing JSDoc strings and so on.
2023-11-19 04:48:38 +01:00

117 lines
3.6 KiB
TypeScript

/* eslint-disable node/global-require */
/**
* Helpers for loading plugins in Node.js
* @module lib/plugin_loader
*/
import path from "path";
import * as libErrors from "./errors";
import * as libPlugin from "./plugin";
import { logger } from "./logging";
/**
* Load plugin information
*
* Loads plugin info modules for the paths to the given plugins. Once
* loaded the info modules will not be reloaded should this function be
* called again.
*
* @param pluginList -
* Mapping of plugin name to require path for the plugins to load.
* @returns Array of plugin info modules.
*/
export async function loadPluginInfos(pluginList: Map<string, string>) {
let plugins: libPlugin.PluginNodeEnvInfo[] = [];
for (let [pluginName, pluginPath] of pluginList) {
let pluginInfo: libPlugin.PluginNodeEnvInfo;
let pluginPackage: { version: string, main?: string };
try {
pluginInfo = require(pluginPath).default;
pluginPackage = require(path.posix.join(pluginPath, "package.json"));
} catch (err: any) {
throw new libErrors.PluginError(pluginName, err);
}
if (pluginInfo.name !== pluginName) {
throw new libErrors.EnvironmentError(
`Expected plugin at ${pluginPath} to be named ${pluginName} but got ${pluginInfo.name}`
);
}
// migrate: ignore incompatible old plugins
if (pluginInfo.messages && !(pluginInfo.messages instanceof Array)) {
logger.warn(`Ignoring incompatible pre alpha.14 plugin ${pluginName}`);
continue;
}
pluginInfo.requirePath = pluginPath;
pluginInfo.version = pluginPackage.version;
plugins.push(pluginInfo);
}
return plugins;
}
function loadPluginClass(
entrypointName: "controllerEntrypoint"|"instanceEntrypoint"|"controlEntrypoint",
className: string,
pluginClass: any,
pluginInfo: libPlugin.PluginNodeEnvInfo
) {
let resolvedPath = path.posix.join(pluginInfo.requirePath, pluginInfo[entrypointName]!);
let entrypoint = require(resolvedPath);
if (!entrypoint[className]) {
throw new libErrors.PluginError(pluginInfo.name,
new Error(`Expected ${resolvedPath} to export a class named ${className}`)
);
}
if (!(entrypoint[className].prototype instanceof pluginClass)) {
throw new libErrors.PluginError(pluginInfo.name,
new Error(`Expected ${className} exported from ${resolvedPath} to be a subclass of ${pluginClass.name}`)
);
}
return entrypoint[className];
}
/**
* Load controller plugin class of a plugin
*
* @param pluginInfo -
* Plugin info object returned from {@link
* loadPluginInfos} to load class from.
* @returns plugin class
*/
export async function loadControllerPluginClass(
pluginInfo: libPlugin.PluginNodeEnvInfo
): Promise<typeof libPlugin.BaseControllerPlugin> {
return loadPluginClass("controllerEntrypoint", "ControllerPlugin", libPlugin.BaseControllerPlugin, pluginInfo);
}
/**
* Load instance plugin class of a plugin
*
* @param pluginInfo -
* Plugin info object returned from {@link
* loadPluginInfos} to load class from.
* @returns plugin class
*/
export async function loadInstancePluginClass(
pluginInfo: libPlugin.PluginNodeEnvInfo
): Promise<typeof libPlugin.BaseInstancePlugin> {
return loadPluginClass("instanceEntrypoint", "InstancePlugin", libPlugin.BaseInstancePlugin, pluginInfo);
}
/**
* Load control plugin class of a plugin
*
* @param pluginInfo -
* Plugin info object returned from {@link
* loadPluginInfos} to load class from.
* @returns plugin class
*/
export async function loadControlPluginClass(
pluginInfo: libPlugin.PluginNodeEnvInfo
): Promise<typeof libPlugin.BaseControlPlugin> {
return loadPluginClass("controlEntrypoint", "ControlPlugin", libPlugin.BaseControlPlugin, pluginInfo);
}