monocart-coverage-reports 2.10.3 → 2.10.5
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 +5 -0
- package/README.zh-Hans.md +9 -3
- package/lib/converter/converter.js +251 -132
- package/lib/converter/find-original-range.js +33 -10
- package/lib/converter/untested.js +298 -0
- package/lib/default/options.js +2 -1
- package/lib/generate.js +3 -238
- package/lib/index.d.ts +9 -2
- package/lib/istanbul/istanbul.js +27 -2
- package/lib/packages/monocart-coverage-vendor.js +16 -15
- package/lib/reports/custom.js +34 -34
- package/lib/reports/v8-json.js +22 -22
- package/lib/reports/v8.js +51 -51
- package/lib/utils/util.js +19 -0
- package/lib/v8/v8.js +16 -35
- package/package.json +11 -13
package/README.md
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
- [VSCode](#vscode)
|
|
46
46
|
- [Jest](#jest)
|
|
47
47
|
- [Vitest](#vitest)
|
|
48
|
+
- [Node Test Runner](#node-test-runner)
|
|
48
49
|
- [Puppeteer](#puppeteer)
|
|
49
50
|
- [Cypress](#cypress)
|
|
50
51
|
- [WebdriverIO](#webdriverio)
|
|
@@ -294,6 +295,7 @@ const [jsCoverage, cssCoverage] = await Promise.all([
|
|
|
294
295
|
const coverageData = [... jsCoverage, ... cssCoverage];
|
|
295
296
|
|
|
296
297
|
```
|
|
298
|
+
Collect coverage with `@playwright/test` [`Automatic fixtures`](https://playwright.dev/docs/test-fixtures#automatic-fixtures), see example: [fixtures.ts](https://github.com/cenfun/playwright-coverage/blob/main/fixtures.ts)
|
|
297
299
|
For more examples, see [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
|
|
298
300
|
|
|
299
301
|
|
|
@@ -987,6 +989,9 @@ c8 --experimental-monocart --reporter=v8 --reporter=console-details node foo.js
|
|
|
987
989
|
- [vitest-monocart-coverage](https://github.com/cenfun/vitest-monocart-coverage) - Vitest custom provider module for coverage reports
|
|
988
990
|
- [merge-code-coverage-vitest](https://github.com/cenfun/merge-code-coverage-vitest) - Example for merging code coverage (Vitest unit + Playwright e2e sharding)
|
|
989
991
|
|
|
992
|
+
### [Node Test Runner](https://nodejs.org/docs/latest/api/test.html)
|
|
993
|
+
- [node-monocart-coverage](https://github.com/cenfun/node-monocart-coverage) - Custom reporter for Node test runner for coverage
|
|
994
|
+
|
|
990
995
|
### [Puppeteer](https://github.com/puppeteer/puppeteer/)
|
|
991
996
|
- [jest-puppeteer-coverage](https://github.com/cenfun/jest-puppeteer-coverage) - Example for Jest puppeteer coverage
|
|
992
997
|
- [maplibre-gl-js](https://github.com/maplibre/maplibre-gl-js) - Example for Jest (unit) + Puppeteer (e2e) + Codecov
|
package/README.zh-Hans.md
CHANGED
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
- [VSCode](#vscode)
|
|
46
46
|
- [Jest](#jest)
|
|
47
47
|
- [Vitest](#vitest)
|
|
48
|
+
- [Node Test Runner](#node-test-runner)
|
|
48
49
|
- [Puppeteer](#puppeteer)
|
|
49
50
|
- [Cypress](#cypress)
|
|
50
51
|
- [WebdriverIO](#webdriverio)
|
|
@@ -117,10 +118,11 @@ mcr node my-app.js -r v8,console-details
|
|
|
117
118
|

|
|
118
119
|
|
|
119
120
|
- `v8-json`
|
|
120
|
-
- 保存 `CoverageResults` 到一个json文件
|
|
121
121
|
- 保存 `CoverageResults` 到一个json文件 (默认是 [`coverage-report.json`](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json))
|
|
122
122
|
- 用于VSCode扩展来显示原生V8代码覆盖率: [Monocart Coverage for VSCode](https://github.com/cenfun/monocart-coverage-vscode)
|
|
123
123
|
|
|
124
|
+

|
|
125
|
+
|
|
124
126
|
> 内置Istanbul报告 (V8和Istanbul格式数据都支持):
|
|
125
127
|
|
|
126
128
|
- `clover`
|
|
@@ -295,6 +297,7 @@ const [jsCoverage, cssCoverage] = await Promise.all([
|
|
|
295
297
|
const coverageData = [... jsCoverage, ... cssCoverage];
|
|
296
298
|
|
|
297
299
|
```
|
|
300
|
+
使用 `@playwright/test` 的 [`Automatic fixtures`](https://playwright.dev/docs/test-fixtures#automatic-fixtures)收集覆盖率数据, 见例子: [fixtures.ts](https://github.com/cenfun/playwright-coverage/blob/main/fixtures.ts)
|
|
298
301
|
参见例子 [./test/test-v8.js](./test/test-v8.js), and [anonymous](./test/test-anonymous.js), [css](./test/test-css.js)
|
|
299
302
|
|
|
300
303
|
|
|
@@ -990,6 +993,9 @@ c8 --experimental-monocart --reporter=v8 --reporter=console-details node foo.js
|
|
|
990
993
|
- [vitest-monocart-coverage](https://github.com/cenfun/vitest-monocart-coverage) - Vitest custom provider module for coverage reports
|
|
991
994
|
- [merge-code-coverage-vitest](https://github.com/cenfun/merge-code-coverage-vitest) - Example for merging code coverage (Vitest unit + Playwright e2e sharding)
|
|
992
995
|
|
|
996
|
+
### [Node Test Runner](https://nodejs.org/docs/latest/api/test.html)
|
|
997
|
+
- [node-monocart-coverage](https://github.com/cenfun/node-monocart-coverage) - Custom reporter for Node test runner for coverage
|
|
998
|
+
|
|
993
999
|
### [Puppeteer](https://github.com/puppeteer/puppeteer/)
|
|
994
1000
|
- [jest-puppeteer-coverage](https://github.com/cenfun/jest-puppeteer-coverage) - Example for Jest puppeteer coverage
|
|
995
1001
|
- [maplibre-gl-js](https://github.com/maplibre/maplibre-gl-js) - Example for Jest (unit) + Puppeteer (e2e) + Codecov
|
|
@@ -1044,7 +1050,7 @@ const coverageOptions = {
|
|
|
1044
1050
|
]
|
|
1045
1051
|
};
|
|
1046
1052
|
```
|
|
1047
|
-
- Github actions
|
|
1053
|
+
- Github actions:
|
|
1048
1054
|
```yml
|
|
1049
1055
|
- name: Codecov
|
|
1050
1056
|
uses: codecov/codecov-action@v4
|
|
@@ -1080,7 +1086,7 @@ const coverageOptions = {
|
|
|
1080
1086
|
lcov: true
|
|
1081
1087
|
};
|
|
1082
1088
|
```
|
|
1083
|
-
- Github actions
|
|
1089
|
+
- Github actions:
|
|
1084
1090
|
```yml
|
|
1085
1091
|
- name: Coveralls
|
|
1086
1092
|
uses: coverallsapp/github-action@v2
|
|
@@ -13,6 +13,8 @@ const findOriginalRange = require('./find-original-range.js');
|
|
|
13
13
|
const { getJsAstInfo, getCssAstInfo } = require('./ast.js');
|
|
14
14
|
const { getIgnoredRanges } = require('./ignore.js');
|
|
15
15
|
|
|
16
|
+
const { getUntestedList } = require('./untested.js');
|
|
17
|
+
|
|
16
18
|
const {
|
|
17
19
|
sortRanges, dedupeCountRanges, mergeRangesWith
|
|
18
20
|
} = require('../utils/dedupe.js');
|
|
@@ -868,8 +870,8 @@ const decodeSourceMappings = (state, originalDecodedMap) => {
|
|
|
868
870
|
|
|
869
871
|
const allDecodedMappings = [];
|
|
870
872
|
decodedList.forEach((segments, generatedLine) => {
|
|
871
|
-
|
|
872
|
-
segments.forEach((segment) => {
|
|
873
|
+
const lastIndex = segments.length - 1;
|
|
874
|
+
segments.forEach((segment, i) => {
|
|
873
875
|
|
|
874
876
|
// const COLUMN = 0;
|
|
875
877
|
// const SOURCES_INDEX = 1;
|
|
@@ -889,7 +891,7 @@ const decodeSourceMappings = (state, originalDecodedMap) => {
|
|
|
889
891
|
column: generatedColumn
|
|
890
892
|
});
|
|
891
893
|
|
|
892
|
-
info = {
|
|
894
|
+
const info = {
|
|
893
895
|
generatedOffset,
|
|
894
896
|
generatedLine,
|
|
895
897
|
generatedColumn,
|
|
@@ -900,12 +902,21 @@ const decodeSourceMappings = (state, originalDecodedMap) => {
|
|
|
900
902
|
nameIndex
|
|
901
903
|
};
|
|
902
904
|
|
|
905
|
+
// first and last column
|
|
906
|
+
if (i === 0) {
|
|
907
|
+
info.first = true;
|
|
908
|
+
}
|
|
909
|
+
if (i === lastIndex) {
|
|
910
|
+
info.last = true;
|
|
911
|
+
}
|
|
912
|
+
|
|
903
913
|
allDecodedMappings.push(info);
|
|
904
914
|
|
|
905
915
|
originalDecodedMap.get(sourceIndex).push(info);
|
|
906
916
|
|
|
907
917
|
});
|
|
908
918
|
|
|
919
|
+
|
|
909
920
|
});
|
|
910
921
|
|
|
911
922
|
// defaults to sort by generated offset, not need sort
|
|
@@ -1324,66 +1335,215 @@ const initJsCoverageList = (item) => {
|
|
|
1324
1335
|
return coverageList;
|
|
1325
1336
|
};
|
|
1326
1337
|
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
if (!uncoveredBytes.length) {
|
|
1331
|
-
return true;
|
|
1338
|
+
const logConvertTime = (msg, time_start, untested) => {
|
|
1339
|
+
if (untested) {
|
|
1340
|
+
return;
|
|
1332
1341
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1342
|
+
Util.logTime(msg, time_start);
|
|
1343
|
+
};
|
|
1344
|
+
|
|
1345
|
+
const convertCoverages = (list, options, untested) => {
|
|
1346
|
+
const stateList = [];
|
|
1347
|
+
|
|
1348
|
+
for (const item of list) {
|
|
1349
|
+
// console.log([item.id]);
|
|
1350
|
+
|
|
1351
|
+
const time_start_ast = Date.now();
|
|
1352
|
+
|
|
1353
|
+
const {
|
|
1354
|
+
type, source, fake, sourcePath
|
|
1355
|
+
} = item;
|
|
1356
|
+
|
|
1357
|
+
// for source file, type could be ts or vue as extname, but js = true
|
|
1358
|
+
const js = type === 'js';
|
|
1359
|
+
item.js = js;
|
|
1360
|
+
|
|
1361
|
+
// source mapping
|
|
1362
|
+
const locator = new Locator(source);
|
|
1363
|
+
const maxContentLength = source.length;
|
|
1364
|
+
|
|
1365
|
+
// ============================
|
|
1366
|
+
// move sourceMap
|
|
1367
|
+
const sourceMap = item.sourceMap;
|
|
1368
|
+
if (sourceMap) {
|
|
1369
|
+
delete item.sourceMap;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
// ============================
|
|
1373
|
+
// move functions and ranges to coverageList
|
|
1374
|
+
let coverageList = [];
|
|
1375
|
+
let astInfo;
|
|
1376
|
+
if (js) {
|
|
1377
|
+
coverageList = initJsCoverageList(item);
|
|
1378
|
+
// remove original functions
|
|
1379
|
+
if (!Util.isDebug()) {
|
|
1380
|
+
delete item.functions;
|
|
1381
|
+
}
|
|
1382
|
+
astInfo = getJsAstInfo(item, coverageList);
|
|
1383
|
+
} else {
|
|
1384
|
+
// convent css covered ranges to rules ranges and include uncovered ranges
|
|
1385
|
+
astInfo = getCssAstInfo(item, coverageList);
|
|
1386
|
+
// remove original ranges
|
|
1387
|
+
if (!Util.isDebug()) {
|
|
1388
|
+
delete item.ranges;
|
|
1389
|
+
}
|
|
1336
1390
|
}
|
|
1391
|
+
|
|
1392
|
+
logConvertTime(` ┌ [convert] parsed ast: ${sourcePath} (${EC.cyan(Util.BSF(maxContentLength))})`, time_start_ast, untested);
|
|
1393
|
+
|
|
1394
|
+
// console.log(sourcePath, astInfo.statements.length);
|
|
1395
|
+
// ============================
|
|
1396
|
+
|
|
1397
|
+
const time_start_unpack = Date.now();
|
|
1398
|
+
|
|
1399
|
+
// current file and it's sources from sourceMap
|
|
1400
|
+
// see const originalState
|
|
1401
|
+
const state = {
|
|
1402
|
+
js,
|
|
1403
|
+
type,
|
|
1404
|
+
source,
|
|
1405
|
+
fake,
|
|
1406
|
+
sourcePath,
|
|
1407
|
+
sourceMap,
|
|
1408
|
+
locator,
|
|
1409
|
+
maxContentLength,
|
|
1410
|
+
decodedMappings: [],
|
|
1411
|
+
rangeCache: new Map(),
|
|
1412
|
+
diffCache: new Map(),
|
|
1413
|
+
|
|
1414
|
+
// alignTextList: [],
|
|
1415
|
+
|
|
1416
|
+
// coverage info
|
|
1417
|
+
bytes: [],
|
|
1418
|
+
functions: [],
|
|
1419
|
+
branches: [],
|
|
1420
|
+
statements: [],
|
|
1421
|
+
astInfo,
|
|
1422
|
+
// for sub source files
|
|
1423
|
+
coverageList,
|
|
1424
|
+
originalList: [],
|
|
1425
|
+
// coverage data
|
|
1426
|
+
v8Data: item
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
unpackDistFile(item, state, options);
|
|
1430
|
+
const unpackedFiles = EC.cyan(`${state.originalList.length} files`);
|
|
1431
|
+
|
|
1432
|
+
stateList.push(state);
|
|
1433
|
+
|
|
1434
|
+
logConvertTime(` ┌ [convert] unpacked sourcemap: ${sourcePath} (${unpackedFiles})`, time_start_unpack, untested);
|
|
1435
|
+
|
|
1337
1436
|
}
|
|
1338
|
-
|
|
1437
|
+
|
|
1438
|
+
return stateList;
|
|
1439
|
+
};
|
|
1440
|
+
|
|
1441
|
+
// ========================================================================================================
|
|
1442
|
+
|
|
1443
|
+
const isUncoveredRange = (range, key, uncoveredGroups) => {
|
|
1444
|
+
|
|
1445
|
+
let uncovered = true;
|
|
1446
|
+
uncoveredGroups.forEach((group) => {
|
|
1447
|
+
const { groupMap, state } = group;
|
|
1448
|
+
|
|
1449
|
+
// ========================================================
|
|
1450
|
+
// self key
|
|
1451
|
+
if (groupMap.has(key)) {
|
|
1452
|
+
return;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// ========================================================
|
|
1456
|
+
// in all group
|
|
1457
|
+
for (const item of groupMap.values()) {
|
|
1458
|
+
if (range.start >= item.start && range.end <= item.end) {
|
|
1459
|
+
return;
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
// ========================================================
|
|
1464
|
+
// no sourcemap mappings in range
|
|
1465
|
+
// check original range in decodedMappings
|
|
1466
|
+
const { decodedMappings } = state;
|
|
1467
|
+
const item = decodedMappings.find((it) => it.originalOffset >= range.start && it.originalOffset <= range.end);
|
|
1468
|
+
if (!item) {
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
// ========================================================
|
|
1473
|
+
uncovered = false;
|
|
1474
|
+
|
|
1475
|
+
});
|
|
1476
|
+
|
|
1477
|
+
return uncovered;
|
|
1478
|
+
|
|
1339
1479
|
};
|
|
1340
1480
|
|
|
1341
1481
|
const mergeV8Data = (state, stateList) => {
|
|
1342
1482
|
// console.log(stateList);
|
|
1343
1483
|
|
|
1344
|
-
//
|
|
1345
|
-
//
|
|
1346
|
-
//
|
|
1347
|
-
//
|
|
1348
|
-
//
|
|
1349
|
-
// console.log(stateList.map((it) => it.
|
|
1350
|
-
// console.log(stateList.map((it) => it.
|
|
1484
|
+
// let debug = false;
|
|
1485
|
+
// if (state.sourcePath.endsWith('counter.tsx')) {
|
|
1486
|
+
// debug = true;
|
|
1487
|
+
// console.log('merge v8 data ===================================', state.sourcePath);
|
|
1488
|
+
// console.log('bytes before ============', stateList.map((it) => it.bytes));
|
|
1489
|
+
// // console.log('statements ==============', stateList.map((it) => it.statements));
|
|
1490
|
+
// // console.log('functions ==============', stateList.map((it) => it.functions));
|
|
1491
|
+
// // console.log('branches ======================', stateList.map((it) => it.branches.map((b) => [`${b.start}-${b.end}`, JSON.stringify(b.locations.map((l) => l.count))])));
|
|
1351
1492
|
// }
|
|
1352
1493
|
|
|
1353
1494
|
// ===========================================================
|
|
1354
1495
|
// bytes
|
|
1355
1496
|
const mergedBytes = [];
|
|
1356
|
-
|
|
1497
|
+
|
|
1498
|
+
const coveredMap = new Map();
|
|
1499
|
+
const uncoveredMap = new Map();
|
|
1500
|
+
const uncoveredGroups = [];
|
|
1357
1501
|
stateList.forEach((st) => {
|
|
1502
|
+
const groupMap = new Map();
|
|
1358
1503
|
const bytes = dedupeCountRanges(st.bytes);
|
|
1359
|
-
const uncoveredBytes = [];
|
|
1360
1504
|
bytes.forEach((range) => {
|
|
1505
|
+
const key = `${range.start}_${range.end}`;
|
|
1361
1506
|
if (range.count) {
|
|
1362
1507
|
mergedBytes.push(range);
|
|
1508
|
+
coveredMap.set(key, true);
|
|
1363
1509
|
} else {
|
|
1364
|
-
|
|
1510
|
+
uncoveredMap.set(key, range);
|
|
1511
|
+
groupMap.set(key, range);
|
|
1365
1512
|
}
|
|
1366
1513
|
});
|
|
1367
|
-
|
|
1514
|
+
|
|
1515
|
+
uncoveredGroups.push({
|
|
1516
|
+
groupMap,
|
|
1517
|
+
state: st
|
|
1518
|
+
});
|
|
1368
1519
|
});
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1520
|
+
|
|
1521
|
+
// if (debug) {
|
|
1522
|
+
// console.log('coveredMap ============', coveredMap);
|
|
1523
|
+
// console.log('uncoveredMap ============', uncoveredMap);
|
|
1524
|
+
// console.log('uncoveredGroups ============', uncoveredGroups);
|
|
1525
|
+
// }
|
|
1526
|
+
|
|
1527
|
+
uncoveredMap.forEach((range, key) => {
|
|
1528
|
+
|
|
1529
|
+
// in covered range
|
|
1530
|
+
if (coveredMap.has(key)) {
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
if (isUncoveredRange(range, key, uncoveredGroups)) {
|
|
1380
1535
|
mergedBytes.push(range);
|
|
1381
|
-
}
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1382
1538
|
});
|
|
1383
1539
|
|
|
1384
1540
|
// will be dedupeCountRanges in collectFileCoverage
|
|
1385
1541
|
state.bytes = mergedBytes;
|
|
1386
1542
|
|
|
1543
|
+
// if (debug) {
|
|
1544
|
+
// console.log('bytes after ============', mergedBytes);
|
|
1545
|
+
// }
|
|
1546
|
+
|
|
1387
1547
|
// ===========================================================
|
|
1388
1548
|
// functions
|
|
1389
1549
|
const allFunctions = stateList.map((it) => it.functions).flat();
|
|
@@ -1423,6 +1583,20 @@ const mergeV8Data = (state, stateList) => {
|
|
|
1423
1583
|
const mergedFunctions = mergeRangesWith(allFunctions, functionComparer, functionHandler);
|
|
1424
1584
|
state.functions = mergedFunctions;
|
|
1425
1585
|
|
|
1586
|
+
// ===========================================================
|
|
1587
|
+
// statements
|
|
1588
|
+
const allStatements = stateList.map((it) => it.statements).flat();
|
|
1589
|
+
const statementComparer = (lastRange, range) => {
|
|
1590
|
+
// exact matched because the statement range is generated from ast
|
|
1591
|
+
return lastRange.start === range.start && lastRange.end === range.end;
|
|
1592
|
+
};
|
|
1593
|
+
const statementHandler = (lastRange, range) => {
|
|
1594
|
+
// merge statements count
|
|
1595
|
+
lastRange.count += range.count;
|
|
1596
|
+
};
|
|
1597
|
+
const mergedStatements = mergeRangesWith(allStatements, statementComparer, statementHandler);
|
|
1598
|
+
state.statements = mergedStatements;
|
|
1599
|
+
|
|
1426
1600
|
// ===========================================================
|
|
1427
1601
|
// branches
|
|
1428
1602
|
const allBranches = stateList.map((it) => it.branches).flat();
|
|
@@ -1449,6 +1623,43 @@ const mergeV8Data = (state, stateList) => {
|
|
|
1449
1623
|
// }
|
|
1450
1624
|
|
|
1451
1625
|
|
|
1626
|
+
};
|
|
1627
|
+
|
|
1628
|
+
const addUntestedFiles = async (stateList, options) => {
|
|
1629
|
+
|
|
1630
|
+
const time_start_untested = Date.now();
|
|
1631
|
+
|
|
1632
|
+
const testedMap = new Map();
|
|
1633
|
+
stateList.forEach((state) => {
|
|
1634
|
+
const { v8Data, originalList } = state;
|
|
1635
|
+
// dedupe dist file if not debug
|
|
1636
|
+
if (!v8Data.dedupe) {
|
|
1637
|
+
testedMap.set(state.sourcePath, true);
|
|
1638
|
+
}
|
|
1639
|
+
originalList.forEach((originalState) => {
|
|
1640
|
+
testedMap.set(originalState.sourcePath, true);
|
|
1641
|
+
});
|
|
1642
|
+
});
|
|
1643
|
+
|
|
1644
|
+
// console.log('testedMap', testedMap);
|
|
1645
|
+
|
|
1646
|
+
const untestedList = await getUntestedList(testedMap, options, 'v8');
|
|
1647
|
+
if (!untestedList) {
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
const untestedStateList = convertCoverages(untestedList, options, true);
|
|
1652
|
+
|
|
1653
|
+
// console.log(untestedStateList);
|
|
1654
|
+
untestedStateList.forEach((state) => {
|
|
1655
|
+
stateList.push(state);
|
|
1656
|
+
});
|
|
1657
|
+
|
|
1658
|
+
// console.log('untestedList', untestedList);
|
|
1659
|
+
|
|
1660
|
+
Util.logTime(` ┌ [convert] added untested files: ${EC.yellow(untestedList.length)}`, time_start_untested);
|
|
1661
|
+
|
|
1662
|
+
|
|
1452
1663
|
};
|
|
1453
1664
|
|
|
1454
1665
|
const generateV8DataList = (stateList, options) => {
|
|
@@ -1527,109 +1738,17 @@ const generateV8DataList = (stateList, options) => {
|
|
|
1527
1738
|
};
|
|
1528
1739
|
};
|
|
1529
1740
|
|
|
1530
|
-
const convertV8List = (v8list, options) => {
|
|
1531
|
-
|
|
1532
|
-
const stateList = [];
|
|
1533
|
-
|
|
1534
|
-
for (const item of v8list) {
|
|
1535
|
-
// console.log([item.id]);
|
|
1536
|
-
|
|
1537
|
-
const time_start_ast = Date.now();
|
|
1538
|
-
|
|
1539
|
-
const {
|
|
1540
|
-
type, source, fake, sourcePath
|
|
1541
|
-
} = item;
|
|
1542
|
-
|
|
1543
|
-
// for source file, type could be ts or vue as extname, but js = true
|
|
1544
|
-
const js = type === 'js';
|
|
1545
|
-
item.js = js;
|
|
1546
|
-
|
|
1547
|
-
// source mapping
|
|
1548
|
-
const locator = new Locator(source);
|
|
1549
|
-
const maxContentLength = source.length;
|
|
1550
|
-
|
|
1551
|
-
// ============================
|
|
1552
|
-
// move sourceMap
|
|
1553
|
-
const sourceMap = item.sourceMap;
|
|
1554
|
-
if (sourceMap) {
|
|
1555
|
-
delete item.sourceMap;
|
|
1556
|
-
}
|
|
1557
|
-
|
|
1558
|
-
// ============================
|
|
1559
|
-
// move functions and ranges to coverageList
|
|
1560
|
-
let coverageList = [];
|
|
1561
|
-
let astInfo;
|
|
1562
|
-
if (js) {
|
|
1563
|
-
coverageList = initJsCoverageList(item);
|
|
1564
|
-
// remove original functions
|
|
1565
|
-
if (!Util.isDebug()) {
|
|
1566
|
-
delete item.functions;
|
|
1567
|
-
}
|
|
1568
|
-
astInfo = getJsAstInfo(item, coverageList);
|
|
1569
|
-
} else {
|
|
1570
|
-
// convent css covered ranges to rules ranges and include uncovered ranges
|
|
1571
|
-
astInfo = getCssAstInfo(item, coverageList);
|
|
1572
|
-
// remove original ranges
|
|
1573
|
-
if (!Util.isDebug()) {
|
|
1574
|
-
delete item.ranges;
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1741
|
+
const convertV8List = async (v8list, options) => {
|
|
1577
1742
|
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
// console.log(sourcePath, astInfo.statements.length);
|
|
1581
|
-
// ============================
|
|
1743
|
+
// for tested files
|
|
1744
|
+
const stateList = convertCoverages(v8list, options);
|
|
1582
1745
|
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
// current file and it's sources from sourceMap
|
|
1586
|
-
// see const originalState
|
|
1587
|
-
const state = {
|
|
1588
|
-
js,
|
|
1589
|
-
type,
|
|
1590
|
-
source,
|
|
1591
|
-
fake,
|
|
1592
|
-
sourcePath,
|
|
1593
|
-
sourceMap,
|
|
1594
|
-
locator,
|
|
1595
|
-
maxContentLength,
|
|
1596
|
-
decodedMappings: [],
|
|
1597
|
-
rangeCache: new Map(),
|
|
1598
|
-
diffCache: new Map(),
|
|
1599
|
-
|
|
1600
|
-
// alignTextList: [],
|
|
1601
|
-
|
|
1602
|
-
// coverage info
|
|
1603
|
-
bytes: [],
|
|
1604
|
-
functions: [],
|
|
1605
|
-
branches: [],
|
|
1606
|
-
statements: [],
|
|
1607
|
-
astInfo,
|
|
1608
|
-
// for sub source files
|
|
1609
|
-
coverageList,
|
|
1610
|
-
originalList: [],
|
|
1611
|
-
// coverage data
|
|
1612
|
-
v8Data: item
|
|
1613
|
-
};
|
|
1614
|
-
|
|
1615
|
-
unpackDistFile(item, state, options);
|
|
1616
|
-
const unpackedFiles = EC.cyan(`${state.originalList.length} files`);
|
|
1617
|
-
|
|
1618
|
-
stateList.push(state);
|
|
1619
|
-
|
|
1620
|
-
Util.logTime(` ┌ [convert] unpacked sourcemap: ${sourcePath} (${unpackedFiles})`, time_start_unpack);
|
|
1621
|
-
|
|
1622
|
-
}
|
|
1746
|
+
// empty coverage handler
|
|
1747
|
+
await addUntestedFiles(stateList, options);
|
|
1623
1748
|
|
|
1624
1749
|
const time_start_convert = Date.now();
|
|
1625
|
-
|
|
1626
1750
|
const dataList = generateV8DataList(stateList, options);
|
|
1627
1751
|
const dataFiles = EC.cyan(`${dataList.v8DataList.length} files`);
|
|
1628
|
-
|
|
1629
|
-
// stateList.forEach((st, i) => {
|
|
1630
|
-
// Util.writeFileSync(`align-text-${i}.js`, `window.gridData = ${JSON.stringify(st.alignTextList, null, 4)}`);
|
|
1631
|
-
// });
|
|
1632
|
-
|
|
1633
1752
|
Util.logTime(` ┌ [convert] converted data list (${dataFiles})`, time_start_convert);
|
|
1634
1753
|
|
|
1635
1754
|
return dataList;
|
|
@@ -407,16 +407,16 @@ const getFixedPosition = (info, direction) => {
|
|
|
407
407
|
|
|
408
408
|
// ========================================================================================================
|
|
409
409
|
|
|
410
|
-
const getOriginalEndOffset = (m,
|
|
410
|
+
const getOriginalEndOffset = (m, originalState) => {
|
|
411
411
|
if (!m.originalEndOffset) {
|
|
412
|
-
const line =
|
|
412
|
+
const line = originalState.locator.getLine(m.originalLine + 1);
|
|
413
413
|
m.originalEndOffset = line ? line.end : m.originalOffset;
|
|
414
414
|
}
|
|
415
415
|
return m.originalEndOffset;
|
|
416
416
|
};
|
|
417
417
|
|
|
418
|
-
const getOriginalText = (m1, m2,
|
|
419
|
-
const originalLocator =
|
|
418
|
+
const getOriginalText = (m1, m2, originalState, startNextLine) => {
|
|
419
|
+
const originalLocator = originalState.locator;
|
|
420
420
|
|
|
421
421
|
const o1 = m1.originalOffset;
|
|
422
422
|
const o2 = m2.originalOffset;
|
|
@@ -442,10 +442,22 @@ const getOriginalText = (m1, m2, cache) => {
|
|
|
442
442
|
};
|
|
443
443
|
}
|
|
444
444
|
|
|
445
|
+
// start from next line
|
|
446
|
+
if (startNextLine) {
|
|
447
|
+
const nextLine = originalState.locator.getLine(m1.originalLine + 2);
|
|
448
|
+
if (nextLine) {
|
|
449
|
+
// console.log(nextLine);
|
|
450
|
+
return {
|
|
451
|
+
originalOffset: nextLine.start + nextLine.indent,
|
|
452
|
+
originalText: nextLine.text.slice(nextLine.indent)
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
445
457
|
// could be multiple lines for original text
|
|
446
458
|
return {
|
|
447
459
|
originalOffset: o1,
|
|
448
|
-
originalText: originalLocator.getSlice(o1, getOriginalEndOffset(m1,
|
|
460
|
+
originalText: originalLocator.getSlice(o1, getOriginalEndOffset(m1, originalState))
|
|
449
461
|
};
|
|
450
462
|
}
|
|
451
463
|
|
|
@@ -454,7 +466,7 @@ const getOriginalText = (m1, m2, cache) => {
|
|
|
454
466
|
if (o1 === o2) {
|
|
455
467
|
return {
|
|
456
468
|
originalOffset: o1,
|
|
457
|
-
originalText: originalLocator.getSlice(o1, getOriginalEndOffset(m1,
|
|
469
|
+
originalText: originalLocator.getSlice(o1, getOriginalEndOffset(m1, originalState))
|
|
458
470
|
};
|
|
459
471
|
}
|
|
460
472
|
|
|
@@ -477,7 +489,7 @@ const getOriginalText = (m1, m2, cache) => {
|
|
|
477
489
|
// should be wrong, ignore m2
|
|
478
490
|
return {
|
|
479
491
|
originalOffset: o1,
|
|
480
|
-
originalText: originalLocator.getSlice(o1, getOriginalEndOffset(m1,
|
|
492
|
+
originalText: originalLocator.getSlice(o1, getOriginalEndOffset(m1, originalState))
|
|
481
493
|
};
|
|
482
494
|
|
|
483
495
|
};
|
|
@@ -553,8 +565,19 @@ const getFixedOriginalStart = (start, mappings, state, cache, options) => {
|
|
|
553
565
|
};
|
|
554
566
|
}
|
|
555
567
|
|
|
568
|
+
// skip last mapping
|
|
569
|
+
let startNextLine = false;
|
|
570
|
+
if (m1.last) {
|
|
571
|
+
const locStart = state.locator.offsetToLocation(start);
|
|
572
|
+
// 1-base
|
|
573
|
+
const lineIndex = locStart.line - 1;
|
|
574
|
+
if (lineIndex > m1.generatedLine) {
|
|
575
|
+
startNextLine = true;
|
|
576
|
+
// console.log(originalState.sourcePath, start, m1, m2);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
556
579
|
|
|
557
|
-
const { originalText, originalOffset } = getOriginalText(m1, m2,
|
|
580
|
+
const { originalText, originalOffset } = getOriginalText(m1, m2, originalState, startNextLine);
|
|
558
581
|
const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, start);
|
|
559
582
|
const direction = 'start';
|
|
560
583
|
|
|
@@ -592,7 +615,7 @@ const getFixedOriginalEnd = (end, mappings, state, cache) => {
|
|
|
592
615
|
|
|
593
616
|
// cross file until e1 line end (not file end)
|
|
594
617
|
if (crossEnd) {
|
|
595
|
-
const originalEndOffset = getOriginalEndOffset(m1,
|
|
618
|
+
const originalEndOffset = getOriginalEndOffset(m1, originalState);
|
|
596
619
|
return {
|
|
597
620
|
originalEnd: originalEndOffset
|
|
598
621
|
};
|
|
@@ -608,7 +631,7 @@ const getFixedOriginalEnd = (end, mappings, state, cache) => {
|
|
|
608
631
|
}
|
|
609
632
|
|
|
610
633
|
|
|
611
|
-
const { originalText, originalOffset } = getOriginalText(m1, m2,
|
|
634
|
+
const { originalText, originalOffset } = getOriginalText(m1, m2, originalState);
|
|
612
635
|
const { generatedText, generatedPos } = getGeneratedText(m1, m2, state, end);
|
|
613
636
|
const direction = 'end';
|
|
614
637
|
|