-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
Copy pathhre.ts
216 lines (187 loc) · 6.08 KB
/
hre.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
import type { UnsafeHardhatRuntimeEnvironmentOptions } from "../types/cli.js";
import type { HardhatUserConfig, HardhatConfig } from "../types/config.js";
import type {
GlobalOptions,
GlobalOptionDefinitions,
} from "../types/global-options.js";
import type {
HardhatUserConfigValidationError,
HookContext,
HookManager,
} from "../types/hooks.js";
import type { HardhatRuntimeEnvironment } from "../types/hre.js";
import type { HardhatPlugin } from "../types/plugins.js";
import type { TaskManager } from "../types/tasks.js";
import type { UserInterruptionManager } from "../types/user-interruptions.js";
import { HardhatError } from "@ignored/hardhat-vnext-errors";
import { findClosestPackageRoot } from "@ignored/hardhat-vnext-utils/package";
import { ResolvedConfigurationVariableImplementation } from "./configuration-variables.js";
import {
buildGlobalOptionDefinitions,
resolveGlobalOptions,
} from "./global-options.js";
import { HookManagerImplementation } from "./hook-manager.js";
import { resolvePluginList } from "./plugins/resolve-plugin-list.js";
import { TaskManagerImplementation } from "./tasks/task-manager.js";
import { UserInterruptionManagerImplementation } from "./user-interruptions.js";
export class HardhatRuntimeEnvironmentImplementation
implements HardhatRuntimeEnvironment
{
public static async create(
inputUserConfig: HardhatUserConfig,
userProvidedGlobalOptions: Partial<GlobalOptions>,
projectRoot?: string,
unsafeOptions?: UnsafeHardhatRuntimeEnvironmentOptions,
): Promise<HardhatRuntimeEnvironmentImplementation> {
const resolvedProjectRoot = await resolveProjectRoot(projectRoot);
const resolvedPlugins =
unsafeOptions?.resolvedPlugins ??
(await resolvePluginList(resolvedProjectRoot, inputUserConfig.plugins));
const hooks = new HookManagerImplementation(
resolvedProjectRoot,
resolvedPlugins,
);
// extend user config:
const extendedUserConfig = await runUserConfigExtensions(
hooks,
inputUserConfig,
);
// validate config
const userConfigValidationErrors = await validateUserConfig(
hooks,
extendedUserConfig,
);
if (userConfigValidationErrors.length > 0) {
throw new HardhatError(HardhatError.ERRORS.GENERAL.INVALID_CONFIG, {
errors: `\t${userConfigValidationErrors
.map(
(error) =>
`* Config error in .${error.path.join(".")}: ${error.message}`,
)
.join("\n\t")}`,
});
}
// Resolve config
const resolvedConfig = await resolveUserConfig(
resolvedProjectRoot,
hooks,
resolvedPlugins,
inputUserConfig,
);
// We override the plugins and the proejct root, as we want to prevent
// the plugins from changing them
const config: HardhatConfig = {
...resolvedConfig,
paths: {
...resolvedConfig.paths,
root: resolvedProjectRoot,
},
plugins: resolvedPlugins,
};
const globalOptionDefinitions =
unsafeOptions?.globalOptionDefinitions ??
buildGlobalOptionDefinitions(resolvedPlugins);
const globalOptions = resolveGlobalOptions(
userProvidedGlobalOptions,
globalOptionDefinitions,
);
// Set the HookContext in the hook manager so that non-config hooks can
// use it
const interruptions = new UserInterruptionManagerImplementation(hooks);
const hookContext: HookContext = {
hooks,
config,
globalOptions,
interruptions,
};
hooks.setContext(hookContext);
const hre = new HardhatRuntimeEnvironmentImplementation(
extendedUserConfig,
config,
hooks,
interruptions,
globalOptions,
globalOptionDefinitions,
);
await hooks.runSequentialHandlers("hre", "created", [hre]);
return hre;
}
public readonly tasks: TaskManager;
private constructor(
public readonly userConfig: HardhatUserConfig,
public readonly config: HardhatConfig,
public readonly hooks: HookManager,
public readonly interruptions: UserInterruptionManager,
public readonly globalOptions: GlobalOptions,
globalOptionDefinitions: GlobalOptionDefinitions,
) {
this.tasks = new TaskManagerImplementation(this, globalOptionDefinitions);
}
}
/**
* Resolves the project root of a Hardhat project based on the config file or
* another path within the project. If not provided, it will be resolved from
* the current working directory.
*
* @param absolutePathWithinProject An absolute path within the project, usually
* the config file.
*/
export async function resolveProjectRoot(
absolutePathWithinProject: string | undefined,
): Promise<string> {
return findClosestPackageRoot(absolutePathWithinProject ?? process.cwd());
}
async function runUserConfigExtensions(
hooks: HookManager,
config: HardhatUserConfig,
): Promise<HardhatUserConfig> {
return hooks.runHandlerChain(
"config",
"extendUserConfig",
[config],
async (c) => {
return c;
},
);
}
async function validateUserConfig(
hooks: HookManager,
config: HardhatUserConfig,
): Promise<HardhatUserConfigValidationError[]> {
// TODO: Validate the plugin and tasks lists
const validationErrors: HardhatUserConfigValidationError[] = [];
const results = await hooks.runParallelHandlers(
"config",
"validateUserConfig",
[config],
);
return [...validationErrors, ...results.flat(1)];
}
async function resolveUserConfig(
projectRoot: string,
hooks: HookManager,
sortedPlugins: HardhatPlugin[],
config: HardhatUserConfig,
): Promise<HardhatConfig> {
const initialResolvedConfig: HardhatConfig = {
plugins: sortedPlugins,
tasks: config.tasks ?? [],
paths: {
root: projectRoot,
cache: config.paths?.cache ?? "", // TODO: resolve cache path
artifacts: config.paths?.artifacts ?? "", // TODO: resolve artifacts path
},
};
return hooks.runHandlerChain(
"config",
"resolveUserConfig",
[
config,
(variable) =>
new ResolvedConfigurationVariableImplementation(hooks, variable),
],
async (_, __) => {
return initialResolvedConfig;
},
);
}