@nomicfoundation/hardhat-foundry
Version:
Hardhat plugin that provides compatibility with Foundry-based projects remappings.
90 lines • 3.25 kB
JavaScript
import { exec } from "node:child_process";
import * as path from "node:path";
import { promisify } from "node:util";
import { HardhatError } from "@nomicfoundation/hardhat-errors";
import { ensureError } from "@nomicfoundation/hardhat-utils/error";
import { exists } from "@nomicfoundation/hardhat-utils/fs";
const execAsync = promisify(exec);
const FORGE_TIMEOUT_MS = 500;
const FORGE_VERSION_TIMEOUT_MS = 500; // 0.5 seconds
// Module-level mock for testing
let execMock;
/**
* Set a mock exec function for testing.
* @param mockExec - The mock exec function to use.
*/
export function setExecMock(mockExec) {
execMock = mockExec;
}
/**
* Reset the mock exec function.
*/
export function resetExecMock() {
execMock = undefined;
}
/**
* Check if a package has a foundry.toml configuration file.
*
* @param packagePath - The absolute filesystem path to the package root.
* @returns True if foundry.toml exists in the package.
*/
export async function hasFoundryConfig(packagePath) {
const foundryTomlPath = path.join(packagePath, "foundry.toml");
return await exists(foundryTomlPath);
}
/**
* Check if forge is installed and available in PATH.
*
* @returns True if forge is installed, false otherwise.
*/
export async function isForgeInstalled() {
const _execAsync = execMock ?? execAsync;
try {
await _execAsync("forge --version", { timeout: FORGE_VERSION_TIMEOUT_MS });
return true;
}
catch {
return false;
}
}
/**
* Execute `forge remappings` in the given package directory to get Solidity remappings.
*
* @param packagePath - The absolute filesystem path to the package root.
* @returns An array of remapping strings (e.g., ["@openzeppelin/=lib/openzeppelin-contracts/"]).
* @throws {HardhatError} If the command fails.
*/
export async function getForgeRemappings(packagePath) {
const _execAsync = execMock ?? execAsync;
try {
const { stdout, stderr } = await _execAsync("forge remappings", {
cwd: packagePath,
timeout: FORGE_TIMEOUT_MS,
env: process.env,
});
// If there's stderr output but no stdout, it might be an error
if (stderr.length > 0 && stdout.length === 0) {
throw new HardhatError(HardhatError.ERRORS.HARDHAT_FOUNDRY.GENERAL.FORGE_REMAPPINGS_FAILED, { packagePath, stderr: stderr.trim() });
}
// Parse the output into individual remappings
const remappings = stdout
.split(/\r?\n/) // Handle both Unix and Windows line endings
.map((line) => line.trim())
.filter((line) => line.length > 0);
return remappings;
}
catch (error) {
ensureError(error);
// Re-throw HardhatErrors as-is, as it's a FORGE_REMAPPINGS_FAILED error
if (HardhatError.isHardhatError(error)) {
throw error;
}
const errorMessage = "stderr" in error &&
typeof error.stderr === "string" &&
error.stderr.length > 0
? error.stderr
: error.message;
throw new HardhatError(HardhatError.ERRORS.HARDHAT_FOUNDRY.GENERAL.FORGE_REMAPPINGS_FAILED, { packagePath, stderr: errorMessage });
}
}
//# sourceMappingURL=forge.js.map