@vitest/coverage-istanbul 2.1.1 → 2.1.3

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/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { IstanbulCoverageProvider } from './provider.js';
2
- import 'vitest';
2
+ import 'magicast';
3
+ import 'vitest/node';
3
4
  import 'vitest/coverage';
5
+ import 'test-exclude';
4
6
  import 'istanbul-lib-coverage';
5
7
  import 'istanbul-lib-instrument';
6
8
 
@@ -1,47 +1,24 @@
1
- import { CoverageProvider, Vitest, AfterSuiteRunMeta, ReportContext, ResolvedCoverageOptions } from 'vitest';
1
+ import * as magicast from 'magicast';
2
+ import { ResolvedCoverageOptions, CoverageProvider, Vitest, ReportContext } from 'vitest/node';
2
3
  import { BaseCoverageProvider } from 'vitest/coverage';
3
- import { CoverageMap } from 'istanbul-lib-coverage';
4
+ import TestExclude from 'test-exclude';
5
+ import libCoverage, { CoverageMap } from 'istanbul-lib-coverage';
4
6
  import { Instrumenter } from 'istanbul-lib-instrument';
5
7
 
6
- type Options = ResolvedCoverageOptions<'istanbul'>;
7
- type Filename = string;
8
- type CoverageFilesByTransformMode = Record<AfterSuiteRunMeta['transformMode'], Filename[]>;
9
- type ProjectName = NonNullable<AfterSuiteRunMeta['projectName']> | typeof DEFAULT_PROJECT;
10
- interface TestExclude {
11
- new (opts: {
12
- cwd?: string | string[];
13
- include?: string | string[];
14
- exclude?: string | string[];
15
- extension?: string | string[];
16
- excludeNodeModules?: boolean;
17
- relativePath?: boolean;
18
- }): {
19
- shouldInstrument: (filePath: string) => boolean;
20
- glob: (cwd: string) => Promise<string[]>;
21
- };
22
- }
23
- declare const DEFAULT_PROJECT: unique symbol;
24
- declare class IstanbulCoverageProvider extends BaseCoverageProvider implements CoverageProvider {
25
- name: string;
26
- ctx: Vitest;
27
- options: Options;
8
+ declare class IstanbulCoverageProvider extends BaseCoverageProvider<ResolvedCoverageOptions<'istanbul'>> implements CoverageProvider {
9
+ name: "istanbul";
10
+ version: string;
28
11
  instrumenter: Instrumenter;
29
- testExclude: InstanceType<TestExclude>;
30
- coverageFiles: Map<ProjectName, CoverageFilesByTransformMode>;
31
- coverageFilesDirectory: string;
32
- pendingPromises: Promise<void>[];
12
+ testExclude: InstanceType<typeof TestExclude>;
33
13
  initialize(ctx: Vitest): void;
34
- resolveOptions(): Options;
35
14
  onFileTransform(sourceCode: string, id: string, pluginCtx: any): {
36
15
  code: string;
37
16
  map: any;
38
17
  } | undefined;
39
- onAfterSuiteRun({ coverage, transformMode, projectName }: AfterSuiteRunMeta): void;
40
- clean(clean?: boolean): Promise<void>;
18
+ createCoverageMap(): libCoverage.CoverageMap;
41
19
  generateCoverage({ allTestsRun }: ReportContext): Promise<CoverageMap>;
42
- reportCoverage(coverageMap: unknown, { allTestsRun }: ReportContext): Promise<void>;
43
20
  generateReports(coverageMap: CoverageMap, allTestsRun: boolean | undefined): Promise<void>;
44
- mergeReports(coverageMaps: unknown[]): Promise<void>;
21
+ parseConfigModule(configFilePath: string): Promise<magicast.ProxifiedModule<any>>;
45
22
  private getCoverageMapForUncoveredFiles;
46
23
  }
47
24
 
package/dist/provider.js CHANGED
@@ -1,16 +1,15 @@
1
- import { promises, existsSync, readdirSync, writeFileSync } from 'node:fs';
2
- import { coverageConfigDefaults } from 'vitest/config';
1
+ import { promises } from 'node:fs';
3
2
  import { BaseCoverageProvider } from 'vitest/coverage';
4
3
  import c from 'tinyrainbow';
5
4
  import { parseModule } from 'magicast';
6
5
  import createDebug from 'debug';
6
+ import TestExclude from 'test-exclude';
7
7
  import libReport from 'istanbul-lib-report';
8
8
  import reports from 'istanbul-reports';
9
9
  import libCoverage from 'istanbul-lib-coverage';
10
10
  import libSourceMaps from 'istanbul-lib-source-maps';
11
11
  import { createInstrumenter } from 'istanbul-lib-instrument';
12
12
  import { defaults } from '@istanbuljs/schema';
13
- import _TestExclude from 'test-exclude';
14
13
  import { C as COVERAGE_STORE_KEY } from './constants-BCJfMgEg.js';
15
14
 
16
15
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
@@ -108,53 +107,24 @@ const isAbsolute = function(p) {
108
107
  return _IS_ABSOLUTE_RE.test(p);
109
108
  };
110
109
 
111
- var version = "2.1.1";
110
+ var version = "2.1.3";
112
111
 
113
- const DEFAULT_PROJECT = Symbol.for("default-project");
114
112
  const debug = createDebug("vitest:coverage");
115
- let uniqueId = 0;
116
113
  class IstanbulCoverageProvider extends BaseCoverageProvider {
117
114
  name = "istanbul";
118
- ctx;
119
- options;
115
+ version = version;
120
116
  instrumenter;
121
117
  testExclude;
122
- coverageFiles = /* @__PURE__ */ new Map();
123
- coverageFilesDirectory;
124
- pendingPromises = [];
125
118
  initialize(ctx) {
126
- const config = ctx.config.coverage;
127
- if (ctx.version !== version) {
128
- ctx.logger.warn(
129
- c.yellow(
130
- `Loaded ${c.inverse(c.yellow(` vitest@${ctx.version} `))} and ${c.inverse(c.yellow(` @vitest/coverage-istanbul@${version} `))}.
131
- Running mixed versions is not supported and may lead into bugs
132
- Update your dependencies and make sure the versions match.`
133
- )
134
- );
135
- }
136
- this.ctx = ctx;
137
- this.options = {
138
- ...coverageConfigDefaults,
139
- // User's options
140
- ...config,
141
- // Resolved fields
142
- provider: "istanbul",
143
- reportsDirectory: resolve(
144
- ctx.config.root,
145
- config.reportsDirectory || coverageConfigDefaults.reportsDirectory
146
- ),
147
- reporter: this.resolveReporters(
148
- config.reporter || coverageConfigDefaults.reporter
149
- ),
150
- thresholds: config.thresholds && {
151
- ...config.thresholds,
152
- lines: config.thresholds["100"] ? 100 : config.thresholds.lines,
153
- branches: config.thresholds["100"] ? 100 : config.thresholds.branches,
154
- functions: config.thresholds["100"] ? 100 : config.thresholds.functions,
155
- statements: config.thresholds["100"] ? 100 : config.thresholds.statements
156
- }
157
- };
119
+ this._initialize(ctx);
120
+ this.testExclude = new TestExclude({
121
+ cwd: ctx.config.root,
122
+ include: this.options.include,
123
+ exclude: this.options.exclude,
124
+ excludeNodeModules: true,
125
+ extension: this.options.extension,
126
+ relativePath: !this.options.allowExternal
127
+ });
158
128
  this.instrumenter = createInstrumenter({
159
129
  produceSourceMap: true,
160
130
  autoWrap: false,
@@ -173,23 +143,6 @@ Update your dependencies and make sure the versions match.`
173
143
  importAttributesKeyword: "with"
174
144
  }
175
145
  });
176
- this.testExclude = new _TestExclude({
177
- cwd: ctx.config.root,
178
- include: this.options.include,
179
- exclude: this.options.exclude,
180
- excludeNodeModules: true,
181
- extension: this.options.extension,
182
- relativePath: !this.options.allowExternal
183
- });
184
- const shard = this.ctx.config.shard;
185
- const tempDirectory = `.tmp${shard ? `-${shard.index}-${shard.count}` : ""}`;
186
- this.coverageFilesDirectory = resolve(
187
- this.options.reportsDirectory,
188
- tempDirectory
189
- );
190
- }
191
- resolveOptions() {
192
- return this.options;
193
146
  }
194
147
  onFileTransform(sourceCode, id, pluginCtx) {
195
148
  if (!this.testExclude.shouldInstrument(id)) {
@@ -209,90 +162,26 @@ Update your dependencies and make sure the versions match.`
209
162
  const map = this.instrumenter.lastSourceMap();
210
163
  return { code, map };
211
164
  }
212
- /*
213
- * Coverage and meta information passed from Vitest runners.
214
- * Note that adding new entries here and requiring on those without
215
- * backwards compatibility is a breaking change.
216
- */
217
- onAfterSuiteRun({ coverage, transformMode, projectName }) {
218
- if (!coverage) {
219
- return;
220
- }
221
- if (transformMode !== "web" && transformMode !== "ssr" && transformMode !== "browser") {
222
- throw new Error(`Invalid transform mode: ${transformMode}`);
223
- }
224
- let entry = this.coverageFiles.get(projectName || DEFAULT_PROJECT);
225
- if (!entry) {
226
- entry = { web: [], ssr: [], browser: [] };
227
- this.coverageFiles.set(projectName || DEFAULT_PROJECT, entry);
228
- }
229
- const filename = resolve(
230
- this.coverageFilesDirectory,
231
- `coverage-${uniqueId++}.json`
232
- );
233
- entry[transformMode].push(filename);
234
- const promise = promises.writeFile(filename, JSON.stringify(coverage), "utf-8");
235
- this.pendingPromises.push(promise);
236
- }
237
- async clean(clean = true) {
238
- if (clean && existsSync(this.options.reportsDirectory)) {
239
- await promises.rm(this.options.reportsDirectory, {
240
- recursive: true,
241
- force: true,
242
- maxRetries: 10
243
- });
244
- }
245
- if (existsSync(this.coverageFilesDirectory)) {
246
- await promises.rm(this.coverageFilesDirectory, {
247
- recursive: true,
248
- force: true,
249
- maxRetries: 10
250
- });
251
- }
252
- await promises.mkdir(this.coverageFilesDirectory, { recursive: true });
253
- this.coverageFiles = /* @__PURE__ */ new Map();
254
- this.pendingPromises = [];
165
+ createCoverageMap() {
166
+ return libCoverage.createCoverageMap({});
255
167
  }
256
168
  async generateCoverage({ allTestsRun }) {
257
- const coverageMap = libCoverage.createCoverageMap({});
258
- let index = 0;
259
- const total = this.pendingPromises.length;
260
- await Promise.all(this.pendingPromises);
261
- this.pendingPromises = [];
262
- for (const coveragePerProject of this.coverageFiles.values()) {
263
- for (const filenames of [
264
- coveragePerProject.ssr,
265
- coveragePerProject.web,
266
- coveragePerProject.browser
267
- ]) {
268
- const coverageMapByTransformMode = libCoverage.createCoverageMap({});
269
- for (const chunk of this.toSlices(
270
- filenames,
271
- this.options.processingConcurrency
272
- )) {
273
- if (debug.enabled) {
274
- index += chunk.length;
275
- debug("Covered files %d/%d", index, total);
276
- }
277
- await Promise.all(
278
- chunk.map(async (filename) => {
279
- const contents = await promises.readFile(filename, "utf-8");
280
- const coverage = JSON.parse(contents);
281
- coverageMapByTransformMode.merge(coverage);
282
- })
283
- );
284
- }
285
- const transformedCoverage = await transformCoverage(
286
- coverageMapByTransformMode
287
- );
169
+ const coverageMap = this.createCoverageMap();
170
+ let coverageMapByTransformMode = this.createCoverageMap();
171
+ await this.readCoverageFiles({
172
+ onFileRead(coverage) {
173
+ coverageMapByTransformMode.merge(coverage);
174
+ },
175
+ onFinished: async () => {
176
+ const transformedCoverage = await transformCoverage(coverageMapByTransformMode);
288
177
  coverageMap.merge(transformedCoverage);
289
- }
290
- }
291
- if (this.options.all && allTestsRun) {
178
+ coverageMapByTransformMode = this.createCoverageMap();
179
+ },
180
+ onDebug: debug
181
+ });
182
+ if (this.options.all && (allTestsRun || !this.options.cleanOnRerun)) {
292
183
  const coveredFiles = coverageMap.files();
293
- const uncoveredCoverage = await this.getCoverageMapForUncoveredFiles(
294
- coveredFiles
295
- );
184
+ const uncoveredCoverage = await this.getCoverageMapForUncoveredFiles(coveredFiles);
296
185
  coverageMap.merge(await transformCoverage(uncoveredCoverage));
297
186
  }
298
187
  if (this.options.excludeAfterRemap) {
@@ -300,20 +189,6 @@ Update your dependencies and make sure the versions match.`
300
189
  }
301
190
  return coverageMap;
302
191
  }
303
- async reportCoverage(coverageMap, { allTestsRun }) {
304
- await this.generateReports(
305
- coverageMap || libCoverage.createCoverageMap({}),
306
- allTestsRun
307
- );
308
- const keepResults = !this.options.cleanOnRerun && this.ctx.config.watch;
309
- if (!keepResults) {
310
- this.coverageFiles = /* @__PURE__ */ new Map();
311
- await promises.rm(this.coverageFilesDirectory, { recursive: true });
312
- if (readdirSync(this.options.reportsDirectory).length === 0) {
313
- await promises.rm(this.options.reportsDirectory, { recursive: true });
314
- }
315
- }
316
- }
317
192
  async generateReports(coverageMap, allTestsRun) {
318
193
  const context = libReport.createContext({
319
194
  dir: this.options.reportsDirectory,
@@ -333,46 +208,13 @@ Update your dependencies and make sure the versions match.`
333
208
  }).execute(context);
334
209
  }
335
210
  if (this.options.thresholds) {
336
- const resolvedThresholds = this.resolveThresholds({
337
- coverageMap,
338
- thresholds: this.options.thresholds,
339
- createCoverageMap: () => libCoverage.createCoverageMap({}),
340
- root: this.ctx.config.root
341
- });
342
- this.checkThresholds({
343
- thresholds: resolvedThresholds,
344
- perFile: this.options.thresholds.perFile,
345
- onError: (error) => this.ctx.logger.error(error)
346
- });
347
- if (this.options.thresholds.autoUpdate && allTestsRun) {
348
- if (!this.ctx.server.config.configFile) {
349
- throw new Error(
350
- 'Missing configurationFile. The "coverage.thresholds.autoUpdate" can only be enabled when configuration file is used.'
351
- );
352
- }
353
- const configFilePath = this.ctx.server.config.configFile;
354
- const configModule = parseModule(
355
- await promises.readFile(configFilePath, "utf8")
356
- );
357
- this.updateThresholds({
358
- thresholds: resolvedThresholds,
359
- perFile: this.options.thresholds.perFile,
360
- configurationFile: configModule,
361
- onUpdate: () => writeFileSync(
362
- configFilePath,
363
- configModule.generate().code,
364
- "utf-8"
365
- )
366
- });
367
- }
211
+ await this.reportThresholds(coverageMap, allTestsRun);
368
212
  }
369
213
  }
370
- async mergeReports(coverageMaps) {
371
- const coverageMap = libCoverage.createCoverageMap({});
372
- for (const coverage of coverageMaps) {
373
- coverageMap.merge(coverage);
374
- }
375
- await this.generateReports(coverageMap, true);
214
+ async parseConfigModule(configFilePath) {
215
+ return parseModule(
216
+ await promises.readFile(configFilePath, "utf8")
217
+ );
376
218
  }
377
219
  async getCoverageMapForUncoveredFiles(coveredFiles) {
378
220
  const allFiles = await this.testExclude.glob(this.ctx.config.root);
@@ -386,7 +228,7 @@ Update your dependencies and make sure the versions match.`
386
228
  }
387
229
  const uncoveredFiles = includedFiles.filter((file) => !coveredFiles.includes(file)).sort();
388
230
  const cacheKey = (/* @__PURE__ */ new Date()).getTime();
389
- const coverageMap = libCoverage.createCoverageMap({});
231
+ const coverageMap = this.createCoverageMap();
390
232
  const transform = this.createUncoveredFileTransformer(this.ctx);
391
233
  for (const [index, filename] of uncoveredFiles.entries()) {
392
234
  debug("Uncovered file %s %d/%d", filename, index, uncoveredFiles.length);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/coverage-istanbul",
3
3
  "type": "module",
4
- "version": "2.1.1",
4
+ "version": "2.1.3",
5
5
  "description": "Istanbul 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": "2.1.1"
40
+ "vitest": "2.1.3"
41
41
  },
42
42
  "dependencies": {
43
43
  "@istanbuljs/schema": "^0.1.3",
@@ -58,8 +58,9 @@
58
58
  "@types/istanbul-lib-report": "^3.0.3",
59
59
  "@types/istanbul-lib-source-maps": "^4.0.4",
60
60
  "@types/istanbul-reports": "^3.0.4",
61
+ "@types/test-exclude": "^6.0.2",
61
62
  "pathe": "^1.1.2",
62
- "vitest": "2.1.1"
63
+ "vitest": "2.1.3"
63
64
  },
64
65
  "scripts": {
65
66
  "build": "rimraf dist && rollup -c",