@vitest/coverage-istanbul 0.22.1 → 0.23.2

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.
@@ -1,7 +1,7 @@
1
1
  const COVERAGE_STORE_KEY = "__VITEST_COVERAGE__";
2
2
 
3
3
  async function getProvider() {
4
- const { IstanbulCoverageProvider } = await import('./provider-c52a4829.js');
4
+ const { IstanbulCoverageProvider } = await import('./provider-a5dc6d7e.js');
5
5
  return new IstanbulCoverageProvider();
6
6
  }
7
7
  function takeCoverage() {
@@ -0,0 +1,11 @@
1
+ const COVERAGE_STORE_KEY = "__VITEST_COVERAGE__";
2
+
3
+ async function getProvider() {
4
+ const { IstanbulCoverageProvider } = await import('./provider-e9ab8aec.js');
5
+ return new IstanbulCoverageProvider();
6
+ }
7
+ function takeCoverage() {
8
+ return globalThis[COVERAGE_STORE_KEY];
9
+ }
10
+
11
+ export { COVERAGE_STORE_KEY as C, getProvider as g, takeCoverage as t };
package/dist/index.d.ts CHANGED
@@ -197,6 +197,7 @@ interface TestExclude {
197
197
  excludeNodeModules?: boolean;
198
198
  }): {
199
199
  shouldInstrument(filePath: string): boolean;
200
+ glob(cwd: string): Promise<string[]>;
200
201
  };
201
202
  }
202
203
  declare class IstanbulCoverageProvider implements CoverageProvider {
@@ -224,6 +225,7 @@ declare class IstanbulCoverageProvider implements CoverageProvider {
224
225
  clean(clean?: boolean): Promise<void>;
225
226
  reportCoverage(): Promise<void>;
226
227
  checkThresholds(coverageMap: CoverageMap, thresholds: Record<Threshold, number | undefined>): void;
228
+ includeUntestedFiles(coverageMap: CoverageMap): Promise<void>;
227
229
  }
228
230
 
229
231
  declare function getProvider(): Promise<IstanbulCoverageProvider>;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { g as getProvider, t as takeCoverage } from './index-86ab9aec.js';
1
+ export { g as getProvider, t as takeCoverage } from './index-aa0610b9.js';
@@ -7,7 +7,7 @@ import libCoverage from 'istanbul-lib-coverage';
7
7
  import libSourceMaps from 'istanbul-lib-source-maps';
8
8
  import { createInstrumenter } from 'istanbul-lib-instrument';
9
9
  import _TestExclude from 'test-exclude';
10
- import { C as COVERAGE_STORE_KEY } from './index-86ab9aec.js';
10
+ import { C as COVERAGE_STORE_KEY } from './index-7fc35403.js';
11
11
 
12
12
  function normalizeWindowsPath(input = "") {
13
13
  if (!input.includes("\\")) {
@@ -204,6 +204,7 @@ class IstanbulCoverageProvider {
204
204
  produceSourceMap: true,
205
205
  autoWrap: false,
206
206
  esModules: true,
207
+ compact: false,
207
208
  coverageVariable: COVERAGE_STORE_KEY,
208
209
  coverageGlobalScope: "globalThis",
209
210
  coverageGlobalScopeFunc: false,
@@ -211,6 +212,7 @@ class IstanbulCoverageProvider {
211
212
  });
212
213
  this.testExclude = new _TestExclude({
213
214
  cwd: ctx.config.root,
215
+ include: typeof this.options.include === "undefined" ? void 0 : [...this.options.include],
214
216
  exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude],
215
217
  excludeNodeModules: true,
216
218
  extension: configDefaults.coverage.extension
@@ -0,0 +1,335 @@
1
+ import { existsSync, promises } from 'fs';
2
+ import path from 'path';
3
+ import { defaultExclude, defaultInclude, configDefaults } from 'vitest/config';
4
+ import libReport from 'istanbul-lib-report';
5
+ import reports from 'istanbul-reports';
6
+ import libCoverage from 'istanbul-lib-coverage';
7
+ import libSourceMaps from 'istanbul-lib-source-maps';
8
+ import { createInstrumenter } from 'istanbul-lib-instrument';
9
+ import _TestExclude from 'test-exclude';
10
+ import { C as COVERAGE_STORE_KEY } from './index-aa0610b9.js';
11
+
12
+ function normalizeWindowsPath(input = "") {
13
+ if (!input.includes("\\")) {
14
+ return input;
15
+ }
16
+ return input.replace(/\\/g, "/");
17
+ }
18
+
19
+ const _UNC_REGEX = /^[/][/]/;
20
+ const _UNC_DRIVE_REGEX = /^[/][/]([.]{1,2}[/])?([a-zA-Z]):[/]/;
21
+ const _IS_ABSOLUTE_RE = /^\/|^\\|^[a-zA-Z]:[/\\]/;
22
+ const sep = "/";
23
+ const delimiter = ":";
24
+ const normalize = function(path2) {
25
+ if (path2.length === 0) {
26
+ return ".";
27
+ }
28
+ path2 = normalizeWindowsPath(path2);
29
+ const isUNCPath = path2.match(_UNC_REGEX);
30
+ const hasUNCDrive = isUNCPath && path2.match(_UNC_DRIVE_REGEX);
31
+ const isPathAbsolute = isAbsolute(path2);
32
+ const trailingSeparator = path2[path2.length - 1] === "/";
33
+ path2 = normalizeString(path2, !isPathAbsolute);
34
+ if (path2.length === 0) {
35
+ if (isPathAbsolute) {
36
+ return "/";
37
+ }
38
+ return trailingSeparator ? "./" : ".";
39
+ }
40
+ if (trailingSeparator) {
41
+ path2 += "/";
42
+ }
43
+ if (isUNCPath) {
44
+ if (hasUNCDrive) {
45
+ return `//./${path2}`;
46
+ }
47
+ return `//${path2}`;
48
+ }
49
+ return isPathAbsolute && !isAbsolute(path2) ? `/${path2}` : path2;
50
+ };
51
+ const join = function(...args) {
52
+ if (args.length === 0) {
53
+ return ".";
54
+ }
55
+ let joined;
56
+ for (let i = 0; i < args.length; ++i) {
57
+ const arg = args[i];
58
+ if (arg.length > 0) {
59
+ if (joined === void 0) {
60
+ joined = arg;
61
+ } else {
62
+ joined += `/${arg}`;
63
+ }
64
+ }
65
+ }
66
+ if (joined === void 0) {
67
+ return ".";
68
+ }
69
+ return normalize(joined);
70
+ };
71
+ const resolve = function(...args) {
72
+ args = args.map((arg) => normalizeWindowsPath(arg));
73
+ let resolvedPath = "";
74
+ let resolvedAbsolute = false;
75
+ for (let i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) {
76
+ const path2 = i >= 0 ? args[i] : process.cwd();
77
+ if (path2.length === 0) {
78
+ continue;
79
+ }
80
+ resolvedPath = `${path2}/${resolvedPath}`;
81
+ resolvedAbsolute = isAbsolute(path2);
82
+ }
83
+ resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);
84
+ if (resolvedAbsolute && !isAbsolute(resolvedPath)) {
85
+ return `/${resolvedPath}`;
86
+ }
87
+ return resolvedPath.length > 0 ? resolvedPath : ".";
88
+ };
89
+ function normalizeString(path2, allowAboveRoot) {
90
+ let res = "";
91
+ let lastSegmentLength = 0;
92
+ let lastSlash = -1;
93
+ let dots = 0;
94
+ let char = null;
95
+ for (let i = 0; i <= path2.length; ++i) {
96
+ if (i < path2.length) {
97
+ char = path2[i];
98
+ } else if (char === "/") {
99
+ break;
100
+ } else {
101
+ char = "/";
102
+ }
103
+ if (char === "/") {
104
+ if (lastSlash === i - 1 || dots === 1) ; else if (dots === 2) {
105
+ if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
106
+ if (res.length > 2) {
107
+ const lastSlashIndex = res.lastIndexOf("/");
108
+ if (lastSlashIndex === -1) {
109
+ res = "";
110
+ lastSegmentLength = 0;
111
+ } else {
112
+ res = res.slice(0, lastSlashIndex);
113
+ lastSegmentLength = res.length - 1 - res.lastIndexOf("/");
114
+ }
115
+ lastSlash = i;
116
+ dots = 0;
117
+ continue;
118
+ } else if (res.length !== 0) {
119
+ res = "";
120
+ lastSegmentLength = 0;
121
+ lastSlash = i;
122
+ dots = 0;
123
+ continue;
124
+ }
125
+ }
126
+ if (allowAboveRoot) {
127
+ res += res.length > 0 ? "/.." : "..";
128
+ lastSegmentLength = 2;
129
+ }
130
+ } else {
131
+ if (res.length > 0) {
132
+ res += `/${path2.slice(lastSlash + 1, i)}`;
133
+ } else {
134
+ res = path2.slice(lastSlash + 1, i);
135
+ }
136
+ lastSegmentLength = i - lastSlash - 1;
137
+ }
138
+ lastSlash = i;
139
+ dots = 0;
140
+ } else if (char === "." && dots !== -1) {
141
+ ++dots;
142
+ } else {
143
+ dots = -1;
144
+ }
145
+ }
146
+ return res;
147
+ }
148
+ const isAbsolute = function(p) {
149
+ return _IS_ABSOLUTE_RE.test(p);
150
+ };
151
+ const toNamespacedPath = function(p) {
152
+ return normalizeWindowsPath(p);
153
+ };
154
+ const extname = function(p) {
155
+ return path.posix.extname(normalizeWindowsPath(p));
156
+ };
157
+ const relative = function(from, to) {
158
+ return path.posix.relative(normalizeWindowsPath(from), normalizeWindowsPath(to));
159
+ };
160
+ const dirname = function(p) {
161
+ return path.posix.dirname(normalizeWindowsPath(p));
162
+ };
163
+ const format = function(p) {
164
+ return normalizeWindowsPath(path.posix.format(p));
165
+ };
166
+ const basename = function(p, ext) {
167
+ return path.posix.basename(normalizeWindowsPath(p), ext);
168
+ };
169
+ const parse = function(p) {
170
+ return path.posix.parse(normalizeWindowsPath(p));
171
+ };
172
+
173
+ const _path = /*#__PURE__*/Object.freeze({
174
+ __proto__: null,
175
+ sep: sep,
176
+ delimiter: delimiter,
177
+ normalize: normalize,
178
+ join: join,
179
+ resolve: resolve,
180
+ normalizeString: normalizeString,
181
+ isAbsolute: isAbsolute,
182
+ toNamespacedPath: toNamespacedPath,
183
+ extname: extname,
184
+ relative: relative,
185
+ dirname: dirname,
186
+ format: format,
187
+ basename: basename,
188
+ parse: parse
189
+ });
190
+
191
+ ({
192
+ ..._path
193
+ });
194
+
195
+ class IstanbulCoverageProvider {
196
+ constructor() {
197
+ this.name = "istanbul";
198
+ this.coverages = [];
199
+ }
200
+ initialize(ctx) {
201
+ this.ctx = ctx;
202
+ this.options = resolveIstanbulOptions(ctx.config.coverage, ctx.config.root);
203
+ this.instrumenter = createInstrumenter({
204
+ produceSourceMap: true,
205
+ autoWrap: false,
206
+ esModules: true,
207
+ compact: false,
208
+ coverageVariable: COVERAGE_STORE_KEY,
209
+ coverageGlobalScope: "globalThis",
210
+ coverageGlobalScopeFunc: false,
211
+ ignoreClassMethods: this.options.ignoreClassMethods
212
+ });
213
+ this.testExclude = new _TestExclude({
214
+ cwd: ctx.config.root,
215
+ include: typeof this.options.include === "undefined" ? void 0 : [...this.options.include],
216
+ exclude: [...defaultExclude, ...defaultInclude, ...this.options.exclude],
217
+ excludeNodeModules: true,
218
+ extension: configDefaults.coverage.extension
219
+ });
220
+ }
221
+ resolveOptions() {
222
+ return this.options;
223
+ }
224
+ onFileTransform(sourceCode, id, pluginCtx) {
225
+ if (!this.testExclude.shouldInstrument(id))
226
+ return;
227
+ const { sourcesContent, ...sourceMap } = pluginCtx.getCombinedSourcemap();
228
+ const code = this.instrumenter.instrumentSync(sourceCode, id, sourceMap);
229
+ const map = this.instrumenter.lastSourceMap();
230
+ return { code, map };
231
+ }
232
+ onAfterSuiteRun({ coverage }) {
233
+ this.coverages.push(coverage);
234
+ }
235
+ async clean(clean = true) {
236
+ if (clean && existsSync(this.options.reportsDirectory))
237
+ await promises.rm(this.options.reportsDirectory, { recursive: true, force: true });
238
+ this.coverages = [];
239
+ }
240
+ async reportCoverage() {
241
+ const mergedCoverage = this.coverages.reduce((coverage, previousCoverageMap) => {
242
+ const map = libCoverage.createCoverageMap(coverage);
243
+ map.merge(previousCoverageMap);
244
+ return map;
245
+ }, {});
246
+ if (this.options.all)
247
+ await this.includeUntestedFiles(mergedCoverage);
248
+ const sourceMapStore = libSourceMaps.createSourceMapStore();
249
+ const coverageMap = await sourceMapStore.transformCoverage(mergedCoverage);
250
+ const context = libReport.createContext({
251
+ dir: this.options.reportsDirectory,
252
+ coverageMap,
253
+ sourceFinder: sourceMapStore.sourceFinder,
254
+ watermarks: this.options.watermarks
255
+ });
256
+ for (const reporter of this.options.reporter) {
257
+ reports.create(reporter, {
258
+ skipFull: this.options.skipFull
259
+ }).execute(context);
260
+ }
261
+ if (this.options.branches || this.options.functions || this.options.lines || this.options.statements) {
262
+ this.checkThresholds(coverageMap, {
263
+ branches: this.options.branches,
264
+ functions: this.options.functions,
265
+ lines: this.options.lines,
266
+ statements: this.options.statements
267
+ });
268
+ }
269
+ }
270
+ checkThresholds(coverageMap, thresholds) {
271
+ const summaries = this.options.perFile ? coverageMap.files().map((file) => ({
272
+ file,
273
+ summary: coverageMap.fileCoverageFor(file).toSummary()
274
+ })) : [{
275
+ file: null,
276
+ summary: coverageMap.getCoverageSummary()
277
+ }];
278
+ for (const { summary, file } of summaries) {
279
+ for (const thresholdKey of ["lines", "functions", "statements", "branches"]) {
280
+ const threshold = thresholds[thresholdKey];
281
+ if (threshold !== void 0) {
282
+ const coverage = summary.data[thresholdKey].pct;
283
+ if (coverage < threshold) {
284
+ process.exitCode = 1;
285
+ let errorMessage = `ERROR: Coverage for ${thresholdKey} (${coverage}%) does not meet`;
286
+ if (!this.options.perFile)
287
+ errorMessage += " global";
288
+ errorMessage += ` threshold (${threshold}%)`;
289
+ if (this.options.perFile && file)
290
+ errorMessage += ` for ${relative("./", file).replace(/\\/g, "/")}`;
291
+ console.error(errorMessage);
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ async includeUntestedFiles(coverageMap) {
298
+ const includedFiles = await this.testExclude.glob(this.ctx.config.root);
299
+ const uncoveredFiles = includedFiles.map((file) => resolve(this.ctx.config.root, file)).filter((file) => !coverageMap.data[file]);
300
+ const transformResults = await Promise.all(uncoveredFiles.map(async (filename) => {
301
+ const transformResult = await this.ctx.vitenode.transformRequest(filename);
302
+ return { transformResult, filename };
303
+ }));
304
+ for (const { transformResult, filename } of transformResults) {
305
+ const sourceMap = transformResult == null ? void 0 : transformResult.map;
306
+ if (sourceMap) {
307
+ this.instrumenter.instrumentSync(
308
+ transformResult.code,
309
+ filename,
310
+ {
311
+ ...sourceMap,
312
+ version: sourceMap.version.toString()
313
+ }
314
+ );
315
+ const lastCoverage = this.instrumenter.lastFileCoverage();
316
+ if (lastCoverage)
317
+ coverageMap.data[lastCoverage.path] = lastCoverage;
318
+ }
319
+ }
320
+ }
321
+ }
322
+ function resolveIstanbulOptions(options, root) {
323
+ const reportsDirectory = resolve(root, options.reportsDirectory || configDefaults.coverage.reportsDirectory);
324
+ const resolved = {
325
+ ...configDefaults.coverage,
326
+ ...options,
327
+ provider: "istanbul",
328
+ reportsDirectory,
329
+ tempDirectory: resolve(reportsDirectory, "tmp"),
330
+ reporter: Array.isArray(options.reporter) ? options.reporter : [options.reporter]
331
+ };
332
+ return resolved;
333
+ }
334
+
335
+ export { IstanbulCoverageProvider };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/coverage-istanbul",
3
3
  "type": "module",
4
- "version": "0.22.1",
4
+ "version": "0.23.2",
5
5
  "description": "Istanbul coverage provider for Vitest",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -43,7 +43,7 @@
43
43
  "istanbul-lib-source-maps": "^4.0.1",
44
44
  "istanbul-reports": "^3.1.5",
45
45
  "test-exclude": "^6.0.0",
46
- "vitest": "0.22.1"
46
+ "vitest": "0.23.2"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@types/istanbul-lib-coverage": "^2.0.4",