hardhat 3.1.3 → 3.1.4

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 (27) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/src/internal/builtin-plugins/coverage/coverage-manager.d.ts +14 -14
  3. package/dist/src/internal/builtin-plugins/coverage/coverage-manager.d.ts.map +1 -1
  4. package/dist/src/internal/builtin-plugins/coverage/coverage-manager.js +66 -110
  5. package/dist/src/internal/builtin-plugins/coverage/coverage-manager.js.map +1 -1
  6. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/solidity.d.ts.map +1 -1
  7. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/solidity.js +13 -6
  8. package/dist/src/internal/builtin-plugins/coverage/hook-handlers/solidity.js.map +1 -1
  9. package/dist/src/internal/builtin-plugins/coverage/process-coverage.d.ts +21 -0
  10. package/dist/src/internal/builtin-plugins/coverage/process-coverage.d.ts.map +1 -0
  11. package/dist/src/internal/builtin-plugins/coverage/process-coverage.js +291 -0
  12. package/dist/src/internal/builtin-plugins/coverage/process-coverage.js.map +1 -0
  13. package/dist/src/internal/builtin-plugins/coverage/reports/html.d.ts +3 -0
  14. package/dist/src/internal/builtin-plugins/coverage/reports/html.d.ts.map +1 -0
  15. package/dist/src/internal/builtin-plugins/coverage/reports/html.js +37 -0
  16. package/dist/src/internal/builtin-plugins/coverage/reports/html.js.map +1 -0
  17. package/dist/src/internal/builtin-plugins/coverage/types.d.ts +9 -3
  18. package/dist/src/internal/builtin-plugins/coverage/types.d.ts.map +1 -1
  19. package/package.json +2 -1
  20. package/src/internal/builtin-plugins/coverage/coverage-manager.ts +121 -176
  21. package/src/internal/builtin-plugins/coverage/hook-handlers/solidity.ts +19 -8
  22. package/src/internal/builtin-plugins/coverage/process-coverage.ts +442 -0
  23. package/src/internal/builtin-plugins/coverage/reports/html.ts +56 -0
  24. package/src/internal/builtin-plugins/coverage/types.ts +8 -3
  25. package/templates/hardhat-3/01-node-test-runner-viem/package.json +1 -1
  26. package/templates/hardhat-3/02-mocha-ethers/package.json +1 -1
  27. package/templates/hardhat-3/03-minimal/package.json +1 -1
@@ -0,0 +1,291 @@
1
+ import chalk from "chalk";
2
+ // Use constants for the Uint8Array to improve memory usage (1 byte vs 8 bytes per item)
3
+ const STATUS_NOT_EXECUTED = 0; // equivalent to false
4
+ const STATUS_EXECUTED = 1; // equivalent to true
5
+ const STATUS_IGNORED = 2; // equivalent to null
6
+ /**
7
+ * Processes the raw EDR coverage information for a file and returns the executed and
8
+ * non-executed statements and lines.
9
+ *
10
+ * @param fileContent The original file content being analyzed
11
+ * @param metadata Coverage metadata received from EDR for this file
12
+ * @param hitTags The coverage tags recorded as executed during the test run
13
+ * for this specific file.
14
+ *
15
+ * @returns An object containing:
16
+ * - statements: the executed and not-executed statements
17
+ * - lines: the executed and not-executed line numbers
18
+ */
19
+ export function getProcessedCoverageInfo(fileContent, metadata, hitTags) {
20
+ const statementsByExecution = partitionStatementsByExecution(metadata, hitTags);
21
+ const { start, end } = getCoverageBounds(statementsByExecution, fileContent.length);
22
+ const characterCoverage = buildCharacterCoverage(fileContent, start, end, statementsByExecution.unexecuted);
23
+ // printStatementsForDebugging(fileContent, statementsByExecution);
24
+ // printCharacterCoverageForDebugging(fileContent, characterCoverage);
25
+ return {
26
+ lines: partitionLinesByExecution(fileContent, characterCoverage),
27
+ };
28
+ }
29
+ function partitionStatementsByExecution(metadata, hitTags) {
30
+ const executed = [];
31
+ const unexecuted = [];
32
+ for (const node of metadata) {
33
+ if (hitTags.has(node.tag)) {
34
+ executed.push(node);
35
+ }
36
+ else {
37
+ unexecuted.push(node);
38
+ }
39
+ }
40
+ return {
41
+ executed,
42
+ unexecuted,
43
+ };
44
+ }
45
+ // Determine the minimum and maximum character indexes that define the range
46
+ // where coverage should be calculated, excluding parts that the tests never
47
+ // reach. This removes irrelevant sections from coverage analysis, such as the
48
+ // beginning or end of each Solidity file.
49
+ // Example:
50
+ // // SPDX-License-Identifier: MIT
51
+ // pragma solidity ^0.8.0;
52
+ function getCoverageBounds(statementsByExecution, fileLength) {
53
+ let start = fileLength;
54
+ let end = 0;
55
+ const { executed, unexecuted } = statementsByExecution;
56
+ for (const s of [...executed, ...unexecuted]) {
57
+ if (s.startUtf16 < start) {
58
+ start = s.startUtf16;
59
+ }
60
+ if (s.endUtf16 > end) {
61
+ end = s.endUtf16;
62
+ }
63
+ }
64
+ return { start, end };
65
+ }
66
+ // Return an array with the same length as the file content. Each position in
67
+ // the array corresponds to a character in the file. The value at each position
68
+ // indicates whether that character was executed during tests (STATUS_EXECUTED),
69
+ // not executed (STATUS_NOT_EXECUTED), or not relevant for coverage
70
+ // (STATUS_IGNORED). STATUS_IGNORED is used to indicate characters that are not
71
+ // executed during test, such as those found at the start or end of every Solidity file.
72
+ // Example:
73
+ // // SPDX-License-Identifier: MIT
74
+ // pragma solidity ^0.8.0;
75
+ function buildCharacterCoverage(fileContent, start, end, unexecutedStatements) {
76
+ // Use Uint8Array instead of Array<null | boolean> for memory efficiency.
77
+ // We initialize with STATUS_IGNORED (equivalent to filling with null)
78
+ const characterCoverage = new Uint8Array(fileContent.length).fill(STATUS_IGNORED);
79
+ // Initially mark all characters that may be executed during the tests as
80
+ // STATUS_EXECUTED. They will be set to false later if they are not executed.
81
+ // The coverage statement received from EDR will provide this information.
82
+ // Setting everything to true first simplifies the logic for extracting
83
+ // coverage data. Starting with false and toggling only covered characters
84
+ // would make statement processing more complex.
85
+ for (let i = start; i < end; i++) {
86
+ if (charMustBeIgnored(fileContent[i])) {
87
+ continue;
88
+ }
89
+ characterCoverage[i] = STATUS_EXECUTED;
90
+ }
91
+ for (const statement of unexecutedStatements) {
92
+ for (let i = statement.startUtf16; i < statement.endUtf16; i++) {
93
+ if (characterCoverage[i] === STATUS_IGNORED) {
94
+ continue;
95
+ }
96
+ characterCoverage[i] = STATUS_NOT_EXECUTED;
97
+ }
98
+ }
99
+ markNonExecutablePatterns(fileContent, characterCoverage);
100
+ return characterCoverage;
101
+ }
102
+ // The following characters are not relevant for the code coverage, so they
103
+ // must be ignored when marking characters as executed (true) or not executed (false)
104
+ function charMustBeIgnored(char) {
105
+ const code = char.charCodeAt(0);
106
+ return (code === 32 || // Space
107
+ (code >= 9 && code <= 13) || // \t (9), \n (10), \v (11), \f (12), \r (13)
108
+ code === 123 || // {
109
+ code === 125 // }
110
+ );
111
+ }
112
+ // Mark different types of substrings as not relevant for code coverage (set them to STATUS_IGNORED).
113
+ // For example, all "else" substrings or comments are not relevant for code coverage.
114
+ function markNonExecutablePatterns(fileContent, characterCoverage) {
115
+ // Comments that start with //
116
+ markMatchingCharsWithIgnored(fileContent, characterCoverage, /\/\/.*?(?=\n|$)/g);
117
+ // Comments wrapped between /* and */
118
+ markMatchingCharsWithIgnored(fileContent, characterCoverage, /\/\*[\s\S]*?\*\//g);
119
+ // Lines containing `else`, since they do not represent executable code by themselves.
120
+ // Keep in mind that `else` is preceded by a closing brace and followed by an opening brace.
121
+ // This can span multiple lines.
122
+ markMatchingCharsWithIgnored(fileContent, characterCoverage, /\}\s*\belse\b\s*\{/g);
123
+ // Lines containing the function signature. This can span multiple lines
124
+ markMatchingCharsWithIgnored(fileContent, characterCoverage, /^\s*(function\s+[A-Za-z_$][A-Za-z0-9_$]*\s*\([\s\S]*?\)[^{]*?)(?=\s*\{)/gm);
125
+ // Lines containing the catch signature. This can span multiple lines.
126
+ markMatchingCharsWithIgnored(fileContent, characterCoverage, /\bcatch\b(?:\s+[A-Za-z_][A-Za-z0-9_]*)?\s*(?:\([\s\S]*?\))?(?=\s*\{)/g);
127
+ }
128
+ function markMatchingCharsWithIgnored(fileContent, characterCoverage, regex) {
129
+ for (const match of fileContent.matchAll(regex)) {
130
+ for (let i = match.index; i < match.index + match[0].length; i++) {
131
+ characterCoverage[i] = STATUS_IGNORED;
132
+ }
133
+ }
134
+ }
135
+ // Generate non overlapping coverage statements. Every character between the start
136
+ // and end indexes is guaranteed to be either executed or not executed.
137
+ // Unlike the statements received from EDR, which may include nested sub
138
+ // statements, these are processed and have no sub statements or overlapping statements.
139
+ // Example:
140
+ // [
141
+ // { start: 12, end: 20, executed: true },
142
+ // { start: 15, end: 17, executed: true }
143
+ // ]
144
+ // ->
145
+ // [
146
+ // { start: 12, end: 20, executed: true }
147
+ // ]
148
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars
149
+ -- currently not used, but it will be used to create more detailed.
150
+ It will be used to return statements from the function `getProcessedCoverageInfo` */
151
+ function getProcessedExecutedStatements(characterCoverage) {
152
+ const executed = generateProcessedStatements(characterCoverage, STATUS_EXECUTED);
153
+ const unexecuted = generateProcessedStatements(characterCoverage, STATUS_NOT_EXECUTED);
154
+ return {
155
+ executed,
156
+ unexecuted,
157
+ };
158
+ }
159
+ // Based on the marked file, where each character is marked as either
160
+ // executed (STATUS_EXECUTED) or not executed (STATUS_NOT_EXECUTED),
161
+ // generate non-overlapping statements that indicate the start and
162
+ // end indices, along with whether they were executed or not.
163
+ function generateProcessedStatements(characterCoverage, targetStatus) {
164
+ const ranges = [];
165
+ const fileLength = characterCoverage.length;
166
+ let start = -1;
167
+ for (let i = 0; i < fileLength; i++) {
168
+ if (characterCoverage[i] === targetStatus) {
169
+ if (start === -1) {
170
+ start = i; // begin new range
171
+ }
172
+ }
173
+ else {
174
+ if (start !== -1) {
175
+ // Map back to boolean for the output object
176
+ ranges.push({
177
+ startUtf16: start,
178
+ endUtf16: i - 1,
179
+ executed: targetStatus === STATUS_EXECUTED,
180
+ });
181
+ start = -1;
182
+ }
183
+ }
184
+ }
185
+ // close last range if file ends inside a run
186
+ if (start !== -1) {
187
+ ranges.push({
188
+ startUtf16: start,
189
+ endUtf16: fileLength - 1,
190
+ executed: targetStatus === STATUS_EXECUTED,
191
+ });
192
+ }
193
+ return ranges;
194
+ }
195
+ // Return the executed and non executed lines based on the marked file.
196
+ // Some lines are excluded from the execution count, for example, comments.
197
+ function partitionLinesByExecution(fileContent, characterCoverage) {
198
+ const executed = new Map();
199
+ const unexecuted = new Map();
200
+ let lineStart = 0;
201
+ let isLineIgnored = true;
202
+ let isLineExecutedOrIgnored = true;
203
+ let lineNumber = 1; // File lines start at 1
204
+ // Helper to process a line and push to correct map
205
+ const processLine = (endIndex) => {
206
+ // Only process if the line isn't entirely ignored
207
+ if (!isLineIgnored) {
208
+ const lineText = fileContent.slice(lineStart, endIndex);
209
+ if (isLineExecutedOrIgnored) {
210
+ executed.set(lineNumber, lineText);
211
+ }
212
+ else {
213
+ unexecuted.set(lineNumber, lineText);
214
+ }
215
+ }
216
+ // Reset state for the next line
217
+ lineStart = endIndex + 1;
218
+ isLineIgnored = true;
219
+ isLineExecutedOrIgnored = true;
220
+ lineNumber++;
221
+ };
222
+ for (let i = 0; i < fileContent.length; i++) {
223
+ const char = fileContent[i];
224
+ const status = characterCoverage[i];
225
+ if (status !== STATUS_IGNORED) {
226
+ isLineIgnored = false;
227
+ }
228
+ if (status === STATUS_NOT_EXECUTED) {
229
+ isLineExecutedOrIgnored = false;
230
+ }
231
+ if (char === "\n") {
232
+ processLine(i);
233
+ }
234
+ }
235
+ // Handle the final line if the file doesn't end in a newline
236
+ if (lineStart < fileContent.length) {
237
+ processLine(fileContent.length);
238
+ }
239
+ return { executed, unexecuted };
240
+ }
241
+ // Enable this function while debugging to display the coverage for a file.
242
+ // The file will be printed with green characters when they are executed,
243
+ // red characters when they are not executed,
244
+ // and gray characters when they are irrelevant for code coverage.
245
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars
246
+ -- this function can be enabled for debugging purposes */
247
+ function printStatementsForDebugging(fileContent, statementsByExecution) {
248
+ const relativePath = statementsByExecution.executed.length > 0
249
+ ? statementsByExecution.executed[0].relativePath
250
+ : statementsByExecution.unexecuted[0].relativePath;
251
+ console.debug("Statements for file: " + relativePath);
252
+ console.debug("Executed statements:");
253
+ let counter = 0;
254
+ for (const statement of statementsByExecution.executed) {
255
+ console.debug(counter++ + " ---");
256
+ for (let i = statement.startUtf16; i < statement.endUtf16; i++) {
257
+ process.stdout.write(chalk.gray(fileContent[i]));
258
+ }
259
+ console.debug();
260
+ }
261
+ console.debug();
262
+ console.debug("Unexecuted statements:");
263
+ counter = 0;
264
+ for (const statement of statementsByExecution.unexecuted) {
265
+ console.debug(counter++ + " ---");
266
+ for (let i = statement.startUtf16; i < statement.endUtf16; i++) {
267
+ process.stdout.write(chalk.gray(fileContent[i]));
268
+ }
269
+ console.debug();
270
+ }
271
+ }
272
+ // Enable this function while debugging to display the coverage for a file.
273
+ // The file will be printed with green characters when they are executed,
274
+ // red characters when they are not executed,
275
+ // and gray characters when they are irrelevant for code coverage.
276
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars
277
+ -- this function can be enabled for debugging purposes */
278
+ function printCharacterCoverageForDebugging(fileContent, characterCoverage) {
279
+ for (let i = 0; i < characterCoverage.length; i++) {
280
+ if (characterCoverage[i] === STATUS_IGNORED) {
281
+ process.stdout.write(chalk.gray(fileContent[i]));
282
+ }
283
+ else if (characterCoverage[i] === STATUS_EXECUTED) {
284
+ process.stdout.write(chalk.green(fileContent[i]));
285
+ }
286
+ else {
287
+ process.stdout.write(chalk.red(fileContent[i]));
288
+ }
289
+ }
290
+ }
291
+ //# sourceMappingURL=process-coverage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-coverage.js","sourceRoot":"","sources":["../../../../../src/internal/builtin-plugins/coverage/process-coverage.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,wFAAwF;AACxF,MAAM,mBAAmB,GAAG,CAAC,CAAC,CAAC,sBAAsB;AACrD,MAAM,eAAe,GAAG,CAAC,CAAC,CAAC,qBAAqB;AAChD,MAAM,cAAc,GAAG,CAAC,CAAC,CAAC,qBAAqB;AAE/C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,wBAAwB,CACtC,WAAmB,EACnB,QAA0B,EAC1B,OAAoB;IAOpB,MAAM,qBAAqB,GAAG,8BAA8B,CAC1D,QAAQ,EACR,OAAO,CACR,CAAC;IAEF,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,iBAAiB,CACtC,qBAAqB,EACrB,WAAW,CAAC,MAAM,CACnB,CAAC;IAEF,MAAM,iBAAiB,GAAG,sBAAsB,CAC9C,WAAW,EACX,KAAK,EACL,GAAG,EACH,qBAAqB,CAAC,UAAU,CACjC,CAAC;IAEF,mEAAmE;IACnE,sEAAsE;IAEtE,OAAO;QACL,KAAK,EAAE,yBAAyB,CAAC,WAAW,EAAE,iBAAiB,CAAC;KACjE,CAAC;AACJ,CAAC;AAED,SAAS,8BAA8B,CACrC,QAA0B,EAC1B,OAAoB;IAKpB,MAAM,QAAQ,GAAgB,EAAE,CAAC;IACjC,MAAM,UAAU,GAAgB,EAAE,CAAC;IAEnC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO;QACL,QAAQ;QACR,UAAU;KACX,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,4EAA4E;AAC5E,8EAA8E;AAC9E,0CAA0C;AAC1C,WAAW;AACX,kCAAkC;AAClC,0BAA0B;AAC1B,SAAS,iBAAiB,CACxB,qBAGC,EACD,UAAkB;IAElB,IAAI,KAAK,GAAG,UAAU,CAAC;IACvB,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,qBAAqB,CAAC;IAEvD,KAAK,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,EAAE,GAAG,UAAU,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,CAAC,UAAU,GAAG,KAAK,EAAE,CAAC;YACzB,KAAK,GAAG,CAAC,CAAC,UAAU,CAAC;QACvB,CAAC;QAED,IAAI,CAAC,CAAC,QAAQ,GAAG,GAAG,EAAE,CAAC;YACrB,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACxB,CAAC;AAED,6EAA6E;AAC7E,+EAA+E;AAC/E,gFAAgF;AAChF,mEAAmE;AACnE,+EAA+E;AAC/E,wFAAwF;AACxF,WAAW;AACX,kCAAkC;AAClC,0BAA0B;AAC1B,SAAS,sBAAsB,CAC7B,WAAmB,EACnB,KAAa,EACb,GAAW,EACX,oBAAiC;IAEjC,yEAAyE;IACzE,sEAAsE;IACtE,MAAM,iBAAiB,GAAG,IAAI,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,CAC/D,cAAc,CACf,CAAC;IAEF,yEAAyE;IACzE,6EAA6E;IAC7E,0EAA0E;IAC1E,uEAAuE;IACvE,0EAA0E;IAC1E,gDAAgD;IAChD,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtC,SAAS;QACX,CAAC;QAED,iBAAiB,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC;IACzC,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,oBAAoB,EAAE,CAAC;QAC7C,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/D,IAAI,iBAAiB,CAAC,CAAC,CAAC,KAAK,cAAc,EAAE,CAAC;gBAC5C,SAAS;YACX,CAAC;YAED,iBAAiB,CAAC,CAAC,CAAC,GAAG,mBAAmB,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,yBAAyB,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;IAE1D,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED,2EAA2E;AAC3E,qFAAqF;AACrF,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAEhC,OAAO,CACL,IAAI,KAAK,EAAE,IAAI,QAAQ;QACvB,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,IAAI,6CAA6C;QAC1E,IAAI,KAAK,GAAG,IAAI,IAAI;QACpB,IAAI,KAAK,GAAG,CAAC,IAAI;KAClB,CAAC;AACJ,CAAC;AAED,qGAAqG;AACrG,qFAAqF;AACrF,SAAS,yBAAyB,CAChC,WAAmB,EACnB,iBAA6B;IAE7B,8BAA8B;IAC9B,4BAA4B,CAC1B,WAAW,EACX,iBAAiB,EACjB,kBAAkB,CACnB,CAAC;IAEF,qCAAqC;IACrC,4BAA4B,CAC1B,WAAW,EACX,iBAAiB,EACjB,mBAAmB,CACpB,CAAC;IAEF,sFAAsF;IACtF,4FAA4F;IAC5F,gCAAgC;IAChC,4BAA4B,CAC1B,WAAW,EACX,iBAAiB,EACjB,qBAAqB,CACtB,CAAC;IAEF,wEAAwE;IACxE,4BAA4B,CAC1B,WAAW,EACX,iBAAiB,EACjB,2EAA2E,CAC5E,CAAC;IAEF,sEAAsE;IACtE,4BAA4B,CAC1B,WAAW,EACX,iBAAiB,EACjB,uEAAuE,CACxE,CAAC;AACJ,CAAC;AAED,SAAS,4BAA4B,CACnC,WAAmB,EACnB,iBAA6B,EAC7B,KAAa;IAEb,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAChD,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACjE,iBAAiB,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC;QACxC,CAAC;IACH,CAAC;AACH,CAAC;AAED,kFAAkF;AAClF,uEAAuE;AACvE,wEAAwE;AACxE,wFAAwF;AACxF,WAAW;AACX,IAAI;AACJ,6CAA6C;AAC7C,2CAA2C;AAC3C,IAAI;AACJ,KAAK;AACL,IAAI;AACJ,4CAA4C;AAC5C,IAAI;AACJ;;oFAEoF;AACpF,SAAS,8BAA8B,CAAC,iBAA6B;IAInE,MAAM,QAAQ,GAAG,2BAA2B,CAC1C,iBAAiB,EACjB,eAAe,CAChB,CAAC;IACF,MAAM,UAAU,GAAG,2BAA2B,CAC5C,iBAAiB,EACjB,mBAAmB,CACpB,CAAC;IAEF,OAAO;QACL,QAAQ;QACR,UAAU;KACX,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,oEAAoE;AACpE,kEAAkE;AAClE,6DAA6D;AAC7D,SAAS,2BAA2B,CAClC,iBAA6B,EAC7B,YAAoB;IAEpB,MAAM,MAAM,GAA8B,EAAE,CAAC;IAC7C,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,CAAC;IAE5C,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IAEf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,IAAI,iBAAiB,CAAC,CAAC,CAAC,KAAK,YAAY,EAAE,CAAC;YAC1C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,KAAK,GAAG,CAAC,CAAC,CAAC,kBAAkB;YAC/B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,4CAA4C;gBAC5C,MAAM,CAAC,IAAI,CAAC;oBACV,UAAU,EAAE,KAAK;oBACjB,QAAQ,EAAE,CAAC,GAAG,CAAC;oBACf,QAAQ,EAAE,YAAY,KAAK,eAAe;iBAC3C,CAAC,CAAC;gBACH,KAAK,GAAG,CAAC,CAAC,CAAC;YACb,CAAC;QACH,CAAC;IACH,CAAC;IAED,6CAA6C;IAC7C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,CAAC;YACV,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,UAAU,GAAG,CAAC;YACxB,QAAQ,EAAE,YAAY,KAAK,eAAe;SAC3C,CAAC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,uEAAuE;AACvE,2EAA2E;AAC3E,SAAS,yBAAyB,CAChC,WAAmB,EACnB,iBAA6B;IAK7B,MAAM,QAAQ,GAAwB,IAAI,GAAG,EAAE,CAAC;IAChD,MAAM,UAAU,GAAwB,IAAI,GAAG,EAAE,CAAC;IAElD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,aAAa,GAAG,IAAI,CAAC;IACzB,IAAI,uBAAuB,GAAG,IAAI,CAAC;IACnC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,wBAAwB;IAE5C,mDAAmD;IACnD,MAAM,WAAW,GAAG,CAAC,QAAgB,EAAE,EAAE;QACvC,kDAAkD;QAClD,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;YAExD,IAAI,uBAAuB,EAAE,CAAC;gBAC5B,QAAQ,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACrC,CAAC;iBAAM,CAAC;gBACN,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;QAED,gCAAgC;QAChC,SAAS,GAAG,QAAQ,GAAG,CAAC,CAAC;QACzB,aAAa,GAAG,IAAI,CAAC;QACrB,uBAAuB,GAAG,IAAI,CAAC;QAC/B,UAAU,EAAE,CAAC;IACf,CAAC,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC5B,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAEpC,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;YAC9B,aAAa,GAAG,KAAK,CAAC;QACxB,CAAC;QACD,IAAI,MAAM,KAAK,mBAAmB,EAAE,CAAC;YACnC,uBAAuB,GAAG,KAAK,CAAC;QAClC,CAAC;QAED,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,WAAW,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,IAAI,SAAS,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC;QACnC,WAAW,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;AAClC,CAAC;AAED,2EAA2E;AAC3E,yEAAyE;AACzE,6CAA6C;AAC7C,kEAAkE;AAClE;yDACyD;AACzD,SAAS,2BAA2B,CAClC,WAAmB,EACnB,qBAGC;IAED,MAAM,YAAY,GAChB,qBAAqB,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QACvC,CAAC,CAAC,qBAAqB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY;QAChD,CAAC,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAEvD,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,YAAY,CAAC,CAAC;IAEtD,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACtC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,SAAS,IAAI,qBAAqB,CAAC,QAAQ,EAAE,CAAC;QACvD,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC;QAElC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IACxC,OAAO,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,SAAS,IAAI,qBAAqB,CAAC,UAAU,EAAE,CAAC;QACzD,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC;QAElC,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;QAED,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,yEAAyE;AACzE,6CAA6C;AAC7C,kEAAkE;AAClE;yDACyD;AACzD,SAAS,kCAAkC,CACzC,WAAmB,EACnB,iBAA6B;IAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClD,IAAI,iBAAiB,CAAC,CAAC,CAAC,KAAK,cAAc,EAAE,CAAC;YAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;aAAM,IAAI,iBAAiB,CAAC,CAAC,CAAC,KAAK,eAAe,EAAE,CAAC;YACpD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Report } from "../coverage-manager.js";
2
+ export declare function generateHtmlReport(report: Report, htmlReportPath: string): Promise<void>;
3
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../../../../../src/internal/builtin-plugins/coverage/reports/html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAYrD,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAwCf"}
@@ -0,0 +1,37 @@
1
+ import path from "node:path";
2
+ import { mkdir } from "@nomicfoundation/hardhat-utils/fs";
3
+ import { istanbulLibCoverage, istanbulLibReport, istanbulReports, } from "@nomicfoundation/hardhat-vendored/coverage";
4
+ export async function generateHtmlReport(report, htmlReportPath) {
5
+ const baseDir = process.cwd();
6
+ const coverageMap = istanbulLibCoverage.createCoverageMap({});
7
+ await mkdir(htmlReportPath);
8
+ // Construct coverage data for each tested file,
9
+ // detailing whether each line was executed or not.
10
+ for (const [p, coverageInfo] of Object.entries(report)) {
11
+ const testedFilePath = path.join(baseDir, p);
12
+ const fc = {
13
+ path: testedFilePath,
14
+ statementMap: {},
15
+ fnMap: {}, // Cannot be derived from current report data
16
+ branchMap: {}, // Cannot be derived from current report data
17
+ s: {},
18
+ f: {}, // Cannot be derived from current report data
19
+ b: {},
20
+ };
21
+ for (const [line, count] of coverageInfo.lineExecutionCounts) {
22
+ fc.statementMap[line] = {
23
+ start: { line, column: 0 },
24
+ end: { line, column: 0 },
25
+ };
26
+ // TODO: currently EDR does not provide per-statement coverage counts
27
+ fc.s[line] = count > 0 ? 1 : 0; // mark as covered if hit at least once
28
+ }
29
+ coverageMap.addFileCoverage(fc);
30
+ }
31
+ const context = istanbulLibReport.createContext({
32
+ dir: htmlReportPath,
33
+ coverageMap,
34
+ });
35
+ istanbulReports.create("html", undefined).execute(context);
36
+ }
37
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../../../../../src/internal/builtin-plugins/coverage/reports/html.ts"],"names":[],"mappings":"AAGA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,KAAK,EAAE,MAAM,mCAAmC,CAAC;AAC1D,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAChB,MAAM,4CAA4C,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAc,EACd,cAAsB;IAEtB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC9B,MAAM,WAAW,GAAG,mBAAmB,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;IAE9D,MAAM,KAAK,CAAC,cAAc,CAAC,CAAC;IAE5B,gDAAgD;IAChD,mDAAmD;IACnD,KAAK,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACvD,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAE7C,MAAM,EAAE,GAAqB;YAC3B,IAAI,EAAE,cAAc;YACpB,YAAY,EAAE,EAAE;YAChB,KAAK,EAAE,EAAE,EAAE,6CAA6C;YACxD,SAAS,EAAE,EAAE,EAAE,6CAA6C;YAC5D,CAAC,EAAE,EAAE;YACL,CAAC,EAAE,EAAE,EAAE,6CAA6C;YACpD,CAAC,EAAE,EAAE;SACN,CAAC;QAEF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,YAAY,CAAC,mBAAmB,EAAE,CAAC;YAC7D,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG;gBACtB,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;gBAC1B,GAAG,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE;aACzB,CAAC;YAEF,qEAAqE;YACrE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,uCAAuC;QACzE,CAAC;QAED,WAAW,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,OAAO,GAAG,iBAAiB,CAAC,aAAa,CAAC;QAC9C,GAAG,EAAE,cAAc;QACnB,WAAW;KACZ,CAAC,CAAC;IAEH,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAC7D,CAAC"}
@@ -1,9 +1,14 @@
1
- export type Tag = string;
1
+ type Tag = string;
2
2
  export interface Statement {
3
3
  relativePath: string;
4
4
  tag: Tag;
5
- startLine: number;
6
- endLine: number;
5
+ startUtf16: number;
6
+ endUtf16: number;
7
+ }
8
+ export interface ReportCoverageStatement {
9
+ startUtf16: number;
10
+ endUtf16: number;
11
+ executed: boolean;
7
12
  }
8
13
  export type CoverageMetadata = Statement[];
9
14
  export type CoverageData = Tag[];
@@ -16,4 +21,5 @@ export interface CoverageManager {
16
21
  enableReport(): void;
17
22
  disableReport(): void;
18
23
  }
24
+ export {};
19
25
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/internal/builtin-plugins/coverage/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC;AACzB,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AACD,MAAM,MAAM,gBAAgB,GAAG,SAAS,EAAE,CAAC;AAC3C,MAAM,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC;AACjC,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC,MAAM,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC,YAAY,IAAI,IAAI,CAAC;IACrB,aAAa,IAAI,IAAI,CAAC;CACvB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/internal/builtin-plugins/coverage/types.ts"],"names":[],"mappings":"AAAA,KAAK,GAAG,GAAG,MAAM,CAAC;AAClB,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,GAAG,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AACD,MAAM,MAAM,gBAAgB,GAAG,SAAS,EAAE,CAAC;AAC3C,MAAM,MAAM,YAAY,GAAG,GAAG,EAAE,CAAC;AACjC,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC,MAAM,CAAC,GAAG,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAExC,YAAY,IAAI,IAAI,CAAC;IACrB,aAAa,IAAI,IAAI,CAAC;CACvB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hardhat",
3
- "version": "3.1.3",
3
+ "version": "3.1.4",
4
4
  "description": "Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.",
5
5
  "homepage": "https://github.com/nomicfoundation/hardhat/tree/v-next/v-next/hardhat",
6
6
  "repository": {
@@ -74,6 +74,7 @@
74
74
  "@nomicfoundation/edr": "0.12.0-next.22",
75
75
  "@nomicfoundation/hardhat-errors": "^3.0.6",
76
76
  "@nomicfoundation/hardhat-utils": "^3.0.5",
77
+ "@nomicfoundation/hardhat-vendored": "^3.0.0",
77
78
  "@nomicfoundation/hardhat-zod-utils": "^3.0.1",
78
79
  "@nomicfoundation/solidity-analyzer": "^0.1.1",
79
80
  "@sentry/core": "^9.4.0",