@vitest/coverage-v8 1.3.0 → 1.4.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/LICENSE CHANGED
@@ -1,7 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021-Present Anthony Fu <https://github.com/antfu>
4
- Copyright (c) 2021-Present Matias Capeletto <https://github.com/patak-dev>
3
+ Copyright (c) 2021-Present Vitest Team
5
4
 
6
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/provider.js CHANGED
@@ -11,6 +11,7 @@ import { parseModule } from 'magicast';
11
11
  import remapping from '@ampproject/remapping';
12
12
  import c from 'picocolors';
13
13
  import { provider } from 'std-env';
14
+ import { stripLiteral } from 'strip-literal';
14
15
  import createDebug from 'debug';
15
16
  import { builtinModules } from 'node:module';
16
17
  import { coverageConfigDefaults, defaultExclude, defaultInclude } from 'vitest/config';
@@ -170,6 +171,7 @@ function cleanUrl(url) {
170
171
 
171
172
  const WRAPPER_LENGTH = 185;
172
173
  const VITE_EXPORTS_LINE_PATTERN = /Object\.defineProperty\(__vite_ssr_exports__.*\n/g;
174
+ const DECORATOR_METADATA_PATTERN = /_ts_metadata\("design:paramtypes", \[[^\]]*?\]\),*/g;
173
175
  const DEFAULT_PROJECT = Symbol.for("default-project");
174
176
  const debug = createDebug("vitest:coverage");
175
177
  let uniqueId = 0;
@@ -253,7 +255,7 @@ class V8CoverageProvider extends BaseCoverageProvider {
253
255
  for (const [projectName, coveragePerProject] of this.coverageFiles.entries()) {
254
256
  for (const [transformMode, filenames] of Object.entries(coveragePerProject)) {
255
257
  let merged = { result: [] };
256
- for (const chunk of toSlices(filenames, this.options.processingConcurrency)) {
258
+ for (const chunk of this.toSlices(filenames, this.options.processingConcurrency)) {
257
259
  if (debug.enabled) {
258
260
  index += chunk.length;
259
261
  debug("Covered files %d/%d", index, total);
@@ -280,7 +282,7 @@ class V8CoverageProvider extends BaseCoverageProvider {
280
282
  coverageMap,
281
283
  watermarks: this.options.watermarks
282
284
  });
283
- if (hasTerminalReporter(this.options.reporter))
285
+ if (this.hasTerminalReporter(this.options.reporter))
284
286
  this.ctx.logger.log(c.blue(" % ") + c.dim("Coverage report from ") + c.yellow(this.name));
285
287
  for (const reporter of this.options.reporter) {
286
288
  reports.create(reporter[0], {
@@ -307,10 +309,8 @@ class V8CoverageProvider extends BaseCoverageProvider {
307
309
  this.updateThresholds({
308
310
  thresholds: resolvedThresholds,
309
311
  perFile: this.options.thresholds.perFile,
310
- configurationFile: {
311
- write: () => writeFileSync(configFilePath, configModule.generate().code, "utf-8"),
312
- read: () => resolveConfig(configModule)
313
- }
312
+ configurationFile: configModule,
313
+ onUpdate: () => writeFileSync(configFilePath, configModule.generate().code, "utf-8")
314
314
  });
315
315
  }
316
316
  }
@@ -319,17 +319,24 @@ class V8CoverageProvider extends BaseCoverageProvider {
319
319
  }
320
320
  async getUntestedFiles(testedFiles) {
321
321
  const transformResults = normalizeTransformResults(this.ctx.vitenode.fetchCache);
322
- const includedFiles = await this.testExclude.glob(this.ctx.config.root);
323
- const uncoveredFiles = includedFiles.map((file) => pathToFileURL(resolve(this.ctx.config.root, file))).filter((file) => !testedFiles.includes(file.pathname));
322
+ const allFiles = await this.testExclude.glob(this.ctx.config.root);
323
+ let includedFiles = allFiles.map((file) => resolve(this.ctx.config.root, file));
324
+ if (this.ctx.config.changed)
325
+ includedFiles = (this.ctx.config.related || []).filter((file) => includedFiles.includes(file));
326
+ const uncoveredFiles = includedFiles.map((file) => pathToFileURL(file)).filter((file) => !testedFiles.includes(file.pathname));
324
327
  let merged = { result: [] };
325
328
  let index = 0;
326
- for (const chunk of toSlices(uncoveredFiles, this.options.processingConcurrency)) {
329
+ for (const chunk of this.toSlices(uncoveredFiles, this.options.processingConcurrency)) {
327
330
  if (debug.enabled) {
328
331
  index += chunk.length;
329
332
  debug("Uncovered files %d/%d", index, uncoveredFiles.length);
330
333
  }
331
334
  const coverages = await Promise.all(chunk.map(async (filename) => {
332
- const { source } = await this.getSources(filename.href, transformResults);
335
+ const transformResult = await this.ctx.vitenode.transformRequest(filename.pathname).catch(() => {
336
+ });
337
+ if (transformResult && stripLiteral(transformResult.code).trim() === "")
338
+ return null;
339
+ const { originalSource } = await this.getSources(filename.href, transformResults);
333
340
  const coverage = {
334
341
  url: filename.href,
335
342
  scriptId: "0",
@@ -337,7 +344,7 @@ class V8CoverageProvider extends BaseCoverageProvider {
337
344
  functions: [{
338
345
  ranges: [{
339
346
  startOffset: 0,
340
- endOffset: source.length,
347
+ endOffset: originalSource.length,
341
348
  count: 0
342
349
  }],
343
350
  isBlockCoverage: true,
@@ -347,7 +354,10 @@ class V8CoverageProvider extends BaseCoverageProvider {
347
354
  };
348
355
  return { result: [coverage] };
349
356
  }));
350
- merged = mergeProcessCovs([merged, ...coverages]);
357
+ merged = mergeProcessCovs([
358
+ merged,
359
+ ...coverages.filter((cov) => cov != null)
360
+ ]);
351
361
  }
352
362
  return merged;
353
363
  }
@@ -360,16 +370,23 @@ class V8CoverageProvider extends BaseCoverageProvider {
360
370
  const length = findLongestFunctionLength(functions);
361
371
  return ".".repeat(length);
362
372
  });
363
- if (!map)
364
- return { source: code || sourcesContent };
373
+ if (!map) {
374
+ return {
375
+ source: code || sourcesContent,
376
+ originalSource: sourcesContent
377
+ };
378
+ }
379
+ const sources = [url];
380
+ if (map.sources && map.sources[0] && !url.endsWith(map.sources[0]))
381
+ sources[0] = new URL(map.sources[0], url).href;
365
382
  return {
366
383
  originalSource: sourcesContent,
367
384
  source: code || sourcesContent,
368
385
  sourceMap: {
369
- sourcemap: removeViteHelpersFromSourceMaps(code, {
386
+ sourcemap: excludeGeneratedCode(code, {
370
387
  ...map,
371
388
  version: 3,
372
- sources: [url],
389
+ sources,
373
390
  sourcesContent: [sourcesContent]
374
391
  })
375
392
  }
@@ -382,7 +399,7 @@ class V8CoverageProvider extends BaseCoverageProvider {
382
399
  const scriptCoverages = coverage.result.filter((result) => this.testExclude.shouldInstrument(fileURLToPath(result.url)));
383
400
  const coverageMap = libCoverage.createCoverageMap({});
384
401
  let index = 0;
385
- for (const chunk of toSlices(scriptCoverages, this.options.processingConcurrency)) {
402
+ for (const chunk of this.toSlices(scriptCoverages, this.options.processingConcurrency)) {
386
403
  if (debug.enabled) {
387
404
  index += chunk.length;
388
405
  debug("Converting %d/%d", index, scriptCoverages.length);
@@ -403,16 +420,17 @@ async function transformCoverage(coverageMap) {
403
420
  const sourceMapStore = libSourceMaps.createSourceMapStore();
404
421
  return await sourceMapStore.transformCoverage(coverageMap);
405
422
  }
406
- function removeViteHelpersFromSourceMaps(source, map) {
407
- if (!source || !source.match(VITE_EXPORTS_LINE_PATTERN))
423
+ function excludeGeneratedCode(source, map) {
424
+ if (!source)
408
425
  return map;
409
- const sourceWithoutHelpers = new MagicString(source);
410
- sourceWithoutHelpers.replaceAll(VITE_EXPORTS_LINE_PATTERN, "\n");
411
- const mapWithoutHelpers = sourceWithoutHelpers.generateMap({
412
- hires: "boundary"
413
- });
426
+ if (!source.match(VITE_EXPORTS_LINE_PATTERN) && !source.match(DECORATOR_METADATA_PATTERN))
427
+ return map;
428
+ const trimmed = new MagicString(source);
429
+ trimmed.replaceAll(VITE_EXPORTS_LINE_PATTERN, "\n");
430
+ trimmed.replaceAll(DECORATOR_METADATA_PATTERN, (match) => "\n".repeat(match.split("\n").length - 1));
431
+ const trimmedMap = trimmed.generateMap({ hires: "boundary" });
414
432
  const combinedMap = remapping(
415
- [{ ...mapWithoutHelpers, version: 3 }, map],
433
+ [{ ...trimmedMap, version: 3 }, map],
416
434
  () => null
417
435
  );
418
436
  return combinedMap;
@@ -432,36 +450,5 @@ function normalizeTransformResults(fetchCache) {
432
450
  }
433
451
  return normalized;
434
452
  }
435
- function hasTerminalReporter(reporters) {
436
- return reporters.some(([reporter]) => reporter === "text" || reporter === "text-summary" || reporter === "text-lcov" || reporter === "teamcity");
437
- }
438
- function toSlices(array, size) {
439
- return array.reduce((chunks, item) => {
440
- const index = Math.max(0, chunks.length - 1);
441
- const lastChunk = chunks[index] || [];
442
- chunks[index] = lastChunk;
443
- if (lastChunk.length >= size)
444
- chunks.push([item]);
445
- else
446
- lastChunk.push(item);
447
- return chunks;
448
- }, []);
449
- }
450
- function resolveConfig(configModule) {
451
- const mod = configModule.exports.default;
452
- try {
453
- if (mod.$type === "object")
454
- return mod;
455
- if (mod.$type === "function-call") {
456
- if (mod.$args[0].$type === "object")
457
- return mod.$args[0];
458
- if (mod.$args[0].$type === "arrow-function-expression" && mod.$args[0].$body.$type === "object")
459
- return mod.$args[0].$body;
460
- }
461
- } catch (error) {
462
- throw new Error(error instanceof Error ? error.message : String(error));
463
- }
464
- throw new Error("Failed to update coverage thresholds. Configuration file is too complex.");
465
- }
466
453
 
467
454
  export { V8CoverageProvider };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/coverage-v8",
3
3
  "type": "module",
4
- "version": "1.3.0",
4
+ "version": "1.4.0",
5
5
  "description": "V8 coverage provider for Vitest",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "dist"
38
38
  ],
39
39
  "peerDependencies": {
40
- "vitest": "1.3.0"
40
+ "vitest": "1.4.0"
41
41
  },
42
42
  "dependencies": {
43
43
  "@ampproject/remapping": "^2.2.1",
@@ -45,12 +45,13 @@
45
45
  "debug": "^4.3.4",
46
46
  "istanbul-lib-coverage": "^3.2.2",
47
47
  "istanbul-lib-report": "^3.0.1",
48
- "istanbul-lib-source-maps": "^4.0.1",
48
+ "istanbul-lib-source-maps": "^5.0.4",
49
49
  "istanbul-reports": "^3.1.6",
50
50
  "magic-string": "^0.30.5",
51
51
  "magicast": "^0.3.3",
52
52
  "picocolors": "^1.0.0",
53
53
  "std-env": "^3.5.0",
54
+ "strip-literal": "^2.0.0",
54
55
  "test-exclude": "^6.0.0",
55
56
  "v8-to-istanbul": "^9.2.0"
56
57
  },
@@ -61,8 +62,8 @@
61
62
  "@types/istanbul-lib-source-maps": "^4.0.4",
62
63
  "@types/istanbul-reports": "^3.0.4",
63
64
  "pathe": "^1.1.1",
64
- "vite-node": "1.3.0",
65
- "vitest": "1.3.0"
65
+ "vite-node": "1.4.0",
66
+ "vitest": "1.4.0"
66
67
  },
67
68
  "scripts": {
68
69
  "build": "rimraf dist && rollup -c",