@@ -15,6 +15,7 @@ import type { TaskManager } from "../types/tasks.js";
15
15
import type { UserInterruptionManager } from "../types/user-interruptions.js" ;
16
16
17
17
import { HardhatError } from "@ignored/hardhat-vnext-errors" ;
18
+ import { findClosestPackageRoot } from "@ignored/hardhat-vnext-utils/package" ;
18
19
19
20
import { ResolvedConfigurationVariableImplementation } from "./configuration-variables.js" ;
20
21
import {
@@ -32,28 +33,24 @@ export class HardhatRuntimeEnvironmentImplementation
32
33
public static async create (
33
34
inputUserConfig : HardhatUserConfig ,
34
35
userProvidedGlobalOptions : Partial < GlobalOptions > ,
36
+ projectRoot ?: string ,
35
37
unsafeOptions ?: UnsafeHardhatRuntimeEnvironmentOptions ,
36
38
) : Promise < HardhatRuntimeEnvironmentImplementation > {
37
- // TODO: Clone with lodash or https://github.com/davidmarkclements/rfdc
38
- // TODO: Or maybe don't clone at all
39
- const clonedUserConfig = inputUserConfig ;
40
-
41
- // Resolve plugins from node modules relative to the current working directory
42
- const basePathForNpmResolution = process . cwd ( ) ;
39
+ const resolvedProjectRoot = await resolveProjectRoot ( projectRoot ) ;
43
40
44
41
const resolvedPlugins =
45
42
unsafeOptions ?. resolvedPlugins ??
46
- ( await resolvePluginList (
47
- clonedUserConfig . plugins ,
48
- basePathForNpmResolution ,
49
- ) ) ;
43
+ ( await resolvePluginList ( resolvedProjectRoot , inputUserConfig . plugins ) ) ;
50
44
51
- const hooks = new HookManagerImplementation ( resolvedPlugins ) ;
45
+ const hooks = new HookManagerImplementation (
46
+ resolvedProjectRoot ,
47
+ resolvedPlugins ,
48
+ ) ;
52
49
53
50
// extend user config:
54
51
const extendedUserConfig = await runUserConfigExtensions (
55
52
hooks ,
56
- clonedUserConfig ,
53
+ inputUserConfig ,
57
54
) ;
58
55
59
56
// validate config
@@ -76,14 +73,20 @@ export class HardhatRuntimeEnvironmentImplementation
76
73
// Resolve config
77
74
78
75
const resolvedConfig = await resolveUserConfig (
76
+ resolvedProjectRoot ,
79
77
hooks ,
80
78
resolvedPlugins ,
81
79
inputUserConfig ,
82
80
) ;
83
81
84
- // We override the plugins, as we want to prevent plugins from changing this
85
- const config = {
82
+ // We override the plugins and the proejct root, as we want to prevent
83
+ // the plugins from changing them
84
+ const config : HardhatConfig = {
86
85
...resolvedConfig ,
86
+ paths : {
87
+ ...resolvedConfig . paths ,
88
+ root : resolvedProjectRoot ,
89
+ } ,
87
90
plugins : resolvedPlugins ,
88
91
} ;
89
92
@@ -138,6 +141,20 @@ export class HardhatRuntimeEnvironmentImplementation
138
141
}
139
142
}
140
143
144
+ /**
145
+ * Resolves the project root of a Hardhat project based on the config file or
146
+ * another path within the project. If not provided, it will be resolved from
147
+ * the current working directory.
148
+ *
149
+ * @param absolutePathWithinProject An absolute path within the project, usually
150
+ * the config file.
151
+ */
152
+ export async function resolveProjectRoot (
153
+ absolutePathWithinProject : string | undefined ,
154
+ ) : Promise < string > {
155
+ return findClosestPackageRoot ( absolutePathWithinProject ?? process . cwd ( ) ) ;
156
+ }
157
+
141
158
async function runUserConfigExtensions (
142
159
hooks : HookManager ,
143
160
config : HardhatUserConfig ,
@@ -169,13 +186,17 @@ async function validateUserConfig(
169
186
}
170
187
171
188
async function resolveUserConfig (
189
+ projectRoot : string ,
172
190
hooks : HookManager ,
173
191
sortedPlugins : HardhatPlugin [ ] ,
174
192
config : HardhatUserConfig ,
175
193
) : Promise < HardhatConfig > {
176
194
const initialResolvedConfig : HardhatConfig = {
177
195
plugins : sortedPlugins ,
178
196
tasks : config . tasks ?? [ ] ,
197
+ paths : {
198
+ root : projectRoot ,
199
+ } ,
179
200
} ;
180
201
181
202
return hooks . runHandlerChain (
0 commit comments