@pokujs/c8 0.1.1 → 1.0.1
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/README.md +159 -9
- package/lib/index.d.ts +4 -1
- package/lib/index.js +97 -3
- package/lib/types.d.ts +68 -0
- package/lib/types.js +2 -0
- package/package.json +31 -15
package/README.md
CHANGED
|
@@ -1,19 +1,169 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<img height="180" alt="Poku's Logo" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/poku.svg">
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
# @pokujs/c8
|
|
5
|
+
|
|
6
|
+
Enjoying **Poku**? [Give him a star to show your support](https://github.com/wellwelwel/poku) ⭐
|
|
7
|
+
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
📚 [**Documentation**](https://poku.io/docs/documentation/helpers/coverage/c8)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
☔️ [**@pokujs/c8**](https://github.com/pokujs/c8) is a **Poku** plugin for **V8** code coverage using [**c8**](https://github.com/bcoe/c8).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Quickstart
|
|
23
|
+
|
|
24
|
+
### Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm i -D @pokujs/c8
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Enable the Plugin
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
// poku.config.js
|
|
34
|
+
import { coverage } from '@pokujs/c8';
|
|
35
|
+
import { defineConfig } from 'poku';
|
|
36
|
+
|
|
37
|
+
export default defineConfig({
|
|
38
|
+
plugins: [coverage()],
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That's it! Run `poku` and a coverage summary will be printed after your test results.
|
|
4
43
|
|
|
5
44
|
> [!IMPORTANT]
|
|
6
45
|
>
|
|
7
|
-
>
|
|
46
|
+
> This plugin relies on **Node.js**' built-in `NODE_V8_COVERAGE` environment variable to collect coverage data. **Bun** and **Deno** do not support this mechanism, so coverage data will not be collected when running tests with these runtimes.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Options
|
|
51
|
+
|
|
52
|
+
```js
|
|
53
|
+
coverage({
|
|
54
|
+
// Reporters
|
|
55
|
+
reporter: ['text', 'lcov'], // default: ['text']
|
|
56
|
+
|
|
57
|
+
// File selection
|
|
58
|
+
include: ['src/**'], // default: [] (all files)
|
|
59
|
+
exclude: ['**/*.test.ts'], // default: c8 defaults
|
|
60
|
+
extension: ['.ts', '.js'], // default: c8 defaults
|
|
61
|
+
|
|
62
|
+
// Thresholds
|
|
63
|
+
checkCoverage: true, // default: false
|
|
64
|
+
lines: 80, // default: 0
|
|
65
|
+
branches: 80, // default: 0
|
|
66
|
+
functions: 80, // default: 0
|
|
67
|
+
statements: 80, // default: 0
|
|
68
|
+
perFile: false, // default: false
|
|
69
|
+
|
|
70
|
+
// Include untested files
|
|
71
|
+
all: true, // default: false
|
|
72
|
+
src: ['src'], // default: [cwd]
|
|
73
|
+
|
|
74
|
+
// Experimental
|
|
75
|
+
experimental: ['monocart'], // default: []
|
|
76
|
+
|
|
77
|
+
// Output
|
|
78
|
+
reportsDirectory: './coverage', // default: './coverage'
|
|
79
|
+
skipFull: false, // default: false
|
|
8
80
|
|
|
9
|
-
|
|
81
|
+
// Advanced
|
|
82
|
+
excludeAfterRemap: false, // default: false
|
|
83
|
+
mergeAsync: false, // default: false
|
|
84
|
+
clean: true, // default: true
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Examples
|
|
91
|
+
|
|
92
|
+
### Basic text coverage
|
|
10
93
|
|
|
11
|
-
```
|
|
12
|
-
|
|
94
|
+
```js
|
|
95
|
+
coverage({
|
|
96
|
+
include: ['src/**'],
|
|
97
|
+
});
|
|
13
98
|
```
|
|
14
99
|
|
|
15
|
-
###
|
|
100
|
+
### Generate HTML and LCOV reports
|
|
16
101
|
|
|
17
|
-
```
|
|
18
|
-
|
|
102
|
+
```js
|
|
103
|
+
coverage({
|
|
104
|
+
include: ['src/**'],
|
|
105
|
+
reporter: ['text', 'html', 'lcov'],
|
|
106
|
+
});
|
|
19
107
|
```
|
|
108
|
+
|
|
109
|
+
### Enforce coverage thresholds
|
|
110
|
+
|
|
111
|
+
Set a single threshold for all metrics at once by passing a `number`:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
coverage({
|
|
115
|
+
include: ['src/**'],
|
|
116
|
+
checkCoverage: 100,
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Or use `true` to set individual thresholds for each metric:
|
|
121
|
+
|
|
122
|
+
```js
|
|
123
|
+
coverage({
|
|
124
|
+
include: ['src/**'],
|
|
125
|
+
checkCoverage: true,
|
|
126
|
+
lines: 95,
|
|
127
|
+
branches: 90,
|
|
128
|
+
functions: 85,
|
|
129
|
+
statements: 95,
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### TypeScript coverage
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
coverage({
|
|
137
|
+
include: ['src/**'],
|
|
138
|
+
extension: ['.ts'],
|
|
139
|
+
all: true,
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Extending Monocart reporters
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
npm i -D monocart-coverage-reports
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
```js
|
|
150
|
+
coverage({
|
|
151
|
+
include: ['src/**'],
|
|
152
|
+
reporter: ['v8', 'console-details', 'codecov'],
|
|
153
|
+
experimental: ['monocart'],
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## How It Works
|
|
160
|
+
|
|
161
|
+
- **`setup`** creates a temp directory and sets `NODE_V8_COVERAGE` — every test process spawned by **Poku** automatically writes **V8** coverage data
|
|
162
|
+
- **`teardown`** uses **c8** to generate reports from the collected data, optionally checks thresholds, then cleans up
|
|
163
|
+
- No modification to test commands or runner configuration needed
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
**MIT** © [**wellwelwel**](https://github.com/wellwelwel) and [**contributors**](https://github.com/pokujs/c8/graphs/contributors).
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
+
exports.coverage = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_os_1 = require("node:os");
|
|
9
|
+
const node_path_1 = require("node:path");
|
|
10
|
+
const node_process_1 = __importDefault(require("node:process"));
|
|
11
|
+
const coverage = (options = Object.create(null)) => {
|
|
12
|
+
let tempDir;
|
|
13
|
+
let originalEnv;
|
|
14
|
+
let userProvidedTempDir;
|
|
15
|
+
return {
|
|
16
|
+
name: '@pokujs/c8',
|
|
17
|
+
setup(context) {
|
|
18
|
+
if (context.runtime !== 'node')
|
|
19
|
+
console.warn(`[@pokujs/c8] V8 coverage is only supported on Node.js (current runtime: ${context.runtime}). Coverage data may not be collected.`);
|
|
20
|
+
originalEnv = node_process_1.default.env.NODE_V8_COVERAGE;
|
|
21
|
+
userProvidedTempDir = typeof options.tempDirectory === 'string';
|
|
22
|
+
tempDir = userProvidedTempDir
|
|
23
|
+
? options.tempDirectory
|
|
24
|
+
: (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'poku-c8-'));
|
|
25
|
+
node_process_1.default.env.NODE_V8_COVERAGE = tempDir;
|
|
26
|
+
},
|
|
27
|
+
async teardown(context) {
|
|
28
|
+
if (originalEnv !== undefined)
|
|
29
|
+
node_process_1.default.env.NODE_V8_COVERAGE = originalEnv;
|
|
30
|
+
else
|
|
31
|
+
delete node_process_1.default.env.NODE_V8_COVERAGE;
|
|
32
|
+
const reporter = Array.isArray(options.reporter)
|
|
33
|
+
? options.reporter
|
|
34
|
+
: [options.reporter ?? 'text'];
|
|
35
|
+
const reportsDirectory = (0, node_path_1.resolve)(context.cwd, options.reportsDirectory ?? './coverage');
|
|
36
|
+
const { default: Report } = await import('c8/lib/report.js');
|
|
37
|
+
const useMonocart = options.experimental?.includes('monocart') ?? false;
|
|
38
|
+
const monocartArgv = useMonocart
|
|
39
|
+
? {
|
|
40
|
+
reporter,
|
|
41
|
+
reportsDir: reportsDirectory,
|
|
42
|
+
tempDirectory: tempDir,
|
|
43
|
+
all: options.all ?? false,
|
|
44
|
+
src: options.src,
|
|
45
|
+
skipFull: options.skipFull ?? false,
|
|
46
|
+
excludeAfterRemap: options.excludeAfterRemap ?? false,
|
|
47
|
+
clean: options.clean !== false,
|
|
48
|
+
}
|
|
49
|
+
: undefined;
|
|
50
|
+
const report = Report({
|
|
51
|
+
tempDirectory: tempDir,
|
|
52
|
+
reportsDirectory,
|
|
53
|
+
reporter,
|
|
54
|
+
include: options.include ?? [],
|
|
55
|
+
exclude: options.exclude,
|
|
56
|
+
extension: options.extension,
|
|
57
|
+
all: options.all ?? false,
|
|
58
|
+
src: options.src,
|
|
59
|
+
resolve: '',
|
|
60
|
+
omitRelative: true,
|
|
61
|
+
excludeNodeModules: true,
|
|
62
|
+
skipFull: options.skipFull ?? false,
|
|
63
|
+
excludeAfterRemap: options.excludeAfterRemap ?? false,
|
|
64
|
+
watermarks: options.watermarks,
|
|
65
|
+
mergeAsync: options.mergeAsync ?? false,
|
|
66
|
+
monocartArgv,
|
|
67
|
+
});
|
|
68
|
+
await report.run();
|
|
69
|
+
if (options.checkCoverage) {
|
|
70
|
+
const { checkCoverages } = await import('c8/lib/commands/check-coverage.js');
|
|
71
|
+
const threshold = typeof options.checkCoverage === 'number'
|
|
72
|
+
? options.checkCoverage
|
|
73
|
+
: undefined;
|
|
74
|
+
await checkCoverages({
|
|
75
|
+
lines: threshold ?? options.lines ?? 0,
|
|
76
|
+
branches: threshold ?? options.branches ?? 0,
|
|
77
|
+
functions: threshold ?? options.functions ?? 0,
|
|
78
|
+
statements: threshold ?? options.statements ?? 0,
|
|
79
|
+
perFile: options.perFile ?? false,
|
|
80
|
+
}, report);
|
|
81
|
+
if (node_process_1.default.exitCode === 1) {
|
|
82
|
+
const coverageFailure = () => {
|
|
83
|
+
node_process_1.default.exitCode = 1;
|
|
84
|
+
};
|
|
85
|
+
node_process_1.default.once('exit', coverageFailure);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (!userProvidedTempDir) {
|
|
89
|
+
try {
|
|
90
|
+
(0, node_fs_1.rmSync)(tempDir, { recursive: true, force: true });
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Best-effort cleanup
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
exports.coverage = coverage;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
type KnownReporter = 'clover' | 'cobertura' | 'codecov' | 'console-details' | 'html' | 'html-spa' | 'json' | 'json-summary' | 'lcov' | 'lcovonly' | 'none' | 'teamcity' | 'text' | 'text-lcov' | 'text-summary' | 'v8';
|
|
2
|
+
type Reporter = KnownReporter | (string & NonNullable<unknown>);
|
|
3
|
+
type KnownExtension = '.cjs' | '.cts' | '.js' | '.jsx' | '.mjs' | '.mts' | '.ts' | '.tsx';
|
|
4
|
+
type Extension = KnownExtension | (string & NonNullable<unknown>);
|
|
5
|
+
export type CoverageOptions = {
|
|
6
|
+
/** Coverage reporters to use. */
|
|
7
|
+
reporter?: Reporter | Reporter[];
|
|
8
|
+
/** Directory where coverage reports are written. */
|
|
9
|
+
reportsDirectory?: string;
|
|
10
|
+
/**
|
|
11
|
+
* Directory where V8 writes raw coverage JSON files.
|
|
12
|
+
*
|
|
13
|
+
* When provided, the directory is **not** auto-cleaned after report generation.
|
|
14
|
+
*/
|
|
15
|
+
tempDirectory?: string;
|
|
16
|
+
/** Glob patterns for source files to include (empty = all). */
|
|
17
|
+
include?: string[];
|
|
18
|
+
/** Glob patterns for source files to exclude. */
|
|
19
|
+
exclude?: string[];
|
|
20
|
+
/** File extensions to consider for coverage. */
|
|
21
|
+
extension?: Extension[];
|
|
22
|
+
/**
|
|
23
|
+
* Include files that were never loaded by any test (reported as 0% coverage).
|
|
24
|
+
*
|
|
25
|
+
* Use `src` to control which directories are scanned.
|
|
26
|
+
*/
|
|
27
|
+
all?: boolean;
|
|
28
|
+
/** Directories to scan when `all` is `true`. */
|
|
29
|
+
src?: string[];
|
|
30
|
+
/** Delete previous coverage data before running. */
|
|
31
|
+
clean?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Enforce coverage thresholds.
|
|
34
|
+
*
|
|
35
|
+
* - `true` — check using individual `lines`, `branches`, `functions`, and `statements` values.
|
|
36
|
+
* - `number` — set all thresholds to that value (e.g., `100` is equivalent to `--100` in c8 CLI).
|
|
37
|
+
*
|
|
38
|
+
* When a threshold is not met, `process.exitCode` is set to `1`.
|
|
39
|
+
*/
|
|
40
|
+
checkCoverage?: boolean | number;
|
|
41
|
+
/** Check thresholds per file instead of globally. */
|
|
42
|
+
perFile?: boolean;
|
|
43
|
+
/** Minimum line coverage percentage. */
|
|
44
|
+
lines?: number;
|
|
45
|
+
/** Minimum branch coverage percentage. */
|
|
46
|
+
branches?: number;
|
|
47
|
+
/** Minimum function coverage percentage. */
|
|
48
|
+
functions?: number;
|
|
49
|
+
/** Minimum statement coverage percentage. */
|
|
50
|
+
statements?: number;
|
|
51
|
+
/** Skip files with 100% coverage in the text report. */
|
|
52
|
+
skipFull?: boolean;
|
|
53
|
+
/** Apply exclude rules after source-map remapping. */
|
|
54
|
+
excludeAfterRemap?: boolean;
|
|
55
|
+
/** Custom watermark thresholds for report coloring. */
|
|
56
|
+
watermarks?: Record<string, [number, number]>;
|
|
57
|
+
/** Use async incremental merge (useful for large test suites). */
|
|
58
|
+
mergeAsync?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* Enable experimental features.
|
|
61
|
+
*
|
|
62
|
+
* - `'monocart'` — Use monocart-coverage-reports instead of the default
|
|
63
|
+
* Istanbul pipeline. Requires `monocart-coverage-reports` to be installed
|
|
64
|
+
* separately.
|
|
65
|
+
*/
|
|
66
|
+
experimental?: 'monocart'[];
|
|
67
|
+
};
|
|
68
|
+
export {};
|
package/lib/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pokujs/c8",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1
|
|
5
|
-
"description": "☔️
|
|
4
|
+
"version": "1.0.1",
|
|
5
|
+
"description": "☔️ A Poku plugin for V8 code coverage using c8.",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -16,34 +16,44 @@
|
|
|
16
16
|
"author": "https://github.com/wellwelwel",
|
|
17
17
|
"funding": {
|
|
18
18
|
"type": "github",
|
|
19
|
-
"url": "https://github.com/
|
|
19
|
+
"url": "https://github.com/pokujs/c8?sponsor=1"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
22
|
"lib"
|
|
23
23
|
],
|
|
24
24
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
25
|
+
"node": ">=18.x.x"
|
|
26
26
|
},
|
|
27
27
|
"scripts": {
|
|
28
|
-
"test": "poku",
|
|
28
|
+
"test": "poku test/e2e",
|
|
29
|
+
"prebuild": "rm -rf lib",
|
|
29
30
|
"build": "tsc",
|
|
30
|
-
"lint": "
|
|
31
|
-
"lint:fix": "
|
|
31
|
+
"lint": "prettier --check .",
|
|
32
|
+
"lint:fix": "prettier --write .github/workflows/*.yml .",
|
|
32
33
|
"update": "pu minor && npm i && (npm audit fix || true)",
|
|
33
34
|
"postupdate": "npm run lint:fix"
|
|
34
35
|
},
|
|
35
36
|
"dependencies": {
|
|
36
37
|
"c8": "^10.1.3"
|
|
37
38
|
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"monocart-coverage-reports": "^2.12.9",
|
|
41
|
+
"poku": "^4.1.0"
|
|
42
|
+
},
|
|
43
|
+
"peerDependenciesMeta": {
|
|
44
|
+
"monocart-coverage-reports": {
|
|
45
|
+
"optional": true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
38
48
|
"devDependencies": {
|
|
39
|
-
"@
|
|
40
|
-
"@
|
|
41
|
-
"
|
|
49
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.7.1",
|
|
50
|
+
"@types/node": "^25.5.0",
|
|
51
|
+
"monocart-coverage-reports": "^2.12.9",
|
|
42
52
|
"packages-update": "^2.0.0",
|
|
43
|
-
"poku": "^
|
|
44
|
-
"prettier": "^3.
|
|
45
|
-
"tsx": "4.
|
|
46
|
-
"typescript": "^
|
|
53
|
+
"poku": "^4.1.0",
|
|
54
|
+
"prettier": "^3.8.1",
|
|
55
|
+
"tsx": "^4.21.0",
|
|
56
|
+
"typescript": "^6.0.2"
|
|
47
57
|
},
|
|
48
58
|
"publishConfig": {
|
|
49
59
|
"access": "public"
|
|
@@ -52,7 +62,13 @@
|
|
|
52
62
|
"🐷",
|
|
53
63
|
"poku",
|
|
54
64
|
"pokujs",
|
|
65
|
+
"testing",
|
|
66
|
+
"plugin",
|
|
55
67
|
"coverage",
|
|
56
|
-
"c8"
|
|
68
|
+
"c8",
|
|
69
|
+
"v8",
|
|
70
|
+
"istanbul",
|
|
71
|
+
"monocart",
|
|
72
|
+
"codecov"
|
|
57
73
|
]
|
|
58
74
|
}
|