hardhat 3.1.10 → 3.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/src/internal/builtin-plugins/artifacts/artifact-manager.d.ts +2 -2
  3. package/dist/src/internal/builtin-plugins/artifacts/artifact-manager.d.ts.map +1 -1
  4. package/dist/src/internal/builtin-plugins/artifacts/artifact-manager.js.map +1 -1
  5. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.d.ts.map +1 -1
  6. package/dist/src/internal/builtin-plugins/artifacts/hook-handlers/hre.js.map +1 -1
  7. package/dist/src/internal/builtin-plugins/coverage/helpers.d.ts +3 -5
  8. package/dist/src/internal/builtin-plugins/coverage/helpers.d.ts.map +1 -1
  9. package/dist/src/internal/builtin-plugins/coverage/helpers.js +7 -19
  10. package/dist/src/internal/builtin-plugins/coverage/helpers.js.map +1 -1
  11. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/test.d.ts +7 -0
  12. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/test.d.ts.map +1 -0
  13. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/test.js +42 -0
  14. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/test.js.map +1 -0
  15. package/dist/src/internal/builtin-plugins/coverage/index.d.ts.map +1 -1
  16. package/dist/src/internal/builtin-plugins/coverage/index.js +1 -0
  17. package/dist/src/internal/builtin-plugins/coverage/index.js.map +1 -1
  18. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.d.ts +3 -5
  19. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.d.ts.map +1 -1
  20. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.js +7 -19
  21. package/dist/src/internal/builtin-plugins/gas-analytics/helpers.js.map +1 -1
  22. package/dist/src/internal/builtin-plugins/gas-analytics/hook-handlers/test.d.ts +7 -0
  23. package/dist/src/internal/builtin-plugins/gas-analytics/hook-handlers/test.d.ts.map +1 -0
  24. package/dist/src/internal/builtin-plugins/gas-analytics/hook-handlers/test.js +42 -0
  25. package/dist/src/internal/builtin-plugins/gas-analytics/hook-handlers/test.js.map +1 -0
  26. package/dist/src/internal/builtin-plugins/gas-analytics/index.d.ts.map +1 -1
  27. package/dist/src/internal/builtin-plugins/gas-analytics/index.js +1 -0
  28. package/dist/src/internal/builtin-plugins/gas-analytics/index.js.map +1 -1
  29. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.d.ts.map +1 -1
  30. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js +17 -20
  31. package/dist/src/internal/builtin-plugins/network-manager/edr/edr-provider.js.map +1 -1
  32. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-generation-errors.d.ts +1 -1
  33. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-generation-errors.d.ts.map +1 -1
  34. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-generation-errors.js +2 -2
  35. package/dist/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-generation-errors.js.map +1 -1
  36. package/dist/src/internal/builtin-plugins/network-manager/edr/type-validation.d.ts +0 -2
  37. package/dist/src/internal/builtin-plugins/network-manager/edr/type-validation.d.ts.map +1 -1
  38. package/dist/src/internal/builtin-plugins/network-manager/edr/type-validation.js +0 -6
  39. package/dist/src/internal/builtin-plugins/network-manager/edr/type-validation.js.map +1 -1
  40. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.d.ts +1 -3
  41. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.d.ts.map +1 -1
  42. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.js +0 -49
  43. package/dist/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.js.map +1 -1
  44. package/dist/src/internal/builtin-plugins/solidity/build-results.d.ts +2 -2
  45. package/dist/src/internal/builtin-plugins/solidity/build-results.d.ts.map +1 -1
  46. package/dist/src/internal/builtin-plugins/solidity/build-results.js +2 -2
  47. package/dist/src/internal/builtin-plugins/solidity/build-results.js.map +1 -1
  48. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts +1 -0
  49. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.d.ts.map +1 -1
  50. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js +13 -5
  51. package/dist/src/internal/builtin-plugins/solidity/build-system/build-system.js.map +1 -1
  52. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.js +1 -1
  53. package/dist/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.js.map +1 -1
  54. package/dist/src/internal/builtin-plugins/solidity/build-system/dependency-graph.d.ts +1 -1
  55. package/dist/src/internal/builtin-plugins/solidity/build-system/dependency-graph.js +1 -1
  56. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.d.ts +2 -1
  57. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.d.ts.map +1 -1
  58. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.d.ts +13 -1
  59. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.d.ts.map +1 -1
  60. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.js +30 -5
  61. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.js.map +1 -1
  62. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/types.d.ts +3 -12
  63. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/types.d.ts.map +1 -1
  64. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/types.js.map +1 -1
  65. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/utils.d.ts +1 -1
  66. package/dist/src/internal/builtin-plugins/solidity/build-system/resolver/utils.d.ts.map +1 -1
  67. package/dist/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.d.ts +8 -6
  68. package/dist/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.d.ts.map +1 -1
  69. package/dist/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.js +103 -27
  70. package/dist/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.js.map +1 -1
  71. package/dist/src/internal/builtin-plugins/solidity/config.js +2 -2
  72. package/dist/src/internal/builtin-plugins/solidity/config.js.map +1 -1
  73. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/hre.d.ts.map +1 -1
  74. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/hre.js +5 -0
  75. package/dist/src/internal/builtin-plugins/solidity/hook-handlers/hre.js.map +1 -1
  76. package/dist/src/internal/builtin-plugins/solidity/tasks/build.js +1 -1
  77. package/dist/src/internal/builtin-plugins/solidity/tasks/build.js.map +1 -1
  78. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.d.ts +1 -1
  79. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.d.ts.map +1 -1
  80. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.js +1 -1
  81. package/dist/src/internal/builtin-plugins/solidity-test/edr-artifacts.js.map +1 -1
  82. package/dist/src/internal/builtin-plugins/solidity-test/runner.d.ts +1 -1
  83. package/dist/src/internal/builtin-plugins/solidity-test/runner.js +1 -1
  84. package/dist/src/internal/builtin-plugins/solidity-test/task-action.d.ts.map +1 -1
  85. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js +16 -27
  86. package/dist/src/internal/builtin-plugins/solidity-test/task-action.js.map +1 -1
  87. package/dist/src/internal/builtin-plugins/telemetry/task-action.d.ts.map +1 -1
  88. package/dist/src/internal/builtin-plugins/telemetry/task-action.js +3 -2
  89. package/dist/src/internal/builtin-plugins/telemetry/task-action.js.map +1 -1
  90. package/dist/src/internal/builtin-plugins/test/task-action.d.ts.map +1 -1
  91. package/dist/src/internal/builtin-plugins/test/task-action.js +40 -13
  92. package/dist/src/internal/builtin-plugins/test/task-action.js.map +1 -1
  93. package/dist/src/internal/builtin-plugins/test/type-extensions.d.ts +27 -0
  94. package/dist/src/internal/builtin-plugins/test/type-extensions.d.ts.map +1 -1
  95. package/dist/src/internal/cli/banner-manager.d.ts +26 -0
  96. package/dist/src/internal/cli/banner-manager.d.ts.map +1 -0
  97. package/dist/src/internal/cli/banner-manager.js +146 -0
  98. package/dist/src/internal/cli/banner-manager.js.map +1 -0
  99. package/dist/src/internal/cli/init/init.d.ts.map +1 -1
  100. package/dist/src/internal/cli/init/init.js +8 -0
  101. package/dist/src/internal/cli/init/init.js.map +1 -1
  102. package/dist/src/internal/cli/main.d.ts.map +1 -1
  103. package/dist/src/internal/cli/main.js +18 -1
  104. package/dist/src/internal/cli/main.js.map +1 -1
  105. package/dist/src/internal/cli/telemetry/analytics/subprocess.js +2 -0
  106. package/dist/src/internal/cli/telemetry/analytics/subprocess.js.map +1 -1
  107. package/dist/src/internal/cli/telemetry/sentry/anonymize-paths.js +1 -1
  108. package/dist/src/internal/cli/telemetry/sentry/vendor/integrations/contextlines.d.ts +1 -1
  109. package/dist/src/internal/cli/telemetry/sentry/vendor/integrations/contextlines.d.ts.map +1 -1
  110. package/dist/src/internal/cli/telemetry/sentry/vendor/integrations/contextlines.js +47 -38
  111. package/dist/src/internal/cli/telemetry/sentry/vendor/integrations/contextlines.js.map +1 -1
  112. package/dist/src/internal/core/user-interruptions.js +1 -1
  113. package/dist/src/types/artifacts.d.ts +32 -3
  114. package/dist/src/types/artifacts.d.ts.map +1 -1
  115. package/dist/src/types/network.d.ts +1 -1
  116. package/dist/src/types/solidity/build-system.d.ts +56 -10
  117. package/dist/src/types/solidity/build-system.d.ts.map +1 -1
  118. package/dist/src/types/solidity/build-system.js +26 -2
  119. package/dist/src/types/solidity/build-system.js.map +1 -1
  120. package/dist/src/types/solidity/resolved-file.d.ts +2 -2
  121. package/dist/src/types/tasks.d.ts +8 -0
  122. package/dist/src/types/tasks.d.ts.map +1 -1
  123. package/dist/src/types/tasks.js.map +1 -1
  124. package/dist/src/types/test.d.ts +11 -0
  125. package/dist/src/types/test.d.ts.map +1 -1
  126. package/dist/src/types/utils.d.ts +16 -0
  127. package/dist/src/types/utils.d.ts.map +1 -1
  128. package/dist/src/utils/result.d.ts +33 -0
  129. package/dist/src/utils/result.d.ts.map +1 -0
  130. package/dist/src/utils/result.js +43 -0
  131. package/dist/src/utils/result.js.map +1 -0
  132. package/package.json +4 -3
  133. package/src/internal/builtin-plugins/artifacts/artifact-manager.ts +4 -1
  134. package/src/internal/builtin-plugins/artifacts/hook-handlers/hre.ts +4 -1
  135. package/src/internal/builtin-plugins/coverage/helpers.ts +11 -29
  136. package/src/internal/builtin-plugins/coverage/hook-handlers/test.ts +68 -0
  137. package/src/internal/builtin-plugins/coverage/index.ts +1 -0
  138. package/src/internal/builtin-plugins/gas-analytics/helpers.ts +11 -29
  139. package/src/internal/builtin-plugins/gas-analytics/hook-handlers/test.ts +68 -0
  140. package/src/internal/builtin-plugins/gas-analytics/index.ts +1 -0
  141. package/src/internal/builtin-plugins/network-manager/edr/edr-provider.ts +21 -28
  142. package/src/internal/builtin-plugins/network-manager/edr/stack-traces/stack-trace-generation-errors.ts +5 -2
  143. package/src/internal/builtin-plugins/network-manager/edr/type-validation.ts +0 -13
  144. package/src/internal/builtin-plugins/network-manager/edr/utils/convert-to-edr.ts +0 -64
  145. package/src/internal/builtin-plugins/solidity/build-results.ts +3 -1
  146. package/src/internal/builtin-plugins/solidity/build-system/build-system.ts +15 -5
  147. package/src/internal/builtin-plugins/solidity/build-system/compiler/compiler.ts +1 -1
  148. package/src/internal/builtin-plugins/solidity/build-system/dependency-graph.ts +1 -1
  149. package/src/internal/builtin-plugins/solidity/build-system/resolver/dependency-resolver.ts +1 -1
  150. package/src/internal/builtin-plugins/solidity/build-system/resolver/remapped-npm-packages-graph.ts +36 -6
  151. package/src/internal/builtin-plugins/solidity/build-system/resolver/types.ts +3 -9
  152. package/src/internal/builtin-plugins/solidity/build-system/resolver/utils.ts +1 -1
  153. package/src/internal/builtin-plugins/solidity/build-system/solc-config-selection.ts +125 -28
  154. package/src/internal/builtin-plugins/solidity/config.ts +2 -2
  155. package/src/internal/builtin-plugins/solidity/hook-handlers/hre.ts +8 -0
  156. package/src/internal/builtin-plugins/solidity/tasks/build.ts +1 -1
  157. package/src/internal/builtin-plugins/solidity-test/edr-artifacts.ts +2 -2
  158. package/src/internal/builtin-plugins/solidity-test/runner.ts +1 -1
  159. package/src/internal/builtin-plugins/solidity-test/task-action.ts +36 -38
  160. package/src/internal/builtin-plugins/telemetry/task-action.ts +4 -2
  161. package/src/internal/builtin-plugins/test/task-action.ts +71 -25
  162. package/src/internal/builtin-plugins/test/type-extensions.ts +42 -0
  163. package/src/internal/cli/banner-manager.ts +234 -0
  164. package/src/internal/cli/init/init.ts +8 -0
  165. package/src/internal/cli/main.ts +19 -1
  166. package/src/internal/cli/telemetry/analytics/subprocess.ts +2 -0
  167. package/src/internal/cli/telemetry/sentry/anonymize-paths.ts +1 -1
  168. package/src/internal/cli/telemetry/sentry/vendor/integrations/contextlines.ts +98 -50
  169. package/src/internal/core/user-interruptions.ts +1 -1
  170. package/src/types/artifacts.ts +40 -3
  171. package/src/types/hre.ts +1 -1
  172. package/src/types/network.ts +1 -1
  173. package/src/types/solidity/build-system.ts +75 -14
  174. package/src/types/solidity/resolved-file.ts +2 -2
  175. package/src/types/tasks.ts +10 -0
  176. package/src/types/test.ts +12 -0
  177. package/src/types/utils.ts +14 -0
  178. package/src/utils/result.ts +57 -0
  179. package/templates/hardhat-3/01-node-test-runner-viem/package.json +9 -9
  180. package/templates/hardhat-3/02-mocha-ethers/package.json +10 -10
  181. package/templates/hardhat-3/03-minimal/package.json +1 -1
  182. package/dist/src/internal/builtin-plugins/network-manager/edr/types/output.d.ts +0 -19
  183. package/dist/src/internal/builtin-plugins/network-manager/edr/types/output.d.ts.map +0 -1
  184. package/dist/src/internal/builtin-plugins/network-manager/edr/types/output.js +0 -2
  185. package/dist/src/internal/builtin-plugins/network-manager/edr/types/output.js.map +0 -1
  186. package/src/internal/builtin-plugins/network-manager/edr/types/output.ts +0 -19
@@ -18,19 +18,17 @@ export class SolcConfigSelector {
18
18
 
19
19
  /**
20
20
  * Creates a new SolcConfigSelector that can be used to select the best solc
21
- * configuration for subgraphs of the given dependency graph.
21
+ * configuration for single-root subgraphs to create their respective
22
+ * individual compilation jobs.
22
23
  *
23
- * All the queries are done in the context of the given dependency graph, and
24
- * using the same build profile.
24
+ * All the queries use the same build profile.
25
25
  *
26
26
  * @param buildProfileName The name of the build profile to use.
27
27
  * @param buildProfile The build profile config.
28
- * @param _dependencyGraph The entire dependency graph of the project.
29
28
  */
30
29
  constructor(
31
30
  buildProfileName: string,
32
31
  buildProfile: SolidityBuildProfileConfig,
33
- _dependencyGraph: DependencyGraph,
34
32
  ) {
35
33
  this.#buildProfileName = buildProfileName;
36
34
  this.#buildProfile = buildProfile;
@@ -46,7 +44,7 @@ export class SolcConfigSelector {
46
44
  */
47
45
  public selectBestSolcConfigForSingleRootGraph(
48
46
  subgraph: DependencyGraph,
49
- ): SolcConfig | CompilationJobCreationError {
47
+ ): { success: true; config: SolcConfig } | CompilationJobCreationError {
50
48
  const roots = subgraph.getRoots();
51
49
 
52
50
  assertHardhatInvariant(
@@ -56,11 +54,11 @@ export class SolcConfigSelector {
56
54
 
57
55
  const [userSourceName, root] = [...roots.entries()][0];
58
56
 
59
- const allVersionPragamas = [...subgraph.getAllFiles()]
57
+ const allVersionPragmas = [...subgraph.getAllFiles()]
60
58
  .map(({ content }) => content.versionPragmas)
61
59
  .flat(1);
62
60
 
63
- const versionRange = Array.from(new Set(allVersionPragamas)).join(" ");
61
+ const versionRange = Array.from(new Set(allVersionPragmas)).join(" ");
64
62
 
65
63
  const overriddenCompiler = this.#buildProfile.overrides[userSourceName];
66
64
 
@@ -75,7 +73,7 @@ export class SolcConfigSelector {
75
73
  );
76
74
  }
77
75
 
78
- return overriddenCompiler;
76
+ return { success: true, config: overriddenCompiler };
79
77
  }
80
78
 
81
79
  // if there's no override, we find a compiler that matches the version range
@@ -100,9 +98,21 @@ export class SolcConfigSelector {
100
98
  `Matching config not found for version '${matchingVersion.toString()}'`,
101
99
  );
102
100
 
103
- return matchingConfig;
101
+ return { success: true, config: matchingConfig };
104
102
  }
105
103
 
104
+ /**
105
+ * Returns a description of why we couldn't get a compiler configuration for
106
+ * the given root file and dependency subgraph.
107
+ *
108
+ * @param root The root file that created the single-root dependency subgraph
109
+ * @param dependencyGraph The dependency subgraph we couldn't get a compiler
110
+ * configuration for
111
+ * @param compilerVersions The compiler versions that are configured for the
112
+ * selected build profile. For overridden roots, it's a single one.
113
+ * @param overridden True if the root has an overridden config.
114
+ * @returns The error why we couldn't get a compiler configuration.
115
+ */
106
116
  #getCompilationJobCreationError(
107
117
  root: ResolvedFile,
108
118
  dependencyGraph: DependencyGraph,
@@ -110,27 +120,70 @@ export class SolcConfigSelector {
110
120
  overridden: boolean,
111
121
  ): CompilationJobCreationError {
112
122
  const rootVersionRange = root.content.versionPragmas.join(" ");
113
- if (maxSatisfying(compilerVersions, rootVersionRange) === null) {
114
- let reason: CompilationJobCreationErrorReason;
115
- let formattedReason: string;
116
- if (overridden) {
117
- reason =
118
- CompilationJobCreationErrorReason.INCOMPATIBLE_OVERRIDDEN_SOLC_VERSION;
119
- formattedReason = `An override with incompatible solc version was found for this file.`;
120
- } else {
121
- reason =
122
- CompilationJobCreationErrorReason.NO_COMPATIBLE_SOLC_VERSION_WITH_ROOT;
123
- formattedReason = `No solc version enabled in this profile is compatible with this file.`;
123
+
124
+ // This logic is pretty different depending if we are dealing with a config
125
+ // override or not. If we are, we have a single compiler option, so things
126
+ // are simpler.
127
+
128
+ if (overridden) {
129
+ // The root may not be compatible with the override version
130
+ if (maxSatisfying(compilerVersions, rootVersionRange) === null) {
131
+ return {
132
+ success: false,
133
+ reason:
134
+ CompilationJobCreationErrorReason.INCOMPATIBLE_OVERRIDDEN_SOLC_VERSION,
135
+ rootFilePath: root.fsPath,
136
+ buildProfile: this.#buildProfileName,
137
+ formattedReason: `An override with incompatible solc version was found for this file.`,
138
+ };
124
139
  }
125
140
 
141
+ // A transitive dependency can have a pragma that's incompatible with
142
+ // the overridden version.
143
+ for (const transitiveDependency of this.#getTransitiveDependencies(
144
+ root,
145
+ dependencyGraph,
146
+ )) {
147
+ const depOwnRange =
148
+ transitiveDependency.dependency.content.versionPragmas.join(" ");
149
+
150
+ if (maxSatisfying(compilerVersions, depOwnRange) === null) {
151
+ return {
152
+ success: false,
153
+ reason:
154
+ CompilationJobCreationErrorReason.OVERRIDDEN_SOLC_VERSION_INCOMPATIBLE_WITH_DEPENDENCY,
155
+ rootFilePath: root.fsPath,
156
+ buildProfile: this.#buildProfileName,
157
+ incompatibleImportPath: transitiveDependency.fsPath,
158
+ formattedReason: `The compiler version override is incompatible with a dependency of this file:\n * ${shortenPath(root.fsPath)}\n * ${transitiveDependency.fsPath.map((s) => shortenPath(s)).join("\n * ")}`,
159
+ };
160
+ }
161
+ }
162
+
163
+ // There's no other case. If the root and all the dependencies are
164
+ // compatible, and we still can choose a version, we have a bug.
165
+ /* c8 ignore next 5 */
166
+ assertHardhatInvariant(
167
+ false,
168
+ "Trying to get the error for an overridden solidity file that has no compatible config, but failed to detect it, as the root and all the dependencies are compatible with the overridden compiler config.",
169
+ );
170
+ }
171
+
172
+ // Non-overridden case: we first check if the root is compatible with any
173
+ // configured compiler
174
+ if (maxSatisfying(compilerVersions, rootVersionRange) === null) {
126
175
  return {
127
- reason,
176
+ success: false,
177
+ reason:
178
+ CompilationJobCreationErrorReason.NO_COMPATIBLE_SOLC_VERSION_WITH_ROOT,
128
179
  rootFilePath: root.fsPath,
129
180
  buildProfile: this.#buildProfileName,
130
- formattedReason,
181
+ formattedReason: `No solc version enabled in this profile is compatible with this file.`,
131
182
  };
132
183
  }
133
184
 
185
+ // We check all the transitive dependencies of the root to try to return
186
+ // the most specific error that we can.
134
187
  for (const transitiveDependency of this.#getTransitiveDependencies(
135
188
  root,
136
189
  dependencyGraph,
@@ -140,21 +193,59 @@ export class SolcConfigSelector {
140
193
  .map((pragmas) => pragmas.join(" "))
141
194
  .join(" ");
142
195
 
196
+ const depOwnRange =
197
+ transitiveDependency.dependency.content.versionPragmas.join(" ");
198
+
199
+ // A transitive dependency can have a pragma that's incompatible with
200
+ // all the configured compilers
201
+ if (maxSatisfying(compilerVersions, depOwnRange) === null) {
202
+ return {
203
+ success: false,
204
+ reason:
205
+ CompilationJobCreationErrorReason.NO_COMPATIBLE_SOLC_VERSION_WITH_DEPENDENCY,
206
+ rootFilePath: root.fsPath,
207
+ buildProfile: this.#buildProfileName,
208
+ incompatibleImportPath: transitiveDependency.fsPath,
209
+ formattedReason: `No solc version enabled in this profile is compatible with a dependency of this file:\n * ${shortenPath(root.fsPath)}\n * ${transitiveDependency.fsPath.map((s) => shortenPath(s)).join("\n * ")}`,
210
+ };
211
+ }
212
+
213
+ // The root and the version ranges to get to this transitive dependency
214
+ // may be contradictory, so no version ever can satisfy them.
143
215
  if (!intersects(rootVersionRange, transitiveDependencyVersionRange)) {
144
216
  return {
217
+ success: false,
145
218
  reason: CompilationJobCreationErrorReason.IMPORT_OF_INCOMPATIBLE_FILE,
146
219
  rootFilePath: root.fsPath,
147
220
  buildProfile: this.#buildProfileName,
148
221
  incompatibleImportPath: transitiveDependency.fsPath,
149
- formattedReason: `Following these imports leads to an incompatible solc version pragma that no version can satisfy:
150
- * ${shortenPath(root.fsPath)}
151
- * ${transitiveDependency.fsPath.map((s) => shortenPath(s)).join("\n * ")}
152
- `,
222
+ formattedReason: `Following these imports leads to an incompatible solc version pragma that no version can satisfy:\n * ${shortenPath(root.fsPath)}\n * ${transitiveDependency.fsPath.map((s) => shortenPath(s)).join("\n * ")}`,
223
+ };
224
+ }
225
+
226
+ // The root and the version ranges to get to this transitive dependency
227
+ // may not be compatible with any configured compiler.
228
+ const combinedRange = `${rootVersionRange} ${transitiveDependencyVersionRange}`;
229
+ if (maxSatisfying(compilerVersions, combinedRange) === null) {
230
+ return {
231
+ success: false,
232
+ reason:
233
+ CompilationJobCreationErrorReason.NO_COMPATIBLE_SOLC_VERSION_FOR_TRANSITIVE_IMPORT_PATH,
234
+ rootFilePath: root.fsPath,
235
+ buildProfile: this.#buildProfileName,
236
+ incompatibleImportPath: transitiveDependency.fsPath,
237
+ formattedReason: `No solc version enabled in this profile is compatible with this file and this import path:\n * ${shortenPath(root.fsPath)}\n * ${transitiveDependency.fsPath.map((s) => shortenPath(s)).join("\n * ")}`,
153
238
  };
154
239
  }
155
240
  }
156
241
 
242
+ // This is a generic case that can happen when the incompatibilities exist
243
+ // but we can't detect them with the above algorithm. For example, if a
244
+ // root imports two compatible dependencies that are incompatible with each
245
+ // other. We could try and improve this error message, but it's
246
+ // computationally expensive and hard to express to the users.
157
247
  return {
248
+ success: false,
158
249
  reason:
159
250
  CompilationJobCreationErrorReason.NO_COMPATIBLE_SOLC_VERSION_FOUND,
160
251
  rootFilePath: root.fsPath,
@@ -163,6 +254,12 @@ export class SolcConfigSelector {
163
254
  };
164
255
  }
165
256
 
257
+ /**
258
+ * Returns a generator of all the transitive dependencies of a root file. For each
259
+ * dependency, it yields the sequence of fsPaths from the root to that dependency,
260
+ * along with the corresponding version pragma paths for each file in the import chain.
261
+ * The paths don't include the root itself.
262
+ */
166
263
  *#getTransitiveDependencies(
167
264
  root: ResolvedFile,
168
265
  dependencyGraph: DependencyGraph,
@@ -179,7 +276,7 @@ export class SolcConfigSelector {
179
276
  continue;
180
277
  }
181
278
 
182
- visited.add(file);
279
+ visited = new Set([...visited, file]);
183
280
 
184
281
  yield {
185
282
  fsPath: [file.fsPath],
@@ -124,7 +124,7 @@ const buildProfilesSolidityUserConfigType = commonSolidityUserConfigType.extend(
124
124
  },
125
125
  );
126
126
 
127
- const soldityUserConfigType = conditionalUnionType(
127
+ const solidityUserConfigType = conditionalUnionType(
128
128
  [
129
129
  [(data) => typeof data === "string", z.string()],
130
130
  [(data) => Array.isArray(data), z.array(z.string()).nonempty()],
@@ -159,7 +159,7 @@ const userConfigType = z.object({
159
159
  ).optional(),
160
160
  })
161
161
  .optional(),
162
- solidity: soldityUserConfigType.optional(),
162
+ solidity: solidityUserConfigType.optional(),
163
163
  });
164
164
 
165
165
  export function validateSolidityUserConfig(
@@ -46,6 +46,14 @@ class LazySolidityBuildSystem implements SolidityBuildSystem {
46
46
  return buildSystem.getScope(fsPath);
47
47
  }
48
48
 
49
+ public isSuccessfulBuildResult(
50
+ buildResult: CompilationJobCreationError | Map<string, FileBuildResult>,
51
+ ): buildResult is Map<string, FileBuildResult> {
52
+ // Note: This duplicates the logic of the actual implementation because it's
53
+ // a synchronous method, so we can't import the implementation.
54
+ return buildResult instanceof Map;
55
+ }
56
+
49
57
  public async build(
50
58
  rootFiles: string[],
51
59
  options?: BuildOptions,
@@ -110,7 +110,7 @@ async function buildForScope(
110
110
  scope,
111
111
  });
112
112
 
113
- throwIfSolidityBuildFailed(results);
113
+ throwIfSolidityBuildFailed(solidity, results);
114
114
 
115
115
  // If we recompiled the entire project we cleanup the artifacts
116
116
  if (isFullCompilation) {
@@ -60,7 +60,7 @@ export async function getBuildInfos(
60
60
  */
61
61
  export async function getEdrArtifacts(
62
62
  artifactManager: ArtifactManager,
63
- ): Promise<Array<{ edrAtifact: EdrArtifact; userSourceName: string }>> {
63
+ ): Promise<Array<{ edrArtifact: EdrArtifact; userSourceName: string }>> {
64
64
  const fullyQualifiedNames = await artifactManager.getAllFullyQualifiedNames();
65
65
 
66
66
  const artifacts = await Promise.all(
@@ -140,7 +140,7 @@ export async function getEdrArtifacts(
140
140
  // from an artifact id between the `run` call and the events emitted by the
141
141
  // test runner.
142
142
  return {
143
- edrAtifact: {
143
+ edrArtifact: {
144
144
  id,
145
145
  contract,
146
146
  },
@@ -38,7 +38,7 @@ export interface RunOptions {
38
38
  * Despite the changes, the signature of the function should still be considered
39
39
  * a draft that may change in the future.
40
40
  *
41
- * TODO: Once the signature is finalised, give feedback to the EDR team.
41
+ * TODO: Once the signature is finalized, give feedback to the EDR team.
42
42
  */
43
43
  export function run(
44
44
  chainType: ChainType,
@@ -1,6 +1,8 @@
1
1
  import type { RunOptions } from "./runner.js";
2
2
  import type { TestEvent } from "./types.js";
3
3
  import type { NewTaskActionFunction } from "../../../types/tasks.js";
4
+ import type { TestSummary } from "../../../types/test.js";
5
+ import type { Result } from "../../../types/utils.js";
4
6
  import type {
5
7
  Artifact as EdrArtifact,
6
8
  BuildInfoAndOutput,
@@ -19,19 +21,10 @@ import { resolveFromRoot } from "@nomicfoundation/hardhat-utils/path";
19
21
  import { createNonClosingWriter } from "@nomicfoundation/hardhat-utils/stream";
20
22
 
21
23
  import { getFullyQualifiedName } from "../../../utils/contract-names.js";
24
+ import { errorResult, successfulResult } from "../../../utils/result.js";
22
25
  import { HardhatRuntimeEnvironmentImplementation } from "../../core/hre.js";
23
26
  import { isSupportedChainType } from "../../edr/chain-type.js";
24
27
  import { ArtifactManagerImplementation } from "../artifacts/artifact-manager.js";
25
- import {
26
- markTestRunStart as initCoverage,
27
- markTestWorkerDone as saveCoverageData,
28
- markTestRunDone as reportCoverage,
29
- } from "../coverage/helpers.js";
30
- import {
31
- markTestRunStart as initGasStats,
32
- markTestWorkerDone as saveGasStatsData,
33
- markTestRunDone as reportGasStats,
34
- } from "../gas-analytics/helpers.js";
35
28
  import { edrGasReportToHardhatGasMeasurements } from "../network-manager/edr/utils/convert-to-edr.js";
36
29
 
37
30
  import { getEdrArtifacts, getBuildInfos } from "./edr-artifacts.js";
@@ -56,7 +49,7 @@ interface TestActionArguments {
56
49
  const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
57
50
  { testFiles, chainType, grep, noCompile, verbosity, testSummaryIndex },
58
51
  hre,
59
- ) => {
52
+ ): Promise<Result<TestSummary, TestSummary>> => {
60
53
  assertHardhatInvariant(
61
54
  hre instanceof HardhatRuntimeEnvironmentImplementation,
62
55
  "Expected HRE to be an instance of HardhatRuntimeEnvironmentImplementation",
@@ -98,7 +91,7 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
98
91
 
99
92
  // EDR needs all artifacts (contracts + tests)
100
93
  const edrArtifacts: Array<{
101
- edrAtifact: EdrArtifact;
94
+ edrArtifact: EdrArtifact;
102
95
  userSourceName: string;
103
96
  }> = [];
104
97
  const buildInfos: BuildInfoAndOutput[] = [];
@@ -110,20 +103,20 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
110
103
  }
111
104
 
112
105
  const sourceNameToUserSourceName = new Map(
113
- edrArtifacts.map(({ userSourceName, edrAtifact }) => [
114
- edrAtifact.id.source,
106
+ edrArtifacts.map(({ userSourceName, edrArtifact }) => [
107
+ edrArtifact.id.source,
115
108
  userSourceName,
116
109
  ]),
117
110
  );
118
111
 
119
- edrArtifacts.forEach(({ userSourceName, edrAtifact }) => {
112
+ edrArtifacts.forEach(({ userSourceName, edrArtifact }) => {
120
113
  if (
121
114
  testRootPaths.includes(
122
115
  resolveFromRoot(hre.config.paths.root, userSourceName),
123
116
  ) &&
124
- isTestSuiteArtifact(edrAtifact)
117
+ isTestSuiteArtifact(edrArtifact)
125
118
  ) {
126
- warnDeprecatedTestFail(edrAtifact, sourceNameToUserSourceName);
119
+ warnDeprecatedTestFail(edrArtifact, sourceNameToUserSourceName);
127
120
  }
128
121
  });
129
122
 
@@ -133,8 +126,8 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
133
126
  resolveFromRoot(hre.config.paths.root, userSourceName),
134
127
  ),
135
128
  )
136
- .filter(({ edrAtifact }) => isTestSuiteArtifact(edrAtifact))
137
- .map(({ edrAtifact }) => edrAtifact.id);
129
+ .filter(({ edrArtifact }) => isTestSuiteArtifact(edrArtifact))
130
+ .map(({ edrArtifact }) => edrArtifact.id);
138
131
 
139
132
  console.log("Running Solidity tests");
140
133
  console.log();
@@ -186,12 +179,16 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
186
179
  const options: RunOptions =
187
180
  solidityTestConfigToRunOptions(solidityTestConfig);
188
181
 
189
- await initCoverage("solidity");
190
- await initGasStats("solidity");
182
+ await hre.hooks.runHandlerChain(
183
+ "test",
184
+ "onTestRunStart",
185
+ ["solidity"],
186
+ async () => {},
187
+ );
191
188
 
192
189
  const runStream = run(
193
190
  chainType,
194
- edrArtifacts.map(({ edrAtifact }) => edrAtifact),
191
+ edrArtifacts.map(({ edrArtifact }) => edrArtifact),
195
192
  testSuiteIds,
196
193
  config,
197
194
  tracingConfig,
@@ -271,26 +268,27 @@ const runSolidityTests: NewTaskActionFunction<TestActionArguments> = async (
271
268
  includesErrors = true;
272
269
  }
273
270
 
274
- await saveCoverageData("solidity");
275
- await saveGasStatsData("solidity");
276
-
277
- // this may print coverage and gas statistics reports
278
- await reportCoverage("solidity");
279
- await reportGasStats("solidity");
271
+ await hre.hooks.runHandlerChain(
272
+ "test",
273
+ "onTestWorkerDone",
274
+ ["solidity"],
275
+ async () => {},
276
+ );
280
277
 
281
- if (includesFailures || includesErrors) {
282
- process.exitCode = 1;
283
- }
278
+ await hre.hooks.runHandlerChain(
279
+ "test",
280
+ "onTestRunDone",
281
+ ["solidity"],
282
+ async () => {},
283
+ );
284
284
 
285
285
  console.log();
286
286
 
287
- return {
288
- failed,
289
- passed,
290
- skipped,
291
- todo: 0,
292
- failureOutput,
293
- };
287
+ const summary = { failed, passed, skipped, todo: 0, failureOutput };
288
+
289
+ return includesFailures || includesErrors
290
+ ? errorResult(summary)
291
+ : successfulResult(summary);
294
292
  };
295
293
 
296
294
  export default runSolidityTests;
@@ -1,5 +1,6 @@
1
1
  import type { NewTaskActionFunction } from "../../../types/tasks.js";
2
2
 
3
+ import { errorResult, successfulResult } from "../../../utils/result.js";
3
4
  import {
4
5
  isTelemetryAllowed,
5
6
  setTelemetryEnabled,
@@ -15,8 +16,7 @@ const configureTelemetry: NewTaskActionFunction<
15
16
  > = async ({ enable, disable }) => {
16
17
  if (enable && disable) {
17
18
  console.error("Cannot enable and disable telemetry at the same time");
18
- process.exitCode = 1;
19
- return;
19
+ return errorResult();
20
20
  }
21
21
 
22
22
  if (enable) {
@@ -40,6 +40,8 @@ const configureTelemetry: NewTaskActionFunction<
40
40
  "Telemetry is disabled, to enable it run `npx hardhat telemetry --enable`",
41
41
  );
42
42
  }
43
+
44
+ return successfulResult();
43
45
  };
44
46
 
45
47
  export default configureTelemetry;
@@ -4,13 +4,21 @@ import type {
4
4
  Task,
5
5
  TaskArguments,
6
6
  } from "../../../types/tasks.js";
7
+ import type { TestSummary } from "../../../types/test.js";
8
+ import type { Result } from "../../../types/utils.js";
7
9
 
8
10
  import {
9
11
  assertHardhatInvariant,
10
12
  HardhatError,
11
13
  } from "@nomicfoundation/hardhat-errors";
14
+ import { isObject } from "@nomicfoundation/hardhat-utils/lang";
12
15
  import chalk, { type ChalkInstance } from "chalk";
13
16
 
17
+ import {
18
+ errorResult,
19
+ isResult,
20
+ successfulResult,
21
+ } from "../../../utils/result.js";
14
22
  import { HardhatRuntimeEnvironmentImplementation } from "../../core/hre.js";
15
23
 
16
24
  interface TestActionArguments {
@@ -21,10 +29,27 @@ interface TestActionArguments {
21
29
  verbosity: number;
22
30
  }
23
31
 
32
+ // Old plugins may only return { failed, passed } without skipped/todo,
33
+ // so we accept a partial shape and fill defaults in the coordinator.
34
+ interface PartialTestSummary extends Omit<TestSummary, "skipped" | "todo"> {
35
+ skipped?: number;
36
+ todo?: number;
37
+ }
38
+
39
+ function isTestSummary(value: unknown): value is PartialTestSummary {
40
+ return (
41
+ isObject(value) &&
42
+ typeof value.failed === "number" &&
43
+ typeof value.passed === "number" &&
44
+ (value.skipped === undefined || typeof value.skipped === "number") &&
45
+ (value.todo === undefined || typeof value.todo === "number")
46
+ );
47
+ }
48
+
24
49
  const runAllTests: NewTaskActionFunction<TestActionArguments> = async (
25
50
  { testFiles, chainType, grep, noCompile, verbosity },
26
51
  hre,
27
- ) => {
52
+ ): Promise<Result<void, void>> => {
28
53
  // If this code is executed, it means the user has not specified a test runner.
29
54
  // If file paths are specified, we need to determine which test runner applies to each test file.
30
55
  // If no file paths are specified, each test runner will execute all tests located under its configured path in the Hardhat configuration.
@@ -49,18 +74,10 @@ const runAllTests: NewTaskActionFunction<TestActionArguments> = async (
49
74
  hre._coverage.disableReport();
50
75
  }
51
76
 
52
- const testSummaries: Record<
53
- string,
54
- {
55
- failed?: number;
56
- passed?: number;
57
- skipped?: number;
58
- todo?: number;
59
- failureOutput?: string;
60
- }
61
- > = {};
77
+ const testSummaries: Record<string, TestSummary> = {};
62
78
 
63
79
  let failureIndex = 1;
80
+ let hasFailures = false;
64
81
  for (const subtask of thisTask.subtasks.values()) {
65
82
  const files = getTestFilesForSubtask(subtask, testFiles, subtasksToFiles);
66
83
 
@@ -84,18 +101,45 @@ const runAllTests: NewTaskActionFunction<TestActionArguments> = async (
84
101
  args.verbosity = verbosity;
85
102
  }
86
103
 
87
- const summaryId = subtask.id[subtask.id.length - 1];
88
-
89
104
  if (subtask.options.has("testSummaryIndex")) {
90
105
  args.testSummaryIndex = failureIndex;
106
+ }
107
+
108
+ const subtaskResult = await subtask.run(args);
91
109
 
92
- testSummaries[summaryId] = await subtask.run(args);
93
- failureIndex += testSummaries[summaryId].failed ?? 0;
94
- } else if (summaryId === "mocha") {
95
- // mocha doesn't use the testSummaryIndex, but it does return failure & success counts
96
- testSummaries[summaryId] = await subtask.run(args);
97
- } else {
98
- await subtask.run(args);
110
+ const isSubtaskResult = isResult(
111
+ subtaskResult,
112
+ isTestSummary,
113
+ isTestSummary,
114
+ );
115
+ const summary = isSubtaskResult
116
+ ? subtaskResult.success
117
+ ? subtaskResult.value
118
+ : subtaskResult.error
119
+ : isTestSummary(subtaskResult)
120
+ ? subtaskResult
121
+ : undefined;
122
+
123
+ if (summary !== undefined) {
124
+ const summaryId = subtask.id[subtask.id.length - 1];
125
+ testSummaries[summaryId] = {
126
+ skipped: 0,
127
+ todo: 0,
128
+ ...summary,
129
+ };
130
+
131
+ if (subtask.options.has("testSummaryIndex")) {
132
+ failureIndex += summary.failed;
133
+ }
134
+ }
135
+
136
+ if (
137
+ (isSubtaskResult && !subtaskResult.success) ||
138
+ // Backwards compatibility: old plugins may not return a Result, so fall
139
+ // back to the process exit code to detect failures
140
+ (process.exitCode !== undefined && process.exitCode !== 0)
141
+ ) {
142
+ hasFailures = true;
99
143
  }
100
144
  }
101
145
 
@@ -106,19 +150,19 @@ const runAllTests: NewTaskActionFunction<TestActionArguments> = async (
106
150
  const outputLines: string[] = [];
107
151
 
108
152
  for (const [subtaskName, results] of Object.entries(testSummaries)) {
109
- if (results.passed !== undefined && results.passed > 0) {
153
+ if (results.passed > 0) {
110
154
  passed.push([subtaskName, results.passed]);
111
155
  }
112
156
 
113
- if (results.failed !== undefined && results.failed > 0) {
157
+ if (results.failed > 0) {
114
158
  failed.push([subtaskName, results.failed]);
115
159
  }
116
160
 
117
- if (results.skipped !== undefined && results.skipped > 0) {
161
+ if (results.skipped > 0) {
118
162
  skipped.push([subtaskName, results.skipped]);
119
163
  }
120
164
 
121
- if (results.todo !== undefined && results.todo > 0) {
165
+ if (results.todo > 0) {
122
166
  todo.push([subtaskName, results.todo]);
123
167
  }
124
168
 
@@ -176,9 +220,11 @@ const runAllTests: NewTaskActionFunction<TestActionArguments> = async (
176
220
  console.log();
177
221
  }
178
222
 
179
- if (process.exitCode !== undefined && process.exitCode !== 0) {
223
+ if (hasFailures) {
180
224
  console.error("Test run failed");
181
225
  }
226
+
227
+ return hasFailures ? errorResult() : successfulResult();
182
228
  };
183
229
 
184
230
  function logSummaryLine(