monocart-coverage-reports 2.5.9 → 2.6.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 +21 -21
- package/README.md +787 -778
- package/lib/cli.js +215 -215
- package/lib/converter/ast-visitor.js +675 -666
- package/lib/converter/ast.js +353 -353
- package/lib/converter/collect-source-maps.js +201 -201
- package/lib/converter/converter.js +1487 -1429
- package/lib/converter/find-original-range.js +737 -737
- package/lib/converter/ignore.js +163 -163
- package/lib/converter/info-branch.js +93 -93
- package/lib/converter/info-function.js +63 -63
- package/lib/converter/info-statement.js +43 -43
- package/lib/default/options.js +84 -84
- package/lib/default/template.html +47 -47
- package/lib/generate.js +720 -532
- package/lib/index.d.ts +360 -324
- package/lib/index.js +183 -180
- package/lib/index.mjs +5 -3
- package/lib/istanbul/istanbul-summary.js +70 -63
- package/lib/istanbul/istanbul.js +146 -146
- package/lib/packages/monocart-coverage-v8.js +1 -1
- package/lib/platform/concurrency.js +74 -74
- package/lib/platform/share.js +484 -484
- package/lib/utils/dedupe.js +118 -118
- package/lib/utils/request.js +62 -62
- package/lib/utils/snapshot.js +381 -0
- package/lib/utils/source-path.js +179 -179
- package/lib/utils/util.js +526 -526
- package/lib/v8/v8-summary.js +138 -138
- package/lib/v8/v8.js +399 -630
- package/package.json +81 -80
package/lib/cli.js
CHANGED
|
@@ -1,216 +1,216 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const EC = require('eight-colors');
|
|
6
|
-
const { fileURLToPath, pathToFileURL } = require('url');
|
|
7
|
-
const {
|
|
8
|
-
foregroundChild,
|
|
9
|
-
program
|
|
10
|
-
} = require('./packages/monocart-coverage-vendor.js');
|
|
11
|
-
|
|
12
|
-
const MCR = require('./index.js');
|
|
13
|
-
const Util = require('./utils/util.js');
|
|
14
|
-
const defaultOptions = require('./default/options.js');
|
|
15
|
-
const { resolveSourceMap } = require('./converter/collect-source-maps.js');
|
|
16
|
-
|
|
17
|
-
const version = require('../package.json').version;
|
|
18
|
-
|
|
19
|
-
const cleanDir = (dir) => {
|
|
20
|
-
Util.rmSync(dir);
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
const resolveConfigPath = (customConfigPath) => {
|
|
24
|
-
|
|
25
|
-
const configList = [
|
|
26
|
-
'.mcrrc',
|
|
27
|
-
'mcr.config.json',
|
|
28
|
-
'mcr.config.mjs',
|
|
29
|
-
'mcr.config.cjs',
|
|
30
|
-
'mcr.config.js'
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
if (customConfigPath) {
|
|
34
|
-
configList.push(customConfigPath);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const existsList = configList.filter((p) => fs.existsSync(p));
|
|
38
|
-
if (!existsList.length) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// last one
|
|
43
|
-
const configPath = existsList.pop();
|
|
44
|
-
Util.logInfo(`Config: ${EC.cyan(configPath)}`);
|
|
45
|
-
|
|
46
|
-
return configPath;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const resolveConfigOptions = async (configPath) => {
|
|
50
|
-
|
|
51
|
-
// json format
|
|
52
|
-
const ext = path.extname(configPath);
|
|
53
|
-
if (ext === '.json' || configPath.slice(-2) === 'rc') {
|
|
54
|
-
return JSON.parse(Util.readFileSync(configPath));
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
let configOptions;
|
|
58
|
-
let err;
|
|
59
|
-
try {
|
|
60
|
-
configOptions = await import(pathToFileURL(configPath));
|
|
61
|
-
} catch (ee) {
|
|
62
|
-
err = ee;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!configOptions) {
|
|
66
|
-
Util.logError(err.message);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
configOptions = configOptions.default || configOptions;
|
|
71
|
-
|
|
72
|
-
return configOptions;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const initOptions = async (cliOptions) => {
|
|
76
|
-
|
|
77
|
-
const configPath = resolveConfigPath(cliOptions.config);
|
|
78
|
-
if (configPath) {
|
|
79
|
-
const configOptions = await resolveConfigOptions(configPath);
|
|
80
|
-
if (configOptions) {
|
|
81
|
-
cliOptions = {
|
|
82
|
-
... configOptions,
|
|
83
|
-
... cliOptions
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// report options
|
|
89
|
-
const options = {
|
|
90
|
-
... defaultOptions
|
|
91
|
-
};
|
|
92
|
-
Object.keys(cliOptions).forEach((k) => {
|
|
93
|
-
if (Util.hasOwn(options, k)) {
|
|
94
|
-
options[k] = cliOptions[k];
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
return options;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const executeCommand = async (command, cliOptions) => {
|
|
102
|
-
|
|
103
|
-
const options = await initOptions(cliOptions);
|
|
104
|
-
|
|
105
|
-
Util.logInfo(`Execute: ${EC.cyan(command)}`);
|
|
106
|
-
// console.log(options);
|
|
107
|
-
|
|
108
|
-
const nodeV8CoverageDir = path.resolve(options.outputDir, '.v8-coverage');
|
|
109
|
-
process.env.NODE_V8_COVERAGE = nodeV8CoverageDir;
|
|
110
|
-
|
|
111
|
-
cleanDir(nodeV8CoverageDir);
|
|
112
|
-
|
|
113
|
-
// console.log('nodeV8CoverageDir', nodeV8CoverageDir);
|
|
114
|
-
|
|
115
|
-
const coverageReport = MCR(options);
|
|
116
|
-
coverageReport.cleanCache();
|
|
117
|
-
|
|
118
|
-
// on start hook
|
|
119
|
-
const onStart = cliOptions.onStart;
|
|
120
|
-
if (typeof onStart === 'function') {
|
|
121
|
-
await onStart(coverageReport);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
foregroundChild(command, {
|
|
125
|
-
shell: true
|
|
126
|
-
}, async () => {
|
|
127
|
-
|
|
128
|
-
if (!fs.existsSync(nodeV8CoverageDir)) {
|
|
129
|
-
EC.logRed(`Not found coverage data: ${Util.relativePath(nodeV8CoverageDir)}`);
|
|
130
|
-
return 1;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const files = fs.readdirSync(nodeV8CoverageDir);
|
|
134
|
-
for (const filename of files) {
|
|
135
|
-
const content = fs.readFileSync(path.resolve(nodeV8CoverageDir, filename)).toString('utf-8');
|
|
136
|
-
const json = JSON.parse(content);
|
|
137
|
-
let coverageList = json.result;
|
|
138
|
-
|
|
139
|
-
// for node sourcemap
|
|
140
|
-
const sourceMapCache = json['source-map-cache'] || {};
|
|
141
|
-
|
|
142
|
-
// filter node internal files
|
|
143
|
-
coverageList = coverageList.filter((entry) => entry.url && entry.url.startsWith('file:'));
|
|
144
|
-
|
|
145
|
-
if (!coverageList.length) {
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
148
|
-
// attached source content
|
|
149
|
-
coverageList.forEach((entry) => {
|
|
150
|
-
// source content
|
|
151
|
-
const filePath = fileURLToPath(entry.url);
|
|
152
|
-
if (fs.existsSync(filePath)) {
|
|
153
|
-
entry.source = fs.readFileSync(filePath).toString('utf8');
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// sourcemap data
|
|
157
|
-
const sourcemapData = sourceMapCache[entry.url];
|
|
158
|
-
if (sourcemapData) {
|
|
159
|
-
if (sourcemapData.data) {
|
|
160
|
-
entry.sourceMap = resolveSourceMap(sourcemapData.data, entry.url);
|
|
161
|
-
}
|
|
162
|
-
// sourcemapData.lineLengths just for fake source file (can not parse to AST)
|
|
163
|
-
if (!entry.source && sourcemapData.lineLengths) {
|
|
164
|
-
// get runtime code with ts-node
|
|
165
|
-
let source = '';
|
|
166
|
-
sourcemapData.lineLengths.forEach((length) => {
|
|
167
|
-
source += `${''.padEnd(length, '*')}\n`;
|
|
168
|
-
});
|
|
169
|
-
entry.fake = true;
|
|
170
|
-
entry.source = source;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
await coverageReport.add(coverageList);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
await coverageReport.generate();
|
|
179
|
-
|
|
180
|
-
// remove nodeV8CoverageDir
|
|
181
|
-
if (options.logging !== 'debug') {
|
|
182
|
-
cleanDir(nodeV8CoverageDir);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return process.exitCode;
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
program
|
|
191
|
-
.name('mcr')
|
|
192
|
-
.description('CLI to generate coverage reports')
|
|
193
|
-
.version(version)
|
|
194
|
-
.argument('<command>', 'command to execute')
|
|
195
|
-
.option('-c, --config <path>', 'custom config path')
|
|
196
|
-
.option('-o, --outputDir <dir>', 'output dir for reports')
|
|
197
|
-
.option('-r, --reports <name[,name]>', 'coverage reports to use')
|
|
198
|
-
.option('-n, --name <name>', 'report name for title')
|
|
199
|
-
.option('-i, --inputDir <dir>', 'input dir for merging raw files')
|
|
200
|
-
|
|
201
|
-
.option('--entryFilter <pattern>', 'entry url filter')
|
|
202
|
-
.option('--sourceFilter <pattern>', 'source path filter')
|
|
203
|
-
|
|
204
|
-
.option('--outputFile <path>', 'output file for v8 report')
|
|
205
|
-
.option('--inline', 'inline html for v8 report')
|
|
206
|
-
.option('--assetsPath <path>', 'assets path if not inline')
|
|
207
|
-
|
|
208
|
-
.option('--lcov', 'generate lcov.info file')
|
|
209
|
-
|
|
210
|
-
.option('--logging <logging>', 'off, error, info, debug')
|
|
211
|
-
|
|
212
|
-
.action((command, cliOptions) => {
|
|
213
|
-
executeCommand(command, cliOptions);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
program.parse();
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const EC = require('eight-colors');
|
|
6
|
+
const { fileURLToPath, pathToFileURL } = require('url');
|
|
7
|
+
const {
|
|
8
|
+
foregroundChild,
|
|
9
|
+
program
|
|
10
|
+
} = require('./packages/monocart-coverage-vendor.js');
|
|
11
|
+
|
|
12
|
+
const MCR = require('./index.js');
|
|
13
|
+
const Util = require('./utils/util.js');
|
|
14
|
+
const defaultOptions = require('./default/options.js');
|
|
15
|
+
const { resolveSourceMap } = require('./converter/collect-source-maps.js');
|
|
16
|
+
|
|
17
|
+
const version = require('../package.json').version;
|
|
18
|
+
|
|
19
|
+
const cleanDir = (dir) => {
|
|
20
|
+
Util.rmSync(dir);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const resolveConfigPath = (customConfigPath) => {
|
|
24
|
+
|
|
25
|
+
const configList = [
|
|
26
|
+
'.mcrrc',
|
|
27
|
+
'mcr.config.json',
|
|
28
|
+
'mcr.config.mjs',
|
|
29
|
+
'mcr.config.cjs',
|
|
30
|
+
'mcr.config.js'
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
if (customConfigPath) {
|
|
34
|
+
configList.push(customConfigPath);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const existsList = configList.filter((p) => fs.existsSync(p));
|
|
38
|
+
if (!existsList.length) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// last one
|
|
43
|
+
const configPath = existsList.pop();
|
|
44
|
+
Util.logInfo(`Config: ${EC.cyan(configPath)}`);
|
|
45
|
+
|
|
46
|
+
return configPath;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const resolveConfigOptions = async (configPath) => {
|
|
50
|
+
|
|
51
|
+
// json format
|
|
52
|
+
const ext = path.extname(configPath);
|
|
53
|
+
if (ext === '.json' || configPath.slice(-2) === 'rc') {
|
|
54
|
+
return JSON.parse(Util.readFileSync(configPath));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let configOptions;
|
|
58
|
+
let err;
|
|
59
|
+
try {
|
|
60
|
+
configOptions = await import(pathToFileURL(configPath));
|
|
61
|
+
} catch (ee) {
|
|
62
|
+
err = ee;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!configOptions) {
|
|
66
|
+
Util.logError(`ERROR: failed to import "${configPath}" ${err.message} `);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
configOptions = configOptions.default || configOptions;
|
|
71
|
+
|
|
72
|
+
return configOptions;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const initOptions = async (cliOptions) => {
|
|
76
|
+
|
|
77
|
+
const configPath = resolveConfigPath(cliOptions.config);
|
|
78
|
+
if (configPath) {
|
|
79
|
+
const configOptions = await resolveConfigOptions(configPath);
|
|
80
|
+
if (configOptions) {
|
|
81
|
+
cliOptions = {
|
|
82
|
+
... configOptions,
|
|
83
|
+
... cliOptions
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// report options
|
|
89
|
+
const options = {
|
|
90
|
+
... defaultOptions
|
|
91
|
+
};
|
|
92
|
+
Object.keys(cliOptions).forEach((k) => {
|
|
93
|
+
if (Util.hasOwn(options, k)) {
|
|
94
|
+
options[k] = cliOptions[k];
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return options;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const executeCommand = async (command, cliOptions) => {
|
|
102
|
+
|
|
103
|
+
const options = await initOptions(cliOptions);
|
|
104
|
+
|
|
105
|
+
Util.logInfo(`Execute: ${EC.cyan(command)}`);
|
|
106
|
+
// console.log(options);
|
|
107
|
+
|
|
108
|
+
const nodeV8CoverageDir = path.resolve(options.outputDir, '.v8-coverage');
|
|
109
|
+
process.env.NODE_V8_COVERAGE = nodeV8CoverageDir;
|
|
110
|
+
|
|
111
|
+
cleanDir(nodeV8CoverageDir);
|
|
112
|
+
|
|
113
|
+
// console.log('nodeV8CoverageDir', nodeV8CoverageDir);
|
|
114
|
+
|
|
115
|
+
const coverageReport = MCR(options);
|
|
116
|
+
coverageReport.cleanCache();
|
|
117
|
+
|
|
118
|
+
// on start hook
|
|
119
|
+
const onStart = cliOptions.onStart;
|
|
120
|
+
if (typeof onStart === 'function') {
|
|
121
|
+
await onStart(coverageReport);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
foregroundChild(command, {
|
|
125
|
+
shell: true
|
|
126
|
+
}, async () => {
|
|
127
|
+
|
|
128
|
+
if (!fs.existsSync(nodeV8CoverageDir)) {
|
|
129
|
+
EC.logRed(`Not found coverage data: ${Util.relativePath(nodeV8CoverageDir)}`);
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const files = fs.readdirSync(nodeV8CoverageDir);
|
|
134
|
+
for (const filename of files) {
|
|
135
|
+
const content = fs.readFileSync(path.resolve(nodeV8CoverageDir, filename)).toString('utf-8');
|
|
136
|
+
const json = JSON.parse(content);
|
|
137
|
+
let coverageList = json.result;
|
|
138
|
+
|
|
139
|
+
// for node sourcemap
|
|
140
|
+
const sourceMapCache = json['source-map-cache'] || {};
|
|
141
|
+
|
|
142
|
+
// filter node internal files
|
|
143
|
+
coverageList = coverageList.filter((entry) => entry.url && entry.url.startsWith('file:'));
|
|
144
|
+
|
|
145
|
+
if (!coverageList.length) {
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// attached source content
|
|
149
|
+
coverageList.forEach((entry) => {
|
|
150
|
+
// source content
|
|
151
|
+
const filePath = fileURLToPath(entry.url);
|
|
152
|
+
if (fs.existsSync(filePath)) {
|
|
153
|
+
entry.source = fs.readFileSync(filePath).toString('utf8');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// sourcemap data
|
|
157
|
+
const sourcemapData = sourceMapCache[entry.url];
|
|
158
|
+
if (sourcemapData) {
|
|
159
|
+
if (sourcemapData.data) {
|
|
160
|
+
entry.sourceMap = resolveSourceMap(sourcemapData.data, entry.url);
|
|
161
|
+
}
|
|
162
|
+
// sourcemapData.lineLengths just for fake source file (can not parse to AST)
|
|
163
|
+
if (!entry.source && sourcemapData.lineLengths) {
|
|
164
|
+
// get runtime code with ts-node
|
|
165
|
+
let source = '';
|
|
166
|
+
sourcemapData.lineLengths.forEach((length) => {
|
|
167
|
+
source += `${''.padEnd(length, '*')}\n`;
|
|
168
|
+
});
|
|
169
|
+
entry.fake = true;
|
|
170
|
+
entry.source = source;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await coverageReport.add(coverageList);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
await coverageReport.generate();
|
|
179
|
+
|
|
180
|
+
// remove nodeV8CoverageDir
|
|
181
|
+
if (options.logging !== 'debug') {
|
|
182
|
+
cleanDir(nodeV8CoverageDir);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return process.exitCode;
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
program
|
|
191
|
+
.name('mcr')
|
|
192
|
+
.description('CLI to generate coverage reports')
|
|
193
|
+
.version(version)
|
|
194
|
+
.argument('<command>', 'command to execute')
|
|
195
|
+
.option('-c, --config <path>', 'custom config path')
|
|
196
|
+
.option('-o, --outputDir <dir>', 'output dir for reports')
|
|
197
|
+
.option('-r, --reports <name[,name]>', 'coverage reports to use')
|
|
198
|
+
.option('-n, --name <name>', 'report name for title')
|
|
199
|
+
.option('-i, --inputDir <dir>', 'input dir for merging raw files')
|
|
200
|
+
|
|
201
|
+
.option('--entryFilter <pattern>', 'entry url filter')
|
|
202
|
+
.option('--sourceFilter <pattern>', 'source path filter')
|
|
203
|
+
|
|
204
|
+
.option('--outputFile <path>', 'output file for v8 report')
|
|
205
|
+
.option('--inline', 'inline html for v8 report')
|
|
206
|
+
.option('--assetsPath <path>', 'assets path if not inline')
|
|
207
|
+
|
|
208
|
+
.option('--lcov', 'generate lcov.info file')
|
|
209
|
+
|
|
210
|
+
.option('--logging <logging>', 'off, error, info, debug')
|
|
211
|
+
|
|
212
|
+
.action((command, cliOptions) => {
|
|
213
|
+
executeCommand(command, cliOptions);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
program.parse();
|