Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 23 additions & 50 deletions packages/api/core/spec/fast/util/forge-config.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { describe, expect, it, vi } from 'vitest';
import findConfig, {
forgeConfigIsValidFilePath,
registerForgeConfigForDirectory,
renderConfigTemplate,
unregisterForgeConfigForDirectory,
} from '../../../src/util/forge-config';

Expand Down Expand Up @@ -78,7 +77,7 @@ describe('findConfig', () => {
'../../fixture/bad_forge_config',
);
const err =
'Expected packageJSON.config.forge to be an object or point to a requirable JS file';
'Expected `config.forge` in package.json to be an object or point to a Forge config file';
await expect(findConfig(fixturePath)).rejects.toThrow(err);
});

Expand All @@ -90,7 +89,7 @@ describe('findConfig', () => {
__dirname,
'../../fixture/bad_external_forge_config',
);
const err = /Unexpected token/;
const err = /Failed to parse/;
await expect(findConfig(fixturePath)).rejects.toThrow(err);
spy.mockRestore();
});
Expand Down Expand Up @@ -294,43 +293,32 @@ describe('findConfig', () => {
});
});

describe('alternate config formats', () => {
it('should resolve the yml config from forge.config.yml specified in config.forge', async () => {
describe('TypeScript', () => {
it('should resolve forge.config.ts', async () => {
const fixturePath = path.resolve(
__dirname,
'../../fixture/dummy_ts_conf',
'../../fixture/dummy_default_ts_conf',
);
const conf = await findConfig(fixturePath);
expect(conf.buildIdentifier).toEqual('yml');
expect(conf.buildIdentifier).toEqual('typescript');
});

describe('TypeScript', () => {
it('should resolve forge.config.ts', async () => {
const fixturePath = path.resolve(
__dirname,
'../../fixture/dummy_default_ts_conf',
);
const conf = await findConfig(fixturePath);
expect(conf.buildIdentifier).toEqual('typescript');
});

it('should resolve forge.config.cts', async () => {
const fixturePath = path.resolve(
__dirname,
'../../fixture/dummy_default_cts_conf',
);
const conf = await findConfig(fixturePath);
expect(conf.buildIdentifier).toEqual('typescript-commonjs');
});
it('should resolve forge.config.cts', async () => {
const fixturePath = path.resolve(
__dirname,
'../../fixture/dummy_default_cts_conf',
);
const conf = await findConfig(fixturePath);
expect(conf.buildIdentifier).toEqual('typescript-commonjs');
});

it('should resolve forge.config.mts', async () => {
const fixturePath = path.resolve(
__dirname,
'../../fixture/dummy_default_mts_conf',
);
const conf = await findConfig(fixturePath);
expect(conf.buildIdentifier).toEqual('typescript-esm');
});
it('should resolve forge.config.mts', async () => {
const fixturePath = path.resolve(
__dirname,
'../../fixture/dummy_default_mts_conf',
);
const conf = await findConfig(fixturePath);
expect(conf.buildIdentifier).toEqual('typescript-esm');
});
});
});
Expand Down Expand Up @@ -366,28 +354,13 @@ describe('forgeConfigIsValidFilePath', () => {
const fixturePath = path.resolve(__dirname, '../../fixture/dummy_js_conf/');
await expect(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this await is no longer necessary

forgeConfigIsValidFilePath(fixturePath, 'forge.different.config'),
).resolves.toEqual(true);
).toEqual(true);
});

it('fails when a file is nonexistent', async () => {
const fixturePath = path.resolve(__dirname, '../../fixture/dummy_js_conf/');
await expect(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: same here

forgeConfigIsValidFilePath(fixturePath, 'forge.nonexistent.config'),
).resolves.toEqual(false);
});
});

describe('renderConfigTemplate', () => {
it('should import a JS file when a string starts with "require:"', () => {
const dir = path.resolve(__dirname, '../../fixture/dummy_js_conf');
const config = {
foo: 'require:foo',
};
renderConfigTemplate(dir, {}, config);
expect(config.foo).toEqual({
bar: {
baz: 'quux',
},
});
).toEqual(false);
});
});

This file was deleted.

20 changes: 0 additions & 20 deletions packages/api/core/spec/fixture/dummy_ts_conf/package.json

This file was deleted.

55 changes: 12 additions & 43 deletions packages/api/core/src/util/forge-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import path from 'node:path';

import { ForgeConfig, ResolvedForgeConfig } from '@electron-forge/shared-types';
import fs from 'fs-extra';
import * as interpret from 'interpret';
import { createJiti } from 'jiti';
import { template } from 'lodash';
import * as rechoir from 'rechoir';

// eslint-disable-next-line n/no-missing-import
import { dynamicImportMaybe } from '../../helper/dynamic-import.js';
Expand Down Expand Up @@ -126,36 +123,17 @@ export function fromBuildIdentifier<T>(
};
}

export async function forgeConfigIsValidFilePath(
export function forgeConfigIsValidFilePath(
dir: string,
forgeConfig: string | ForgeConfig,
): Promise<boolean> {
): boolean {
return (
typeof forgeConfig === 'string' &&
((await fs.pathExists(path.resolve(dir, forgeConfig))) ||
fs.pathExists(path.resolve(dir, `${forgeConfig}.js`)))
(fs.existsSync(path.resolve(dir, forgeConfig)) ||
fs.existsSync(path.resolve(dir, `${forgeConfig}.js`)))
);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function renderConfigTemplate(
dir: string,
templateObj: any,
obj: any,
): void {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'object' && value !== null) {
renderConfigTemplate(dir, templateObj, value);
} else if (typeof value === 'string') {
obj[key] = template(value)(templateObj);
if (obj[key].startsWith('require:')) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
obj[key] = require(path.resolve(dir, obj[key].substr(8)));
}
}
}
}

type MaybeESM<T> = T | { default: T };
type AsyncForgeConfigGenerator = () => Promise<ForgeConfig>;

Expand All @@ -172,27 +150,21 @@ export default async (dir: string): Promise<ResolvedForgeConfig> => {
}

if (!forgeConfig || typeof forgeConfig === 'string') {
// interpret.extensions doesn't support `.mts` files
for (const extension of [
'.js',
'.mts',
...Object.keys(interpret.extensions),
]) {
for (const extension of ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts']) {
const pathToConfig = path.resolve(dir, `forge.config${extension}`);
if (await fs.pathExists(pathToConfig)) {
// Use rechoir to parse alternative syntaxes (except for TypeScript where we use jiti)
if (!['.cts', '.mts', '.ts'].includes(extension)) {
rechoir.prepare(interpret.extensions, pathToConfig, dir);
}
if (fs.existsSync(pathToConfig)) {
forgeConfig = `forge.config${extension}`;
break;
}
}
}
forgeConfig = forgeConfig || ({} as ForgeConfig);

if (await forgeConfigIsValidFilePath(dir, forgeConfig)) {
const forgeConfigPath = path.resolve(dir, forgeConfig as string);
if (
typeof forgeConfig === 'string' &&
forgeConfigIsValidFilePath(dir, forgeConfig)
) {
const forgeConfigPath = path.resolve(dir, forgeConfig);
try {
let loadFn;
if (['.cts', '.mts', '.ts'].includes(path.extname(forgeConfigPath))) {
Expand All @@ -216,7 +188,7 @@ export default async (dir: string): Promise<ResolvedForgeConfig> => {
}
} else if (typeof forgeConfig !== 'object') {
throw new Error(
'Expected packageJSON.config.forge to be an object or point to a requirable JS file',
'Expected `config.forge` in package.json to be an object or point to a Forge config file',
);
}
const defaultForgeConfig = {
Expand All @@ -233,9 +205,6 @@ export default async (dir: string): Promise<ResolvedForgeConfig> => {
pluginInterface: null as any,
};

const templateObj = { ...packageJSON, year: new Date().getFullYear() };
renderConfigTemplate(dir, templateObj, resolvedForgeConfig);

resolvedForgeConfig.pluginInterface = await PluginInterface.create(
dir,
resolvedForgeConfig,
Expand Down
Loading