Skip to content

Commit 9ca7f5a

Browse files
committed
feat: recursively merge the network config override
1 parent 95b012a commit 9ca7f5a

File tree

2 files changed

+102
-58
lines changed

2 files changed

+102
-58
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import type {
2+
EdrNetworkUserConfig,
3+
HttpNetworkUserConfig,
4+
NetworkConfig,
5+
NetworkConfigOverride,
6+
NetworkUserConfig,
7+
} from "../../../types/config.js";
8+
9+
import { isObject } from "@ignored/hardhat-vnext-utils/lang";
10+
11+
/**
12+
* Converts the NetworkConfigOverride into a valid NetworkUserConfig. This
13+
* function determines the network type based on the provided `networkConfig`
14+
* and sets default values for any required properties that are missing from
15+
* the `networkConfigOverride`.
16+
*
17+
* @warning
18+
* This function is not type-safe. It assumes that `networkConfigOverride` does
19+
* not contain mixed properties from different network types. Always validate
20+
* the resulting NetworkUserConfig before using it.
21+
*
22+
* @param networkConfigOverride The partial configuration override provided by
23+
* the user.
24+
* @param networkConfig The base network configuration used to infer defaults
25+
* and the network type.
26+
* @returns A fully resolved NetworkUserConfig with defaults applied.
27+
*/
28+
export async function normalizeNetworkConfigOverride(
29+
networkConfigOverride: NetworkConfigOverride,
30+
networkConfig: NetworkConfig,
31+
): Promise<NetworkUserConfig> {
32+
let networkConfigOverrideWithType: NetworkUserConfig;
33+
34+
if (networkConfig.type === "http") {
35+
const networkConfigOverrideAsHttp =
36+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
37+
-- Assumes that networkConfigOverride is a HttpNetworkUserConfig. */
38+
networkConfigOverride as HttpNetworkUserConfig;
39+
40+
networkConfigOverrideWithType = {
41+
...networkConfigOverrideAsHttp,
42+
type: "http",
43+
url: networkConfigOverrideAsHttp.url ?? (await networkConfig.url.get()),
44+
};
45+
} else {
46+
const networkConfigOverrideAsEdr =
47+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
48+
-- Assumes that networkConfigOverride is an EdrNetworkUserConfig. */
49+
networkConfigOverride as EdrNetworkUserConfig;
50+
51+
networkConfigOverrideWithType = {
52+
...networkConfigOverrideAsEdr,
53+
type: "edr",
54+
};
55+
}
56+
57+
return networkConfigOverrideWithType;
58+
}
59+
60+
/**
61+
* Merges two network configurations. This function is used to merge the
62+
* network configuration with the network configuration override. It recursively
63+
* merges nested objects.
64+
*
65+
* @param target The resolved network configuration.
66+
* @param source The partial network configuration override provided by the user. It
67+
* should be resolved and contain only the properties that the user wants to
68+
* override.
69+
* @returns A new network configuration object with the override applied.
70+
*/
71+
export function mergeConfigOverride<T extends object>(
72+
target: T,
73+
source: Partial<T> = {},
74+
): T {
75+
const result = { ...target };
76+
77+
for (const key in source) {
78+
if (isObject(source[key])) {
79+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
80+
-- result[key] is either an object or undefined, so we default it to {} */
81+
result[key] = mergeConfigOverride(
82+
result[key] ?? {},
83+
source[key],
84+
) as T[Extract<keyof T, string>];
85+
} else {
86+
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
87+
-- source[key] could be undefined, but as it is a resolved config as well,
88+
result[key] should allow it */
89+
result[key] = source[key] as T[Extract<keyof T, string>];
90+
}
91+
}
92+
93+
return result;
94+
}

v-next/hardhat/src/internal/builtin-plugins/network-manager/network-manager.ts

+8-58
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import type {
2-
EdrNetworkUserConfig,
3-
HttpNetworkUserConfig,
42
NetworkConfig,
53
NetworkConfigOverride,
6-
NetworkUserConfig,
74
} from "../../../types/config.js";
85
import type { HookManager } from "../../../types/hooks.js";
96
import type {
@@ -22,6 +19,10 @@ import { HardhatError } from "@ignored/hardhat-vnext-errors";
2219

2320
import { resolveConfigurationVariable } from "../../core/configuration-variables.js";
2421

22+
import {
23+
mergeConfigOverride,
24+
normalizeNetworkConfigOverride,
25+
} from "./config-override.js";
2526
import { resolveNetworkConfigOverride } from "./config-resolution.js";
2627
import { EdrProvider } from "./edr/edr-provider.js";
2728
import { isEdrSupportedChainType } from "./edr/utils/chain-type.js";
@@ -138,12 +139,10 @@ export class NetworkManagerImplementation implements NetworkManager {
138139
);
139140
}
140141

141-
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
142-
-- Cast to NetworkConfig as we know the types match, but TS can't infer it */
143-
const resolvedNetworkConfig = {
144-
...this.#networkConfigs[resolvedNetworkName],
145-
...resolvedNetworkConfigOverride,
146-
} as NetworkConfig;
142+
const resolvedNetworkConfig = mergeConfigOverride(
143+
this.#networkConfigs[resolvedNetworkName],
144+
resolvedNetworkConfigOverride,
145+
);
147146

148147
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
149148
-- Cast to ChainTypeT because we know it's valid */
@@ -236,52 +235,3 @@ export class NetworkManagerImplementation implements NetworkManager {
236235
);
237236
}
238237
}
239-
240-
/**
241-
* Converts the NetworkConfigOverride into a valid NetworkUserConfig. This
242-
* function determines the network type based on the provided `networkConfig`
243-
* and sets default values for any required properties that are missing from
244-
* the `networkConfigOverride`.
245-
*
246-
* @warning
247-
* This function is not type-safe. It assumes that `networkConfigOverride` does
248-
* not contain mixed properties from different network types. Always validate
249-
* the resulting NetworkUserConfig before using it.
250-
*
251-
* @param networkConfigOverride The partial configuration override provided by
252-
* the user.
253-
* @param networkConfig The base network configuration used to infer defaults
254-
* and the network type.
255-
* @returns A fully resolved NetworkUserConfig with defaults applied.
256-
*/
257-
async function normalizeNetworkConfigOverride(
258-
networkConfigOverride: NetworkConfigOverride,
259-
networkConfig: NetworkConfig,
260-
): Promise<NetworkUserConfig> {
261-
let networkConfigOverrideWithType: NetworkUserConfig;
262-
263-
if (networkConfig.type === "http") {
264-
const networkConfigOverrideAsHttp =
265-
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
266-
-- Assumes that networkConfigOverride is a HttpNetworkUserConfig. */
267-
networkConfigOverride as HttpNetworkUserConfig;
268-
269-
networkConfigOverrideWithType = {
270-
...networkConfigOverrideAsHttp,
271-
type: "http",
272-
url: networkConfigOverrideAsHttp.url ?? (await networkConfig.url.get()),
273-
};
274-
} else {
275-
const networkConfigOverrideAsEdr =
276-
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions
277-
-- Assumes that networkConfigOverride is an EdrNetworkUserConfig. */
278-
networkConfigOverride as EdrNetworkUserConfig;
279-
280-
networkConfigOverrideWithType = {
281-
...networkConfigOverrideAsEdr,
282-
type: "edr",
283-
};
284-
}
285-
286-
return networkConfigOverrideWithType;
287-
}

0 commit comments

Comments
 (0)