From 2c081eabca4ad1844118f46126172774e612bc68 Mon Sep 17 00:00:00 2001 From: Martin Elend Date: Thu, 19 Sep 2024 23:43:36 +0200 Subject: [PATCH] feat(core): adding register/unregisterForgeConfigForDirectory to utils (#3626) --- packages/api/core/src/util/forge-config.ts | 14 ++++- packages/api/core/src/util/index.ts | 26 +++++++++- packages/api/core/src/util/resolve-dir.ts | 9 +++- .../api/core/test/fast/forge-config_spec.ts | 52 ++++++++++++++++++- .../api/core/test/fast/resolve-dir_spec.ts | 11 ++++ 5 files changed, 107 insertions(+), 5 deletions(-) diff --git a/packages/api/core/src/util/forge-config.ts b/packages/api/core/src/util/forge-config.ts index f6619461ca..1269d062f2 100644 --- a/packages/api/core/src/util/forge-config.ts +++ b/packages/api/core/src/util/forge-config.ts @@ -74,6 +74,14 @@ const proxify = (buildIdentifier: string | (() => strin }; /* eslint-enable @typescript-eslint/no-explicit-any */ +export const registeredForgeConfigs: Map = new Map(); +export function registerForgeConfigForDirectory(dir: string, config: ForgeConfig): void { + registeredForgeConfigs.set(path.resolve(dir), config); +} +export function unregisterForgeConfigForDirectory(dir: string): void { + registeredForgeConfigs.delete(path.resolve(dir)); +} + export type BuildIdentifierMap = Record; export type BuildIdentifierConfig = { map: BuildIdentifierMap; @@ -109,8 +117,12 @@ type MaybeESM = T | { default: T }; type AsyncForgeConfigGenerator = () => Promise; export default async (dir: string): Promise => { + let forgeConfig: ForgeConfig | string | null | undefined = registeredForgeConfigs.get(dir); + const packageJSON = await readRawPackageJson(dir); - let forgeConfig: ForgeConfig | string | null = packageJSON.config && packageJSON.config.forge ? packageJSON.config.forge : null; + if (forgeConfig === undefined) { + forgeConfig = packageJSON.config && packageJSON.config.forge ? packageJSON.config.forge : null; + } if (!forgeConfig || typeof forgeConfig === 'string') { for (const extension of ['.js', ...Object.keys(interpret.extensions)]) { diff --git a/packages/api/core/src/util/index.ts b/packages/api/core/src/util/index.ts index bf55a7b631..c9d76afaec 100644 --- a/packages/api/core/src/util/index.ts +++ b/packages/api/core/src/util/index.ts @@ -1,6 +1,14 @@ import { getElectronVersion, hasYarn, yarnOrNpmSpawn } from '@electron-forge/core-utils'; -import { BuildIdentifierConfig, BuildIdentifierMap, fromBuildIdentifier } from './forge-config'; +import { + BuildIdentifierConfig, + BuildIdentifierMap, + fromBuildIdentifier, + registerForgeConfigForDirectory, + unregisterForgeConfigForDirectory, +} from './forge-config'; + +import type { ForgeConfig } from '@electron-forge/shared-types'; export default class ForgeUtils { /** @@ -19,4 +27,20 @@ export default class ForgeUtils { hasYarn = hasYarn; yarnOrNpmSpawn = yarnOrNpmSpawn; + + /** + * Register a virtual config file for forge to find. + * Takes precedence over other configuration options like a forge.config.js file. + * Dir should point to the folder containing the app. + */ + registerForgeConfigForDirectory(dir: string, config: ForgeConfig): void { + return registerForgeConfigForDirectory(dir, config); + } + + /** + * Unregister a forge config previously registered with registerForgeConfigForDirectory. + */ + unregisterForgeConfigForDirectory(dir: string): void { + return unregisterForgeConfigForDirectory(dir); + } } diff --git a/packages/api/core/src/util/resolve-dir.ts b/packages/api/core/src/util/resolve-dir.ts index 1713df7528..cc77eda72a 100644 --- a/packages/api/core/src/util/resolve-dir.ts +++ b/packages/api/core/src/util/resolve-dir.ts @@ -4,6 +4,7 @@ import { getElectronVersion } from '@electron-forge/core-utils'; import debug from 'debug'; import fs from 'fs-extra'; +import { registeredForgeConfigs } from './forge-config'; import { readRawPackageJson } from './read-package-json'; const d = debug('electron-forge:project-resolver'); @@ -12,15 +13,19 @@ const d = debug('electron-forge:project-resolver'); // and / or forge config then we need to be able to resolve // the dir without calling getElectronVersion export default async (dir: string): Promise => { - let mDir = dir; + let mDir = path.resolve(dir); let bestGuessDir: string | null = null; let lastError: string | null = null; let prevDir; while (prevDir !== mDir) { prevDir = mDir; - const testPath = path.resolve(mDir, 'package.json'); d('searching for project in:', mDir); + if (registeredForgeConfigs.has(mDir)) { + d('virtual config found in:', mDir); + return mDir; + } + const testPath = path.resolve(mDir, 'package.json'); if (await fs.pathExists(testPath)) { const packageJSON = await readRawPackageJson(mDir); diff --git a/packages/api/core/test/fast/forge-config_spec.ts b/packages/api/core/test/fast/forge-config_spec.ts index 9b40dee5dc..ade49b3a97 100644 --- a/packages/api/core/test/fast/forge-config_spec.ts +++ b/packages/api/core/test/fast/forge-config_spec.ts @@ -3,7 +3,12 @@ import path from 'path'; import { ResolvedForgeConfig } from '@electron-forge/shared-types'; import { expect } from 'chai'; -import findConfig, { forgeConfigIsValidFilePath, renderConfigTemplate } from '../../src/util/forge-config'; +import findConfig, { + forgeConfigIsValidFilePath, + registerForgeConfigForDirectory, + renderConfigTemplate, + unregisterForgeConfigForDirectory, +} from '../../src/util/forge-config'; const defaults = { packagerConfig: {}, @@ -47,6 +52,51 @@ describe('forge-config', () => { expect(config).to.deep.equal(defaults); }); + it('should resolve to the virtual config if present', async () => { + const fixturePath = path.resolve(__dirname, '../fixture/no_forge_config'); + try { + registerForgeConfigForDirectory(fixturePath, { outDir: 'magic' }); + const config = await findConfig(fixturePath); + delete (config as any).pluginInterface; + expect(config).to.be.deep.equal({ + ...defaults, + outDir: 'magic', + }); + } finally { + unregisterForgeConfigForDirectory(fixturePath); + } + }); + + it('should resolve virtual config instead of package.json', async () => { + const fixturePath = path.resolve(__dirname, '../fixture/dummy_app'); + try { + registerForgeConfigForDirectory(fixturePath, { outDir: 'magic' }); + const config = await findConfig(fixturePath); + delete (config as any).pluginInterface; + expect(config).to.be.deep.equal({ + ...defaults, + outDir: 'magic', + }); + } finally { + unregisterForgeConfigForDirectory(fixturePath); + } + }); + + it('should resolve virtual config instead of forge.config.js', async () => { + const fixturePath = path.resolve(__dirname, '../fixture/async_forge_config'); + try { + registerForgeConfigForDirectory(fixturePath, { outDir: 'magic' }); + const config = await findConfig(fixturePath); + delete (config as any).pluginInterface; + expect(config).to.be.deep.equal({ + ...defaults, + outDir: 'magic', + }); + } finally { + unregisterForgeConfigForDirectory(fixturePath); + } + }); + it('should resolve the object in package.json with defaults if one exists', async () => { const config = await findConfig(path.resolve(__dirname, '../fixture/dummy_app')); // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/api/core/test/fast/resolve-dir_spec.ts b/packages/api/core/test/fast/resolve-dir_spec.ts index 93bb098775..f90b521be4 100644 --- a/packages/api/core/test/fast/resolve-dir_spec.ts +++ b/packages/api/core/test/fast/resolve-dir_spec.ts @@ -2,6 +2,7 @@ import path from 'path'; import { expect } from 'chai'; +import { registerForgeConfigForDirectory, unregisterForgeConfigForDirectory } from '../../src/util/forge-config'; import resolveDir from '../../src/util/resolve-dir'; describe('resolve-dir', () => { @@ -20,4 +21,14 @@ describe('resolve-dir', () => { expect(await resolveDir(path.resolve(__dirname, '../fixture/dummy_app/foo'))).to.not.be.equal(null); expect(await resolveDir(path.resolve(__dirname, '../fixture/dummy_app/foo'))).to.be.equal(path.resolve(__dirname, '../fixture/dummy_app')); }); + + it('should return a directory if it finds a virtual config', async () => { + try { + registerForgeConfigForDirectory('/foo/var/virtual', {}); + expect(await resolveDir('/foo/var/virtual')).to.not.be.equal(null); + expect(await resolveDir(path.resolve(__dirname, '/foo/var/virtual'))).to.be.equal(path.resolve(__dirname, '/foo/var/virtual')); + } finally { + unregisterForgeConfigForDirectory('/foo/var/virtual'); + } + }); });