diff --git a/packages/api/core/src/api/import.ts b/packages/api/core/src/api/import.ts index 9934f6a805..9eb38e1c03 100644 --- a/packages/api/core/src/api/import.ts +++ b/packages/api/core/src/api/import.ts @@ -9,7 +9,7 @@ import { deps, devDeps, exactDevDeps } from './init-scripts/init-npm'; import { setInitialForgeConfig } from '../util/forge-config'; import { info, warn } from '../util/messages'; import installDepList from '../util/install-dependencies'; -import readPackageJSON from '../util/read-package-json'; +import { readRawPackageJson } from '../util/read-package-json'; const d = debug('electron-forge:import'); @@ -72,7 +72,7 @@ export default async ({ await initGit(dir); - let packageJSON = await readPackageJSON(dir); + let packageJSON = await readRawPackageJson(dir); if (packageJSON.config && packageJSON.config.forge) { warn(interactive, 'It looks like this project is already configured for "electron-forge"'.green); if (typeof shouldContinueOnExisting === 'function') { @@ -161,14 +161,14 @@ export default async ({ await installDepList(dir, exactDevDeps, true, true); }); - packageJSON = await readPackageJSON(dir); + packageJSON = await readRawPackageJson(dir); if (!packageJSON.version) { warn(interactive, 'Please set the "version" in your application\'s package.json'.yellow); } packageJSON.config = packageJSON.config || {}; - const templatePackageJSON = await readPackageJSON(path.resolve(__dirname, '../../tmpl')); + const templatePackageJSON = await readRawPackageJson(path.resolve(__dirname, '../../tmpl')); packageJSON.config.forge = templatePackageJSON.config.forge; setInitialForgeConfig(packageJSON); diff --git a/packages/api/core/src/api/init-scripts/init-npm.ts b/packages/api/core/src/api/init-scripts/init-npm.ts index 57c9c83150..8208605ddc 100644 --- a/packages/api/core/src/api/init-scripts/init-npm.ts +++ b/packages/api/core/src/api/init-scripts/init-npm.ts @@ -6,7 +6,7 @@ import username from 'username'; import { setInitialForgeConfig } from '../../util/forge-config'; import installDepList from '../../util/install-dependencies'; -import readPackageJSON from '../../util/read-package-json'; +import { readRawPackageJson } from '../../util/read-package-json'; const d = debug('electron-forge:init:npm'); @@ -22,7 +22,7 @@ export const exactDevDeps = ['electron']; export default async (dir: string) => { await asyncOra('Initializing NPM Module', async () => { - const packageJSON = await readPackageJSON(path.resolve(__dirname, '../../../tmpl')); + const packageJSON = await readRawPackageJson(path.resolve(__dirname, '../../../tmpl')); packageJSON.productName = packageJSON.name = path.basename(dir).toLowerCase(); packageJSON.author = await username(); setInitialForgeConfig(packageJSON); diff --git a/packages/api/core/src/api/make.ts b/packages/api/core/src/api/make.ts index e353424baf..41a7b5da1e 100644 --- a/packages/api/core/src/api/make.ts +++ b/packages/api/core/src/api/make.ts @@ -6,10 +6,10 @@ import fs from 'fs-extra'; import path from 'path'; import getForgeConfig from '../util/forge-config'; -import runHook from '../util/hook'; +import { runHook, runMutatingHook } from '../util/hook'; import { info, warn } from '../util/messages'; import parseArchs from '../util/parse-archs'; -import readPackageJSON from '../util/read-package-json'; +import { readMutatedPackageJson } from '../util/read-package-json'; import resolveDir from '../util/resolve-dir'; import getCurrentOutDir from '../util/out-dir'; import getElectronVersion from '../util/electron-version'; @@ -147,9 +147,9 @@ export default async ({ info(interactive, `Making for the following targets: ${`${targets.map((t, i) => makers[i].name).join(', ')}`.cyan}`); - const packageJSON = await readPackageJSON(dir); + const packageJSON = await readMutatedPackageJson(dir, forgeConfig); const appName = forgeConfig.packagerConfig.name || packageJSON.productName || packageJSON.name; - let outputs: ForgeMakeResult[] = []; + const outputs: ForgeMakeResult[] = []; await runHook(forgeConfig, 'preMake'); @@ -197,12 +197,7 @@ export default async ({ } } - const result = await runHook(forgeConfig, 'postMake', outputs) as ForgeMakeResult[] | undefined; // If the postMake hooks modifies the locations / names of the outputs it must return // the new locations so that the publish step knows where to look - if (Array.isArray(result)) { - outputs = result; - } - - return outputs; + return await runMutatingHook(forgeConfig, 'postMake', outputs); }; diff --git a/packages/api/core/src/api/package.ts b/packages/api/core/src/api/package.ts index 29ba4fdf77..b4e1b2b9d9 100644 --- a/packages/api/core/src/api/package.ts +++ b/packages/api/core/src/api/package.ts @@ -9,9 +9,9 @@ import pify from 'pify'; import packager from 'electron-packager'; import getForgeConfig from '../util/forge-config'; -import runHook from '../util/hook'; +import { runHook } from '../util/hook'; import { warn } from '../util/messages'; -import readPackageJSON from '../util/read-package-json'; +import { readMutatedPackageJson } from '../util/read-package-json'; import rebuildHook from '../util/rebuild'; import requireSearch from '../util/require-search'; import resolveDir from '../util/resolve-dir'; @@ -96,13 +96,13 @@ export default async ({ } dir = resolvedDir; - const packageJSON = await readPackageJSON(dir); + const forgeConfig = await getForgeConfig(dir); + const packageJSON = await readMutatedPackageJson(dir, forgeConfig); if (!packageJSON.main) { throw 'packageJSON.main must be set to a valid entry point for your Electron app'; } - const forgeConfig = await getForgeConfig(dir); const calculatedOutDir = outDir || getCurrentOutDir(dir, forgeConfig); let packagerSpinner: OraImpl | null = null; @@ -133,7 +133,7 @@ export default async ({ ]; afterCopyHooks.push(async (buildPath, electronVersion, pPlatform, pArch, done) => { - const copiedPackageJSON = await readPackageJSON(buildPath); + const copiedPackageJSON = await readMutatedPackageJson(buildPath, forgeConfig); if (copiedPackageJSON.config && copiedPackageJSON.config.forge) { delete copiedPackageJSON.config.forge; } diff --git a/packages/api/core/src/api/publish.ts b/packages/api/core/src/api/publish.ts index eea9ece3ce..3adfa0904e 100644 --- a/packages/api/core/src/api/publish.ts +++ b/packages/api/core/src/api/publish.ts @@ -7,7 +7,7 @@ import fs from 'fs-extra'; import path from 'path'; import getForgeConfig from '../util/forge-config'; -import readPackageJSON from '../util/read-package-json'; +import { readMutatedPackageJson } from '../util/read-package-json'; import resolveDir from '../util/resolve-dir'; import PublishState from '../util/publish-state'; import getCurrentOutDir from '../util/out-dir'; @@ -73,9 +73,9 @@ const publish = async ({ throw 'Can\'t resume a dry run and use the provided makeResults at the same time'; } - let packageJSON = await readPackageJSON(dir); - const forgeConfig = await getForgeConfig(dir); + let packageJSON = await readMutatedPackageJson(dir, forgeConfig); + const calculatedOutDir = outDir || getCurrentOutDir(dir, forgeConfig); const dryRunDir = path.resolve(calculatedOutDir, 'publish-dry-run'); diff --git a/packages/api/core/src/api/start.ts b/packages/api/core/src/api/start.ts index 103729e9da..50614bf024 100644 --- a/packages/api/core/src/api/start.ts +++ b/packages/api/core/src/api/start.ts @@ -4,11 +4,11 @@ import { StartOptions, ForgePlatform, ForgeArch } from '@electron-forge/shared-t import { spawn, ChildProcess } from 'child_process'; import path from 'path'; -import readPackageJSON from '../util/read-package-json'; +import { readMutatedPackageJson } from '../util/read-package-json'; import rebuild from '../util/rebuild'; import resolveDir from '../util/resolve-dir'; import getForgeConfig from '../util/forge-config'; -import runHook from '../util/hook'; +import { runHook } from '../util/hook'; import getElectronVersion from '../util/electron-version'; export { StartOptions }; @@ -32,14 +32,13 @@ export default async ({ dir = resolvedDir; }); - const packageJSON = await readPackageJSON(dir); + const forgeConfig = await getForgeConfig(dir); + const packageJSON = await readMutatedPackageJson(dir, forgeConfig); if (!packageJSON.version) { throw `Please set your application's 'version' in '${dir}/package.json'.`; } - const forgeConfig = await getForgeConfig(dir); - await rebuild( dir, getElectronVersion(packageJSON), diff --git a/packages/api/core/src/util/forge-config.ts b/packages/api/core/src/util/forge-config.ts index 60867dd096..24400591d6 100644 --- a/packages/api/core/src/util/forge-config.ts +++ b/packages/api/core/src/util/forge-config.ts @@ -3,9 +3,9 @@ import fs from 'fs-extra'; import path from 'path'; import _template from 'lodash.template'; -import readPackageJSON from './read-package-json'; +import { readRawPackageJson } from './read-package-json'; import PluginInterface from './plugin-interface'; -import runHook from './hook'; +import { runMutatingHook } from './hook'; const underscoreCase = (str: string) => str.replace(/(.)([A-Z][a-z]+)/g, '$1_$2').replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase(); @@ -70,7 +70,7 @@ export function fromBuildIdentifier(map: { [key: string]: T | undefined }) { } export default async (dir: string) => { - const packageJSON = await readPackageJSON(dir); + const packageJSON = await readRawPackageJson(dir); let forgeConfig: ForgeConfig | string = packageJSON.config.forge; if (typeof forgeConfig === 'string' && (await fs.pathExists(path.resolve(dir, forgeConfig)) || await fs.pathExists(path.resolve(dir, `${forgeConfig}.js`)))) { @@ -109,7 +109,7 @@ export default async (dir: string) => { forgeConfig.pluginInterface = new PluginInterface(dir, forgeConfig); - await runHook(forgeConfig, 'resolveForgeConfig', forgeConfig); + forgeConfig = await runMutatingHook(forgeConfig, 'resolveForgeConfig', forgeConfig); return proxify(forgeConfig.buildIdentifier || '', forgeConfig, 'ELECTRON_FORGE'); }; diff --git a/packages/api/core/src/util/hook.ts b/packages/api/core/src/util/hook.ts index 19ef5c0a98..ebf0c63170 100644 --- a/packages/api/core/src/util/hook.ts +++ b/packages/api/core/src/util/hook.ts @@ -3,7 +3,7 @@ import debug from 'debug'; const d = debug('electron-forge:hook'); -export default async (forgeConfig: ForgeConfig, hookName: string, ...hookArgs: any[]) => { +export const runHook = async (forgeConfig: ForgeConfig, hookName: string, ...hookArgs: any[]) => { const hooks = forgeConfig.hooks; if (hooks) { d(`hook triggered: ${hookName}`); @@ -14,3 +14,18 @@ export default async (forgeConfig: ForgeConfig, hookName: string, ...hookArgs: a } await forgeConfig.pluginInterface.triggerHook(hookName, hookArgs); }; + +export const runMutatingHook = async (forgeConfig: ForgeConfig, hookName: string, item: T): Promise => { + const hooks = forgeConfig.hooks; + if (hooks) { + d(`hook triggered: ${hookName}`); + if (typeof hooks[hookName] === 'function') { + d('calling mutating hook:', hookName, 'with item:', item); + const result = await hooks[hookName](forgeConfig, item); + if (typeof result !== 'undefined') { + item = result; + } + } + } + return await forgeConfig.pluginInterface.triggerMutatingHook(hookName, item); +}; diff --git a/packages/api/core/src/util/plugin-interface.ts b/packages/api/core/src/util/plugin-interface.ts index d9683f71a3..ddce0007df 100644 --- a/packages/api/core/src/util/plugin-interface.ts +++ b/packages/api/core/src/util/plugin-interface.ts @@ -54,6 +54,18 @@ export default class PluginInterface implements IForgePluginInterface { } } + async triggerMutatingHook(hookName: string, item: T) { + for (const plugin of this.plugins) { + if (typeof plugin.getHook === 'function') { + const hook = plugin.getHook(hookName); + if (hook) { + item = await hook(this.config, item); + } + } + } + return item; + } + async overrideStartLogic(opts: StartOptions) { let newStartFn; const claimed = []; diff --git a/packages/api/core/src/util/read-package-json.ts b/packages/api/core/src/util/read-package-json.ts index 31e58aa1cc..9c6b480090 100644 --- a/packages/api/core/src/util/read-package-json.ts +++ b/packages/api/core/src/util/read-package-json.ts @@ -1,5 +1,11 @@ +import { ForgeConfig } from '@electron-forge/shared-types'; import fs from 'fs-extra'; import path from 'path'; -export default async (dir: string) => +import { runMutatingHook } from './hook'; + +export const readRawPackageJson = async (dir: string) => await fs.readJson(path.resolve(dir, 'package.json')); + +export const readMutatedPackageJson = async (dir: string, forgeConfig: ForgeConfig) => + runMutatingHook(forgeConfig, 'readPackageJson', await readRawPackageJson(dir)); diff --git a/packages/api/core/src/util/resolve-dir.ts b/packages/api/core/src/util/resolve-dir.ts index 7eef1ebc7f..6b7f122aee 100644 --- a/packages/api/core/src/util/resolve-dir.ts +++ b/packages/api/core/src/util/resolve-dir.ts @@ -1,11 +1,14 @@ import debug from 'debug'; import fs from 'fs-extra'; import path from 'path'; -import readPackageJSON from './read-package-json'; +import { readRawPackageJson } from './read-package-json'; import getElectronVersion from './electron-version'; const d = debug('electron-forge:project-resolver'); +// FIXME: If we want getElectronVersion to be overridable by plugins +// and / or forge config then we need to be able to resolve +// the dir without calling getElectronVersion export default async (dir: string) => { let mDir = dir; let prevDir; @@ -14,8 +17,10 @@ export default async (dir: string) => { const testPath = path.resolve(mDir, 'package.json'); d('searching for project in:', mDir); if (await fs.pathExists(testPath)) { - const packageJSON = await readPackageJSON(mDir); + const packageJSON = await readRawPackageJson(mDir); + // TODO: Move this check to inside the forge config resolver and use + // mutatedPackageJson reader const electronVersion = getElectronVersion(packageJSON); if (electronVersion) { if (!/[0-9]/.test(electronVersion[0])) { diff --git a/packages/api/core/test/fast/hook_spec.ts b/packages/api/core/test/fast/hook_spec.ts index 864a96792d..aa994c36fa 100644 --- a/packages/api/core/test/fast/hook_spec.ts +++ b/packages/api/core/test/fast/hook_spec.ts @@ -1,28 +1,46 @@ import { ForgeConfig } from '@electron-forge/shared-types'; import { expect } from 'chai'; -import { stub } from 'sinon'; +import { stub, SinonStub } from 'sinon'; -import runHook from '../../src/util/hook'; +import { runHook, runMutatingHook } from '../../src/util/hook'; const fakeConfig = { pluginInterface: { triggerHook: async () => false, + triggerMutatingHook: async (_: any, item: any) => item, }, } as any as ForgeConfig; -describe('runHook', () => { - it('should not error when running non existent hooks', async () => { - await runHook(Object.assign({}, fakeConfig), 'magic'); +describe('hooks', () => { + describe('runHook', () => { + it('should not error when running non existent hooks', async () => { + await runHook(Object.assign({}, fakeConfig), 'magic'); + }); + + it('should not error when running a hook that is not a function', async () => { + await runHook(Object.assign({ hooks: { myHook: 'abc' } }, fakeConfig), 'abc'); + }); + + it('should run the hook if it is provided as a function', async () => { + const myStub = stub(); + myStub.returns(Promise.resolve()); + await runHook(Object.assign({ hooks: { myHook: myStub } }, fakeConfig), 'myHook'); + expect(myStub.callCount).to.equal(1); + }); }); - it('should not error when running a hook that is not a function', async () => { - await runHook(Object.assign({ hooks: { myHook: 'abc' } }, fakeConfig), 'abc'); - }); + describe('runMutatingHook', () => { + it('should return the input when running non existent hooks', async () => { + expect(await runMutatingHook(Object.assign({}, fakeConfig), 'magic', 'input')).to.equal('input'); + }); - it('should run the hook if it is provided as a function', async () => { - const myStub = stub(); - myStub.returns(Promise.resolve()); - await runHook(Object.assign({ hooks: { myHook: myStub } }, fakeConfig), 'myHook'); - expect(myStub.callCount).to.equal(1); + it('should return the mutated input when returned from a hook', async () => { + fakeConfig.pluginInterface.triggerMutatingHook = stub().returnsArg(1); + const myStub = stub(); + myStub.returns(Promise.resolve('magneto')); + const output = await runMutatingHook(Object.assign({ hooks: { myHook: myStub } }, fakeConfig), 'myHook', 'input'); + expect(output).to.equal('magneto'); + expect((fakeConfig.pluginInterface.triggerMutatingHook as SinonStub).firstCall.args[1]).to.equal('magneto'); + }); }); }); diff --git a/packages/api/core/test/fast/publish_spec.ts b/packages/api/core/test/fast/publish_spec.ts index e583af74e8..d517deb182 100644 --- a/packages/api/core/test/fast/publish_spec.ts +++ b/packages/api/core/test/fast/publish_spec.ts @@ -33,7 +33,9 @@ describe('publish', () => { publish = proxyquire.noCallThru().load('../../src/api/publish', { './make': async (...args: any[]) => makeStub(...args), '../util/resolve-dir': async (dir: string) => resolveStub(dir), - '../util/read-package-json': () => Promise.resolve(require('../fixture/dummy_app/package.json')), + '../util/read-package-json': { + readMutatedPackageJson: () => Promise.resolve(require('../fixture/dummy_app/package.json')), + }, '../util/forge-config': async () => { const config = await (require('../../src/util/forge-config').default(path.resolve(__dirname, '../fixture/dummy_app'))); diff --git a/packages/api/core/test/fast/read-package-json_spec.ts b/packages/api/core/test/fast/read-package-json_spec.ts index 0f995cb9f1..97bdf7bf21 100644 --- a/packages/api/core/test/fast/read-package-json_spec.ts +++ b/packages/api/core/test/fast/read-package-json_spec.ts @@ -1,10 +1,34 @@ import path from 'path'; import { expect } from 'chai'; -import readPackageJSON from '../../src/util/read-package-json'; +import { readRawPackageJson, readMutatedPackageJson } from '../../src/util/read-package-json'; describe('read-package-json', () => { - it('should find a package.json file from the given directory', async () => { - expect(await readPackageJSON(path.resolve(__dirname, '../..'))).to.deep.equal(require('../../package.json')); + describe('readRawPackageJson', () => { + it('should find a package.json file from the given directory', async () => { + expect(await readRawPackageJson(path.resolve(__dirname, '../..'))).to.deep.equal(require('../../package.json')); + }); + }); + + describe('readMutatedPackageJson', () => { + it('should find a package.json file from the given directory', async () => { + expect(await readMutatedPackageJson( + path.resolve(__dirname, '../..'), { + pluginInterface: { + triggerMutatingHook: (_: any, pj: any) => Promise.resolve(pj), + }, + } as any, + )).to.deep.equal(require('../../package.json')); + }); + + it('should allow mutations from hooks', async () => { + expect(await readMutatedPackageJson( + path.resolve(__dirname, '../..'), { + pluginInterface: { + triggerMutatingHook: () => Promise.resolve('test_mut'), + }, + } as any, + )).to.deep.equal('test_mut'); + }); }); }); diff --git a/packages/api/core/test/fast/start_spec.ts b/packages/api/core/test/fast/start_spec.ts index 4e64668d13..d84d47c07b 100644 --- a/packages/api/core/test/fast/start_spec.ts +++ b/packages/api/core/test/fast/start_spec.ts @@ -29,7 +29,9 @@ describe('start', () => { }), [path.resolve(__dirname, 'node_modules/electron')]: 'fake_electron_path', '../util/resolve-dir': async (dir: string) => resolveStub(dir), - '../util/read-package-json': () => Promise.resolve(packageJSON), + '../util/read-package-json': { + readMutatedPackageJson: () => Promise.resolve(packageJSON), + }, '../util/rebuild': () => Promise.resolve(), child_process: { spawn: spawnStub, diff --git a/packages/api/core/test/slow/api_spec_slow.ts b/packages/api/core/test/slow/api_spec_slow.ts index f2b03f7ec1..b95e9522c1 100644 --- a/packages/api/core/test/slow/api_spec_slow.ts +++ b/packages/api/core/test/slow/api_spec_slow.ts @@ -8,7 +8,7 @@ import proxyquire from 'proxyquire'; import { createDefaultCertificate } from '@electron-forge/maker-appx'; import installDeps from '../../src/util/install-dependencies'; -import readPackageJSON from '../../src/util/read-package-json'; +import { readRawPackageJson } from '../../src/util/read-package-json'; import yarnOrNpm from '../../src/util/yarn-or-npm'; import { InitOptions } from '../../src/api'; @@ -155,7 +155,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }); it('creates a forge config', async () => { - const packageJSON = await readPackageJSON(dir); + const packageJSON = await readRawPackageJson(dir); packageJSON.name = 'Name'; packageJSON.productName = 'Product Name'; packageJSON.customProp = 'propVal'; @@ -176,7 +176,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }, }, customProp, - } = await readPackageJSON(dir); + } = await readRawPackageJson(dir); expect(winstallerName).to.equal('Name'); expect(customProp).to.equal('propVal'); @@ -195,7 +195,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { dirID += 1; await forge.init({ dir }); - const packageJSON = await readPackageJSON(dir); + const packageJSON = await readRawPackageJson(dir); packageJSON.name = 'testapp'; packageJSON.productName = 'Test App'; packageJSON.config.forge.packagerConfig.asar = false; @@ -215,11 +215,11 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }); it('throws an error when all is set', async () => { - let packageJSON = await readPackageJSON(dir); + let packageJSON = await readRawPackageJson(dir); packageJSON.config.forge.packagerConfig.all = true; await fs.writeJson(path.join(dir, 'package.json'), packageJSON); await expect(forge.package({ dir })).to.eventually.be.rejectedWith(/packagerConfig\.all is not supported by Electron Forge/); - packageJSON = await readPackageJSON(dir); + packageJSON = await readRawPackageJson(dir); delete packageJSON.config.forge.packagerConfig.all; await fs.writeJson(path.join(dir, 'package.json'), packageJSON); }); @@ -235,7 +235,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }); it('can make from custom outDir without errors', async () => { - const packageJSON = await readPackageJSON(dir); + const packageJSON = await readRawPackageJson(dir); packageJSON.config.forge.makers = [{ name: require.resolve('@electron-forge/maker-zip') }]; await fs.writeJson(path.resolve(dir, 'package.json'), packageJSON); @@ -253,7 +253,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }); it('can package without errors', async () => { - const packageJSON = await readPackageJSON(dir); + const packageJSON = await readRawPackageJson(dir); delete packageJSON.dependencies.ref; packageJSON.config.forge.packagerConfig.asar = true; await fs.writeJson(path.resolve(dir, 'package.json'), packageJSON); @@ -276,7 +276,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }); it('should not affect the actual forge config', async () => { - const normalPackageJSON = await readPackageJSON(dir); + const normalPackageJSON = await readRawPackageJson(dir); expect(normalPackageJSON).to.have.nested.property('config.forge'); }); @@ -316,7 +316,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { const testMakeTarget = function testMakeTarget(target: () => { name: string }, shouldPass: boolean, ...options: any[]) { describe(`make (with target=${path.basename(target().name)})`, async () => { before(async () => { - const packageJSON = await readPackageJSON(dir); + const packageJSON = await readRawPackageJson(dir); packageJSON.config.forge.makers = [target()]; await fs.writeFile(path.resolve(dir, 'package.json'), JSON.stringify(packageJSON)); }); diff --git a/packages/plugin/auto-unpack-natives/src/AutoUnpackNativesPlugin.ts b/packages/plugin/auto-unpack-natives/src/AutoUnpackNativesPlugin.ts index 79a9f0c2b8..d2e8babe4e 100644 --- a/packages/plugin/auto-unpack-natives/src/AutoUnpackNativesPlugin.ts +++ b/packages/plugin/auto-unpack-natives/src/AutoUnpackNativesPlugin.ts @@ -36,5 +36,6 @@ export default class AutoUnpackNativesPlugin extends PluginBase Promise; + export type ForgeHookFn = (forgeConfig: ForgeConfig, ...args: any[]) => Promise; export interface IForgePluginInterface { triggerHook(hookName: string, hookArgs: any[]): Promise; + triggerMutatingHook(hookName: string, item: T): Promise; overrideStartLogic(opts: any): Promise; } export interface ForgeConfig {