Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

monocart-coverage-reports

Package Overview
Dependencies
Maintainers
1
Versions
91
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

monocart-coverage-reports - npm Package Compare versions

Comparing version 2.0.8 to 2.0.9

36

lib/converter/branches.js

@@ -33,7 +33,7 @@ const Util = require('../utils/util.js');

type,
loc: {
start: branchStart,
// could be updated if multiple locations
end: branchStart
},
start: branchStart,
// could be updated if multiple locations
end: branchStart,
locations: [],

@@ -50,3 +50,3 @@ reverseParents,

const branchStart = group.loc.start;
const branchStart = group.start;

@@ -71,3 +71,3 @@ // the block is not exact correct, if there is a block wrapped

// update group end
group.loc.end = end;
group.end = end;

@@ -230,3 +230,3 @@ locationMap.set(start, branchInfo);

if (prevLocation) {
const { loc, locations } = group;
const { locations } = group;
locations.sort((a, b) => {

@@ -236,3 +236,3 @@ return a.start - b.start;

// update group end after sorted
loc.end = locations[locations.length - 1].end;
group.end = locations[locations.length - 1].end;
}

@@ -280,3 +280,3 @@ },

}
// console.log(parentCount, 'uncovered list', noBlockList.length, group.loc.start);
// console.log(parentCount, 'uncovered list', noBlockList.length, group.start);
let count = parentCount - blockCount;

@@ -300,3 +300,3 @@ noBlockList.forEach((item) => {

// const start = group.loc.start;
// const start = group.start;
// if (start > 7874 && start < 7922) {

@@ -391,5 +391,15 @@ // console.log(group.type, parentCount, 'locations', group.locations);

branchMap.forEach((group) => {
// add start/end for none with group start/end
group.locations.forEach((item) => {
if (item.none) {
item.start = group.start;
item.end = group.end;
}
});
branches.push({
type: group.type,
loc: group.loc,
start: group.start,
end: group.end,
locations: group.locations

@@ -401,3 +411,3 @@ });

branches.sort((a, b) => {
return a.loc.start - b.loc.start;
return a.start - b.start;
});

@@ -404,0 +414,0 @@

@@ -8,5 +8,13 @@ // https://github.com/demurgos/v8-coverage

* It detects skipped or repeated statements. The root range counts the number of function calls.
*
* @functionName can be an empty string. This is common for the FunctionCov representing the whole module.
*/
// https://github.com/bcoe/v8-coverage
/**
* @ranges is always non-empty. The first range is called the "root range".
* @isBlockCoverage indicates if the function has block coverage information.
If this is false, it usually means that the functions was never called.
It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
* @functionName can be an empty string. This is common for the FunctionCov representing the whole module.
*/
// if you have a line of code that says `var x= 10; console.log(x);` that's one line and 2 statements.

@@ -105,3 +113,2 @@

// console.log('===========================================', state.sourcePath);
// console.log(coverageInfo.lines);
// }

@@ -214,17 +221,2 @@

// ========================================================================================================
const createEmptyCoverageInfo = () => {
return {
// v8 UI
data: {
bytes: [],
functions: [],
branches: []
},
// istanbul
functions: [],
branches: []
};
};
// istanbul coverage format

@@ -243,21 +235,43 @@ /**

const { sourcePath } = item;
const { coverageInfo, locator } = state;
const {
data,
bytes,
functions,
branches
} = coverageInfo;
branches,
locator
} = state;
// ==========================================
// v8
data.bytes = dedupeCountRanges(data.bytes);
// v8 data
const data = {
bytes: dedupeCountRanges(bytes),
functions: [],
branches: []
};
// ==========================================
// ignore
const ignoredRanges = getIgnoredRanges(locator, options);
if (ignoredRanges) {
// data bytes is start/end/count object
handleIgnoredRanges(data.bytes, ignoredRanges);
handleIgnoredRanges(data.functions, ignoredRanges);
handleIgnoredRanges(data.branches, ignoredRanges);
// functions is InfoFunction start/end/count instance
handleIgnoredRanges(functions, ignoredRanges);
// branches is InfoBranch start/end/count instance
handleIgnoredRanges(branches, ignoredRanges);
// branch locations start/end/count object
branches.forEach((group) => {
if (group.ignored) {
// all branch group ignored
group.locations.forEach((it) => {
it.ignored = true;
});
} else {
handleIgnoredRanges(group.locations, ignoredRanges);
}
});
// console.log(ignoredRanges);

@@ -267,2 +281,13 @@

data.functions = functions.map((info) => {
return info.getRange();
});
// branch group with locations to flat branches
data.branches = branches.map((info) => {
return info.getRanges();
}).flat();
// ==========================================
// lines
// after bytes with ignored, before calculateV8Lines

@@ -273,2 +298,4 @@ const {

// ==========================================
// v8 data and summary
item.data = data;

@@ -295,3 +322,3 @@ item.summary = {

lines.forEach((line, index) => {
lines.filter((it) => !it.ignored).forEach((line, index) => {
istanbulCoverage.statementMap[`${index}`] = line.generate();

@@ -301,10 +328,11 @@ istanbulCoverage.s[`${index}`] = line.count;

functions.forEach((fn, index) => {
istanbulCoverage.fnMap[`${index}`] = fn.generate();
functions.filter((it) => !it.ignored).forEach((fn, index) => {
istanbulCoverage.fnMap[`${index}`] = fn.generate(locator);
istanbulCoverage.f[`${index}`] = fn.count;
});
branches.forEach((branch, index) => {
istanbulCoverage.branchMap[`${index}`] = branch.generate();
istanbulCoverage.b[`${index}`] = branch.generateCounts();
branches.filter((it) => !it.ignored).forEach((branch, index) => {
const { map, counts } = branch.generate(locator);
istanbulCoverage.branchMap[`${index}`] = map;
istanbulCoverage.b[`${index}`] = counts;
});

@@ -320,4 +348,2 @@

const addJsBytesCoverage = (state, range) => {
const { coverageInfo } = state;
const { data } = coverageInfo;
const {

@@ -327,3 +353,3 @@ startOffset, endOffset, count

// add bytes range
data.bytes.push({
state.bytes.push({
start: startOffset,

@@ -336,4 +362,2 @@ end: endOffset,

const addCssBytesCoverage = (state, range) => {
const { coverageInfo } = state;
const { data } = coverageInfo;
const {

@@ -343,3 +367,3 @@ start, end, count

// add css bytes range, already start, end
data.bytes.push({
state.bytes.push({
start,

@@ -351,15 +375,2 @@ end,

const updateOffsetToLocation = (locator, loc) => {
const sLoc = locator.offsetToLocation(loc.start);
loc.start = {
line: sLoc.line,
column: sLoc.column
};
const eLoc = locator.offsetToLocation(loc.end);
loc.end = {
line: eLoc.line,
column: eLoc.column
};
};
// ========================================================================================================

@@ -371,13 +382,6 @@

if (!state.js) {
// use css rules data for functions
return;
}
const {
locator, coverageInfo, astInfo
} = state;
const v8Functions = coverageInfo.data.functions;
const istanbulFunctions = coverageInfo.functions;
const { functions, astInfo } = state;
astInfo.functions.forEach((it) => {

@@ -387,24 +391,6 @@ const {

} = it;
v8Functions.push({
start,
end,
count
});
const loc = {
start,
end
};
updateOffsetToLocation(locator, loc);
const functionInfo = new InfoFunction(loc, count, functionName);
istanbulFunctions.push(functionInfo);
const functionInfo = new InfoFunction(start, end, count, functionName);
functions.push(functionInfo);
});
// if (state.sourcePath.endsWith('store.js')) {
// console.log('==========================================================');
// console.log(astInfo.functions);
// console.log(functions);
// }
};

@@ -419,48 +405,9 @@

const {
locator, coverageInfo, astInfo
} = state;
const v8Branches = coverageInfo.data.branches;
const isTanbulBranches = coverageInfo.branches;
const { branches, astInfo } = state;
astInfo.branches.forEach((it) => {
const branchType = it.type;
const branchLoc = {
... it.loc
};
updateOffsetToLocation(locator, branchLoc);
// locations
// [ { start:{line,column}, end:{line,column}, count }, ...]
const locations = it.locations.map((oLoc) => {
const newLoc = {
... oLoc
};
if (newLoc.none) {
// the branch count is not very accurate
v8Branches.push({
start: it.loc.start,
end: it.loc.end,
count: oLoc.count,
none: true
});
return newLoc;
}
// the branch count is not very accurate
v8Branches.push({
start: oLoc.start,
end: oLoc.end,
count: oLoc.count
});
updateOffsetToLocation(locator, newLoc);
return newLoc;
});
const branchInfo = new InfoBranch(branchLoc, locations, branchType);
isTanbulBranches.push(branchInfo);
const {
start, end, locations, type
} = it;
const branchInfo = new InfoBranch(start, end, locations, type);
branches.push(branchInfo);
});

@@ -552,10 +499,8 @@

const {
type, loc, locations
} = it;
const { type, locations } = it;
// rename to startOffset and endOffset
const bRange = {
startOffset: loc.start,
endOffset: loc.end
startOffset: it.start,
endOffset: it.end
};

@@ -571,6 +516,4 @@

const newBranchLoc = {
start: originalRange.startOffset,
end: originalRange.endOffset
};
const groupStart = originalRange.startOffset;
const groupEnd = originalRange.endOffset;

@@ -585,2 +528,4 @@ let hasError;

if (newLoc.none) {
newLoc.start = groupStart;
newLoc.end = groupEnd;
return newLoc;

@@ -608,2 +553,3 @@ }

// mapping to new range
const oRage = res.originalRange;

@@ -616,2 +562,3 @@ newLoc.start = oRage.startOffset;

// ignored group when found error
if (hasError) {

@@ -624,3 +571,4 @@ return;

type,
loc: newBranchLoc,
start: groupStart,
end: groupEnd,
locations: newLocations

@@ -819,3 +767,6 @@ });

decodedMappings,
coverageInfo: createEmptyCoverageInfo(),
// coverage info
bytes: [],
functions: [],
branches: [],
astInfo: {

@@ -840,2 +791,3 @@ functions: [],

const sourceList = [];
originalMap.forEach((originalState) => {

@@ -849,3 +801,4 @@

const url = fileUrls[sourcePath] || sourcePath;
const id = Util.calculateSha1(url + source);
// add dist for id
const id = Util.calculateSha1(distFile + url + source);

@@ -862,3 +815,3 @@ const sourceItem = {

// generate coverage, coverageInfo for current file, state for dist file
// generate coverage for current file, state for dist file
collectFileCoverage(sourceItem, originalState, state.coverageData, options);

@@ -923,3 +876,2 @@

// console.log('=================================', originalState.sourcePath);
// console.log(originalState.coverageInfo.lineMap);
// }

@@ -979,3 +931,3 @@

// global file sources and coverage data
// global file sources and coverage
const fileSources = {};

@@ -1010,5 +962,2 @@ const coverageData = {};

// ============================
const coverageInfo = createEmptyCoverageInfo();
// ============================
// move functions and ranges to coverageList

@@ -1043,5 +992,8 @@ let coverageList = [];

locator,
coverageInfo,
// coverage info
bytes: [],
functions: [],
branches: [],
astInfo,
// for istanbul data
// for istanbul
fileSources: {},

@@ -1048,0 +1000,0 @@ coverageData: {}

@@ -0,6 +1,6 @@

const Util = require('../utils/util.js');
module.exports = class InfoBranch {
constructor(loc, locations, type) {
this.loc = loc;
this.line = loc.start.line;
// [ { start:{line,column}, end:{line,column}, count }, ...]
constructor(start, end, locations, type) {
this.start = start;
this.end = end;
this.locations = locations;

@@ -10,21 +10,66 @@ this.type = type || 'branch';

generate() {
return {
loc: this.loc,
getRanges() {
return this.locations.map((item) => {
const range = {
start: item.start,
end: item.end,
count: item.count
};
if (item.none) {
range.none = true;
}
if (item.ignored) {
range.ignored = true;
}
return range;
});
}
generate(locator) {
const groupLoc = {
start: this.start,
end: this.end
};
Util.updateOffsetToLocation(locator, groupLoc);
const line = groupLoc.start.line;
// remove ignored
const locations = this.locations.filter((it) => !it.ignored);
// [ { start:{line,column}, end:{line,column}, count }, ...]
locations.forEach((item) => {
Util.updateOffsetToLocation(locator, item);
});
const map = {
loc: groupLoc,
type: this.type,
locations: this.locations.map((item) => {
const { start, end } = item;
locations: locations.map((item) => {
const {
start, end, none
} = item;
if (none) {
// none with group start/end, should be empty for istanbul
return {
start: {},
end: {}
};
}
return {
start: start || {},
end: end || {}
start,
end
};
}),
line: this.line
line: line
};
const counts = locations.map((item) => item.count);
return {
map,
counts
};
}
generateCounts() {
return this.locations.map((item) => item.count);
}
};

@@ -0,5 +1,6 @@

const Util = require('../utils/util.js');
module.exports = class InfoFunction {
constructor(loc, count, name) {
this.loc = loc;
this.line = loc.start.line;
constructor(start, end, count, name) {
this.start = start;
this.end = end;
this.count = count;

@@ -9,10 +10,32 @@ this.name = name || '(anonymous)';

generate() {
getRange() {
const range = {
start: this.start,
end: this.end,
count: this.count
};
if (this.ignored) {
range.ignored = true;
}
return range;
}
generate(locator) {
const loc = {
start: this.start,
end: this.end
};
Util.updateOffsetToLocation(locator, loc);
const line = loc.start.line;
return {
name: this.name,
decl: this.loc,
loc: this.loc,
line: this.line
decl: loc,
loc: loc,
line: line
};
}
};

@@ -246,2 +246,15 @@ const fs = require('fs');

updateOffsetToLocation: (locator, loc) => {
const sLoc = locator.offsetToLocation(loc.start);
loc.start = {
line: sLoc.line,
column: sLoc.column
};
const eLoc = locator.offsetToLocation(loc.end);
loc.end = {
line: eLoc.line,
column: eLoc.column
};
},
forEachFile: function(dir, extList, callback) {

@@ -248,0 +261,0 @@ if (!fs.existsSync(dir)) {

{
"name": "monocart-coverage-reports",
"version": "2.0.8",
"version": "2.0.9",
"description": "Monocart coverage reports",

@@ -20,6 +20,7 @@ "main": "lib/index.js",

"build": "sf lint && sf b -p && npm run build-test",
"test-node": "npm run test-node-env && npm run test-node-ins && npm run test-node-api && npm run test-node-cdp",
"test-node-env": "cross-env NODE_V8_COVERAGE=.temp/v8-coverage node ./test/test-node-env.js && node ./test/generate-node-report.js",
"test-node": "npm run test-node-env && npm run test-node-api && npm run test-node-fgc && npm run test-node-ins && npm run test-node-cdp",
"test-node-env": "cross-env NODE_V8_COVERAGE=.temp/v8-coverage-env node ./test/test-node-env.js && node ./test/generate-node-report.js",
"test-node-api": "cross-env NODE_V8_COVERAGE=.temp/v8-coverage-api node ./test/test-node-api.js",
"test-node-fgc": "node ./test/test-node-fgc.js",
"test-node-ins": "node ./test/test-node-ins.js",
"test-node-api": "cross-env NODE_V8_COVERAGE=.temp/v8-coverage node ./test/test-node-api.js",
"test-node-cdp": "node --inspect=9229 ./test/test-node-cdp.js",

@@ -26,0 +27,0 @@ "test-browser": "node ./test/test.js",

@@ -13,2 +13,3 @@ # Monocart Coverage Reports

* [Multiprocessing Support](#multiprocessing-support)
* [onEnd Hook](#onend-hook)
* [Compare Reports](#compare-reports)

@@ -25,2 +26,3 @@ * [Compare Workflows](#compare-workflows)

* [Chromium Coverage API](#chromium-coverage-api)
* [V8 Coverage Data Format](#v8-coverage-data-format)
* [Istanbul Introduction](#istanbul-introduction)

@@ -134,7 +136,38 @@ * [Thanks](#thanks)

## onEnd Hook
For example, checking thresholds:
```js
const EC = require('eight-colors');
const coverageOptions = {
name: 'My Coverage Report',
outputDir: './coverage-reports',
onEnd: (coverageResults) => {
const thresholds = {
bytes: 80,
lines: 60
};
console.log('check thresholds ...', thresholds);
const errors = [];
const { summary } = coverageResults;
Object.keys(thresholds).forEach((k) => {
const pct = summary[k].pct;
if (pct < thresholds[k]) {
errors.push(`Coverage threshold for ${k} (${pct} %) not met: ${thresholds[k]} %`);
}
});
if (errors.length) {
const errMsg = errors.join('\n');
console.log(EC.red(errMsg));
// throw new Error(errMsg);
// process.exit(1);
}
}
}
```
## Compare Reports
| | Istanbul | V8 | V8 to Istanbul |
| :--------------| :------ | :------ | :---------------------- |
| Coverage data | Istanbul (Object) | V8 (Array) | V8 (Array) |
| Output | [Istanbul reports](#istanbul-reports) | [V8 reports](#v8-reports) | [Istanbul reports](#istanbul-reports) |
| Coverage data | [Istanbul](https://github.com/gotwarlost/istanbul/blob/master/coverage.json.md) (Object) | [V8](#v8-coverage-data-format) (Array) | [V8](#v8-coverage-data-format) (Array) |
| Output | [Istanbul reports](#available-reports) | [V8 reports](#available-reports) | [Istanbul reports](#available-reports) |
| - Bytes | ❌ | ✅ | ❌ |

@@ -187,9 +220,12 @@ | - Statements | ✅ | ❌ | ☑️❔ |

- example:
> cross-env NODE_V8_COVERAGE=`.temp/v8-coverage` node [./test/test-node-env.js](./test/test-node-env.js) && node [./test/generate-node-report.js](./test/generate-node-report.js)
> cross-env NODE_V8_COVERAGE=`.temp/v8-coverage-env` node [./test/test-node-env.js](./test/test-node-env.js) && node [./test/generate-node-report.js](./test/generate-node-report.js)
- Using [V8](https://nodejs.org/docs/latest/api/v8.html#v8takecoverage) API
- Using [V8](https://nodejs.org/docs/latest/api/v8.html#v8takecoverage) API + NODE_V8_COVERAGE
- Writing the coverage started by NODE_V8_COVERAGE to disk on demand with `v8.takeCoverage()` and stopping with `v8.stopCoverage()`.
- example:
> cross-env NODE_V8_COVERAGE=`.temp/v8-coverage` node [./test/test-node-api.js](./test/test-node-api.js)
> cross-env NODE_V8_COVERAGE=`.temp/v8-coverage-api` node [./test/test-node-api.js](./test/test-node-api.js)
- Using [foreground-child](https://github.com/tapjs/foreground-child) + NODE_V8_COVERAGE
- example: [./test/test-node-fgc.js](./test/test-node-fgc.js)
- Using [Inspector](https://nodejs.org/docs/latest/api/inspector.html) API (or module [collect-v8-coverage](https://github.com/SimenB/collect-v8-coverage))

@@ -208,20 +244,20 @@ - Connecting to the V8 inspector and enable V8 coverage.

```
1, dist/main.js
2, dist/vendor.js
3, dist/something-else.js
dist/main.js
dist/vendor.js
dist/something-else.js
```
We can use `entryFilter` to filter the entry files. For example, we should remove `vendor.js` and `something-else.js` if they are not in our coverage scope.
```
1, dist/main.js
dist/main.js
```
When inline or linked sourcemap exists to the entry file, the source files will be extracted from the sourcemap for the entry file, and the entry file will be removed if `logging` is not `debug`.
```
1, src/index.js
2, src/components/app.js
3, node_modules/dependency/dist/dependency.js
> src/index.js
> src/components/app.js
> node_modules/dependency/dist/dependency.js
```
We can use `sourceFilter` to filter the source files. For example, we should remove `dependency.js` if it is not in our coverage scope.
```
1, src/index.js
2, src/components/app.js
> src/index.js
> src/components/app.js
```

@@ -253,9 +289,11 @@ Example:

if (block.isBlockCoverage) {
// v8-to-istanbul: count range as branch here.
// v8-to-istanbul: new CovBranch()
// Problem: not every block is branch, and the first block is actually function.
if (block.functionName && i === 0) {
// v8-to-istanbul: count range as function here.
// v8-to-istanbul: new CovFunction()
// Problem: no anonymous function
}
} else if (block.functionName) {
// v8-to-istanbul: count range as function here.
// v8-to-istanbul: new CovFunction()
// Problem: no anonymous function
}

@@ -309,2 +347,46 @@ }

## V8 Coverage Data Format
```js
// Coverage data for a source range.
export interface CoverageRange {
// JavaScript script source offset for the range start.
startOffset: integer;
// JavaScript script source offset for the range end.
endOffset: integer;
// Collected execution count of the source range.
count: integer;
}
// Coverage data for a JavaScript function.
/**
* @functionName can be an empty string.
* @ranges is always non-empty. The first range is called the "root range".
* @isBlockCoverage indicates if the function has block coverage information.
If this is false, it usually means that the functions was never called.
It seems to be equivalent to ranges.length === 1 && ranges[0].count === 0.
*/
export interface FunctionCoverage {
// JavaScript function name.
functionName: string;
// Source ranges inside the function with coverage data.
ranges: CoverageRange[];
// Whether coverage data for this function has block granularity.
isBlockCoverage: boolean;
}
// Coverage data for a JavaScript script.
export interface ScriptCoverage {
// JavaScript script id.
scriptId: Runtime.ScriptId;
// JavaScript script name or url.
url: string;
// Functions contained in the script that has coverage data.
functions: FunctionCoverage[];
}
export type V8CoverageData = ScriptCoverage[];
```
see devtools-protocol [ScriptCoverage](https://chromedevtools.github.io/devtools-protocol/tot/Profiler/#type-ScriptCoverage)
## Istanbul Introduction

@@ -311,0 +393,0 @@ - [Istanbul coverage report](https://istanbul.js.org/) - Instrumenting source codes and generating coverage reports

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc