UNPKG

@electron-forge/core

Version:

A complete tool for building modern Electron applications

161 lines (143 loc) 5.61 kB
import { PluginBase } from '@electron-forge/plugin-base'; import { ForgeListrTaskDefinition, ForgeMutatingHookFn, ForgeMutatingHookSignatures, ForgeSimpleHookFn, ForgeSimpleHookSignatures, IForgePlugin, IForgePluginInterface, ResolvedForgeConfig, StartResult, } from '@electron-forge/shared-types'; import chalk from 'chalk'; import debug from 'debug'; import { StartOptions } from '../api'; import requireSearch from './require-search'; const d = debug('electron-forge:plugins'); function isForgePlugin(plugin: IForgePlugin | unknown): plugin is IForgePlugin { return (plugin as IForgePlugin).__isElectronForgePlugin; } export default class PluginInterface implements IForgePluginInterface { private plugins: IForgePlugin[]; private config: ResolvedForgeConfig; constructor(dir: string, forgeConfig: ResolvedForgeConfig) { this.plugins = forgeConfig.plugins.map((plugin) => { if (isForgePlugin(plugin)) { return plugin; } if (typeof plugin === 'object' && 'name' in plugin && 'config' in plugin) { const { name: pluginName, config: opts } = plugin; if (typeof pluginName !== 'string') { throw new Error(`Expected plugin[0] to be a string but found ${pluginName}`); } // eslint-disable-next-line @typescript-eslint/no-explicit-any const Plugin = requireSearch<any>(dir, [pluginName]); if (!Plugin) { throw new Error(`Could not find module with name: ${pluginName}. Make sure it's listed in the devDependencies of your package.json`); } return new Plugin(opts); } throw new Error(`Expected plugin to either be a plugin instance or a { name, config } object but found ${plugin}`); }); // TODO: fix hack // eslint-disable-next-line @typescript-eslint/no-explicit-any this.config = null as any; Object.defineProperty(this, 'config', { value: forgeConfig, enumerable: false, configurable: false, writable: false, }); for (const plugin of this.plugins) { plugin.init(dir, forgeConfig); } this.triggerHook = this.triggerHook.bind(this); this.overrideStartLogic = this.overrideStartLogic.bind(this); } async triggerHook<Hook extends keyof ForgeSimpleHookSignatures>(hookName: Hook, hookArgs: ForgeSimpleHookSignatures[Hook]): Promise<void> { for (const plugin of this.plugins) { if (typeof plugin.getHooks === 'function') { let hooks = plugin.getHooks()[hookName] as ForgeSimpleHookFn<Hook>[] | ForgeSimpleHookFn<Hook>; if (hooks) { if (typeof hooks === 'function') hooks = [hooks]; for (const hook of hooks) { await hook(this.config, ...hookArgs); } } } } } async getHookListrTasks<Hook extends keyof ForgeSimpleHookSignatures>( hookName: Hook, hookArgs: ForgeSimpleHookSignatures[Hook] ): Promise<ForgeListrTaskDefinition[]> { const tasks: ForgeListrTaskDefinition[] = []; for (const plugin of this.plugins) { if (typeof plugin.getHooks === 'function') { let hooks = plugin.getHooks()[hookName] as ForgeSimpleHookFn<Hook>[] | ForgeSimpleHookFn<Hook>; if (hooks) { if (typeof hooks === 'function') hooks = [hooks]; for (const hook of hooks) { tasks.push({ title: `${chalk.cyan(`[plugin-${plugin.name}]`)} ${(hook as any).__hookName || `Running ${chalk.yellow(hookName)} hook`}`, task: async (_, task) => { if ((hook as any).__hookName) { // Also give it the task await (hook as any).call(task, ...(hookArgs as any[])); } else { await hook(this.config, ...hookArgs); } }, options: {}, }); } } } } return tasks; } async triggerMutatingHook<Hook extends keyof ForgeMutatingHookSignatures>( hookName: Hook, ...item: ForgeMutatingHookSignatures[Hook] ): Promise<ForgeMutatingHookSignatures[Hook][0]> { let result: ForgeMutatingHookSignatures[Hook][0] = item[0]; for (const plugin of this.plugins) { if (typeof plugin.getHooks === 'function') { let hooks = plugin.getHooks()[hookName] as ForgeMutatingHookFn<Hook>[] | ForgeMutatingHookFn<Hook>; if (hooks) { if (typeof hooks === 'function') hooks = [hooks]; for (const hook of hooks) { result = (await hook(this.config, ...item)) || result; } } } } return result; } async overrideStartLogic(opts: StartOptions): Promise<StartResult> { let newStartFn; const claimed: string[] = []; for (const plugin of this.plugins) { if (typeof plugin.startLogic === 'function' && plugin.startLogic !== PluginBase.prototype.startLogic) { claimed.push(plugin.name); newStartFn = plugin.startLogic; } } if (claimed.length > 1) { throw new Error(`Multiple plugins tried to take control of the start command, please remove one of them\n --> ${claimed.join(', ')}`); } if (claimed.length === 1 && newStartFn) { d(`plugin: "${claimed[0]}" has taken control of the start command`); const result = await newStartFn(opts); if (typeof result === 'object' && 'tasks' in result) { result.tasks = result.tasks.map((task) => ({ ...task, title: `${chalk.cyan(`[plugin-${claimed[0]}]`)} ${task.title}`, })); } return result; } return false; } }