diff --git a/v-next/hardhat/.eslintrc.cjs b/v-next/hardhat/.eslintrc.cjs index 70d742d97d..939317ab1c 100644 --- a/v-next/hardhat/.eslintrc.cjs +++ b/v-next/hardhat/.eslintrc.cjs @@ -1,11 +1,3 @@ const { createConfig } = require("../../config-v-next/eslint.cjs"); module.exports = createConfig(__filename); - -module.exports.rules["no-restricted-imports"][1].paths.push({ - // TODO: Rename this once we migrate to the official package names - name: "@ignored/hardhat-vnext-core", - importNames: ["createBaseHardhatRuntimeEnvironment"], - message: - "Use `createHardhatRuntimeEnvironment` from `hre.js` instead of this function.", -}); diff --git a/v-next/hardhat/src/config.ts b/v-next/hardhat/src/config.ts index 7107a18dd2..890b8c9453 100644 --- a/v-next/hardhat/src/config.ts +++ b/v-next/hardhat/src/config.ts @@ -1,24 +1,8 @@ -import { findClosestHardhatConfig } from "./internal/helpers/config-loading.js"; - -// Note: We import the builtin plugins' types here, so that any type extension -// they may have gets loaded. -import "./internal/builtin-plugins/index.js"; - export type * from "./internal/core/config.js"; export * from "./internal/core/config.js"; -/** - * Attempts to find the nearest Hardhat config file, starting from the current - * working directory. If no config file is found, an error is thrown. - * - * @returns The path to the nearest Hardhat config file. - */ -export async function resolveHardhatConfigPath(): Promise { - const configPath = process.env.HARDHAT_CONFIG; +export type { HardhatUserConfig } from "./types/config.js"; - if (configPath !== undefined) { - return configPath; - } - - return findClosestHardhatConfig(); -} +// NOTE: We import the builtin plugins in this module, so that their +// type-extensions are loaded then the user imports `hardhat/config`. +import "./internal/builtin-plugins/index.js"; diff --git a/v-next/hardhat/src/hre.ts b/v-next/hardhat/src/hre.ts index 59678b3c31..c923c5ddd8 100644 --- a/v-next/hardhat/src/hre.ts +++ b/v-next/hardhat/src/hre.ts @@ -1,64 +1,6 @@ -import type { UnsafeHardhatRuntimeEnvironmentOptions } from "./internal/core/types.js"; -import type { HardhatUserConfig } from "./types/config.js"; -import type { GlobalOptions } from "./types/global-options.js"; -import type { HardhatRuntimeEnvironment } from "./types/hre.js"; +// NOTE: We import the builtin plugins in this module, so that their +// type-extensions are loaded then the user imports `hardhat/hre`. +import "./internal/builtin-plugins/index.js"; -import { BUILTIN_GLOBAL_OPTIONS_DEFINITIONS } from "./internal/builtin-global-options.js"; -import { builtinPlugins } from "./internal/builtin-plugins/index.js"; -import { resolveProjectRoot } from "./internal/core/hre.js"; -import { - buildGlobalOptionDefinitions, - createBaseHardhatRuntimeEnvironment, - resolvePluginList, -} from "./internal/core/index.js"; - -/** - * Creates an instances of the Hardhat Runtime Environment. - * - * @param config - The user's Hardhat configuration. - * @param userProvidedGlobalOptions - The global options provided by the - * user. - * @param projectRoot - The root of the Hardhat project. Hardhat expects this - * to be the root of the npm project containing your config file. If none is - * provided, it will use the root of the npm project that contains the CWD. - * @returns The Hardhat Runtime Environment. - */ -export async function createHardhatRuntimeEnvironment( - config: HardhatUserConfig, - userProvidedGlobalOptions: Partial = {}, - projectRoot?: string, - unsafeOptions: UnsafeHardhatRuntimeEnvironmentOptions = {}, -): Promise { - const resolvedProjectRoot = await resolveProjectRoot(projectRoot); - - if (unsafeOptions.resolvedPlugins === undefined) { - const plugins = [...builtinPlugins, ...(config.plugins ?? [])]; - - const resolvedPlugins = await resolvePluginList( - resolvedProjectRoot, - plugins, - ); - - unsafeOptions.resolvedPlugins = resolvedPlugins; - } - - if (unsafeOptions.globalOptionDefinitions === undefined) { - const pluginGlobalOptionDefinitions = buildGlobalOptionDefinitions( - unsafeOptions.resolvedPlugins, - ); - - const globalOptionDefinitions = new Map([ - ...BUILTIN_GLOBAL_OPTIONS_DEFINITIONS, - ...pluginGlobalOptionDefinitions, - ]); - - unsafeOptions.globalOptionDefinitions = globalOptionDefinitions; - } - - return createBaseHardhatRuntimeEnvironment( - config, - userProvidedGlobalOptions, - resolvedProjectRoot, - unsafeOptions, - ); -} +export { resolveHardhatConfigPath } from "./internal/config-loading.js"; +export { createHardhatRuntimeEnvironment } from "./internal/hre-intialization.js"; diff --git a/v-next/hardhat/src/index.ts b/v-next/hardhat/src/index.ts index 75e3334c7c..eeb3097ea3 100644 --- a/v-next/hardhat/src/index.ts +++ b/v-next/hardhat/src/index.ts @@ -5,31 +5,15 @@ import type { HardhatRuntimeEnvironment } from "./types/hre.js"; import type { TaskManager } from "./types/tasks.js"; import type { UserInterruptionManager } from "./types/user-interruptions.js"; -import { resolveHardhatConfigPath } from "./config.js"; -import { createHardhatRuntimeEnvironment } from "./hre.js"; -import { resolveProjectRoot } from "./internal/core/index.js"; -import { - getGlobalHardhatRuntimeEnvironment, - setGlobalHardhatRuntimeEnvironment, -} from "./internal/global-hre-instance.js"; -import { importUserConfig } from "./internal/helpers/config-loading.js"; +import { getOrCreateGlobalHardhatRuntimeEnvironment } from "./internal/hre-intialization.js"; -let maybeHre: HardhatRuntimeEnvironment | undefined = - getGlobalHardhatRuntimeEnvironment(); +// NOTE: We import the builtin plugins in this module, so that their +// type-extensions are loaded then the user imports `hardhat`. +import "./internal/builtin-plugins/index.js"; -if (maybeHre === undefined) { - /* eslint-disable no-restricted-syntax -- Allow top-level await here */ - const configPath = await resolveHardhatConfigPath(); - const projectRoot = await resolveProjectRoot(configPath); - const userConfig = await importUserConfig(configPath); - - maybeHre = await createHardhatRuntimeEnvironment(userConfig, {}, projectRoot); - /* eslint-enable no-restricted-syntax */ - - setGlobalHardhatRuntimeEnvironment(maybeHre); -} - -const hre: HardhatRuntimeEnvironment = maybeHre; +const hre: HardhatRuntimeEnvironment = + // eslint-disable-next-line no-restricted-syntax -- Allow top-level await here + await getOrCreateGlobalHardhatRuntimeEnvironment(); export const config: HardhatConfig = hre.config; export const tasks: TaskManager = hre.tasks; diff --git a/v-next/hardhat/src/internal/builtin-global-options.ts b/v-next/hardhat/src/internal/builtin-global-options.ts index 0d42b80394..eff895351c 100644 --- a/v-next/hardhat/src/internal/builtin-global-options.ts +++ b/v-next/hardhat/src/internal/builtin-global-options.ts @@ -1,6 +1,7 @@ import type { GlobalOptionDefinitions } from "../types/global-options.js"; -import { globalOption, ArgumentType } from "../config.js"; +import { globalOption } from "../config.js"; +import { ArgumentType } from "../types/arguments.js"; export const BUILTIN_GLOBAL_OPTIONS_DEFINITIONS: GlobalOptionDefinitions = new Map([ diff --git a/v-next/hardhat/src/internal/builtin-plugins/clean/task-action.ts b/v-next/hardhat/src/internal/builtin-plugins/clean/task-action.ts index f53e6dbfaf..d421c5a9bb 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/clean/task-action.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/clean/task-action.ts @@ -2,7 +2,7 @@ import type { NewTaskActionFunction } from "../../../types/tasks.js"; import { emptyDir, remove } from "@ignored/hardhat-vnext-utils/fs"; -import { getCacheDir } from "../../core/global-dir.js"; +import { getCacheDir } from "../../global-dir.js"; interface CleanActionArguments { global: boolean; diff --git a/v-next/hardhat/src/internal/builtin-plugins/console/task-action.ts b/v-next/hardhat/src/internal/builtin-plugins/console/task-action.ts index f610814150..86cdb1e0e3 100644 --- a/v-next/hardhat/src/internal/builtin-plugins/console/task-action.ts +++ b/v-next/hardhat/src/internal/builtin-plugins/console/task-action.ts @@ -6,7 +6,7 @@ import repl from "node:repl"; import debug from "debug"; -import { getCacheDir } from "../../core/global-dir.js"; +import { getCacheDir } from "../../global-dir.js"; const log = debug("hardhat:core:tasks:console"); diff --git a/v-next/hardhat/src/internal/cli/helpers/utils.ts b/v-next/hardhat/src/internal/cli/helpers/utils.ts index e948b247d1..d77d9f29a4 100644 --- a/v-next/hardhat/src/internal/cli/helpers/utils.ts +++ b/v-next/hardhat/src/internal/cli/helpers/utils.ts @@ -1,7 +1,9 @@ -import type { ArgumentTypeToValueType } from "../../../types/arguments.js"; +import type { + ArgumentType, + ArgumentTypeToValueType, +} from "../../../types/arguments.js"; import type { GlobalOptionDefinitions } from "../../../types/global-options.js"; import type { Task } from "../../../types/tasks.js"; -import type { ArgumentType } from "../../core/config.js"; import { camelToKebabCase } from "@ignored/hardhat-vnext-utils/string"; diff --git a/v-next/hardhat/src/internal/cli/init/init.ts b/v-next/hardhat/src/internal/cli/init/init.ts index 601145ad45..1951f7ea98 100644 --- a/v-next/hardhat/src/internal/cli/init/init.ts +++ b/v-next/hardhat/src/internal/cli/init/init.ts @@ -1,6 +1,6 @@ import { HardhatError } from "@ignored/hardhat-vnext-errors"; -import { findClosestHardhatConfig } from "../../helpers/config-loading.js"; +import { findClosestHardhatConfig } from "../../config-loading.js"; import { createProject } from "./project-creation.js"; diff --git a/v-next/hardhat/src/internal/cli/main.ts b/v-next/hardhat/src/internal/cli/main.ts index 257e67b5f5..e269e606e0 100644 --- a/v-next/hardhat/src/internal/cli/main.ts +++ b/v-next/hardhat/src/internal/cli/main.ts @@ -1,7 +1,3 @@ -import type { - OptionDefinition, - PositionalArgumentDefinition, -} from "../../types/arguments.js"; import type { GlobalOptionDefinitions, GlobalOptions, @@ -14,23 +10,26 @@ import { assertHardhatInvariant, } from "@ignored/hardhat-vnext-errors"; import { isCi } from "@ignored/hardhat-vnext-utils/ci"; -import { getRealPath } from "@ignored/hardhat-vnext-utils/fs"; import { kebabToCamelCase } from "@ignored/hardhat-vnext-utils/string"; import debug from "debug"; -import { resolveHardhatConfigPath } from "../../config.js"; -import { createHardhatRuntimeEnvironment } from "../../hre.js"; +import { + ArgumentType, + type OptionDefinition, + type PositionalArgumentDefinition, +} from "../../types/arguments.js"; import { BUILTIN_GLOBAL_OPTIONS_DEFINITIONS } from "../builtin-global-options.js"; import { builtinPlugins } from "../builtin-plugins/index.js"; -import { ArgumentType } from "../core/config.js"; import { - buildGlobalOptionDefinitions, - parseArgumentValue, - resolvePluginList, - resolveProjectRoot, -} from "../core/index.js"; + importUserConfig, + resolveHardhatConfigPath, +} from "../config-loading.js"; +import { parseArgumentValue } from "../core/arguments.js"; +import { buildGlobalOptionDefinitions } from "../core/global-options.js"; +import { resolveProjectRoot } from "../core/hre.js"; +import { resolvePluginList } from "../core/plugins/resolve-plugin-list.js"; import { setGlobalHardhatRuntimeEnvironment } from "../global-hre-instance.js"; -import { importUserConfig } from "../helpers/config-loading.js"; +import { createHardhatRuntimeEnvironment } from "../hre-intialization.js"; import { printErrorMessages } from "./error-handler.js"; import { getGlobalHelpString } from "./helpers/getGlobalHelpString.js"; @@ -73,17 +72,13 @@ export async function main( log("Retrieved telemetry consent"); - if (builtinGlobalOptions.configPath === undefined) { - builtinGlobalOptions.configPath = await resolveHardhatConfigPath(); - - log("Resolved config path"); - } - - const projectRoot = await resolveProjectRoot( - await getRealPath(builtinGlobalOptions.configPath), + const configPath = await resolveHardhatConfigPath( + builtinGlobalOptions.configPath, ); - const userConfig = await importUserConfig(builtinGlobalOptions.configPath); + const projectRoot = await resolveProjectRoot(configPath); + + const userConfig = await importUserConfig(configPath); log("User config imported"); @@ -97,10 +92,12 @@ export async function main( const pluginGlobalOptionDefinitions = buildGlobalOptionDefinitions(resolvedPlugins); + const globalOptionDefinitions = new Map([ ...BUILTIN_GLOBAL_OPTIONS_DEFINITIONS, ...pluginGlobalOptionDefinitions, ]); + const userProvidedGlobalOptions = await parseGlobalOptions( globalOptionDefinitions, cliArguments, @@ -111,7 +108,11 @@ export async function main( const hre = await createHardhatRuntimeEnvironment( userConfig, - { ...builtinGlobalOptions, ...userProvidedGlobalOptions }, + { + ...builtinGlobalOptions, + config: configPath, + ...userProvidedGlobalOptions, + }, projectRoot, { resolvedPlugins, globalOptionDefinitions }, ); diff --git a/v-next/hardhat/src/internal/cli/telemetry/analytics/utils.ts b/v-next/hardhat/src/internal/cli/telemetry/analytics/utils.ts index ca26e5c4bf..3409d52aac 100644 --- a/v-next/hardhat/src/internal/cli/telemetry/analytics/utils.ts +++ b/v-next/hardhat/src/internal/cli/telemetry/analytics/utils.ts @@ -9,7 +9,7 @@ import { } from "@ignored/hardhat-vnext-utils/fs"; import debug from "debug"; -import { getTelemetryDir } from "../../../core/global-dir.js"; +import { getTelemetryDir } from "../../../global-dir.js"; const log = debug("hardhat:cli:telemetry:analytics:utils"); diff --git a/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts b/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts index 62475f8a9d..4e7c570d44 100644 --- a/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts +++ b/v-next/hardhat/src/internal/cli/telemetry/telemetry-permissions.ts @@ -8,7 +8,7 @@ import { } from "@ignored/hardhat-vnext-utils/fs"; import debug from "debug"; -import { getConfigDir } from "../../core/global-dir.js"; +import { getConfigDir } from "../../global-dir.js"; import { confirmationPromptWithTimeout } from "../prompt/prompt.js"; import { sendTelemetryConsentAnalytics } from "./analytics/analytics.js"; diff --git a/v-next/hardhat/src/internal/config-loading.ts b/v-next/hardhat/src/internal/config-loading.ts new file mode 100644 index 0000000000..fc008e2be2 --- /dev/null +++ b/v-next/hardhat/src/internal/config-loading.ts @@ -0,0 +1,113 @@ +import type { HardhatUserConfig } from "../types/config.js"; + +import { isAbsolute, resolve } from "node:path"; +import { pathToFileURL } from "node:url"; + +import { HardhatError } from "@ignored/hardhat-vnext-errors"; +import { exists, findUp } from "@ignored/hardhat-vnext-utils/fs"; +import { isObject } from "@ignored/hardhat-vnext-utils/lang"; +import debug from "debug"; + +const log = debug("hardhat:core:config-loading"); + +/** + * Resolves the path to the Hardhat config file using these rules: + * - If the user provided a path, that path is returned. + * - Otherwise, if the HARDHAT_CONFIG env var is set, that path is returned. + * - Otherwise, the closest Hardhat config file to the current working + * directory is returned. + * + * @param userProvidedPath An optional path to the Hardhat config file, provided + * by the user. + * @returns The path to the Hardhat config file, as an absolute path. + * @throws HardhatError If no Hardhat config file can be found. + */ +export async function resolveHardhatConfigPath( + userProvidedPath?: string, +): Promise { + const configPath = userProvidedPath ?? process.env.HARDHAT_CONFIG; + + if (configPath !== undefined) { + return normalizeConfigPath(configPath); + } + + if (process.env.HARDHAT_CONFIG !== undefined) { + log("Using config file path from the HARDHAT_CONFIG env var"); + return normalizeConfigPath(process.env.HARDHAT_CONFIG); + } + + return findClosestHardhatConfig(); +} + +/** + * Finds the closest Hardhat config file to the current working directory. + * + * @returns The absolute path to the closest Hardhat config file. + * @throw HardhatError if no Hardhat config file can be found. + */ +export async function findClosestHardhatConfig(): Promise { + let hardhatConfigPath = await findUp("hardhat.config.ts"); + + if (hardhatConfigPath !== undefined) { + return hardhatConfigPath; + } + + hardhatConfigPath = await findUp("hardhat.config.js"); + + if (hardhatConfigPath !== undefined) { + return hardhatConfigPath; + } + + throw new HardhatError(HardhatError.ERRORS.GENERAL.NO_CONFIG_FILE_FOUND); +} + +/** + * Imports the user config and returns it. + * @param configPath The path to the config file. + * @returns The user config. + */ +export async function importUserConfig( + configPath: string, +): Promise { + const normalizedPath = await normalizeConfigPath(configPath); + + const imported = await import(pathToFileURL(normalizedPath).href); + + if (!("default" in imported)) { + throw new HardhatError(HardhatError.ERRORS.GENERAL.NO_CONFIG_EXPORTED, { + configPath, + }); + } + + const config = imported.default; + + if (!isObject(config)) { + throw new HardhatError(HardhatError.ERRORS.GENERAL.INVALID_CONFIG_OBJECT, { + configPath, + }); + } + + return config; +} + +/** + * Returns an abolute version of the config path, throwing if the path + * doesn't exist. + * + * @param configPath The path to the config file. + * @returns The absolute path to the config file. + * @throws HardhatError if the path doesn't exist. + */ +async function normalizeConfigPath(configPath: string): Promise { + const normalizedPath = isAbsolute(configPath) + ? configPath + : resolve(process.cwd(), configPath); + + if (!(await exists(normalizedPath))) { + throw new HardhatError(HardhatError.ERRORS.GENERAL.INVALID_CONFIG_PATH, { + configPath, + }); + } + + return normalizedPath; +} diff --git a/v-next/hardhat/src/internal/core/config-validation.ts b/v-next/hardhat/src/internal/core/config-validation.ts index c2a7a9b2e0..989f0d83cc 100644 --- a/v-next/hardhat/src/internal/core/config-validation.ts +++ b/v-next/hardhat/src/internal/core/config-validation.ts @@ -1,4 +1,4 @@ -import type { HardhatUserConfig } from "./config.js"; +import type { HardhatUserConfig } from "../../types/config.js"; import type { HardhatUserConfigValidationError, HookManager, diff --git a/v-next/hardhat/src/internal/core/config.ts b/v-next/hardhat/src/internal/core/config.ts index ce1e84aa18..f4e0a04059 100644 --- a/v-next/hardhat/src/internal/core/config.ts +++ b/v-next/hardhat/src/internal/core/config.ts @@ -18,10 +18,6 @@ import { TaskOverrideDefinitionBuilderImplementation, } from "./tasks/builders.js"; -export type { HardhatUserConfig } from "../../types/config.js"; - -export { ArgumentType } from "../../types/arguments.js"; - /** * Creates a configuration variable, which will be fetched at runtime. */ diff --git a/v-next/hardhat/src/internal/core/index.ts b/v-next/hardhat/src/internal/core/index.ts deleted file mode 100644 index d2476d9cee..0000000000 --- a/v-next/hardhat/src/internal/core/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { UnsafeHardhatRuntimeEnvironmentOptions } from "./types.js"; -import type { HardhatUserConfig } from "../../types/config.js"; -import type { GlobalOptions } from "../../types/global-options.js"; -import type { HardhatRuntimeEnvironment } from "../../types/hre.js"; - -import { HardhatRuntimeEnvironmentImplementation } from "./hre.js"; - -/** - * Creates an instances of the Hardhat Runtime Environment without any of the - * built-in plugins. - * - * To get the built-in plugins, use `createHardhatRuntimeEnvironment` from - * `hardhat/hre` instead. - * - * @param config - The user's Hardhat configuration. - * @param userProvidedGlobalOptions - The global options provided by the - * user. - * @param projectRoot - The root of the Hardhat project. Hardhat expects this - * to be the root of the npm project containing your config file. If none is - * provided, it will use the root of the npm project that contains the CWD. - * @param unsafeOptions - Options used to bypass some initialization, to avoid - * redoing it in the CLI. Should only be used in the official CLI. - * @returns The Hardhat Runtime Environment. - */ -export async function createBaseHardhatRuntimeEnvironment( - config: HardhatUserConfig, - userProvidedGlobalOptions: Partial = {}, - projectRoot?: string, - unsafeOptions?: UnsafeHardhatRuntimeEnvironmentOptions, -): Promise { - return HardhatRuntimeEnvironmentImplementation.create( - config, - userProvidedGlobalOptions, - projectRoot, - unsafeOptions, - ); -} - -export { resolveProjectRoot } from "./hre.js"; -export { parseArgumentValue } from "./arguments.js"; -export { resolvePluginList } from "./plugins/resolve-plugin-list.js"; -export { buildGlobalOptionDefinitions } from "./global-options.js"; diff --git a/v-next/hardhat/src/internal/core/global-dir.ts b/v-next/hardhat/src/internal/global-dir.ts similarity index 100% rename from v-next/hardhat/src/internal/core/global-dir.ts rename to v-next/hardhat/src/internal/global-dir.ts diff --git a/v-next/hardhat/src/internal/helpers/config-loading.ts b/v-next/hardhat/src/internal/helpers/config-loading.ts deleted file mode 100644 index 474ae5366f..0000000000 --- a/v-next/hardhat/src/internal/helpers/config-loading.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { HardhatUserConfig } from "../../types/config.js"; - -import { isAbsolute, resolve } from "node:path"; -import { pathToFileURL } from "node:url"; - -import { HardhatError } from "@ignored/hardhat-vnext-errors"; -import { findUp } from "@ignored/hardhat-vnext-utils/fs"; -import { isObject } from "@ignored/hardhat-vnext-utils/lang"; - -export async function findClosestHardhatConfig(): Promise { - let hardhatConfigPath = await findUp("hardhat.config.ts"); - - if (hardhatConfigPath !== undefined) { - return hardhatConfigPath; - } - - hardhatConfigPath = await findUp("hardhat.config.js"); - - if (hardhatConfigPath !== undefined) { - return hardhatConfigPath; - } - - throw new HardhatError(HardhatError.ERRORS.GENERAL.NO_CONFIG_FILE_FOUND); -} - -export async function importUserConfig( - configPath: string, -): Promise { - const normalizedPath = isAbsolute(configPath) - ? configPath - : resolve(process.cwd(), configPath); - - const { exists } = await import("@ignored/hardhat-vnext-utils/fs"); - - if (!(await exists(normalizedPath))) { - throw new HardhatError(HardhatError.ERRORS.GENERAL.INVALID_CONFIG_PATH, { - configPath, - }); - } - - const imported = await import(pathToFileURL(normalizedPath).href); - - if (!("default" in imported)) { - throw new HardhatError(HardhatError.ERRORS.GENERAL.NO_CONFIG_EXPORTED, { - configPath, - }); - } - - const config = imported.default; - - if (!isObject(config) || config === null) { - throw new HardhatError(HardhatError.ERRORS.GENERAL.INVALID_CONFIG_OBJECT, { - configPath, - }); - } - - return config; -} diff --git a/v-next/hardhat/src/internal/hre-intialization.ts b/v-next/hardhat/src/internal/hre-intialization.ts new file mode 100644 index 0000000000..3b3de8a77d --- /dev/null +++ b/v-next/hardhat/src/internal/hre-intialization.ts @@ -0,0 +1,101 @@ +import type { UnsafeHardhatRuntimeEnvironmentOptions } from "./core/types.js"; +import type { HardhatUserConfig } from "../types/config.js"; +import type { GlobalOptions } from "../types/global-options.js"; +import type { HardhatRuntimeEnvironment } from "../types/hre.js"; + +import { BUILTIN_GLOBAL_OPTIONS_DEFINITIONS } from "./builtin-global-options.js"; +import { builtinPlugins } from "./builtin-plugins/index.js"; +import { + importUserConfig, + resolveHardhatConfigPath, +} from "./config-loading.js"; +import { buildGlobalOptionDefinitions } from "./core/global-options.js"; +import { + resolveProjectRoot, + HardhatRuntimeEnvironmentImplementation, +} from "./core/hre.js"; +import { resolvePluginList } from "./core/plugins/resolve-plugin-list.js"; +import { + getGlobalHardhatRuntimeEnvironment, + setGlobalHardhatRuntimeEnvironment, +} from "./global-hre-instance.js"; + +/** + * Creates an instances of the Hardhat Runtime Environment. + * + * @param config - The user's Hardhat configuration. Note that the config + * doesn't have to come from a file, but if it does, you should provide its + * path as the `config` property in the `userProvidedGlobalOptions` object. + * @param userProvidedGlobalOptions - The global options provided by the + * user. + * @param projectRoot - The root of the Hardhat project. Hardhat expects this + * to be the root of the npm project containing your config file. If none is + * provided, it will use the root of the npm project that contains the CWD. + * @returns The Hardhat Runtime Environment. + */ +export async function createHardhatRuntimeEnvironment( + config: HardhatUserConfig, + userProvidedGlobalOptions: Partial = {}, + projectRoot?: string, + unsafeOptions: UnsafeHardhatRuntimeEnvironmentOptions = {}, +): Promise { + const resolvedProjectRoot = await resolveProjectRoot(projectRoot); + + if (unsafeOptions.resolvedPlugins === undefined) { + const plugins = [...builtinPlugins, ...(config.plugins ?? [])]; + + const resolvedPlugins = await resolvePluginList( + resolvedProjectRoot, + plugins, + ); + + unsafeOptions.resolvedPlugins = resolvedPlugins; + } + + if (unsafeOptions.globalOptionDefinitions === undefined) { + const pluginGlobalOptionDefinitions = buildGlobalOptionDefinitions( + unsafeOptions.resolvedPlugins, + ); + + const globalOptionDefinitions = new Map([ + ...BUILTIN_GLOBAL_OPTIONS_DEFINITIONS, + ...pluginGlobalOptionDefinitions, + ]); + + unsafeOptions.globalOptionDefinitions = globalOptionDefinitions; + } + + return HardhatRuntimeEnvironmentImplementation.create( + config, + userProvidedGlobalOptions, + resolvedProjectRoot, + unsafeOptions, + ); +} + +/** + * Gets the global Hardhat Runtime Environment, or creates it if it doesn't exist. + * + * This function is meant to be used when `hardhat` is imported as a library. + */ +export async function getOrCreateGlobalHardhatRuntimeEnvironment(): Promise { + let globalHre = getGlobalHardhatRuntimeEnvironment(); + + if (globalHre !== undefined) { + return globalHre; + } + + const configPath = await resolveHardhatConfigPath(); + const projectRoot = await resolveProjectRoot(configPath); + const userConfig = await importUserConfig(configPath); + + globalHre = await createHardhatRuntimeEnvironment( + userConfig, + { config: configPath }, + projectRoot, + ); + + setGlobalHardhatRuntimeEnvironment(globalHre); + + return globalHre; +} diff --git a/v-next/hardhat/test/fixture-projects/config-custom-path/other.config.js b/v-next/hardhat/test/fixture-projects/config-custom-path/other.config.js new file mode 100644 index 0000000000..ff8b4c5632 --- /dev/null +++ b/v-next/hardhat/test/fixture-projects/config-custom-path/other.config.js @@ -0,0 +1 @@ +export default {}; diff --git a/v-next/hardhat/test/internal/builtin-plugins/clean/task-action.ts b/v-next/hardhat/test/internal/builtin-plugins/clean/task-action.ts index b28b5c6c51..deff15bffa 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/clean/task-action.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/clean/task-action.ts @@ -13,9 +13,9 @@ import { } from "@ignored/hardhat-vnext-utils/fs"; import { useFixtureProject } from "@nomicfoundation/hardhat-test-utils"; -import { createHardhatRuntimeEnvironment } from "../../../../src/hre.js"; import cleanAction from "../../../../src/internal/builtin-plugins/clean/task-action.js"; -import { getCacheDir } from "../../../../src/internal/core/global-dir.js"; +import { getCacheDir } from "../../../../src/internal/global-dir.js"; +import { createHardhatRuntimeEnvironment } from "../../../../src/internal/hre-intialization.js"; let hre: HardhatRuntimeEnvironment; let globalCacheDir: string; diff --git a/v-next/hardhat/test/internal/builtin-plugins/console/task-action.ts b/v-next/hardhat/test/internal/builtin-plugins/console/task-action.ts index a06537778d..8ae1e4c6b3 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/console/task-action.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/console/task-action.ts @@ -13,8 +13,8 @@ import { exists, remove } from "@ignored/hardhat-vnext-utils/fs"; import { useFixtureProject } from "@nomicfoundation/hardhat-test-utils"; import debug from "debug"; -import { createHardhatRuntimeEnvironment } from "../../../../src/hre.js"; import consoleAction from "../../../../src/internal/builtin-plugins/console/task-action.js"; +import { createHardhatRuntimeEnvironment } from "../../../../src/internal/hre-intialization.js"; const log = debug("hardhat:test:console:task-action"); diff --git a/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts b/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts index 051efb0354..16b35cc0e6 100644 --- a/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts +++ b/v-next/hardhat/test/internal/builtin-plugins/run/task-action.ts @@ -8,8 +8,8 @@ import { useFixtureProject, } from "@nomicfoundation/hardhat-test-utils"; -import { createHardhatRuntimeEnvironment } from "../../../../src/hre.js"; import runScriptWithHardhat from "../../../../src/internal/builtin-plugins/run/task-action.js"; +import { createHardhatRuntimeEnvironment } from "../../../../src/internal/hre-intialization.js"; describe("run/task-action", function () { let hre: HardhatRuntimeEnvironment; diff --git a/v-next/hardhat/test/internal/cli/init/init.ts b/v-next/hardhat/test/internal/cli/init/init.ts index 4d860b4622..ad93fb445f 100644 --- a/v-next/hardhat/test/internal/cli/init/init.ts +++ b/v-next/hardhat/test/internal/cli/init/init.ts @@ -15,7 +15,7 @@ import { import { initHardhat } from "../../../../src/internal/cli/init/init.js"; import { EMPTY_HARDHAT_CONFIG } from "../../../../src/internal/cli/init/sample-config-file.js"; -import { findClosestHardhatConfig } from "../../../../src/internal/helpers/config-loading.js"; +import { findClosestHardhatConfig } from "../../../../src/internal/config-loading.js"; async function deleteHardhatConfigFile() { await remove(path.join(process.cwd(), "hardhat.config.ts")); diff --git a/v-next/hardhat/test/internal/cli/main.ts b/v-next/hardhat/test/internal/cli/main.ts index 76d7a980ce..5a464ac52a 100644 --- a/v-next/hardhat/test/internal/cli/main.ts +++ b/v-next/hardhat/test/internal/cli/main.ts @@ -23,7 +23,6 @@ import { } from "@nomicfoundation/hardhat-test-utils"; import chalk from "chalk"; -import { createHardhatRuntimeEnvironment } from "../../../src/hre.js"; import { main, parseGlobalOptions, @@ -37,6 +36,7 @@ import { task, } from "../../../src/internal/core/config.js"; import { resetGlobalHardhatRuntimeEnvironment } from "../../../src/internal/global-hre-instance.js"; +import { createHardhatRuntimeEnvironment } from "../../../src/internal/hre-intialization.js"; import { getHardhatVersion } from "../../../src/internal/utils/package.js"; import { ArgumentType } from "../../../src/types/arguments.js"; diff --git a/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts b/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts index 6409c9be58..edad31b516 100644 --- a/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts +++ b/v-next/hardhat/test/internal/cli/telemetry/telemetry-permissions.ts @@ -5,7 +5,7 @@ import { afterEach, beforeEach, describe, it } from "node:test"; import { remove, writeJsonFile } from "@ignored/hardhat-vnext-utils/fs"; import { isTelemetryAllowed } from "../../../../src/internal/cli/telemetry/telemetry-permissions.js"; -import { getConfigDir } from "../../../../src/internal/core/global-dir.js"; +import { getConfigDir } from "../../../../src/internal/global-dir.js"; async function setTelemetryConsentFile(consent: boolean) { const configDir = await getConfigDir(); diff --git a/v-next/hardhat/test/internal/core/config-validation.ts b/v-next/hardhat/test/internal/core/config-validation.ts index 576082bd7f..a9c3ae33f3 100644 --- a/v-next/hardhat/test/internal/core/config-validation.ts +++ b/v-next/hardhat/test/internal/core/config-validation.ts @@ -1,8 +1,4 @@ import type { HardhatUserConfig } from "../../../src/config.js"; -import type { - PositionalArgumentDefinition, - OptionDefinition, -} from "../../../src/types/arguments.js"; import type { HardhatPlugin } from "../../../src/types/plugins.js"; import type { EmptyTaskDefinition, @@ -14,7 +10,6 @@ import type { import assert from "node:assert/strict"; import { describe, it } from "node:test"; -import { ArgumentType } from "../../../src/config.js"; import { validatePositionalArguments, validateOptions, @@ -25,6 +20,11 @@ import { validatePluginsConfig, collectValidationErrorsForUserConfig, } from "../../../src/internal/core/config-validation.js"; +import { + type PositionalArgumentDefinition, + type OptionDefinition, + ArgumentType, +} from "../../../src/types/arguments.js"; import { TaskDefinitionType } from "../../../src/types/tasks.js"; describe("config validation", function () { diff --git a/v-next/hardhat/test/internal/core/configuration-variables/configuration-variables.ts b/v-next/hardhat/test/internal/core/configuration-variables/configuration-variables.ts index d3cfbec6e4..484e8a2a52 100644 --- a/v-next/hardhat/test/internal/core/configuration-variables/configuration-variables.ts +++ b/v-next/hardhat/test/internal/core/configuration-variables/configuration-variables.ts @@ -1,3 +1,5 @@ +import type { HardhatRuntimeEnvironment } from "../../../../src/types/hre.js"; + import assert from "node:assert/strict"; import { before, describe, it } from "node:test"; @@ -5,47 +7,18 @@ import { HardhatError } from "@ignored/hardhat-vnext-errors"; import { assertRejectsWithHardhatError } from "@nomicfoundation/hardhat-test-utils"; import { ResolvedConfigurationVariableImplementation } from "../../../../src/internal/core/configuration-variables.js"; -import { HookManagerImplementation } from "../../../../src/internal/core/hook-manager.js"; -import { resolveProjectRoot } from "../../../../src/internal/core/index.js"; -import { UserInterruptionManagerImplementation } from "../../../../src/internal/core/user-interruptions.js"; +import { HardhatRuntimeEnvironmentImplementation } from "../../../../src/internal/core/hre.js"; describe("ResolvedConfigurationVariable", () => { - let hookManager: HookManagerImplementation; + let hre: HardhatRuntimeEnvironment; before(async () => { - const projectRoot = await resolveProjectRoot(process.cwd()); - - hookManager = new HookManagerImplementation(projectRoot, []); - const userInterruptionsManager = new UserInterruptionManagerImplementation( - hookManager, - ); - - hookManager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - hooks: hookManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - interruptions: userInterruptionsManager, - }); + hre = await HardhatRuntimeEnvironmentImplementation.create({}, {}); }); it("should return the value of a string variable", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, "foo", ); @@ -54,7 +27,7 @@ describe("ResolvedConfigurationVariable", () => { it("should return the value of a configuration variable from an environment variable", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, { name: "foo", _type: "ConfigurationVariable" }, ); @@ -67,7 +40,7 @@ describe("ResolvedConfigurationVariable", () => { it("should throw if the environment variable is not found", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, { name: "foo", _type: "ConfigurationVariable" }, ); @@ -80,7 +53,7 @@ describe("ResolvedConfigurationVariable", () => { it("should return the cached value if called multiple times", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, { name: "foo", _type: "ConfigurationVariable" }, ); @@ -97,7 +70,7 @@ describe("ResolvedConfigurationVariable", () => { it("should return the value of a configuration variable as a URL", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, { name: "foo", _type: "ConfigurationVariable" }, ); @@ -110,7 +83,7 @@ describe("ResolvedConfigurationVariable", () => { it("should throw if the configuration variable is not a valid URL", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, { name: "foo", _type: "ConfigurationVariable" }, ); @@ -129,7 +102,7 @@ describe("ResolvedConfigurationVariable", () => { it("should return the value of a configuration variable as a BigInt", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, { name: "foo", _type: "ConfigurationVariable" }, ); @@ -142,7 +115,7 @@ describe("ResolvedConfigurationVariable", () => { it("should throw if the configuration variable is not a valid BigInt", async () => { const variable = new ResolvedConfigurationVariableImplementation( - hookManager, + hre.hooks, { name: "foo", _type: "ConfigurationVariable" }, ); diff --git a/v-next/hardhat/test/internal/core/global-options.ts b/v-next/hardhat/test/internal/core/global-options.ts index 18cf949ebb..2e7ed4198c 100644 --- a/v-next/hardhat/test/internal/core/global-options.ts +++ b/v-next/hardhat/test/internal/core/global-options.ts @@ -7,15 +7,13 @@ import { HardhatError } from "@ignored/hardhat-vnext-errors"; import { assertThrowsHardhatError } from "@nomicfoundation/hardhat-test-utils"; import { RESERVED_ARGUMENT_NAMES } from "../../../src/internal/core/arguments.js"; -import { - ArgumentType, - globalOption, -} from "../../../src/internal/core/config.js"; +import { globalOption } from "../../../src/internal/core/config.js"; import { buildGlobalOptionDefinition, buildGlobalOptionDefinitions, resolveGlobalOptions, } from "../../../src/internal/core/global-options.js"; +import { ArgumentType } from "../../../src/types/arguments.js"; import { createTestEnvManager } from "./utils.js"; diff --git a/v-next/hardhat/test/internal/core/hook-manager.ts b/v-next/hardhat/test/internal/core/hook-manager.ts index 93b46fea47..10dc3b9056 100644 --- a/v-next/hardhat/test/internal/core/hook-manager.ts +++ b/v-next/hardhat/test/internal/core/hook-manager.ts @@ -4,7 +4,6 @@ sequential tests require casting - see the `runSequentialHandlers` describe */ import type { HardhatUserConfig } from "../../../src/config.js"; import type { ConfigurationVariable } from "../../../src/types/config.js"; import type { - HookManager, ConfigHooks, HardhatUserConfigValidationError, HookContext, @@ -13,8 +12,6 @@ import type { } from "../../../src/types/hooks.js"; import type { HardhatRuntimeEnvironment } from "../../../src/types/hre.js"; import type { HardhatPlugin } from "../../../src/types/plugins.js"; -import type { TaskManager, Task } from "../../../src/types/tasks.js"; -import type { UserInterruptionManager } from "../../../src/types/user-interruptions.js"; import assert from "node:assert/strict"; import { describe, it, beforeEach, before } from "node:test"; @@ -24,8 +21,10 @@ import { ensureError } from "@ignored/hardhat-vnext-utils/error"; import { assertRejectsWithHardhatError } from "@nomicfoundation/hardhat-test-utils"; import { HookManagerImplementation } from "../../../src/internal/core/hook-manager.js"; -import { resolveProjectRoot } from "../../../src/internal/core/hre.js"; -import { UserInterruptionManagerImplementation } from "../../../src/internal/core/user-interruptions.js"; +import { + HardhatRuntimeEnvironmentImplementation, + resolveProjectRoot, +} from "../../../src/internal/core/hre.js"; describe("HookManager", () => { let projectRoot: string; @@ -36,11 +35,13 @@ describe("HookManager", () => { describe("plugin hooks", () => { describe("running", () => { - let hookManager: HookManager; + let hre: HardhatRuntimeEnvironment; + let forceConfigValidationErrorFromPlugin: boolean; let sequence: string[]; - beforeEach(() => { + beforeEach(async () => { sequence = []; + forceConfigValidationErrorFromPlugin = false; const examplePlugin: HardhatPlugin = { id: "example", @@ -50,12 +51,16 @@ describe("HookManager", () => { validateUserConfig: async ( _config: HardhatUserConfig, ): Promise => { - return [ - { - path: [], - message: "FromPlugin", - }, - ]; + if (forceConfigValidationErrorFromPlugin) { + return [ + { + path: [], + message: "FromPlugin", + }, + ]; + } + + return []; }, extendUserConfig: async ( config: HardhatUserConfig, @@ -88,40 +93,14 @@ describe("HookManager", () => { }, }; - const manager = new HookManagerImplementation(projectRoot, [ - examplePlugin, - ]); - - const userInterruptionsManager = - new UserInterruptionManagerImplementation(hookManager); - - manager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - hooks: hookManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - interruptions: userInterruptionsManager, - }); - - hookManager = manager; + hre = await HardhatRuntimeEnvironmentImplementation.create( + { plugins: [examplePlugin] }, + {}, + ); }); it("should use plugins during handler runs", async () => { - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { extendUserConfig: async ( config: HardhatUserConfig, next: (nextConfig: HardhatUserConfig) => Promise, @@ -134,7 +113,11 @@ describe("HookManager", () => { }, }); - await hookManager.runHandlerChain( + // We clear the sequense here, as we used the plugin already during the + // initialization of the HRE + sequence = []; + + await hre.hooks.runHandlerChain( "config", "extendUserConfig", [{}], @@ -154,7 +137,7 @@ describe("HookManager", () => { }); it("Should use plugins during a sequential run", async () => { - hookManager.registerHandlers("hre", { + hre.hooks.registerHandlers("hre", { testExample: async ( _context: HookContext, _input: string, @@ -163,7 +146,7 @@ describe("HookManager", () => { }, } as Partial); - const result = await hookManager.runSequentialHandlers( + const result = await hre.hooks.runSequentialHandlers( "hre", "testExample" as any, ["input"], @@ -173,21 +156,9 @@ describe("HookManager", () => { }); it("should use plugins during parallel handlers runs", async () => { - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR.*/ - const originalConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const originalConfig: HardhatUserConfig = {}; - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { validateUserConfig: async ( _config: HardhatUserConfig, ): Promise => { @@ -200,7 +171,9 @@ describe("HookManager", () => { }, }); - const results = await hookManager.runParallelHandlers( + forceConfigValidationErrorFromPlugin = true; + + const results = await hre.hooks.runParallelHandlers( "config", "validateUserConfig", [originalConfig], @@ -232,19 +205,7 @@ describe("HookManager", () => { }, }; - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR. */ - const expectedConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const expectedConfig: HardhatUserConfig = {}; const manager = new HookManagerImplementation(projectRoot, [ examplePlugin, @@ -331,58 +292,19 @@ describe("HookManager", () => { }); describe("dynamic hooks", () => { - describe("runHandlerChain", () => { - let hookManager: HookManager; - - beforeEach(() => { - const manager = new HookManagerImplementation(projectRoot, []); - - const userInterruptionsManager = - new UserInterruptionManagerImplementation(hookManager); - - manager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - hooks: hookManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - interruptions: userInterruptionsManager, - }); + let hre: HardhatRuntimeEnvironment; - hookManager = manager; - }); + beforeEach(async () => { + hre = await HardhatRuntimeEnvironmentImplementation.create({}, {}); + }); + describe("runHandlerChain", () => { it("should return the default implementation if no other handlers are provided", async () => { const notExpectedConfig = {}; - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - const defaultImplementationVersionOfConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const defaultImplementationVersionOfConfig: HardhatUserConfig = {}; - const resultConfig = await hookManager.runHandlerChain( + const resultConfig = await hre.hooks.runHandlerChain( "config", "extendUserConfig", [notExpectedConfig], @@ -397,7 +319,7 @@ describe("HookManager", () => { it("should run the handlers as a chain finishing with the default implementation", async () => { const sequence: string[] = []; - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { extendUserConfig: async ( config: HardhatUserConfig, next: (nextConfig: HardhatUserConfig) => Promise, @@ -410,7 +332,7 @@ describe("HookManager", () => { }, }); - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { extendUserConfig: async ( config: HardhatUserConfig, next: (nextConfig: HardhatUserConfig) => Promise, @@ -423,7 +345,7 @@ describe("HookManager", () => { }, }); - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { extendUserConfig: async ( config: HardhatUserConfig, next: (nextConfig: HardhatUserConfig) => Promise, @@ -436,7 +358,7 @@ describe("HookManager", () => { }, }); - await hookManager.runHandlerChain( + await hre.hooks.runHandlerChain( "config", "extendUserConfig", [{}], @@ -458,21 +380,9 @@ describe("HookManager", () => { }); it("should pass the parameters directly for config hooks", async () => { - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - const expectedConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const expectedConfig: HardhatUserConfig = {}; - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { extendUserConfig: async ( config: HardhatUserConfig, next: (nextConfig: HardhatUserConfig) => Promise, @@ -489,7 +399,7 @@ describe("HookManager", () => { }, }); - const resultConfig = await hookManager.runHandlerChain( + const resultConfig = await hre.hooks.runHandlerChain( "config", "extendUserConfig", [expectedConfig], @@ -513,7 +423,7 @@ describe("HookManager", () => { name: "example", }; - hookManager.registerHandlers("configurationVariables", { + hre.hooks.registerHandlers("configurationVariables", { fetchValue: async ( context: HookContext, variable: ConfigurationVariable, @@ -539,7 +449,7 @@ describe("HookManager", () => { }, }); - const resultValue = await hookManager.runHandlerChain( + const resultValue = await hre.hooks.runHandlerChain( "configurationVariables", "fetchValue", [exampleConfigVar], @@ -576,56 +486,18 @@ describe("HookManager", () => { * } */ describe("runSequentialHandlers", () => { - let hookManager: HookManager; - - beforeEach(() => { - const manager = new HookManagerImplementation(projectRoot, []); - - const userInterruptionsManager = - new UserInterruptionManagerImplementation(hookManager); - - manager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - hooks: hookManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - interruptions: userInterruptionsManager, - }); - - hookManager = manager; - }); - it("Should return the empty set if no handlers are registered", async () => { - const mockHre = buildMockHardhatRuntimeEnvironment( - projectRoot, - hookManager, - ); - - const resultHre = await hookManager.runSequentialHandlers( + const resultHreCreated = await hre.hooks.runSequentialHandlers( "hre", "created", - [mockHre], + [hre], ); - assert.deepEqual(resultHre, []); + assert.deepEqual(resultHreCreated, []); }); it("Should return a return entry per handler", async () => { - hookManager.registerHandlers("hre", { + hre.hooks.registerHandlers("hre", { testExample: async ( _context: HookContext, _input: string, @@ -634,7 +506,7 @@ describe("HookManager", () => { }, } as Partial); - hookManager.registerHandlers("hre", { + hre.hooks.registerHandlers("hre", { testExample: async ( _context: HookContext, _input: string, @@ -643,7 +515,7 @@ describe("HookManager", () => { }, } as Partial); - hookManager.registerHandlers("hre", { + hre.hooks.registerHandlers("hre", { testExample: async ( _context: HookContext, _input: string, @@ -652,7 +524,7 @@ describe("HookManager", () => { }, } as Partial); - const result = await hookManager.runSequentialHandlers( + const result = await hre.hooks.runSequentialHandlers( "hre", "testExample" as keyof HardhatHooks["hre"], ["input"] as any, @@ -662,7 +534,7 @@ describe("HookManager", () => { }); it("Should let handlers access the passed context (for non-config hooks)", async () => { - hookManager.registerHandlers("hre", { + hre.hooks.registerHandlers("hre", { testExample: async ( context: HookContext, input: string, @@ -676,7 +548,7 @@ describe("HookManager", () => { }, } as Partial); - const result = await hookManager.runSequentialHandlers( + const result = await hre.hooks.runSequentialHandlers( "hre", "testExample" as any, ["input"], @@ -686,21 +558,9 @@ describe("HookManager", () => { }); it("Should stop config handlers having access to the hook context", async () => { - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - const expectedConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const expectedConfig: HardhatUserConfig = {}; - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { validateUserConfig: async ( config: HardhatUserConfig, ): Promise => { @@ -714,7 +574,7 @@ describe("HookManager", () => { }, }); - const validationResult = await hookManager.runSequentialHandlers( + const validationResult = await hre.hooks.runSequentialHandlers( "config", "validateUserConfig", [expectedConfig], @@ -725,55 +585,10 @@ describe("HookManager", () => { }); describe("runParallelHandlers", () => { - let hookManager: HookManager; - - beforeEach(() => { - const manager = new HookManagerImplementation(projectRoot, []); - - const userInterruptionsManager = - new UserInterruptionManagerImplementation(hookManager); - - manager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - hooks: hookManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - interruptions: userInterruptionsManager, - }); - - hookManager = manager; - }); - it("Should return an empty result set if no handlers are provided", async () => { - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - const originalConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const originalConfig: HardhatUserConfig = {}; - const results = await hookManager.runParallelHandlers( + const results = await hre.hooks.runParallelHandlers( "config", "validateUserConfig", [originalConfig], @@ -783,21 +598,9 @@ describe("HookManager", () => { }); it("Should return a result per handler", async () => { - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - const originalConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const originalConfig: HardhatUserConfig = {}; - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { validateUserConfig: async ( _config: HardhatUserConfig, ): Promise => { @@ -810,7 +613,7 @@ describe("HookManager", () => { }, }); - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { validateUserConfig: async ( _config: HardhatUserConfig, ): Promise => { @@ -823,7 +626,7 @@ describe("HookManager", () => { }, }); - const results = await hookManager.runParallelHandlers( + const results = await hre.hooks.runParallelHandlers( "config", "validateUserConfig", [originalConfig], @@ -846,52 +649,35 @@ describe("HookManager", () => { }); it("Should pass the context to the handler (for non-config)", async () => { - const mockHre = buildMockHardhatRuntimeEnvironment( - projectRoot, - hookManager, - ); - - hookManager.registerHandlers("hre", { + hre.hooks.registerHandlers("hre", { created: async ( context: HookContext, - hre: HardhatRuntimeEnvironment, + hreInHandler: HardhatRuntimeEnvironment, ): Promise => { assert( context !== null && typeof context === "object", "hook context should be passed", ); - assert.equal(hre, mockHre); + assert.equal(hreInHandler, hre); }, }); - const result = await hookManager.runParallelHandlers("hre", "created", [ - mockHre, + const result = await hre.hooks.runParallelHandlers("hre", "created", [ + hre, ]); assert.deepEqual(result, [undefined]); }); it("Should not pass the hook context for config", async () => { - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - const expectedConfig: HardhatUserConfig = { - plugins: [], - tasks: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any; + const expectedConfig: HardhatUserConfig = {}; const validationError = { path: [], message: "first", }; - hookManager.registerHandlers("config", { + hre.hooks.registerHandlers("config", { validateUserConfig: async ( config: HardhatUserConfig, ): Promise => { @@ -900,7 +686,7 @@ describe("HookManager", () => { }, }); - const results = await hookManager.runParallelHandlers( + const results = await hre.hooks.runParallelHandlers( "config", "validateUserConfig", [expectedConfig], @@ -911,39 +697,6 @@ describe("HookManager", () => { }); describe("unregisterHandlers", () => { - let hookManager: HookManager; - - beforeEach(() => { - const manager = new HookManagerImplementation(projectRoot, []); - - const userInterruptionsManager = - new UserInterruptionManagerImplementation(hookManager); - - manager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - hooks: hookManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - interruptions: userInterruptionsManager, - }); - - hookManager = manager; - }); - it("Should unhook a handler", async () => { const hookCategory = { validateUserConfig: async ( @@ -953,11 +706,11 @@ describe("HookManager", () => { }, }; - hookManager.registerHandlers("config", hookCategory); + hre.hooks.registerHandlers("config", hookCategory); - hookManager.unregisterHandlers("config", hookCategory); + hre.hooks.unregisterHandlers("config", hookCategory); - const results = await hookManager.runParallelHandlers( + const results = await hre.hooks.runParallelHandlers( "config", "validateUserConfig", [ @@ -1013,14 +766,14 @@ describe("HookManager", () => { }; // Arrange - hookManager.registerHandlers("config", firstHook); - hookManager.registerHandlers("config", secondHook); - hookManager.registerHandlers("config", thirdHook); + hre.hooks.registerHandlers("config", firstHook); + hre.hooks.registerHandlers("config", secondHook); + hre.hooks.registerHandlers("config", thirdHook); // Act - hookManager.unregisterHandlers("config", secondHook); + hre.hooks.unregisterHandlers("config", secondHook); - const results = await hookManager.runParallelHandlers( + const results = await hre.hooks.runParallelHandlers( "config", "validateUserConfig", [ @@ -1057,57 +810,8 @@ describe("HookManager", () => { }, }; - hookManager.unregisterHandlers("config", exampleHook); + hre.hooks.unregisterHandlers("config", exampleHook); }); }); }); }); - -function buildMockHardhatRuntimeEnvironment( - projectRoot: string, - hookManager: HookManager, -): HardhatRuntimeEnvironment { - const mockInteruptionManager: UserInterruptionManager = { - displayMessage: async () => {}, - requestInput: async () => "", - requestSecretInput: async () => "", - uninterrupted: async ( - f: () => ReturnT, - ): Promise> => { - /* eslint-disable-next-line @typescript-eslint/return-await, @typescript-eslint/await-thenable -- this is following the pattern in the real implementation */ - return await f(); - }, - }; - - const mockTaskManager: TaskManager = { - getTask: () => { - throw new Error("Method not implemented."); - }, - rootTasks: new Map(), - }; - - const mockHre: HardhatRuntimeEnvironment = { - hooks: hookManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - tasks: mockTaskManager, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - interruptions: mockInteruptionManager, - }; - - return mockHre; -} diff --git a/v-next/hardhat/test/internal/core/tasks/builders.ts b/v-next/hardhat/test/internal/core/tasks/builders.ts index dc7a58c1cb..0d85dee3f6 100644 --- a/v-next/hardhat/test/internal/core/tasks/builders.ts +++ b/v-next/hardhat/test/internal/core/tasks/builders.ts @@ -4,13 +4,13 @@ import { after, before, describe, it } from "node:test"; import { HardhatError } from "@ignored/hardhat-vnext-errors"; import { assertThrowsHardhatError } from "@nomicfoundation/hardhat-test-utils"; -import { ArgumentType } from "../../../../src/config.js"; import { RESERVED_ARGUMENT_NAMES } from "../../../../src/internal/core/arguments.js"; import { EmptyTaskDefinitionBuilderImplementation, NewTaskDefinitionBuilderImplementation, TaskOverrideDefinitionBuilderImplementation, } from "../../../../src/internal/core/tasks/builders.js"; +import { ArgumentType } from "../../../../src/types/arguments.js"; import { TaskDefinitionType } from "../../../../src/types/tasks.js"; describe("Task builders", () => { diff --git a/v-next/hardhat/test/internal/core/tasks/task-manager.ts b/v-next/hardhat/test/internal/core/tasks/task-manager.ts index 33e837fb1a..d73aecc47d 100644 --- a/v-next/hardhat/test/internal/core/tasks/task-manager.ts +++ b/v-next/hardhat/test/internal/core/tasks/task-manager.ts @@ -8,16 +8,14 @@ import { } from "@nomicfoundation/hardhat-test-utils"; import { RESERVED_ARGUMENT_NAMES } from "../../../../src/internal/core/arguments.js"; -import { - ArgumentType, - globalOption, -} from "../../../../src/internal/core/config.js"; -import { createBaseHardhatRuntimeEnvironment } from "../../../../src/internal/core/index.js"; +import { globalOption } from "../../../../src/internal/core/config.js"; +import { HardhatRuntimeEnvironmentImplementation } from "../../../../src/internal/core/hre.js"; import { EmptyTaskDefinitionBuilderImplementation, NewTaskDefinitionBuilderImplementation, TaskOverrideDefinitionBuilderImplementation, } from "../../../../src/internal/core/tasks/builders.js"; +import { ArgumentType } from "../../../../src/types/arguments.js"; import { TaskDefinitionType } from "../../../../src/types/tasks.js"; /** @@ -32,47 +30,50 @@ import { TaskDefinitionType } from "../../../../src/types/tasks.js"; */ describe("TaskManagerImplementation", () => { it("should initialize the task manager with an empty set of tasks if no plugins or tasks are provided", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({}); + const hre = await HardhatRuntimeEnvironmentImplementation.create({}, {}); assert.equal(hre.tasks.rootTasks.size, 0); }); it("should initialize the task manager with the tasks from the plugins", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - new NewTaskDefinitionBuilderImplementation("task2") - .addFlag({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - globalOptions: [ - globalOption({ - name: "globalOption1", - description: "", - type: ArgumentType.STRING, - defaultValue: "", - }), - ], - }, - { - id: "plugin2", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task3") - .addPositionalArgument({ name: "posArg1" }) - .addVariadicArgument({ name: "varArg1" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + new NewTaskDefinitionBuilderImplementation("task2") + .addFlag({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + globalOptions: [ + globalOption({ + name: "globalOption1", + description: "", + type: ArgumentType.STRING, + defaultValue: "", + }), + ], + }, + { + id: "plugin2", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task3") + .addPositionalArgument({ name: "posArg1" }) + .addVariadicArgument({ name: "varArg1" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); // task1 in plugin1 should be available const task1 = hre.tasks.getTask("task1"); @@ -97,23 +98,26 @@ describe("TaskManagerImplementation", () => { }); it("should initialize the task manager with the tasks from the config", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - new NewTaskDefinitionBuilderImplementation("task2") - .addFlag({ name: "flag1" }) - .setAction(() => {}) - .build(), - new NewTaskDefinitionBuilderImplementation("task3") - .addPositionalArgument({ name: "posArg1" }) - .addVariadicArgument({ name: "varArg1" }) - .setAction(() => {}) - .build(), - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + new NewTaskDefinitionBuilderImplementation("task2") + .addFlag({ name: "flag1" }) + .setAction(() => {}) + .build(), + new NewTaskDefinitionBuilderImplementation("task3") + .addPositionalArgument({ name: "posArg1" }) + .addVariadicArgument({ name: "varArg1" }) + .setAction(() => {}) + .build(), + ], + }, + {}, + ); // task1 in plugin1 should be available const task1 = hre.tasks.getTask("task1"); @@ -138,30 +142,33 @@ describe("TaskManagerImplementation", () => { }); it("should override a task within the same plugin", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setDescription("description1") - .addOption({ name: "arg1", defaultValue: "default" }) - .addFlag({ name: "flag1" }) - .addPositionalArgument({ name: "posArg1" }) - .addVariadicArgument({ name: "varArg1" }) - .setAction(() => {}) - .build(), - // overriding task1 with a new description and arguments - new TaskOverrideDefinitionBuilderImplementation("task1") - .setDescription("description2") - .addOption({ name: "arg2", defaultValue: "default" }) - .addFlag({ name: "flag2" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setDescription("description1") + .addOption({ name: "arg1", defaultValue: "default" }) + .addFlag({ name: "flag1" }) + .addPositionalArgument({ name: "posArg1" }) + .addVariadicArgument({ name: "varArg1" }) + .setAction(() => {}) + .build(), + // overriding task1 with a new description and arguments + new TaskOverrideDefinitionBuilderImplementation("task1") + .setDescription("description2") + .addOption({ name: "arg2", defaultValue: "default" }) + .addFlag({ name: "flag2" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.deepEqual(task1.id, ["task1"]); @@ -188,35 +195,38 @@ describe("TaskManagerImplementation", () => { }); it("should override a task from a different plugin", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setDescription("description1") - .addOption({ name: "arg1", defaultValue: "default" }) - .addFlag({ name: "flag1" }) - .addPositionalArgument({ name: "posArg1" }) - .addVariadicArgument({ name: "varArg1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - // overriding task1 with a new description and arguments - new TaskOverrideDefinitionBuilderImplementation("task1") - .setDescription("description2") - .addOption({ name: "arg2", defaultValue: "default" }) - .addFlag({ name: "flag2" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setDescription("description1") + .addOption({ name: "arg1", defaultValue: "default" }) + .addFlag({ name: "flag1" }) + .addPositionalArgument({ name: "posArg1" }) + .addVariadicArgument({ name: "varArg1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + // overriding task1 with a new description and arguments + new TaskOverrideDefinitionBuilderImplementation("task1") + .setDescription("description2") + .addOption({ name: "arg2", defaultValue: "default" }) + .addFlag({ name: "flag2" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.deepEqual(task1.id, ["task1"]); @@ -243,42 +253,45 @@ describe("TaskManagerImplementation", () => { }); it("should override the same task multiple times", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setDescription("description1") - .addOption({ name: "arg1", defaultValue: "default" }) - .addFlag({ name: "flag1" }) - .addPositionalArgument({ name: "posArg1" }) - .addVariadicArgument({ name: "varArg1" }) - .setAction(() => {}) - .build(), - // overriding task1 with a new description and arguments - new TaskOverrideDefinitionBuilderImplementation("task1") - .setDescription("description2") - .addOption({ name: "arg2", defaultValue: "default" }) - .addFlag({ name: "flag2" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - // overriding task1 with a new description and arguments - new TaskOverrideDefinitionBuilderImplementation("task1") - .setDescription("description3") - .addOption({ name: "arg3", defaultValue: "default" }) - .addFlag({ name: "flag3" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setDescription("description1") + .addOption({ name: "arg1", defaultValue: "default" }) + .addFlag({ name: "flag1" }) + .addPositionalArgument({ name: "posArg1" }) + .addVariadicArgument({ name: "varArg1" }) + .setAction(() => {}) + .build(), + // overriding task1 with a new description and arguments + new TaskOverrideDefinitionBuilderImplementation("task1") + .setDescription("description2") + .addOption({ name: "arg2", defaultValue: "default" }) + .addFlag({ name: "flag2" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + // overriding task1 with a new description and arguments + new TaskOverrideDefinitionBuilderImplementation("task1") + .setDescription("description3") + .addOption({ name: "arg3", defaultValue: "default" }) + .addFlag({ name: "flag3" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.deepEqual(task1.id, ["task1"]); @@ -308,19 +321,22 @@ describe("TaskManagerImplementation", () => { }); it("should add an empty task", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new EmptyTaskDefinitionBuilderImplementation( - "task1", - "description1", - ).build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new EmptyTaskDefinitionBuilderImplementation( + "task1", + "description1", + ).build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.deepEqual(task1.id, ["task1"]); @@ -328,37 +344,40 @@ describe("TaskManagerImplementation", () => { }); it("should add subtasks", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new EmptyTaskDefinitionBuilderImplementation( - "task1", - "description1", - ).build(), - // adds a subtask to the empty task - new NewTaskDefinitionBuilderImplementation(["task1", "subtask1"]) - .setAction(() => {}) - .build(), - ], - }, + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new EmptyTaskDefinitionBuilderImplementation( + "task1", + "description1", + ).build(), + // adds a subtask to the empty task + new NewTaskDefinitionBuilderImplementation(["task1", "subtask1"]) + .setAction(() => {}) + .build(), + ], + }, - { - id: "plugin2", - tasks: [ - // adds a subtask to the non-empty task - new NewTaskDefinitionBuilderImplementation([ - "task1", - "subtask1", - "subsubtask1", - ]) - .setAction(() => {}) - .build(), - ], - }, - ], - }); + { + id: "plugin2", + tasks: [ + // adds a subtask to the non-empty task + new NewTaskDefinitionBuilderImplementation([ + "task1", + "subtask1", + "subsubtask1", + ]) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.deepEqual(task1.id, ["task1"]); @@ -385,30 +404,33 @@ describe("TaskManagerImplementation", () => { describe("errors", () => { it("should throw if there's a global option with the same name as a task option", async () => { await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - globalOptions: [ - globalOption({ - name: "arg1", - description: "", - type: ArgumentType.STRING, - defaultValue: "", - }), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + globalOptions: [ + globalOption({ + name: "arg1", + description: "", + type: ArgumentType.STRING, + defaultValue: "", + }), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.TASK_OPTION_ALREADY_DEFINED, { @@ -422,31 +444,34 @@ describe("TaskManagerImplementation", () => { it("should throw if there's a global option with the same name as a task positional argument", async () => { await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addPositionalArgument({ name: "arg1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - globalOptions: [ - globalOption({ - name: "arg1", - description: "", - type: ArgumentType.STRING, - defaultValue: "", - }), - ], - }, - ], - }), - + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addPositionalArgument({ name: "arg1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + globalOptions: [ + globalOption({ + name: "arg1", + description: "", + type: ArgumentType.STRING, + defaultValue: "", + }), + ], + }, + ], + }, + {}, + ), + HardhatError.ERRORS.TASK_DEFINITIONS.TASK_OPTION_ALREADY_DEFINED, { actorFragment: "Plugin plugin1 is", @@ -459,24 +484,27 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to add a task with an empty id", async () => { await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - // Manually creating a task as the builder doesn't allow empty ids - { - type: TaskDefinitionType.NEW_TASK, - id: [], // empty id - description: "", - action: () => {}, - options: {}, - positionalArguments: [], - }, - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + // Manually creating a task as the builder doesn't allow empty ids + { + type: TaskDefinitionType.NEW_TASK, + id: [], // empty id + description: "", + action: () => {}, + options: {}, + positionalArguments: [], + }, + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.EMPTY_TASK_ID, {}, ); @@ -484,22 +512,25 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to add a subtask for a task that doesn't exist", async () => { await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation([ - "task1", - "subtask1", - ]) - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation([ + "task1", + "subtask1", + ]) + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.SUBTASK_WITHOUT_PARENT, { task: "task1", @@ -510,28 +541,31 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to add a task that already exists", async () => { await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg2", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg2", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.TASK_ALREADY_DEFINED, { actorFragment: "Plugin plugin2 is", @@ -544,18 +578,21 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to override a task that doesn't exist", async () => { // task1 will not be found as it's not defined await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.TASK_NOT_FOUND, { task: "task1", @@ -566,28 +603,31 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to override a task and there is a name clash with an existing option", async () => { // added argument clash with an existing option await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -599,28 +639,31 @@ describe("TaskManagerImplementation", () => { // added flag clash with an existing option await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addFlag({ name: "arg1" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addFlag({ name: "arg1" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -634,28 +677,31 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to override a task and there is a name clash with an exising flag argument", async () => { // added argument clash with an existing flag await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addFlag({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addOption({ name: "flag1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addFlag({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addOption({ name: "flag1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -667,28 +713,31 @@ describe("TaskManagerImplementation", () => { // added flag clash with an existing flag await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addFlag({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addFlag({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addFlag({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addFlag({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -702,28 +751,31 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to override a task and there is a name clash with an exising positional argument", async () => { // added argument clash with an existing positional argument await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addPositionalArgument({ name: "arg1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addPositionalArgument({ name: "arg1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -735,28 +787,31 @@ describe("TaskManagerImplementation", () => { // added flag clash with an existing positional argument await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addPositionalArgument({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addFlag({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addPositionalArgument({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addFlag({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -770,28 +825,31 @@ describe("TaskManagerImplementation", () => { it("should throw if trying to override a task and there is a name clash with an exising variadic argument", async () => { // added argument clash with an existing variadic argument await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addVariadicArgument({ name: "arg1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addVariadicArgument({ name: "arg1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -803,28 +861,31 @@ describe("TaskManagerImplementation", () => { // added flag clash with an existing variadic argument await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addVariadicArgument({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .addFlag({ name: "flag1" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addVariadicArgument({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .addFlag({ name: "flag1" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS .TASK_OVERRIDE_OPTION_ALREADY_DEFINED, { @@ -839,23 +900,26 @@ describe("TaskManagerImplementation", () => { // this will fail as the config tasks are processed after // the plugin tasks so the override logic will not find task1 await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => {}) - .build(), - ], - plugins: [ - { - id: "plugin1", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(() => {}) - .build(), - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => {}) + .build(), + ], + plugins: [ + { + id: "plugin1", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.TASK_NOT_FOUND, { task: "task1", @@ -866,63 +930,72 @@ describe("TaskManagerImplementation", () => { describe("plain object validations", () => { it("should throw if the task definition object has an empty id", async () => { await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.EMPTY_TASK, - id: [], - description: "", - }, - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.EMPTY_TASK, + id: [], + description: "", + }, + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.EMPTY_TASK_ID, {}, ); await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.NEW_TASK, - id: [], - description: "", - action: () => {}, - options: {}, - positionalArguments: [], - }, - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.NEW_TASK, + id: [], + description: "", + action: () => {}, + options: {}, + positionalArguments: [], + }, + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.EMPTY_TASK_ID, {}, ); await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.TASK_OVERRIDE, - id: [], - description: "", - action: () => {}, - options: {}, - }, - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.TASK_OVERRIDE, + id: [], + description: "", + action: () => {}, + options: {}, + }, + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.EMPTY_TASK_ID, {}, ); @@ -931,23 +1004,26 @@ describe("TaskManagerImplementation", () => { it("should throw if the task definition object has an invalid action file URL", async () => { const invalidActionFileUrl = "not-a-valid-file-url"; await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.NEW_TASK, - id: ["task-id"], - description: "", - action: invalidActionFileUrl, - options: {}, - positionalArguments: [], - }, - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.NEW_TASK, + id: ["task-id"], + description: "", + action: invalidActionFileUrl, + options: {}, + positionalArguments: [], + }, + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.INVALID_FILE_ACTION, { action: invalidActionFileUrl, @@ -955,22 +1031,25 @@ describe("TaskManagerImplementation", () => { ); await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.TASK_OVERRIDE, - id: ["task-id"], - description: "", - action: invalidActionFileUrl, - options: {}, - }, - ], - }, - ], - }), + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.TASK_OVERRIDE, + id: ["task-id"], + description: "", + action: invalidActionFileUrl, + options: {}, + }, + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.INVALID_FILE_ACTION, { action: invalidActionFileUrl, @@ -981,30 +1060,33 @@ describe("TaskManagerImplementation", () => { it("should throw if the task definition object has an option with an invalid name", async () => { const invalidName = "invalid-name"; await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.NEW_TASK, - id: ["task-id"], - description: "", - action: () => {}, - options: { - [invalidName]: { - name: invalidName, - description: "A description", - type: ArgumentType.STRING, - defaultValue: "default", + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.NEW_TASK, + id: ["task-id"], + description: "", + action: () => {}, + options: { + [invalidName]: { + name: invalidName, + description: "A description", + type: ArgumentType.STRING, + defaultValue: "default", + }, }, + positionalArguments: [], }, - positionalArguments: [], - }, - ], - }, - ], - }), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.ARGUMENTS.INVALID_NAME, { name: invalidName, @@ -1012,29 +1094,32 @@ describe("TaskManagerImplementation", () => { ); await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.TASK_OVERRIDE, - id: ["task-id"], - description: "", - action: () => {}, - options: { - [invalidName]: { - name: invalidName, - description: "A description", - type: ArgumentType.STRING, - defaultValue: "default", + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.TASK_OVERRIDE, + id: ["task-id"], + description: "", + action: () => {}, + options: { + [invalidName]: { + name: invalidName, + description: "A description", + type: ArgumentType.STRING, + defaultValue: "default", + }, }, }, - }, - ], - }, - ], - }), + ], + }, + ], + }, + {}, + ), HardhatError.ERRORS.ARGUMENTS.INVALID_NAME, { name: invalidName, @@ -1045,7 +1130,79 @@ describe("TaskManagerImplementation", () => { it("should throw if the task definition object has an option with an reserved name", async () => { RESERVED_ARGUMENT_NAMES.forEach(async (reservedName) => { await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.NEW_TASK, + id: ["task-id"], + description: "", + action: () => {}, + options: { + [reservedName]: { + name: reservedName, + description: "A description", + type: ArgumentType.STRING, + defaultValue: "default", + }, + }, + positionalArguments: [], + }, + ], + }, + ], + }, + {}, + ), + HardhatError.ERRORS.ARGUMENTS.RESERVED_NAME, + { + name: reservedName, + }, + ); + + await assertRejectsWithHardhatError( + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.TASK_OVERRIDE, + id: ["task-id"], + description: "", + action: () => {}, + options: { + [reservedName]: { + name: reservedName, + description: "A description", + type: ArgumentType.STRING, + defaultValue: "default", + }, + }, + }, + ], + }, + ], + }, + {}, + ), + HardhatError.ERRORS.ARGUMENTS.RESERVED_NAME, + { + name: reservedName, + }, + ); + }); + }); + + it("should throw if the task definition object has arguments with an duplicated name", async () => { + const duplicatedName = "duplicatedName"; + await assertRejectsWithHardhatError( + HardhatRuntimeEnvironmentImplementation.create( + { plugins: [ { id: "plugin1", @@ -1056,173 +1213,154 @@ describe("TaskManagerImplementation", () => { description: "", action: () => {}, options: { - [reservedName]: { - name: reservedName, + [duplicatedName]: { + name: duplicatedName, description: "A description", type: ArgumentType.STRING, defaultValue: "default", }, }, - positionalArguments: [], + positionalArguments: [ + { + name: duplicatedName, + description: "A description", + type: ArgumentType.STRING, + isVariadic: false, + }, + ], }, ], }, ], - }), - HardhatError.ERRORS.ARGUMENTS.RESERVED_NAME, - { - name: reservedName, }, - ); + {}, + ), + HardhatError.ERRORS.ARGUMENTS.DUPLICATED_NAME, + { + name: duplicatedName, + }, + ); - await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ + await assertRejectsWithHardhatError( + HardhatRuntimeEnvironmentImplementation.create( + { plugins: [ { id: "plugin1", tasks: [ { - type: TaskDefinitionType.TASK_OVERRIDE, + type: TaskDefinitionType.NEW_TASK, id: ["task-id"], description: "", action: () => {}, - options: { - [reservedName]: { - name: reservedName, + options: {}, + positionalArguments: [ + { + name: duplicatedName, description: "A description", type: ArgumentType.STRING, - defaultValue: "default", + isVariadic: false, }, - }, + { + name: duplicatedName, + description: "A description", + type: ArgumentType.STRING, + isVariadic: false, + }, + ], }, ], }, ], - }), - HardhatError.ERRORS.ARGUMENTS.RESERVED_NAME, - { - name: reservedName, }, - ); - }); - }); - - it("should throw if the task definition object has arguments with an duplicated name", async () => { - const duplicatedName = "duplicatedName"; - await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.NEW_TASK, - id: ["task-id"], - description: "", - action: () => {}, - options: { - [duplicatedName]: { - name: duplicatedName, - description: "A description", - type: ArgumentType.STRING, - defaultValue: "default", - }, - }, - positionalArguments: [ - { - name: duplicatedName, - description: "A description", - type: ArgumentType.STRING, - isVariadic: false, - }, - ], - }, - ], - }, - ], - }), + {}, + ), HardhatError.ERRORS.ARGUMENTS.DUPLICATED_NAME, { name: duplicatedName, }, ); + }); + it("should throw if the task definition object has a positional argument with an invalid name", async () => { + const invalidName = "invalid-name"; await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.NEW_TASK, - id: ["task-id"], - description: "", - action: () => {}, - options: {}, - positionalArguments: [ - { - name: duplicatedName, - description: "A description", - type: ArgumentType.STRING, - isVariadic: false, - }, - { - name: duplicatedName, - description: "A description", - type: ArgumentType.STRING, - isVariadic: false, - }, - ], - }, - ], - }, - ], - }), - HardhatError.ERRORS.ARGUMENTS.DUPLICATED_NAME, + HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + { + type: TaskDefinitionType.NEW_TASK, + id: ["task-id"], + description: "", + action: () => {}, + options: {}, + positionalArguments: [ + { + name: invalidName, + description: "A description", + type: ArgumentType.STRING, + isVariadic: false, + }, + ], + }, + ], + }, + ], + }, + {}, + ), + HardhatError.ERRORS.ARGUMENTS.INVALID_NAME, { - name: duplicatedName, + name: invalidName, }, ); }); - it("should throw if the task definition object has a positional argument with an invalid name", async () => { - const invalidName = "invalid-name"; - await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ + it("should throw if the task definition object has a positional argument with an reserved name", async () => { + RESERVED_ARGUMENT_NAMES.forEach(async (reservedName) => { + await assertRejectsWithHardhatError( + HardhatRuntimeEnvironmentImplementation.create( { - id: "plugin1", - tasks: [ + plugins: [ { - type: TaskDefinitionType.NEW_TASK, - id: ["task-id"], - description: "", - action: () => {}, - options: {}, - positionalArguments: [ + id: "plugin1", + tasks: [ { - name: invalidName, - description: "A description", - type: ArgumentType.STRING, - isVariadic: false, + type: TaskDefinitionType.NEW_TASK, + id: ["task-id"], + description: "", + action: () => {}, + options: {}, + positionalArguments: [ + { + name: reservedName, + description: "A description", + type: ArgumentType.STRING, + isVariadic: false, + }, + ], }, ], }, ], }, - ], - }), - HardhatError.ERRORS.ARGUMENTS.INVALID_NAME, - { - name: invalidName, - }, - ); + {}, + ), + HardhatError.ERRORS.ARGUMENTS.RESERVED_NAME, + { + name: reservedName, + }, + ); + }); }); - it("should throw if the task definition object has a positional argument with an reserved name", async () => { - RESERVED_ARGUMENT_NAMES.forEach(async (reservedName) => { - await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ + it("should throw if the task definition object has a required positional argument after an optional argument", async () => { + await assertRejectsWithHardhatError( + HardhatRuntimeEnvironmentImplementation.create( + { plugins: [ { id: "plugin1", @@ -1235,7 +1373,14 @@ describe("TaskManagerImplementation", () => { options: {}, positionalArguments: [ { - name: reservedName, + name: "posArg", + description: "A description", + type: ArgumentType.STRING, + isVariadic: false, + defaultValue: "default", + }, + { + name: "posArg2", description: "A description", type: ArgumentType.STRING, isVariadic: false, @@ -1245,48 +1390,9 @@ describe("TaskManagerImplementation", () => { ], }, ], - }), - HardhatError.ERRORS.ARGUMENTS.RESERVED_NAME, - { - name: reservedName, }, - ); - }); - }); - - it("should throw if the task definition object has a required positional argument after an optional argument", async () => { - await assertRejectsWithHardhatError( - createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - { - type: TaskDefinitionType.NEW_TASK, - id: ["task-id"], - description: "", - action: () => {}, - options: {}, - positionalArguments: [ - { - name: "posArg", - description: "A description", - type: ArgumentType.STRING, - isVariadic: false, - defaultValue: "default", - }, - { - name: "posArg2", - description: "A description", - type: ArgumentType.STRING, - isVariadic: false, - }, - ], - }, - ], - }, - ], - }), + {}, + ), HardhatError.ERRORS.TASK_DEFINITIONS.REQUIRED_ARG_AFTER_OPTIONAL, { name: "posArg2", @@ -1298,23 +1404,26 @@ describe("TaskManagerImplementation", () => { describe("getTask", () => { it("should return the task if it exists", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => {}) - .build(), - ], - }, - ], - tasks: [ - new NewTaskDefinitionBuilderImplementation("task2") - .setAction(() => {}) - .build(), - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => {}) + .build(), + ], + }, + ], + tasks: [ + new NewTaskDefinitionBuilderImplementation("task2") + .setAction(() => {}) + .build(), + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.deepEqual(task1.id, ["task1"]); @@ -1326,7 +1435,7 @@ describe("TaskManagerImplementation", () => { }); it("should throw if the task doesn't exist", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({}); + const hre = await HardhatRuntimeEnvironmentImplementation.create({}, {}); // task1 will not be found as it's not defined assertThrowsHardhatError( () => hre.tasks.getTask("task1"), @@ -1345,40 +1454,46 @@ describe("TaskManagerImplementation", () => { describe("run", () => { it("should run a task without arguments", async () => { let taskRun = false; - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => { - taskRun = true; - }) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => { + taskRun = true; + }) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.equal(taskRun, false); - await task1.run({}); - assert.equal(taskRun, true); - }); - - it("should return the result of the task action", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => "task run successfully") - .build(), - ], - }, - ], - }); + await task1.run({}); + assert.equal(taskRun, true); + }); + + it("should return the result of the task action", async () => { + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => "task run successfully") + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); const result = await task1.run({}); @@ -1388,26 +1503,29 @@ describe("TaskManagerImplementation", () => { it("should run a overridden task without arguments", async () => { let taskRun = false; let overrideTaskRun = false; - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => { - taskRun = true; - }) - .build(), - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(async (args, _hre, runSuper) => { - await runSuper(args); - overrideTaskRun = true; - }) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => { + taskRun = true; + }) + .build(), + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(async (args, _hre, runSuper) => { + await runSuper(args); + overrideTaskRun = true; + }) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.equal(taskRun, false); @@ -1422,45 +1540,48 @@ describe("TaskManagerImplementation", () => { let override1TaskRun = false; let override2TaskRun = false; let override3TaskRun = false; - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => { - taskRun = true; - }) - .build(), - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(async (args, _hre, runSuper) => { - await runSuper(args); - override1TaskRun = true; - }) - .build(), - ], - }, - { - id: "plugin2", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(async (args, _hre, runSuper) => { - await runSuper(args); - override2TaskRun = true; - }) - .build(), - ], - }, - ], - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(async (args, _hre, runSuper) => { - await runSuper(args); - override3TaskRun = true; - }) - .build(), - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => { + taskRun = true; + }) + .build(), + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(async (args, _hre, runSuper) => { + await runSuper(args); + override1TaskRun = true; + }) + .build(), + ], + }, + { + id: "plugin2", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(async (args, _hre, runSuper) => { + await runSuper(args); + override2TaskRun = true; + }) + .build(), + ], + }, + ], + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(async (args, _hre, runSuper) => { + await runSuper(args); + override3TaskRun = true; + }) + .build(), + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.equal(taskRun, false); @@ -1477,25 +1598,28 @@ describe("TaskManagerImplementation", () => { it("should not run the original task action if the override task action doesn't call runSuper", async () => { let taskRun = false; let overrideTaskRun = false; - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => { - taskRun = true; - }) - .build(), - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(async (_args, _hre, _runSuper) => { - overrideTaskRun = true; - }) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => { + taskRun = true; + }) + .build(), + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(async (_args, _hre, _runSuper) => { + overrideTaskRun = true; + }) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.equal(taskRun, false); @@ -1506,45 +1630,50 @@ describe("TaskManagerImplementation", () => { }); it("should run a task with arguments", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .addOption({ name: "withDefault", defaultValue: "default" }) - .addFlag({ name: "flag1" }) - .addPositionalArgument({ name: "posArg" }) - .addVariadicArgument({ name: "varArg" }) - .setAction((args) => { - assert.deepEqual(args, { - arg1: "arg1Value", - flag1: true, - posArg: "posValue", - varArg: ["varValue1", "varValue2"], - withDefault: "default", - }); - }) - .build(), - new TaskOverrideDefinitionBuilderImplementation("task1") - .addOption({ name: "arg2", defaultValue: "default" }) - .addFlag({ name: "flag2" }) - .setAction(async ({ arg2, flag2, ...args }, _hre, runSuper) => { - await runSuper(args); - assert.deepEqual( - { arg2, flag2 }, - { - arg2: "arg2Value", - flag2: true, + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .addOption({ name: "withDefault", defaultValue: "default" }) + .addFlag({ name: "flag1" }) + .addPositionalArgument({ name: "posArg" }) + .addVariadicArgument({ name: "varArg" }) + .setAction((args) => { + assert.deepEqual(args, { + arg1: "arg1Value", + flag1: true, + posArg: "posValue", + varArg: ["varValue1", "varValue2"], + withDefault: "default", + }); + }) + .build(), + new TaskOverrideDefinitionBuilderImplementation("task1") + .addOption({ name: "arg2", defaultValue: "default" }) + .addFlag({ name: "flag2" }) + .setAction( + async ({ arg2, flag2, ...args }, _hre, runSuper) => { + await runSuper(args); + assert.deepEqual( + { arg2, flag2 }, + { + arg2: "arg2Value", + flag2: true, + }, + ); }, - ); - }) - .build(), - ], - }, - ], - }); + ) + .build(), + ], + }, + ], + }, + {}, + ); // withDefault option is intentionally omitted const providedArgs = { arg1: "arg1Value", @@ -1573,38 +1702,41 @@ describe("TaskManagerImplementation", () => { }); it("should run a task with arguments and resolve their default values", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ - name: "arg1", - defaultValue: "arg1DefaultValue", - }) - .addFlag({ name: "flag1" }) - .addPositionalArgument({ - name: "posArg", - defaultValue: "posValue", - }) - .addVariadicArgument({ - name: "varArg", - defaultValue: ["varValue1", "varValue2"], - }) - .setAction((args) => { - assert.deepEqual(args, { - arg1: "arg1DefaultValue", - flag1: false, - posArg: "posValue", - varArg: ["varValue1", "varValue2"], - }); - }) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ + name: "arg1", + defaultValue: "arg1DefaultValue", + }) + .addFlag({ name: "flag1" }) + .addPositionalArgument({ + name: "posArg", + defaultValue: "posValue", + }) + .addVariadicArgument({ + name: "varArg", + defaultValue: ["varValue1", "varValue2"], + }) + .setAction((args) => { + assert.deepEqual(args, { + arg1: "arg1DefaultValue", + flag1: false, + posArg: "posValue", + varArg: ["varValue1", "varValue2"], + }); + }) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); await task1.run({}); @@ -1612,25 +1744,28 @@ describe("TaskManagerImplementation", () => { it("should run an empty task that was overriden", async () => { let overrideTaskRun = false; - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new EmptyTaskDefinitionBuilderImplementation( - "task1", - "description1", - ).build(), - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(async (args, _hre, runSuper) => { - await runSuper(args); - overrideTaskRun = true; - }) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new EmptyTaskDefinitionBuilderImplementation( + "task1", + "description1", + ).build(), + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(async (args, _hre, runSuper) => { + await runSuper(args); + overrideTaskRun = true; + }) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); assert.equal(overrideTaskRun, false); @@ -1643,22 +1778,25 @@ describe("TaskManagerImplementation", () => { "./fixture-projects/file-actions/action-fn.js", ); - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction((args) => args) - .build(), - new TaskOverrideDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(actionUrl) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction((args) => args) + .build(), + new TaskOverrideDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(actionUrl) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); const response = await task1.run({ arg1: "arg1Value" }); @@ -1670,22 +1808,25 @@ describe("TaskManagerImplementation", () => { "./fixture-projects/file-actions/no-run-super.js", ); - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction("file://not-a-module") - .build(), - new TaskOverrideDefinitionBuilderImplementation("task1") - .addOption({ name: "arg1", defaultValue: "default" }) - .setAction(validActionUrl) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction("file://not-a-module") + .build(), + new TaskOverrideDefinitionBuilderImplementation("task1") + .addOption({ name: "arg1", defaultValue: "default" }) + .setAction(validActionUrl) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); const response = await task1.run({ arg1: "arg1Value" }); @@ -1697,19 +1838,22 @@ describe("TaskManagerImplementation", () => { describe("validations", () => { it("should throw if the task is empty", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new EmptyTaskDefinitionBuilderImplementation( - "task1", - "description1", - ).build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new EmptyTaskDefinitionBuilderImplementation( + "task1", + "description1", + ).build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); await assertRejectsWithHardhatError( @@ -1722,18 +1866,21 @@ describe("TaskManagerImplementation", () => { }); it("should throw if the provided argument is not one of the task arguments", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => {}) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); await assertRejectsWithHardhatError( @@ -1747,20 +1894,23 @@ describe("TaskManagerImplementation", () => { }); it("should throw if a required argument is missing", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addPositionalArgument({ name: "posArg" }) - .addVariadicArgument({ name: "varArg" }) - .setAction(() => {}) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addPositionalArgument({ name: "posArg" }) + .addVariadicArgument({ name: "varArg" }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); @@ -1792,31 +1942,34 @@ describe("TaskManagerImplementation", () => { }); it("should throw if the provided value for the argument is not of the correct type", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .addOption({ - name: "option", - type: ArgumentType.BIGINT, - defaultValue: 1n, - }) - .addPositionalArgument({ - name: "posArg", - type: ArgumentType.INT, - }) - .addVariadicArgument({ - name: "varArg", - type: ArgumentType.FILE, - }) - .setAction(() => {}) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .addOption({ + name: "option", + type: ArgumentType.BIGINT, + defaultValue: 1n, + }) + .addPositionalArgument({ + name: "posArg", + type: ArgumentType.INT, + }) + .addVariadicArgument({ + name: "varArg", + type: ArgumentType.FILE, + }) + .setAction(() => {}) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); @@ -1886,18 +2039,21 @@ describe("TaskManagerImplementation", () => { }); it("should throw if an action url is provided but the corresponding module can't be resolved", async () => { - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction("file://not-a-module") - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction("file://not-a-module") + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); await assertRejectsWithHardhatError( @@ -1921,19 +2077,22 @@ describe("TaskManagerImplementation", () => { ); // the missing dependency is used in the NEW_TASK action - let hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - npmPackage: "non-installed-package", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(nonInstalledPackageActionUrl) - .build(), - ], - }, - ], - }); + let hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + npmPackage: "non-installed-package", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(nonInstalledPackageActionUrl) + .build(), + ], + }, + ], + }, + {}, + ); await assertRejectsWithHardhatError( hre.tasks.getTask("task1").run({}), @@ -1944,27 +2103,30 @@ describe("TaskManagerImplementation", () => { ); // the missing dependency is used in the TASK_OVERRIDE action - hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(() => {}) - .build(), - ], - }, - { - id: "plugin2", - npmPackage: "non-installed-package", - tasks: [ - new TaskOverrideDefinitionBuilderImplementation("task1") - .setAction(nonInstalledPackageActionUrl) - .build(), - ], - }, - ], - }); + hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(() => {}) + .build(), + ], + }, + { + id: "plugin2", + npmPackage: "non-installed-package", + tasks: [ + new TaskOverrideDefinitionBuilderImplementation("task1") + .setAction(nonInstalledPackageActionUrl) + .build(), + ], + }, + ], + }, + {}, + ); await assertRejectsWithHardhatError( hre.tasks.getTask("task1").run({}), @@ -1980,18 +2142,21 @@ describe("TaskManagerImplementation", () => { "./fixture-projects/file-actions/no-default.js", ); - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(actionUrl) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(actionUrl) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); await assertRejectsWithHardhatError( @@ -2009,18 +2174,21 @@ describe("TaskManagerImplementation", () => { "./fixture-projects/file-actions/no-default-fn.js", ); - const hre = await createBaseHardhatRuntimeEnvironment({ - plugins: [ - { - id: "plugin1", - tasks: [ - new NewTaskDefinitionBuilderImplementation("task1") - .setAction(actionUrl) - .build(), - ], - }, - ], - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create( + { + plugins: [ + { + id: "plugin1", + tasks: [ + new NewTaskDefinitionBuilderImplementation("task1") + .setAction(actionUrl) + .build(), + ], + }, + ], + }, + {}, + ); const task1 = hre.tasks.getTask("task1"); await assertRejectsWithHardhatError( diff --git a/v-next/hardhat/test/internal/core/user-interruptions/user-interruptions-manager.ts b/v-next/hardhat/test/internal/core/user-interruptions/user-interruptions-manager.ts index 0c8382ed4c..ea35bc653e 100644 --- a/v-next/hardhat/test/internal/core/user-interruptions/user-interruptions-manager.ts +++ b/v-next/hardhat/test/internal/core/user-interruptions/user-interruptions-manager.ts @@ -1,50 +1,14 @@ import type { UserInterruptionHooks } from "../../../../src/types/hooks.js"; import assert from "node:assert/strict"; -import { before, describe, it } from "node:test"; +import { describe, it } from "node:test"; -import { HookManagerImplementation } from "../../../../src/internal/core/hook-manager.js"; -import { resolveProjectRoot } from "../../../../src/internal/core/index.js"; -import { UserInterruptionManagerImplementation } from "../../../../src/internal/core/user-interruptions.js"; +import { HardhatRuntimeEnvironmentImplementation } from "../../../../src/internal/core/hre.js"; describe("UserInterruptionManager", () => { - let projectRoot: string; - - before(async () => { - projectRoot = await resolveProjectRoot(process.cwd()); - }); - describe("displayMessage", () => { it("Should call a dynamic handler with a given message from an interruptor", async () => { - const hookManager = new HookManagerImplementation(projectRoot, []); - const userInterruptionManager = new UserInterruptionManagerImplementation( - hookManager, - ); - - // TODO: Setting the context like this is a bit fragile. If this test - // breaks we should probably switch to initializing an entire HRE in these - // tests. - hookManager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - hooks: hookManager, - interruptions: userInterruptionManager, - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create({}, {}); let called = false; let givenInterruptor: string = ""; @@ -58,9 +22,9 @@ describe("UserInterruptionManager", () => { }, }; - hookManager.registerHandlers("userInterruptions", handlers); + hre.hooks.registerHandlers("userInterruptions", handlers); - await userInterruptionManager.displayMessage( + await hre.interruptions.displayMessage( "test-interruptor", "test-message", ); @@ -73,31 +37,7 @@ describe("UserInterruptionManager", () => { describe("requestInput", () => { it("Should call a dynamic handler with a given input description from an interruptor", async () => { - const hookManager = new HookManagerImplementation(projectRoot, []); - const userInterruptionManager = new UserInterruptionManagerImplementation( - hookManager, - ); - hookManager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - hooks: hookManager, - interruptions: userInterruptionManager, - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create({}, {}); let called = false; let givenInterruptor: string = ""; @@ -112,9 +52,9 @@ describe("UserInterruptionManager", () => { }, }; - hookManager.registerHandlers("userInterruptions", handlers); + hre.hooks.registerHandlers("userInterruptions", handlers); - const input = await userInterruptionManager.requestInput( + const input = await hre.interruptions.requestInput( "test-interruptor", "test-input-description", ); @@ -128,31 +68,7 @@ describe("UserInterruptionManager", () => { describe("requestSecretInput", () => { it("Should call a dynamic handler with a given input description from an interruptor", async () => { - const hookManager = new HookManagerImplementation(projectRoot, []); - const userInterruptionManager = new UserInterruptionManagerImplementation( - hookManager, - ); - hookManager.setContext({ - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - config: { - tasks: [], - plugins: [], - paths: { - root: projectRoot, - cache: "", - artifacts: "", - tests: "", - }, - } as any, - /* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- - TODO: This is a temporary fix to land a refactor sooner without creating - more merge conflicts than needed. It will be fixed in a subsequent PR */ - globalOptions: {} as any, - hooks: hookManager, - interruptions: userInterruptionManager, - }); + const hre = await HardhatRuntimeEnvironmentImplementation.create({}, {}); let called = false; let givenInterruptor: string = ""; @@ -167,9 +83,9 @@ describe("UserInterruptionManager", () => { }, }; - hookManager.registerHandlers("userInterruptions", handlers); + hre.hooks.registerHandlers("userInterruptions", handlers); - const input = await userInterruptionManager.requestSecretInput( + const input = await hre.interruptions.requestSecretInput( "test-interruptor", "test-input-description", ); diff --git a/v-next/hardhat/test/internal/core/global-dir.ts b/v-next/hardhat/test/internal/global-dir.ts similarity index 86% rename from v-next/hardhat/test/internal/core/global-dir.ts rename to v-next/hardhat/test/internal/global-dir.ts index a909267a33..0153190378 100644 --- a/v-next/hardhat/test/internal/core/global-dir.ts +++ b/v-next/hardhat/test/internal/global-dir.ts @@ -1,7 +1,7 @@ import assert from "node:assert/strict"; import { describe, it } from "node:test"; -import { getConfigDir } from "../../../src/internal/core/global-dir.js"; +import { getConfigDir } from "../../src/internal/global-dir.js"; describe("global-dir", () => { describe("getGlobalDir", () => { diff --git a/v-next/hardhat/test/hre/index.ts b/v-next/hardhat/test/internal/hre-intialization.ts similarity index 73% rename from v-next/hardhat/test/hre/index.ts rename to v-next/hardhat/test/internal/hre-intialization.ts index 5a3722921a..1e934ec77d 100644 --- a/v-next/hardhat/test/hre/index.ts +++ b/v-next/hardhat/test/internal/hre-intialization.ts @@ -2,21 +2,25 @@ import assert from "node:assert/strict"; import { afterEach, describe, it } from "node:test"; import { HardhatError } from "@ignored/hardhat-vnext-errors"; +import { getRealPath } from "@ignored/hardhat-vnext-utils/fs"; import { assertRejectsWithHardhatError, useFixtureProject, } from "@nomicfoundation/hardhat-test-utils"; -import { resolveHardhatConfigPath } from "../../src/config.js"; -import { createHardhatRuntimeEnvironment } from "../../src/hre.js"; import { builtinPlugins } from "../../src/internal/builtin-plugins/index.js"; +import { resolveHardhatConfigPath } from "../../src/internal/config-loading.js"; import { getGlobalHardhatRuntimeEnvironment, resetGlobalHardhatRuntimeEnvironment, setGlobalHardhatRuntimeEnvironment, } from "../../src/internal/global-hre-instance.js"; +import { + createHardhatRuntimeEnvironment, + getOrCreateGlobalHardhatRuntimeEnvironment, +} from "../../src/internal/hre-intialization.js"; -describe("HRE", () => { +describe("HRE intialization", () => { afterEach(() => { resetGlobalHardhatRuntimeEnvironment(); }); @@ -58,12 +62,39 @@ describe("HRE", () => { describe("config loading", () => { describe("resolveConfigPath", async () => { - it("should return the HARDHAT_CONFIG env variable if it is set", async () => { - process.env.HARDHAT_CONFIG = "env.config.js"; + describe("With custom config path", () => { + useFixtureProject("config-custom-path"); + + it("should return the HARDHAT_CONFIG env variable if it is set", async () => { + try { + // We set the env var to a hardhat config and then clean it up + process.env.HARDHAT_CONFIG = "other.config.js"; + + assert.equal( + await resolveHardhatConfigPath(), + await getRealPath("other.config.js"), + ); + } finally { + delete process.env.HARDHAT_CONFIG; + } + }); - assert.equal(await resolveHardhatConfigPath(), "env.config.js"); + it("should noramlize and return the provided path", async () => { + assert.equal( + await resolveHardhatConfigPath("other.config.js"), + await getRealPath("other.config.js"), + ); + }); - delete process.env.HARDHAT_CONFIG; + it("should throw if the config file is not found", async () => { + await assertRejectsWithHardhatError( + resolveHardhatConfigPath("non-existent.config.js"), + HardhatError.ERRORS.GENERAL.INVALID_CONFIG_PATH, + { + configPath: "non-existent.config.js", + }, + ); + }); }); it("should throw if the config file is not found", async () => { @@ -134,8 +165,12 @@ describe("HRE", () => { describe("programmatic API", () => { useFixtureProject("loaded-config"); + afterEach(() => { + resetGlobalHardhatRuntimeEnvironment(); + }); + it("should load the plugins from the config file", async () => { - const hre = await import("../../src/index.js"); + const hre = await getOrCreateGlobalHardhatRuntimeEnvironment(); const { testPlugin } = await import( "../fixture-projects/loaded-config/hardhat.config.js" ); @@ -144,10 +179,12 @@ describe("HRE", () => { }); it("should load the global options", async () => { - const hre = await import("../../src/index.js"); + const hre = await getOrCreateGlobalHardhatRuntimeEnvironment(); + + const configPath = await getRealPath("hardhat.config.ts"); assert.deepEqual(hre.globalOptions, { - config: "", + config: configPath, help: false, init: false, showStackTraces: false,