monocart-coverage-reports 2.13.2 → 3.0.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/README.md +267 -114
- package/README.zh-Hans.md +268 -115
- package/lib/assets.js +6 -6
- package/lib/cli.js +191 -95
- package/lib/client/cdp-client.js +74 -43
- package/lib/client/coverage-client.js +24 -8
- package/lib/client/ws-session.js +115 -37
- package/lib/converter/ast-visitor.js +5 -7
- package/lib/converter/ast.js +6 -6
- package/lib/converter/collect-source-maps.js +9 -9
- package/lib/converter/converter.js +41 -115
- package/lib/converter/fake-source-coverage.js +64 -0
- package/lib/converter/find-original-range.js +3 -3
- package/lib/converter/flatten-source-maps.js +2 -4
- package/lib/converter/ignore.js +2 -4
- package/lib/converter/info-branch.js +5 -3
- package/lib/converter/info-function.js +5 -3
- package/lib/converter/info-statement.js +5 -3
- package/lib/converter/range-index.js +78 -0
- package/lib/converter/source-range-merge.js +103 -0
- package/lib/converter/untested.js +27 -55
- package/lib/default/options.js +13 -1
- package/lib/generate.js +44 -26
- package/lib/index.d.ts +52 -4
- package/lib/index.js +35 -41
- package/lib/istanbul/istanbul-summary.js +2 -2
- package/lib/istanbul/istanbul.js +35 -13
- package/lib/packages/chunks/chunk-RVOSNMVU.js +2 -0
- package/lib/packages/monocart-coverage-assets.js +4 -3
- package/lib/packages/monocart-coverage-converter.js +27 -0
- package/lib/packages/monocart-coverage-vendor.js +2 -41
- package/lib/packages/monocart-coverage-vendor.js.LICENSE +3 -221
- package/lib/platform/concurrency.js +47 -43
- package/lib/platform/share.js +1 -1
- package/lib/register/hooks.js +19 -13
- package/lib/register/register.js +5 -3
- package/lib/reports/codacy.js +3 -5
- package/lib/reports/codecov.js +3 -5
- package/lib/reports/console-details.js +5 -5
- package/lib/reports/console-summary.js +4 -4
- package/lib/reports/custom.js +8 -24
- package/lib/reports/markdown-details.js +4 -6
- package/lib/reports/markdown-summary.js +4 -6
- package/lib/reports/raw.js +10 -12
- package/lib/reports/v8-json.js +3 -5
- package/lib/reports/v8.js +3 -5
- package/lib/utils/dedupe.js +1 -1
- package/lib/utils/gc.js +30 -14
- package/lib/utils/markdown.js +2 -2
- package/lib/utils/merge/merge.js +2 -4
- package/lib/utils/merge/range-tree.js +1 -1
- package/lib/utils/request.js +85 -73
- package/lib/utils/snapshot.js +4 -4
- package/lib/utils/source-path.js +5 -5
- package/lib/utils/util.js +61 -41
- package/lib/v8/v8-summary.js +2 -4
- package/lib/v8/v8.js +11 -11
- package/migrate-to-3.md +175 -0
- package/package.json +153 -149
- package/skills/monocart-coverage-reports/SKILL.md +106 -0
- package/skills/monocart-coverage-reports/references/cli.md +108 -0
- package/skills/monocart-coverage-reports/references/collection.md +152 -0
- package/skills/monocart-coverage-reports/references/filtering-and-sourcemaps.md +170 -0
- package/skills/monocart-coverage-reports/references/reports-and-ci.md +219 -0
- package/skills/monocart-coverage-reports/references/repository-map.md +55 -0
- package/lib/index.mjs +0 -9
- package/lib/register/hooks.mjs +0 -3
- package/lib/register/register.mjs +0 -3
package/lib/client/ws-session.js
CHANGED
|
@@ -1,63 +1,141 @@
|
|
|
1
|
-
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
|
|
3
|
+
const parseMessage = (data) => {
|
|
4
|
+
const message = JSON.parse(data);
|
|
5
|
+
if (!message || typeof message !== 'object' || Array.isArray(message)) {
|
|
6
|
+
throw new Error('Expected a CDP message object');
|
|
7
|
+
}
|
|
8
|
+
return message;
|
|
9
|
+
};
|
|
2
10
|
|
|
3
11
|
class WSSession extends EventEmitter {
|
|
4
|
-
constructor(ws) {
|
|
12
|
+
constructor(ws, { timeout = 30000 } = {}) {
|
|
5
13
|
super();
|
|
14
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
15
|
+
throw new RangeError('WebSocket request timeout must be a non-negative finite number');
|
|
16
|
+
}
|
|
6
17
|
this.ws = ws;
|
|
18
|
+
this.timeout = timeout;
|
|
7
19
|
this.requestId = 1;
|
|
8
20
|
this.requestCache = new Map();
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (id) {
|
|
16
|
-
const request = this.requestCache.get(id);
|
|
17
|
-
this.requestCache.delete(id);
|
|
18
|
-
if (request) {
|
|
19
|
-
request.resolve(message.result);
|
|
20
|
-
}
|
|
21
|
-
return;
|
|
21
|
+
this.events = {
|
|
22
|
+
message: (data) => this.onMessage(data),
|
|
23
|
+
error: (error) => this.disconnect(error),
|
|
24
|
+
close: () => {
|
|
25
|
+
this.disconnect(new Error('WebSocket closed'));
|
|
26
|
+
this.unbind(ws);
|
|
22
27
|
}
|
|
28
|
+
};
|
|
29
|
+
for (const [name, handler] of Object.entries(this.events)) {
|
|
30
|
+
ws.on(name, handler);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
23
33
|
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
onMessage(data) {
|
|
35
|
+
let message;
|
|
36
|
+
try {
|
|
37
|
+
message = parseMessage(data);
|
|
38
|
+
} catch (cause) {
|
|
39
|
+
this.disconnect(new Error('Invalid WebSocket JSON message', {
|
|
40
|
+
cause
|
|
41
|
+
}));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const { id, method } = message;
|
|
45
|
+
if (id) {
|
|
46
|
+
const pending = this.requestCache.get(id);
|
|
47
|
+
if (!pending) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
let error;
|
|
51
|
+
if (message.error) {
|
|
52
|
+
error = new Error(`Protocol error (${pending.method}): ${message.error.message}`);
|
|
53
|
+
error.code = message.error.code;
|
|
54
|
+
error.data = message.error.data;
|
|
26
55
|
}
|
|
56
|
+
this.settleRequest(id, error, message.result);
|
|
57
|
+
} else if (typeof method === 'string') {
|
|
58
|
+
this.emit(method, message.params, message.sessionId);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
27
61
|
|
|
28
|
-
|
|
62
|
+
settleRequest(id, error, result) {
|
|
63
|
+
const pending = this.requestCache.get(id);
|
|
64
|
+
if (!pending) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
this.requestCache.delete(id);
|
|
68
|
+
clearTimeout(pending.timer);
|
|
69
|
+
if (error) {
|
|
70
|
+
pending.reject(error);
|
|
71
|
+
} else {
|
|
72
|
+
pending.resolve(result);
|
|
73
|
+
}
|
|
29
74
|
}
|
|
30
75
|
|
|
31
76
|
send(method, params) {
|
|
32
77
|
return new Promise((resolve, reject) => {
|
|
33
|
-
|
|
34
|
-
|
|
78
|
+
const ws = this.ws;
|
|
79
|
+
if (!ws || (typeof ws.readyState === 'number' && ws.readyState !== 1)) {
|
|
80
|
+
reject(new Error('Invalid or closed websocket'));
|
|
35
81
|
return;
|
|
36
82
|
}
|
|
37
83
|
const id = this.requestId++;
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
method,
|
|
41
|
-
params: params || {}
|
|
84
|
+
const pending = {
|
|
85
|
+
resolve, reject, method, timer: null
|
|
42
86
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
87
|
+
// Register before send: a response may arrive before its callback.
|
|
88
|
+
this.requestCache.set(id, pending);
|
|
89
|
+
if (this.timeout > 0) {
|
|
90
|
+
pending.timer = setTimeout(() => {
|
|
91
|
+
const error = new Error(`WebSocket request timed out: ${method}`);
|
|
92
|
+
error.code = 'ETIMEDOUT';
|
|
93
|
+
this.settleRequest(id, error);
|
|
94
|
+
}, this.timeout);
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
ws.send(JSON.stringify({
|
|
98
|
+
id, method, params: params || {}
|
|
99
|
+
}), (error) => {
|
|
100
|
+
if (error) {
|
|
101
|
+
this.settleRequest(id, error);
|
|
102
|
+
}
|
|
50
103
|
});
|
|
51
|
-
})
|
|
104
|
+
} catch (error) {
|
|
105
|
+
this.settleRequest(id, error);
|
|
106
|
+
}
|
|
52
107
|
});
|
|
53
108
|
}
|
|
54
109
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
110
|
+
disconnect(error) {
|
|
111
|
+
const ws = this.ws;
|
|
112
|
+
this.ws = null;
|
|
113
|
+
for (const id of this.requestCache.keys()) {
|
|
114
|
+
this.settleRequest(id, error);
|
|
59
115
|
}
|
|
116
|
+
if (ws) {
|
|
117
|
+
ws.off('message', this.events.message);
|
|
118
|
+
if (ws.readyState === 3) {
|
|
119
|
+
this.unbind(ws);
|
|
120
|
+
} else {
|
|
121
|
+
// Keep error/close handlers until close to consume termination errors.
|
|
122
|
+
ws.terminate();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
unbind(ws) {
|
|
128
|
+
if (this.events) {
|
|
129
|
+
for (const [name, handler] of Object.entries(this.events)) {
|
|
130
|
+
ws.off(name, handler);
|
|
131
|
+
}
|
|
132
|
+
this.events = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
detach() {
|
|
137
|
+
this.disconnect(new Error('WebSocket detached'));
|
|
60
138
|
}
|
|
61
139
|
}
|
|
62
140
|
|
|
63
|
-
|
|
141
|
+
export { WSSession };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { Util } from '../utils/util.js';
|
|
2
|
+
import { findContainingRange } from './range-index.js';
|
|
2
3
|
|
|
3
4
|
const BranchTypes = {
|
|
4
5
|
ConditionalExpression: 'ConditionalExpression',
|
|
@@ -83,17 +84,14 @@ const getFunctionBlock = (start, end, functionState) => {
|
|
|
83
84
|
return block;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
const uncoveredBlock =
|
|
87
|
+
const uncoveredBlock = findContainingRange(blockUncoveredRanges, start, end);
|
|
87
88
|
if (uncoveredBlock) {
|
|
88
89
|
return uncoveredBlock;
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
// the block is not exact correct, if there is a block wrapped
|
|
92
93
|
// [x8]{ var a = b || [x4]c }, b is no block, but it can be found in x8 block
|
|
93
|
-
|
|
94
|
-
if (coveredBlocks.length) {
|
|
95
|
-
return coveredBlocks.pop();
|
|
96
|
-
}
|
|
94
|
+
return findContainingRange(blockCoveredRanges, start, end);
|
|
97
95
|
|
|
98
96
|
};
|
|
99
97
|
|
|
@@ -803,7 +801,7 @@ const collectAstInfo = (ast, coverageInfo) => {
|
|
|
803
801
|
|
|
804
802
|
};
|
|
805
803
|
|
|
806
|
-
|
|
804
|
+
export {
|
|
807
805
|
BranchTypes,
|
|
808
806
|
collectAstInfo
|
|
809
807
|
};
|
package/lib/converter/ast.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import * as acorn from 'acorn';
|
|
2
|
+
import * as acornLoose from 'acorn-loose';
|
|
3
|
+
import { parseCss } from '../packages/monocart-coverage-converter.js';
|
|
4
|
+
import { Util } from '../utils/util.js';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import { collectAstInfo } from './ast-visitor.js';
|
|
7
7
|
|
|
8
8
|
const getCoverageInfo = (coverageList) => {
|
|
9
9
|
const functionMap = new Map();
|
|
@@ -358,7 +358,7 @@ const getCssAstInfo = (item, coverageList) => {
|
|
|
358
358
|
};
|
|
359
359
|
|
|
360
360
|
|
|
361
|
-
|
|
361
|
+
export {
|
|
362
362
|
getJsAstInfo,
|
|
363
363
|
getCssAstInfo
|
|
364
364
|
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import EC from 'eight-colors';
|
|
4
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
5
|
+
import { Concurrency } from '../platform/concurrency.js';
|
|
6
|
+
import convertSourceMap from 'convert-source-map';
|
|
7
|
+
import { flattenSourceMaps } from './flatten-source-maps.js';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
import { Util } from '../utils/util.js';
|
|
10
10
|
|
|
11
11
|
const getSourceMapCandidates = (source) => {
|
|
12
12
|
if (!source.includes('sourceMappingURL=')) {
|
|
@@ -319,7 +319,7 @@ const collectSourceMaps = async (v8list, options) => {
|
|
|
319
319
|
|
|
320
320
|
};
|
|
321
321
|
|
|
322
|
-
|
|
322
|
+
export {
|
|
323
323
|
collectSourceMaps,
|
|
324
324
|
resolveSourceMap
|
|
325
325
|
};
|
|
@@ -4,27 +4,29 @@
|
|
|
4
4
|
* @author cenfun@gmail.com
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import EC from 'eight-colors';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
import { Locator } from 'monocart-locator';
|
|
10
|
+
import { Util } from '../utils/util.js';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
import { findOriginalRange } from './find-original-range.js';
|
|
13
|
+
import { isUncoveredRange } from './source-range-merge.js';
|
|
14
|
+
import { handleUncoveredInCovered } from './fake-source-coverage.js';
|
|
15
|
+
import { getJsAstInfo, getCssAstInfo } from './ast.js';
|
|
16
|
+
import { getIgnoredRanges } from './ignore.js';
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
import { getUntestedList } from './untested.js';
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
import {
|
|
19
21
|
sortRanges, dedupeCountRanges, mergeRangesWith
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
+
} from '../utils/dedupe.js';
|
|
23
|
+
import { getSourceType, initSourceMapSourcesPath } from '../utils/source-path.js';
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
import { decode } from '@jridgewell/sourcemap-codec';
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
import { InfoBranch } from './info-branch.js';
|
|
28
|
+
import { InfoFunction } from './info-function.js';
|
|
29
|
+
import { InfoStatement } from './info-statement.js';
|
|
28
30
|
|
|
29
31
|
// ========================================================================================================
|
|
30
32
|
|
|
@@ -212,7 +214,7 @@ const calculateV8Summary = (list) => {
|
|
|
212
214
|
* * `f` - hit count for functions
|
|
213
215
|
* * `b` - hit count for branches
|
|
214
216
|
*/
|
|
215
|
-
const collectFileCoverage = (v8Data, state, options) => {
|
|
217
|
+
const collectFileCoverage = (v8Data, state, options, needsIstanbul) => {
|
|
216
218
|
|
|
217
219
|
const {
|
|
218
220
|
bytes,
|
|
@@ -220,7 +222,6 @@ const collectFileCoverage = (v8Data, state, options) => {
|
|
|
220
222
|
branches,
|
|
221
223
|
statements,
|
|
222
224
|
|
|
223
|
-
sourcePath,
|
|
224
225
|
locator
|
|
225
226
|
} = state;
|
|
226
227
|
|
|
@@ -313,7 +314,19 @@ const collectFileCoverage = (v8Data, state, options) => {
|
|
|
313
314
|
v8Data.summary = summary;
|
|
314
315
|
|
|
315
316
|
// ==========================================
|
|
316
|
-
//
|
|
317
|
+
// Istanbul location maps are not needed by V8-only reports. Keep the
|
|
318
|
+
// V8 ranges, counts and summaries above identical in either mode.
|
|
319
|
+
if (!needsIstanbul) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return collectIstanbulCoverage(state);
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
const collectIstanbulCoverage = (state) => {
|
|
327
|
+
const {
|
|
328
|
+
sourcePath, locator, statements, functions, branches
|
|
329
|
+
} = state;
|
|
317
330
|
const istanbulData = {
|
|
318
331
|
path: sourcePath,
|
|
319
332
|
|
|
@@ -1157,56 +1170,6 @@ const generateCoverageForDist = (state) => {
|
|
|
1157
1170
|
|
|
1158
1171
|
};
|
|
1159
1172
|
|
|
1160
|
-
const handleUncoveredInCovered = (state, originalStateMap) => {
|
|
1161
|
-
if (!state.fake) {
|
|
1162
|
-
return;
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
// fake statements/branches/functions
|
|
1166
|
-
originalStateMap.forEach((originalState) => {
|
|
1167
|
-
const { bytes } = originalState;
|
|
1168
|
-
const list = [];
|
|
1169
|
-
originalState.bytes = bytes.filter((item) => {
|
|
1170
|
-
if (item.count === 0) {
|
|
1171
|
-
const range = bytes.find((it) => {
|
|
1172
|
-
if (it.count === 0) {
|
|
1173
|
-
return false;
|
|
1174
|
-
}
|
|
1175
|
-
if (it.start > item.end) {
|
|
1176
|
-
return false;
|
|
1177
|
-
}
|
|
1178
|
-
if (it.end < item.start) {
|
|
1179
|
-
return false;
|
|
1180
|
-
}
|
|
1181
|
-
return true;
|
|
1182
|
-
});
|
|
1183
|
-
if (range) {
|
|
1184
|
-
list.push(item);
|
|
1185
|
-
return false;
|
|
1186
|
-
}
|
|
1187
|
-
}
|
|
1188
|
-
return true;
|
|
1189
|
-
});
|
|
1190
|
-
|
|
1191
|
-
if (!list.length) {
|
|
1192
|
-
return;
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
list.forEach((item) => {
|
|
1196
|
-
['statements', 'branches', 'functions'].forEach((key) => {
|
|
1197
|
-
originalState[key] = originalState[key].filter((it) => {
|
|
1198
|
-
if (it.start === item.start && it.end === item.end) {
|
|
1199
|
-
return false;
|
|
1200
|
-
}
|
|
1201
|
-
return true;
|
|
1202
|
-
});
|
|
1203
|
-
});
|
|
1204
|
-
});
|
|
1205
|
-
|
|
1206
|
-
});
|
|
1207
|
-
|
|
1208
|
-
};
|
|
1209
|
-
|
|
1210
1173
|
const unpackSourceMap = (state, options) => {
|
|
1211
1174
|
|
|
1212
1175
|
const { sourceMap, sourcePath } = state;
|
|
@@ -1525,44 +1488,6 @@ const convertCoverages = (list, options, untested) => {
|
|
|
1525
1488
|
|
|
1526
1489
|
// ========================================================================================================
|
|
1527
1490
|
|
|
1528
|
-
const isUncoveredRange = (range, key, uncoveredGroups) => {
|
|
1529
|
-
|
|
1530
|
-
let uncovered = true;
|
|
1531
|
-
uncoveredGroups.forEach((group) => {
|
|
1532
|
-
const { groupMap, state } = group;
|
|
1533
|
-
|
|
1534
|
-
// ========================================================
|
|
1535
|
-
// self key
|
|
1536
|
-
if (groupMap.has(key)) {
|
|
1537
|
-
return;
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
// ========================================================
|
|
1541
|
-
// in all group
|
|
1542
|
-
for (const item of groupMap.values()) {
|
|
1543
|
-
if (range.start >= item.start && range.end <= item.end) {
|
|
1544
|
-
return;
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
// ========================================================
|
|
1549
|
-
// no sourcemap mappings in range
|
|
1550
|
-
// check original range in decodedMappings
|
|
1551
|
-
const { decodedMappings } = state;
|
|
1552
|
-
const item = decodedMappings.find((it) => it.originalOffset >= range.start && it.originalOffset <= range.end);
|
|
1553
|
-
if (!item) {
|
|
1554
|
-
return;
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
// ========================================================
|
|
1558
|
-
uncovered = false;
|
|
1559
|
-
|
|
1560
|
-
});
|
|
1561
|
-
|
|
1562
|
-
return uncovered;
|
|
1563
|
-
|
|
1564
|
-
};
|
|
1565
|
-
|
|
1566
1491
|
const mergeV8Data = (state, stateList) => {
|
|
1567
1492
|
// console.log(stateList);
|
|
1568
1493
|
|
|
@@ -1747,7 +1672,7 @@ const addUntestedFiles = async (stateList, options) => {
|
|
|
1747
1672
|
|
|
1748
1673
|
};
|
|
1749
1674
|
|
|
1750
|
-
const generateV8DataList = (stateList, options) => {
|
|
1675
|
+
const generateV8DataList = (stateList, options, needsIstanbul) => {
|
|
1751
1676
|
|
|
1752
1677
|
const stateMap = new Map();
|
|
1753
1678
|
|
|
@@ -1801,11 +1726,13 @@ const generateV8DataList = (stateList, options) => {
|
|
|
1801
1726
|
const coverageData = {};
|
|
1802
1727
|
stateMap.forEach((state) => {
|
|
1803
1728
|
const { v8Data } = state;
|
|
1804
|
-
const istanbulData = collectFileCoverage(v8Data, state, options);
|
|
1805
|
-
const { sourcePath, source } = v8Data;
|
|
1729
|
+
const istanbulData = collectFileCoverage(v8Data, state, options, needsIstanbul);
|
|
1806
1730
|
v8DataList.push(v8Data);
|
|
1807
|
-
|
|
1808
|
-
|
|
1731
|
+
if (needsIstanbul) {
|
|
1732
|
+
const { sourcePath, source } = v8Data;
|
|
1733
|
+
fileSources[sourcePath] = source;
|
|
1734
|
+
coverageData[sourcePath] = istanbulData;
|
|
1735
|
+
}
|
|
1809
1736
|
});
|
|
1810
1737
|
|
|
1811
1738
|
// sort v8DataList (files)
|
|
@@ -1823,7 +1750,8 @@ const generateV8DataList = (stateList, options) => {
|
|
|
1823
1750
|
};
|
|
1824
1751
|
};
|
|
1825
1752
|
|
|
1826
|
-
|
|
1753
|
+
// Direct users of the converter retain the full result by default.
|
|
1754
|
+
const convertV8List = async (v8list, options, needsIstanbul = true) => {
|
|
1827
1755
|
|
|
1828
1756
|
// for tested files
|
|
1829
1757
|
const stateList = convertCoverages(v8list, options);
|
|
@@ -1832,13 +1760,11 @@ const convertV8List = async (v8list, options) => {
|
|
|
1832
1760
|
await addUntestedFiles(stateList, options);
|
|
1833
1761
|
|
|
1834
1762
|
const time_start_convert = Date.now();
|
|
1835
|
-
const dataList = generateV8DataList(stateList, options);
|
|
1763
|
+
const dataList = generateV8DataList(stateList, options, needsIstanbul);
|
|
1836
1764
|
const dataFiles = EC.cyan(`${dataList.v8DataList.length} files`);
|
|
1837
1765
|
Util.logTime(`${EC.magenta('│ ')}${EC.cyan('├')} [convert] converted data list (${dataFiles})`, time_start_convert);
|
|
1838
1766
|
|
|
1839
1767
|
return dataList;
|
|
1840
1768
|
};
|
|
1841
1769
|
|
|
1842
|
-
|
|
1843
|
-
convertV8List
|
|
1844
|
-
};
|
|
1770
|
+
export { convertV8List };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const rangeKey = (range) => `${range.start}_${range.end}`;
|
|
2
|
+
|
|
3
|
+
const handleUncoveredInCovered = (state, originalStateMap) => {
|
|
4
|
+
if (!state.fake) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
originalStateMap.forEach((originalState) => {
|
|
9
|
+
const { bytes } = originalState;
|
|
10
|
+
// The old check treats every non-zero count as covered, not just > 0.
|
|
11
|
+
const covered = bytes.filter((range) => range.count !== 0);
|
|
12
|
+
if (!covered.length || covered.length === bytes.length) {
|
|
13
|
+
originalState.bytes = bytes.slice();
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Sort a separate array so byte order and original range objects stay
|
|
18
|
+
// unchanged. Prefix maxima also handle nested/overlapping coverage.
|
|
19
|
+
covered.sort((a, b) => a.start - b.start);
|
|
20
|
+
const starts = new Float64Array(covered.length);
|
|
21
|
+
const maxEnds = new Float64Array(covered.length);
|
|
22
|
+
let maxEnd = -Infinity;
|
|
23
|
+
for (let i = 0; i < covered.length; i++) {
|
|
24
|
+
starts[i] = covered[i].start;
|
|
25
|
+
maxEnd = Math.max(maxEnd, covered[i].end);
|
|
26
|
+
maxEnds[i] = maxEnd;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const removed = new Set();
|
|
30
|
+
originalState.bytes = bytes.filter((range) => {
|
|
31
|
+
if (range.count !== 0) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
let low = 0;
|
|
35
|
+
let high = starts.length;
|
|
36
|
+
while (low < high) {
|
|
37
|
+
const mid = Math.floor((low + high) / 2);
|
|
38
|
+
// Preserve the original inclusive overlap test: touching
|
|
39
|
+
// endpoints count as overlap even though ranges are half-open.
|
|
40
|
+
if (starts[mid] <= range.end) {
|
|
41
|
+
low = mid + 1;
|
|
42
|
+
} else {
|
|
43
|
+
high = mid;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (low > 0 && maxEnds[low - 1] >= range.start) {
|
|
47
|
+
removed.add(rangeKey(range));
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (!removed.size) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Remove exact start/end matches, not every overlapping AST range.
|
|
57
|
+
// Each metadata array is filtered once, regardless of removal count.
|
|
58
|
+
for (const key of ['statements', 'branches', 'functions']) {
|
|
59
|
+
originalState[key] = originalState[key].filter((range) => !removed.has(rangeKey(range)));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export { handleUncoveredInCovered };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { diffSequence } from '../packages/monocart-coverage-converter.js';
|
|
2
|
+
import { Util } from '../utils/util.js';
|
|
3
3
|
const EC = Util.EC;
|
|
4
4
|
|
|
5
5
|
const findMapping = (list, offset) => {
|
|
@@ -977,4 +977,4 @@ const findOriginalRange = (start, end, state, originalMap, options = {}) => {
|
|
|
977
977
|
|
|
978
978
|
};
|
|
979
979
|
|
|
980
|
-
|
|
980
|
+
export { findOriginalRange };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { decode } from '@jridgewell/sourcemap-codec';
|
|
2
2
|
|
|
3
3
|
const COLUMN = 0;
|
|
4
4
|
const SOURCES_INDEX = 1;
|
|
@@ -181,6 +181,4 @@ const flattenSourceMaps = function(indexedMap, mapUrl) {
|
|
|
181
181
|
return indexedMap;
|
|
182
182
|
};
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
flattenSourceMaps
|
|
186
|
-
};
|
|
184
|
+
export { flattenSourceMaps };
|
package/lib/converter/ignore.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { Util } from '../utils/util.js';
|
|
2
2
|
|
|
3
3
|
const getNextN = (content, currentLine, item, locator) => {
|
|
4
4
|
|
|
@@ -220,6 +220,4 @@ const getIgnoredRanges = (locator, options) => {
|
|
|
220
220
|
};
|
|
221
221
|
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
getIgnoredRanges
|
|
225
|
-
};
|
|
223
|
+
export { getIgnoredRanges };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { Util } from '../utils/util.js';
|
|
2
|
+
class InfoBranch {
|
|
3
3
|
constructor(data, original) {
|
|
4
4
|
const {
|
|
5
5
|
start, end, locations, type
|
|
@@ -90,4 +90,6 @@ module.exports = class InfoBranch {
|
|
|
90
90
|
};
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { InfoBranch };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { Util } from '../utils/util.js';
|
|
2
|
+
class InfoFunction {
|
|
3
3
|
constructor(data, original) {
|
|
4
4
|
|
|
5
5
|
const {
|
|
@@ -63,4 +63,6 @@ module.exports = class InfoFunction {
|
|
|
63
63
|
line: line
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
|
-
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { InfoFunction };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { Util } from '../utils/util.js';
|
|
2
|
+
class InfoStatement {
|
|
3
3
|
constructor(data, original) {
|
|
4
4
|
const {
|
|
5
5
|
start, end, count
|
|
@@ -40,4 +40,6 @@ module.exports = class InfoStatement {
|
|
|
40
40
|
|
|
41
41
|
return loc;
|
|
42
42
|
}
|
|
43
|
-
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { InfoStatement };
|