@rpcbase/test 0.357.0 → 0.358.0
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.
- package/dist/clearDatabase.js +12 -10
- package/dist/clearDatabase.js.map +1 -1
- package/dist/cli.js +556 -439
- package/dist/cli.js.map +1 -1
- package/dist/coverage/collect.js +101 -63
- package/dist/coverage/collect.js.map +1 -1
- package/dist/coverage/config-loader.js +230 -180
- package/dist/coverage/config-loader.js.map +1 -1
- package/dist/coverage/config.js +100 -76
- package/dist/coverage/config.js.map +1 -1
- package/dist/coverage/console-text-report.js +220 -175
- package/dist/coverage/console-text-report.js.map +1 -1
- package/dist/coverage/files.js +58 -45
- package/dist/coverage/files.js.map +1 -1
- package/dist/coverage/fixtures.js +38 -27
- package/dist/coverage/fixtures.js.map +1 -1
- package/dist/coverage/global-setup.js +18 -15
- package/dist/coverage/global-setup.js.map +1 -1
- package/dist/coverage/index.js +55 -38
- package/dist/coverage/index.js.map +1 -1
- package/dist/coverage/report.js +466 -341
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/reporter.js +60 -47
- package/dist/coverage/reporter.js.map +1 -1
- package/dist/coverage/v8-tracker.js +147 -115
- package/dist/coverage/v8-tracker.js.map +1 -1
- package/dist/index.js +75 -46
- package/dist/index.js.map +1 -1
- package/dist/runners/playwright.js +563 -438
- package/dist/runners/playwright.js.map +1 -1
- package/dist/runners/process.d.ts.map +1 -1
- package/dist/runners/process.js +183 -125
- package/dist/runners/process.js.map +1 -1
- package/dist/runners/vitest.js +171 -124
- package/dist/runners/vitest.js.map +1 -1
- package/dist/serverCoverage.js +42 -28
- package/dist/serverCoverage.js.map +1 -1
- package/dist/vitest.config.d.ts +1 -1
- package/dist/vitest.config.js +74 -62
- package/dist/vitest.config.js.map +1 -1
- package/package.json +6 -6
package/dist/coverage/report.js
CHANGED
|
@@ -1,397 +1,522 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { createCollectCoverageMatcher, toPosix } from "./collect.js";
|
|
3
|
-
import { generateConsoleTextCoverageReport } from "./console-text-report.js";
|
|
4
|
-
import fsPromises from "node:fs/promises";
|
|
1
|
+
import fs from "node:fs/promises";
|
|
5
2
|
import path from "node:path";
|
|
6
3
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import picomatch from "picomatch";
|
|
8
4
|
import * as libCoverage from "istanbul-lib-coverage";
|
|
9
5
|
import * as libInstrument from "istanbul-lib-instrument";
|
|
10
6
|
import fg from "fast-glob";
|
|
7
|
+
import picomatch from "picomatch";
|
|
11
8
|
import v8ToIstanbul from "v8-to-istanbul";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
import { createCollectCoverageMatcher, toPosix } from "./collect.js";
|
|
10
|
+
import { generateConsoleTextCoverageReport } from "./console-text-report.js";
|
|
11
|
+
import { findCoverageFiles } from "./files.js";
|
|
12
|
+
const TEXT_REPORT_FILENAME = "coverage.txt";
|
|
13
|
+
class CoverageThresholdError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "CoverageThresholdError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
20
19
|
async function generateCoverageReport(config) {
|
|
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
|
-
|
|
20
|
+
const coverageFiles = await findCoverageFiles(config);
|
|
21
|
+
if (coverageFiles.length === 0) {
|
|
22
|
+
console.warn("[coverage] no V8 coverage artifacts were generated");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const coverageLib = resolveCoverageLib();
|
|
26
|
+
const coverageMap = coverageLib.createCoverageMap({});
|
|
27
|
+
const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir);
|
|
28
|
+
for (const file of coverageFiles) {
|
|
29
|
+
const payload = await readCoverageFile(file);
|
|
30
|
+
if (!payload) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
for (const script of payload.scripts) {
|
|
34
|
+
await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (config.includeAllFiles) {
|
|
38
|
+
await includeUntestedFiles(coverageMap, config, matchesCollectCoverageFrom);
|
|
39
|
+
}
|
|
40
|
+
if (coverageMap.files().length === 0) {
|
|
41
|
+
console.warn("[coverage] no library files matched the coverage filters");
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
await fs.rm(config.coverageReportDir, {
|
|
45
|
+
recursive: true,
|
|
46
|
+
force: true
|
|
47
|
+
});
|
|
48
|
+
await fs.mkdir(config.coverageReportDir, {
|
|
49
|
+
recursive: true
|
|
50
|
+
});
|
|
51
|
+
const {
|
|
52
|
+
createContext,
|
|
53
|
+
reports
|
|
54
|
+
} = await loadIstanbulModules();
|
|
55
|
+
const context = createContext({
|
|
56
|
+
dir: config.coverageReportDir,
|
|
57
|
+
coverageMap,
|
|
58
|
+
defaultSummarizer: "pkg"
|
|
59
|
+
});
|
|
60
|
+
const {
|
|
61
|
+
output: reportOutput,
|
|
62
|
+
summarizer
|
|
63
|
+
} = generateConsoleTextCoverageReport(reports, context);
|
|
64
|
+
process.stdout.write(reportOutput);
|
|
65
|
+
reports.create("text", {
|
|
66
|
+
file: TEXT_REPORT_FILENAME,
|
|
67
|
+
summarizer
|
|
68
|
+
}).execute(context);
|
|
69
|
+
console.log(`[coverage] Full text report saved to ${path.join(config.coverageReportDir, TEXT_REPORT_FILENAME)}`);
|
|
70
|
+
const summary = coverageMap.getCoverageSummary();
|
|
71
|
+
enforceThresholds(summary, config.thresholds, "global");
|
|
72
|
+
const targets = Array.isArray(config.thresholdTargets) ? config.thresholdTargets : [];
|
|
73
|
+
if (targets.length > 0) {
|
|
74
|
+
const fileSummaries = buildFileSummaries(coverageMap, config.rootDir);
|
|
75
|
+
for (const target of targets) {
|
|
76
|
+
const matcher = createGlobMatcher(target.pattern);
|
|
77
|
+
const matchResult = collectTargetSummary(fileSummaries, matcher, coverageLib);
|
|
78
|
+
if (matchResult.matched === 0) {
|
|
79
|
+
console.warn(`[coverage] threshold pattern "${target.pattern}" did not match any files — skipping`);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
enforceThresholds(matchResult.summary, target.thresholds, target.pattern);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
70
85
|
}
|
|
71
86
|
async function collectCoveredFiles(config) {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
87
|
+
const coverageFiles = await findCoverageFiles(config);
|
|
88
|
+
if (coverageFiles.length === 0) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const coverageLib = resolveCoverageLib();
|
|
92
|
+
const coverageMap = coverageLib.createCoverageMap({});
|
|
93
|
+
const matchesCollectCoverageFrom = createCollectCoverageMatcher(config.collectCoverageFrom, config.rootDir);
|
|
94
|
+
for (const file of coverageFiles) {
|
|
95
|
+
const payload = await readCoverageFile(file);
|
|
96
|
+
if (!payload) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
for (const script of payload.scripts) {
|
|
100
|
+
await mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return coverageMap.files().sort();
|
|
82
104
|
}
|
|
83
105
|
async function loadIstanbulModules() {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
106
|
+
maybeForceColor();
|
|
107
|
+
const [libReportMod, reportsMod] = await Promise.all([import("istanbul-lib-report"), import("istanbul-reports")]);
|
|
108
|
+
const createContext = typeof libReportMod.createContext === "function" ? libReportMod.createContext : libReportMod.default?.createContext;
|
|
109
|
+
if (typeof createContext !== "function") {
|
|
110
|
+
throw new Error("istanbul-lib-report exports are unavailable");
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
createContext,
|
|
114
|
+
reports: reportsMod.default ?? reportsMod
|
|
115
|
+
};
|
|
92
116
|
}
|
|
93
117
|
function maybeForceColor() {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
118
|
+
if (process.stdout.isTTY) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (process.env.FORCE_COLOR !== void 0) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (process.env.NO_COLOR !== void 0 || process.env.NODE_DISABLE_COLORS !== void 0) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
if (process.env.CI !== void 0) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
process.env.FORCE_COLOR = "1";
|
|
99
131
|
}
|
|
100
132
|
async function mergeScriptCoverage(coverageMap, script, config, matchesCollectCoverageFrom) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
133
|
+
const scriptPath = script.absolutePath;
|
|
134
|
+
if (!scriptPath) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (isNodeModulesPath(scriptPath)) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (isViteVirtualModulePath(scriptPath)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
let source = script.source && script.source.length > 0 ? script.source : "";
|
|
144
|
+
if (!source) {
|
|
145
|
+
try {
|
|
146
|
+
source = await fs.readFile(scriptPath, "utf8");
|
|
147
|
+
} catch (error) {
|
|
148
|
+
const base = path.basename(scriptPath);
|
|
149
|
+
if (error?.code === "ENOENT" && base && !base.includes(".")) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (error?.code === "ENOENT" && !matchesCollectCoverageFrom(scriptPath)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
throw error;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const sourceMap = await loadSourceMapForScript(scriptPath, source);
|
|
159
|
+
const converter = v8ToIstanbul(scriptPath, 0, sourceMap ? {
|
|
160
|
+
source,
|
|
161
|
+
sourceMap: {
|
|
162
|
+
sourcemap: sourceMap
|
|
163
|
+
}
|
|
164
|
+
} : {
|
|
165
|
+
source
|
|
166
|
+
});
|
|
167
|
+
await converter.load();
|
|
168
|
+
converter.applyCoverage(script.functions);
|
|
169
|
+
const filtered = filterCoverageMap(converter.toIstanbul(), config, matchesCollectCoverageFrom);
|
|
170
|
+
if (Object.keys(filtered).length > 0) {
|
|
171
|
+
coverageMap.merge(filtered);
|
|
172
|
+
}
|
|
123
173
|
}
|
|
124
174
|
async function readCoverageFile(file) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
175
|
+
try {
|
|
176
|
+
const raw = await fs.readFile(file, "utf8");
|
|
177
|
+
return JSON.parse(raw);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.warn(`[coverage] failed to parse ${file}:`, error);
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
132
182
|
}
|
|
133
183
|
function enforceThresholds(summary, thresholds, label = "global") {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
184
|
+
const failures = [];
|
|
185
|
+
for (const metric of Object.keys(thresholds)) {
|
|
186
|
+
const minimum = thresholds[metric];
|
|
187
|
+
const actual = summary[metric]?.pct ?? 0;
|
|
188
|
+
if (actual < minimum) {
|
|
189
|
+
failures.push({
|
|
190
|
+
metric,
|
|
191
|
+
actual,
|
|
192
|
+
minimum
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (failures.length === 0) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const details = failures.map(({
|
|
200
|
+
metric,
|
|
201
|
+
actual,
|
|
202
|
+
minimum
|
|
203
|
+
}) => `${metric}: ${actual.toFixed(2)}% < ${minimum}%`).join("; ");
|
|
204
|
+
throw new CoverageThresholdError(`[coverage] thresholds not met (target: ${label}) — ${details}`);
|
|
146
205
|
}
|
|
147
206
|
function resolveCoverageLib() {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
207
|
+
const candidate = libCoverage;
|
|
208
|
+
if (typeof candidate.createCoverageMap === "function") {
|
|
209
|
+
return candidate;
|
|
210
|
+
}
|
|
211
|
+
if (candidate.default && typeof candidate.default.createCoverageMap === "function") {
|
|
212
|
+
return candidate.default;
|
|
213
|
+
}
|
|
214
|
+
throw new Error("istanbul-lib-coverage exports are unavailable");
|
|
152
215
|
}
|
|
153
216
|
function resolveInstrumentLib() {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
217
|
+
const candidate = libInstrument;
|
|
218
|
+
if (typeof candidate.createInstrumenter === "function") {
|
|
219
|
+
return candidate;
|
|
220
|
+
}
|
|
221
|
+
if (candidate.default && typeof candidate.default.createInstrumenter === "function") {
|
|
222
|
+
return candidate.default;
|
|
223
|
+
}
|
|
224
|
+
throw new Error("istanbul-lib-instrument exports are unavailable");
|
|
158
225
|
}
|
|
159
226
|
async function includeUntestedFiles(coverageMap, config, matchesCollectCoverageFrom) {
|
|
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
|
-
|
|
227
|
+
const existing = new Set(coverageMap.files().map((filePath) => path.resolve(String(filePath ?? ""))));
|
|
228
|
+
const candidates = await findCollectCoverageFiles(config, matchesCollectCoverageFrom);
|
|
229
|
+
if (candidates.length === 0) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const instrumentLib = resolveInstrumentLib();
|
|
233
|
+
const instrumenter = instrumentLib.createInstrumenter({
|
|
234
|
+
esModules: true,
|
|
235
|
+
parserPlugins: ["typescript", "jsx", "classProperties", "classPrivateProperties", "classPrivateMethods", "decorators-legacy", "importMeta", "topLevelAwait"]
|
|
236
|
+
});
|
|
237
|
+
for (const filePath of candidates) {
|
|
238
|
+
const normalized = path.resolve(filePath);
|
|
239
|
+
if (existing.has(normalized)) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
const source = await fs.readFile(normalized, "utf8").catch(() => null);
|
|
243
|
+
if (source === null) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
try {
|
|
247
|
+
instrumenter.instrumentSync(source, normalized);
|
|
248
|
+
const fileCoverage = instrumenter.lastFileCoverage();
|
|
249
|
+
if (!fileCoverage) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
coverageMap.addFileCoverage(fileCoverage);
|
|
253
|
+
existing.add(normalized);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
const relative = path.relative(config.rootDir, normalized);
|
|
256
|
+
console.warn(`[coverage] failed to instrument ${relative && !relative.startsWith("..") ? relative : normalized}:`, error);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
192
259
|
}
|
|
193
|
-
|
|
194
|
-
"**/.git/**",
|
|
195
|
-
"**/.next/**",
|
|
196
|
-
"**/.turbo/**",
|
|
197
|
-
"**/.vite/**",
|
|
198
|
-
"**/.vitest/**",
|
|
199
|
-
"**/build/**",
|
|
200
|
-
"**/coverage/**",
|
|
201
|
-
"**/dist/**",
|
|
202
|
-
"**/node_modules/**",
|
|
203
|
-
"**/playwright-report/**",
|
|
204
|
-
"**/spec/**",
|
|
205
|
-
"**/test/**",
|
|
206
|
-
"**/test-results/**",
|
|
207
|
-
"**/tests/**",
|
|
208
|
-
"**/__tests__/**",
|
|
209
|
-
"**/*.d.ts",
|
|
210
|
-
"**/*.map"
|
|
211
|
-
];
|
|
260
|
+
const DEFAULT_COLLECT_COVERAGE_IGNORES = ["**/.git/**", "**/.next/**", "**/.turbo/**", "**/.vite/**", "**/.vitest/**", "**/build/**", "**/coverage/**", "**/dist/**", "**/node_modules/**", "**/playwright-report/**", "**/spec/**", "**/test/**", "**/test-results/**", "**/tests/**", "**/__tests__/**", "**/*.d.ts", "**/*.map"];
|
|
212
261
|
async function findCollectCoverageFiles(config, matchesCollectCoverageFrom) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
262
|
+
const patterns = Array.isArray(config.collectCoverageFrom) ? config.collectCoverageFrom : [];
|
|
263
|
+
if (patterns.length === 0) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
const rawFiles = await fg(patterns, {
|
|
267
|
+
cwd: config.rootDir,
|
|
268
|
+
absolute: true,
|
|
269
|
+
dot: true,
|
|
270
|
+
onlyFiles: true,
|
|
271
|
+
unique: true,
|
|
272
|
+
followSymbolicLinks: false,
|
|
273
|
+
ignore: DEFAULT_COLLECT_COVERAGE_IGNORES
|
|
274
|
+
}).catch(() => []);
|
|
275
|
+
const collected = /* @__PURE__ */ new Set();
|
|
276
|
+
for (const file of rawFiles) {
|
|
277
|
+
const normalized = path.resolve(String(file ?? ""));
|
|
278
|
+
if (!normalized) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
if (normalized.endsWith(".d.ts") || normalized.endsWith(".map")) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
if (isNodeModulesPath(normalized)) {
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (isViteVirtualModulePath(normalized)) {
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
if (!matchesCollectCoverageFrom(normalized)) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
collected.add(normalized);
|
|
294
|
+
}
|
|
295
|
+
return Array.from(collected).sort();
|
|
235
296
|
}
|
|
236
297
|
function buildFileSummaries(coverageMap, rootDir) {
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
298
|
+
const normalizedRoot = path.resolve(rootDir);
|
|
299
|
+
return coverageMap.files().map((filePath) => {
|
|
300
|
+
const normalizedAbsolute = path.resolve(filePath);
|
|
301
|
+
const summary = coverageMap.fileCoverageFor(filePath).toSummary();
|
|
302
|
+
const relativePath = path.relative(normalizedRoot, normalizedAbsolute);
|
|
303
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
304
|
+
if (relativePath) {
|
|
305
|
+
const relativePosix = toPosix(relativePath);
|
|
306
|
+
candidates.add(relativePosix);
|
|
307
|
+
candidates.add(`./${relativePosix}`);
|
|
308
|
+
} else {
|
|
309
|
+
candidates.add(toPosix(path.basename(normalizedAbsolute)));
|
|
310
|
+
}
|
|
311
|
+
return {
|
|
312
|
+
summary,
|
|
313
|
+
candidates: Array.from(candidates)
|
|
314
|
+
};
|
|
315
|
+
});
|
|
253
316
|
}
|
|
254
317
|
function collectTargetSummary(fileSummaries, matcher, coverageLib) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
318
|
+
const summary = coverageLib.createCoverageSummary();
|
|
319
|
+
let matched = 0;
|
|
320
|
+
for (const file of fileSummaries) {
|
|
321
|
+
if (file.candidates.some((candidate) => matcher(candidate))) {
|
|
322
|
+
summary.merge(file.summary);
|
|
323
|
+
matched += 1;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
summary,
|
|
328
|
+
matched
|
|
329
|
+
};
|
|
265
330
|
}
|
|
266
331
|
function createGlobMatcher(pattern) {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
332
|
+
const normalized = toPosix(String(pattern ?? "")).trim();
|
|
333
|
+
if (!normalized) {
|
|
334
|
+
return () => false;
|
|
335
|
+
}
|
|
336
|
+
if (isAbsoluteGlobPattern(normalized)) {
|
|
337
|
+
throw new Error(`[coverage] threshold patterns must be relative (absolute paths are not supported): "${pattern}"`);
|
|
338
|
+
}
|
|
339
|
+
return picomatch(normalized, {
|
|
340
|
+
dot: true
|
|
341
|
+
});
|
|
271
342
|
}
|
|
272
343
|
function isAbsoluteGlobPattern(pattern) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
344
|
+
const normalized = String(pattern ?? "").trim();
|
|
345
|
+
if (!normalized) {
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
if (normalized.startsWith("/")) {
|
|
349
|
+
return true;
|
|
350
|
+
}
|
|
351
|
+
if (normalized.startsWith("file://")) {
|
|
352
|
+
return true;
|
|
353
|
+
}
|
|
354
|
+
return /^[A-Za-z]:\//.test(normalized);
|
|
278
355
|
}
|
|
279
356
|
function stripQuery(url) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
357
|
+
const queryIndex = url.indexOf("?");
|
|
358
|
+
const hashIndex = url.indexOf("#");
|
|
359
|
+
const endIndex = Math.min(queryIndex === -1 ? Number.POSITIVE_INFINITY : queryIndex, hashIndex === -1 ? Number.POSITIVE_INFINITY : hashIndex);
|
|
360
|
+
if (!Number.isFinite(endIndex)) {
|
|
361
|
+
return url;
|
|
362
|
+
}
|
|
363
|
+
return url.slice(0, endIndex);
|
|
285
364
|
}
|
|
286
365
|
function extractSourceMappingUrl(source) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
366
|
+
const regex = /\/\/[#@]\s*sourceMappingURL=([^\s]+)/g;
|
|
367
|
+
let last = null;
|
|
368
|
+
let match = null;
|
|
369
|
+
while ((match = regex.exec(source)) !== null) {
|
|
370
|
+
last = match[1];
|
|
371
|
+
}
|
|
372
|
+
return typeof last === "string" && last.length > 0 ? last : null;
|
|
292
373
|
}
|
|
293
374
|
function resolveSourceMapPath(scriptPath, mappingUrl) {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
375
|
+
const cleaned = stripQuery(mappingUrl);
|
|
376
|
+
if (cleaned.startsWith("file://")) {
|
|
377
|
+
return fileURLToPath(cleaned);
|
|
378
|
+
}
|
|
379
|
+
if (path.isAbsolute(cleaned)) {
|
|
380
|
+
return cleaned;
|
|
381
|
+
}
|
|
382
|
+
return path.resolve(path.dirname(scriptPath), cleaned);
|
|
298
383
|
}
|
|
299
384
|
function filterCoverageMap(map, config, matchesCollectCoverageFrom) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
385
|
+
if (!map || typeof map !== "object") {
|
|
386
|
+
return {};
|
|
387
|
+
}
|
|
388
|
+
const filtered = {};
|
|
389
|
+
for (const [filePath, fileCoverage] of Object.entries(map)) {
|
|
390
|
+
const absolutePath = resolveCoveragePath(filePath, config.rootDir);
|
|
391
|
+
if (!absolutePath) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
if (absolutePath.endsWith(".d.ts") || absolutePath.endsWith(".map")) {
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (isNodeModulesPath(absolutePath)) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
if (isViteVirtualModulePath(absolutePath)) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
if (!matchesCollectCoverageFrom(absolutePath)) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (fileCoverage && typeof fileCoverage === "object") {
|
|
407
|
+
filtered[absolutePath] = {
|
|
408
|
+
...fileCoverage,
|
|
409
|
+
path: absolutePath
|
|
410
|
+
};
|
|
411
|
+
} else {
|
|
412
|
+
filtered[absolutePath] = fileCoverage;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return filtered;
|
|
316
416
|
}
|
|
317
417
|
function resolveCoveragePath(filePath, rootDir) {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
418
|
+
const raw = String(filePath ?? "").trim();
|
|
419
|
+
if (!raw) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
const cleaned = stripQuery(raw);
|
|
423
|
+
if (cleaned.startsWith("file://")) {
|
|
424
|
+
try {
|
|
425
|
+
return path.normalize(fileURLToPath(cleaned));
|
|
426
|
+
} catch {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
if (path.isAbsolute(cleaned)) {
|
|
431
|
+
return path.normalize(cleaned);
|
|
432
|
+
}
|
|
433
|
+
if (cleaned.includes("://")) {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
return path.normalize(path.resolve(rootDir, cleaned));
|
|
329
437
|
}
|
|
330
438
|
function isNodeModulesPath(filePath) {
|
|
331
|
-
|
|
439
|
+
return path.normalize(String(filePath ?? "")).split(path.sep).includes("node_modules");
|
|
332
440
|
}
|
|
333
441
|
function isViteVirtualModulePath(filePath) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
442
|
+
const normalized = path.normalize(String(filePath ?? ""));
|
|
443
|
+
const baseName = path.basename(normalized);
|
|
444
|
+
return baseName === "__vite-browser-external" || baseName.startsWith("__vite-browser-external:") || baseName.startsWith("__vite-");
|
|
337
445
|
}
|
|
338
446
|
function parseSourceMapPayload(raw) {
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
447
|
+
if (!raw || typeof raw !== "object") {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
const sources = raw.sources;
|
|
451
|
+
if (!Array.isArray(sources) || sources.length === 0) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
return raw;
|
|
343
455
|
}
|
|
344
456
|
function normalizeSourceMap(sourceMap, scriptPath) {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
457
|
+
const root = typeof sourceMap.sourceRoot === "string" ? sourceMap.sourceRoot.replace("file://", "") : "";
|
|
458
|
+
const dir = path.dirname(scriptPath);
|
|
459
|
+
const fixedSources = sourceMap.sources.map((source) => {
|
|
460
|
+
const raw = String(source ?? "");
|
|
461
|
+
const cleaned = stripQuery(raw);
|
|
462
|
+
if (cleaned.startsWith("file://")) {
|
|
463
|
+
try {
|
|
464
|
+
return path.normalize(fileURLToPath(cleaned));
|
|
465
|
+
} catch {
|
|
466
|
+
return cleaned;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
const withoutWebpack = cleaned.replace(/^webpack:\/\//, "");
|
|
470
|
+
const candidate = path.join(root, withoutWebpack);
|
|
471
|
+
if (path.isAbsolute(candidate)) {
|
|
472
|
+
return path.normalize(candidate);
|
|
473
|
+
}
|
|
474
|
+
const normalizedCandidate = candidate.split("/").join(path.sep);
|
|
475
|
+
if (dir.endsWith(`${path.sep}dist`) && !normalizedCandidate.startsWith(`..${path.sep}`)) {
|
|
476
|
+
if (normalizedCandidate.startsWith(`src${path.sep}`) || normalizedCandidate.startsWith(`lib${path.sep}`)) {
|
|
477
|
+
return path.normalize(path.resolve(dir, "..", normalizedCandidate));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return path.normalize(path.resolve(dir, normalizedCandidate));
|
|
481
|
+
});
|
|
482
|
+
return {
|
|
483
|
+
...sourceMap,
|
|
484
|
+
sources: fixedSources
|
|
485
|
+
};
|
|
367
486
|
}
|
|
368
487
|
async function loadSourceMapForScript(scriptPath, source) {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
488
|
+
const mappingUrl = extractSourceMappingUrl(source);
|
|
489
|
+
if (!mappingUrl) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
const cleaned = stripQuery(mappingUrl);
|
|
493
|
+
if (cleaned.startsWith("data:")) {
|
|
494
|
+
const commaIndex = cleaned.indexOf(",");
|
|
495
|
+
if (commaIndex === -1) {
|
|
496
|
+
return null;
|
|
497
|
+
}
|
|
498
|
+
const meta = cleaned.slice(0, commaIndex);
|
|
499
|
+
const payload = cleaned.slice(commaIndex + 1);
|
|
500
|
+
const raw = meta.includes(";base64") ? Buffer.from(payload, "base64").toString("utf8") : decodeURIComponent(payload);
|
|
501
|
+
try {
|
|
502
|
+
const parsed = parseSourceMapPayload(JSON.parse(raw));
|
|
503
|
+
return parsed ? normalizeSourceMap(parsed, scriptPath) : null;
|
|
504
|
+
} catch {
|
|
505
|
+
return null;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
try {
|
|
509
|
+
const mapPath = resolveSourceMapPath(scriptPath, cleaned);
|
|
510
|
+
const raw = await fs.readFile(mapPath, "utf8");
|
|
511
|
+
const parsed = parseSourceMapPayload(JSON.parse(raw));
|
|
512
|
+
return parsed ? normalizeSourceMap(parsed, scriptPath) : null;
|
|
513
|
+
} catch {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
393
516
|
}
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
517
|
+
export {
|
|
518
|
+
CoverageThresholdError,
|
|
519
|
+
collectCoveredFiles,
|
|
520
|
+
generateCoverageReport
|
|
521
|
+
};
|
|
522
|
+
//# sourceMappingURL=report.js.map
|