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.9.3 to 2.10.0

lib/assets.js

27

lib/converter/converter.js

@@ -22,3 +22,3 @@ /**

const { decode } = require('@jridgewell/sourcemap-codec');
const { minimatch } = require('minimatch');
const { minimatch } = require('../packages/monocart-coverage-vendor.js');

@@ -286,4 +286,4 @@ const InfoBranch = require('./info-branch.js');

data.functions = functions.map((info) => {
return info.getRange();
data.functions = functions.map((info, i) => {
return info.getRange(i);
});

@@ -560,3 +560,3 @@ sortRanges(data.functions);

const result = findOriginalRange(start, end, state, originalStateMap);
const result = findOriginalRange(start, end, state, originalStateMap, true);
if (result.error) {

@@ -577,2 +577,6 @@ logMappingErrors('function', result);

if (result.name) {
originalFunction.functionName = result.name;
}
// body start and end

@@ -870,3 +874,3 @@ updateFunctionBodyRange(start, end, bodyStart, bodyEnd, originalFunction);

// const NAMES_INDEX = 4;
const [generatedColumn, sourceIndex, originalLine, originalColumn] = segment;
const [generatedColumn, sourceIndex, originalLine, originalColumn, nameIndex] = segment;
// the segment length could be 1, 4 or 5

@@ -891,3 +895,4 @@

originalLine,
originalColumn
originalColumn,
nameIndex
};

@@ -1111,2 +1116,4 @@

state.fileUrls = fileUrls;
// for function names
state.sourceMapNames = sourceMap.names || [];

@@ -1506,2 +1513,10 @@ // ===============================================

// sort v8DataList (files)
v8DataList.sort((a, b) => {
if (a.sourcePath > b.sourcePath) {
return 1;
}
return -1;
});
return {

@@ -1508,0 +1523,0 @@ v8DataList,

@@ -1,2 +0,2 @@

const diffSequence = require('diff-sequences').default;
const { diffSequence } = require('../packages/monocart-coverage-vendor.js');
const Util = require('../utils/util.js');

@@ -537,4 +537,9 @@ const EC = Util.EC;

// ========================================================================================================
const getFunctionName = (mp, state, checkName) => {
if (checkName && typeof mp.nameIndex !== 'undefined') {
return state.sourceMapNames[mp.nameIndex];
}
};
const getFixedOriginalStart = (start, mappings, state, cache) => {
const getFixedOriginalStart = (start, mappings, state, cache, checkName) => {

@@ -547,3 +552,4 @@ const [m1, m2] = mappings;

return {
originalStart: m2.originalOffset
originalStart: m2.originalOffset,
originalName: getFunctionName(m2, state, checkName)
};

@@ -579,3 +585,4 @@ }

return {
originalStart: originalOffset + originalPos
originalStart: originalOffset + originalPos,
originalName: getFunctionName(m1, state, checkName)
};

@@ -641,3 +648,3 @@ };

const getOriginalStartPosition = (cache, state) => {
const getOriginalStartPosition = (cache, state, checkName) => {

@@ -647,3 +654,3 @@ const { start, startMappings } = cache;

if (Array.isArray(startMappings)) {
return getFixedOriginalStart(start, startMappings, state, cache);
return getFixedOriginalStart(start, startMappings, state, cache, checkName);
}

@@ -653,3 +660,4 @@

return {
originalStart: startMappings.originalOffset
originalStart: startMappings.originalOffset,
originalName: getFunctionName(startMappings, state, checkName)
};

@@ -881,3 +889,3 @@ };

const findOriginalRange = (start, end, state, originalMap) => {
const findOriginalRange = (start, end, state, originalMap, checkName) => {

@@ -911,4 +919,4 @@ const { sourcePath, rangeCache } = state;

const originalStartResult = getOriginalStartPosition(cache, state);
const { originalStart } = originalStartResult;
const originalStartResult = getOriginalStartPosition(cache, state, checkName);
const { originalStart, originalName } = originalStartResult;
// could be used for end

@@ -939,2 +947,3 @@ cache.originalStart = originalStart;

end: originalEnd,
name: originalName,
originalState

@@ -941,0 +950,0 @@ };

const { decode } = require('@jridgewell/sourcemap-codec');
const COLUMN = 0;
const SOURCES_INDEX = 1;
const SOURCE_LINE = 2;
const SOURCE_COLUMN = 3;
const NAMES_INDEX = 4;
function getLine(arr, index) {

@@ -10,4 +16,17 @@ for (let i = arr.length; i <= index; i++) {

function addMappings(options, sourcesOffset) {
function getMapping(seg, column, sourcesOffset, namesOffset) {
const sourcesIndex = sourcesOffset + seg[SOURCES_INDEX];
const sourceLine = seg[SOURCE_LINE];
const sourceColumn = seg[SOURCE_COLUMN];
if (seg.length === 4) {
return [column, sourcesIndex, sourceLine, sourceColumn];
}
return [column, sourcesIndex, sourceLine, sourceColumn, namesOffset + seg[NAMES_INDEX]];
}
function addMappings(options, sourcesOffset, namesOffset) {
const {

@@ -22,6 +41,2 @@ input,

const decoded = decode(input.mappings);
const COLUMN = 0;
const SOURCES_INDEX = 1;
const SOURCE_LINE = 2;
const SOURCE_COLUMN = 3;

@@ -52,6 +67,3 @@ for (let i = 0; i < decoded.length; i++) {

const sourcesIndex = sourcesOffset + seg[SOURCES_INDEX];
const sourceLine = seg[SOURCE_LINE];
const sourceColumn = seg[SOURCE_COLUMN];
out.push([column, sourcesIndex, sourceLine, sourceColumn]);
out.push(getMapping(seg, column, sourcesOffset, namesOffset));
}

@@ -71,3 +83,5 @@ }

const sourcesOffset = options.sources.length;
const namesOffset = options.names.length;
// sources and sourcesContent
if (!input.sourcesContent) {

@@ -81,4 +95,11 @@ input.sourcesContent = [];

addMappings(options, sourcesOffset);
// names
if (input.names) {
input.names.forEach((n) => {
options.names.push(n);
});
}
addMappings(options, sourcesOffset, namesOffset);
}

@@ -135,3 +156,2 @@

const names = [];
const ignoreList = [];

@@ -153,3 +173,2 @@ const lineOffset = 0;

names,
ignoreList,

@@ -164,2 +183,3 @@ lineOffset,

indexedMap.sourcesContent = sourcesContent;
indexedMap.names = names;
indexedMap.decodedMappings = decodedMappings;

@@ -166,0 +186,0 @@

@@ -72,14 +72,75 @@ const Util = require('../utils/util.js');

// both v8 or c8
const hasIgnoreKey = (content) => {
const v8Key = 'v8 ignore';
if (content.startsWith(v8Key)) {
return v8Key.length;
const getStartEndNextInfo = (content) => {
content = content.trim();
const start = 'start';
const stop = 'stop';
const next = 'next';
if (content.startsWith(start)) {
return {
type: 'range',
value: stop
};
}
const c8Key = 'c8 ignore';
if (content.startsWith(c8Key)) {
return c8Key.length;
if (content.startsWith(stop)) {
return {
type: 'range',
value: stop
};
}
// istanbul ignore has different rules, can not support it
if (content.startsWith(next)) {
return {
type: 'next',
value: content.slice(next.length)
};
}
};
const getDisableEnableNextInfo = (content) => {
content = content.trim();
const start = 'disable';
const stop = 'enable';
const next = 'ignore next';
if (content.startsWith(start)) {
return {
type: 'range',
value: stop
};
}
if (content.startsWith(stop)) {
return {
type: 'range',
value: stop
};
}
if (content.startsWith(next)) {
return {
type: 'next',
value: content.slice(next.length)
};
}
};
const getIgnoreInfo = (content) => {
content = content.trim();
const v8_ignore = 'v8 ignore';
if (content.startsWith(v8_ignore)) {
return getStartEndNextInfo(content.slice(v8_ignore.length));
}
const c8_ignore = 'c8 ignore';
if (content.startsWith(c8_ignore)) {
return getStartEndNextInfo(content.slice(c8_ignore.length));
}
const node_coverage = 'node:coverage';
if (content.startsWith(node_coverage)) {
return getDisableEnableNextInfo(content.slice(node_coverage.length));
}
};
const getIgnoredRanges = (locator, options) => {

@@ -105,16 +166,15 @@ if (!options.v8Ignore) {

} = item;
let content = block ? text.slice(2, -2) : text.slice(2);
content = content.trim();
const ignoreKey = hasIgnoreKey(content);
if (!ignoreKey) {
const content = block ? text.slice(2, -2) : text.slice(2);
const ignoreInfo = getIgnoreInfo(content);
if (!ignoreInfo) {
return;
}
content = content.slice(ignoreKey).trim();
const { type, value } = ignoreInfo;
if (ignoreStart) {
// v-8 ignore stop
if (content === 'stop') {
ignoreStart.end = extendEnd(end, source, maxLength);
if (type === 'range' && value === ignoreStart.value) {
ignoreStart.ignoreData.end = extendEnd(end, source, maxLength);
ignoreStart = null;

@@ -126,18 +186,20 @@ }

// v-8 ignore start
if (content === 'start') {
if (type === 'range') {
// add first for sort by start
ignoreStart = {
type: 'start-stop',
const ignoreData = {
type,
start: extendStart(start, source),
end: start
};
list.push(ignoreStart);
list.push(ignoreData);
ignoreStart = {
ignoreData,
value
};
return;
}
// v-8 ignore next N
const nextKey = 'next';
if (content.startsWith(nextKey)) {
content = content.slice(nextKey.length).trim();
addNextIgnore(list, content, item, locator);
// next N
if (type === 'next') {
addNextIgnore(list, value.trim(), item, locator);
}

@@ -144,0 +206,0 @@

@@ -19,4 +19,9 @@ const Util = require('../utils/util.js');

getRange() {
getName(index) {
return this.functionName || `(anonymous_${index})`;
}
getRange(index) {
const range = {
name: this.getName(index),
start: this.start,

@@ -55,6 +60,4 @@ end: this.end,

const functionName = this.functionName || `(anonymous_${index})`;
return {
name: functionName,
name: this.getName(index),
decl: decl,

@@ -61,0 +64,0 @@ loc: loc,

const fs = require('fs');
const path = require('path');
const CG = require('console-grid');
const EC = require('eight-colors');
const { pathToFileURL, fileURLToPath } = require('url');
const EC = require('eight-colors');
const { minimatch } = require('./packages/monocart-coverage-vendor.js');
const Util = require('./utils/util.js');
const { convertV8List } = require('./converter/converter.js');
const { resolveSourceMap } = require('./converter/collect-source-maps.js');
// ========================================================================================================
// built-in reports
// istanbul
const {

@@ -12,28 +20,60 @@ initIstanbulData, mergeIstanbulCoverage, saveIstanbulReports

// v8
const { mergeV8Coverage, saveV8Report } = require('./v8/v8.js');
const { convertV8List } = require('./converter/converter.js');
const { resolveSourceMap } = require('./converter/collect-source-maps.js');
// both
const { codecovReport } = require('./reports/codecov.js');
const { codacyReport } = require('./reports/codacy.js');
const { minimatch } = require('minimatch');
const { getGroupedRows } = require('./utils/snapshot.js');
const generateMarkdownGrid = require('./utils/markdown.js');
const { consoleDetailsReport } = require('./reports/console-details.js');
const { consoleSummaryReport } = require('./reports/console-summary.js');
// ========================================================================================================
const { markdownDetailsReport } = require('./reports/markdown-details.js');
const { markdownSummaryReport } = require('./reports/markdown-summary.js');
// maybe v8 or to istanbul reports
const generateV8ListReports = async (v8list, coverageData, fileSources, options) => {
let istanbulReportPath;
// v8 to istanbul reports
if (options.reportGroup.istanbul) {
const istanbulCoverageResults = await saveIstanbulReports(coverageData, fileSources, options);
istanbulReportPath = istanbulCoverageResults.reportPath;
}
const { rawReport } = require('./reports/raw.js');
// v8 reports and v8 coverage results
// could be no v8 or v8-json, but requires v8 coverage results
const v8CoverageResults = await saveV8Report(v8list, options, istanbulReportPath);
return v8CoverageResults;
const allBuiltInReports = {
// v8
'v8': 'v8',
'v8-json': 'v8',
// istanbul
'clover': 'istanbul',
'cobertura': 'istanbul',
'html': 'istanbul',
'html-spa': 'istanbul',
'json': 'istanbul',
'json-summary': 'istanbul',
'lcov': 'istanbul',
'lcovonly': 'istanbul',
'none': 'istanbul',
'teamcity': 'istanbul',
'text': 'istanbul',
'text-lcov': 'istanbul',
'text-summary': 'istanbul',
// both
'codecov': 'both',
'codacy': 'both',
'console-details': 'both',
'console-summary': 'both',
'markdown-details': 'both',
'markdown-summary': 'both',
'raw': 'both'
};
const bothBuiltInReports = {
'codecov': codecovReport,
'codacy': codacyReport,
'console-details': consoleDetailsReport,
'console-summary': consoleSummaryReport,
'markdown-details': markdownDetailsReport,
'markdown-summary': markdownSummaryReport,
'raw': rawReport
};
// ========================================================================================================

@@ -73,38 +113,8 @@

const allBuildInReports = {
// v8
'v8': 'v8',
'v8-json': 'v8',
// istanbul
'clover': 'istanbul',
'cobertura': 'istanbul',
'html': 'istanbul',
'html-spa': 'istanbul',
'json': 'istanbul',
'json-summary': 'istanbul',
'lcov': 'istanbul',
'lcovonly': 'istanbul',
'none': 'istanbul',
'teamcity': 'istanbul',
'text': 'istanbul',
'text-lcov': 'istanbul',
'text-summary': 'istanbul',
// both
'codecov': 'both',
'codacy': 'both',
'console-details': 'both',
'console-summary': 'both',
'markdown-details': 'both',
'markdown-summary': 'both',
'raw': 'both'
};
// group v8 and istanbul
const reportGroup = {};
const groupMap = new Map();
Object.keys(reportMap).forEach((k) => {
const options = reportMap[k];
let type = allBuildInReports[k];
let type = allBuiltInReports[k];
if (!type) {

@@ -115,9 +125,9 @@ // for custom reporter

let group = reportGroup[type];
let group = groupMap.get(type);
if (!group) {
group = {};
reportGroup[type] = group;
group = new Map();
groupMap.set(type, group);
}
group[k] = options;
group.set(k, options);

@@ -127,9 +137,9 @@ });

// requires a default istanbul report if data is istanbul
if (dataType === 'istanbul' && !reportGroup.istanbul) {
reportGroup.istanbul = {
html: {}
};
if (dataType === 'istanbul' && !groupMap.has('istanbul')) {
const istanbulGroup = new Map();
istanbulGroup.set('html', {});
groupMap.set('istanbul', istanbulGroup);
}
return reportGroup;
return groupMap;
};

@@ -139,402 +149,17 @@

const nFormatter = (v) => {
if (typeof v === 'number') {
return Util.NF(v);
// maybe v8 or to istanbul reports
const generateV8ListReports = async (v8list, coverageData, fileSources, options) => {
let istanbulReportPath;
// v8 to istanbul reports
if (options.reportGroup.has('istanbul')) {
const istanbulCoverageResults = await saveIstanbulReports(coverageData, fileSources, options);
istanbulReportPath = istanbulCoverageResults.reportPath;
}
return v;
};
const getRowData = (rowName, summary, metrics, color) => {
const summaryRow = {};
let lowest = {
pct: 100,
status: 'high'
};
metrics.map((k) => {
const s = summary[k];
if (!s) {
return;
}
const percent = s.pct;
if (typeof percent !== 'number') {
return;
}
summaryRow[k] = Util.getColorStrByStatus(Util.PSF(percent, 100, 2), s.status, color);
if (percent < lowest.pct) {
lowest = s;
}
});
summaryRow.nameStatus = lowest.status;
summaryRow.name = rowName;
return summaryRow;
// v8 reports and v8 coverage results
// could be no v8 or v8-json, but requires v8 coverage results
const v8CoverageResults = await saveV8Report(v8list, options, istanbulReportPath);
return v8CoverageResults;
};
const getDetailsRows = (files, metrics, cdOptions, color) => {
const skipPercent = cdOptions.skipPercent;
if (typeof skipPercent === 'number' && skipPercent > 0) {
files = files.filter((file) => {
const { summary } = file;
for (const k of metrics) {
const percent = summary[k].pct;
if (typeof percent === 'number' && percent < skipPercent) {
return true;
}
}
return false;
});
}
const flatRows = [];
files.forEach((file) => {
// do NOT add debug file
if (file.debug) {
return;
}
const { sourcePath, summary } = file;
const fileRow = getRowData(sourcePath, summary, metrics, color);
fileRow.uncoveredLines = Util.getUncoveredLines(file.data.lines, color);
flatRows.push(fileRow);
});
return getGroupedRows(flatRows);
};
const handleCodecovReport = async (reportData, reportOptions, options) => {
const codecovOptions = {
outputFile: 'codecov.json',
... reportOptions
};
const jsonPath = path.resolve(options.outputDir, codecovOptions.outputFile);
// https://docs.codecov.com/docs/codecov-custom-coverage-format
const coverage = {};
reportData.files.forEach((item) => {
const { sourcePath, data } = item;
coverage[sourcePath] = data.lines;
});
const codecovData = {
coverage
};
await Util.writeFile(jsonPath, JSON.stringify(codecovData));
return Util.relativePath(jsonPath);
};
const handleCodacyReport = async (reportData, reportOptions, options) => {
const codacyOptions = {
outputFile: 'codacy.json',
... reportOptions
};
const jsonPath = path.resolve(options.outputDir, codacyOptions.outputFile);
// https://api.codacy.com/swagger#tocscoveragereport
const fileReports = [];
reportData.files.forEach((item) => {
const { sourcePath, data } = item;
const coverage = {};
for (const [key, value] of Object.entries(data.lines)) {
if (typeof value === 'number') {
coverage[key] = value;
} else {
// partial coverage not supported?
coverage[key] = 0;
}
}
fileReports.push({
filename: sourcePath,
coverage
});
});
const codacyData = {
fileReports
};
await Util.writeFile(jsonPath, JSON.stringify(codacyData));
return Util.relativePath(jsonPath);
};
const handleConsoleDetailsReport = (reportData, reportOptions, options) => {
const cdOptions = {
maxCols: 50,
skipPercent: 0,
metrics: [],
... reportOptions
};
const {
type, name, summary, files
} = reportData;
if (name) {
Util.logInfo(EC.cyan(name));
}
const color = 'ansicode';
const metrics = Util.getMetrics(cdOptions.metrics, type);
const rows = getDetailsRows(files, metrics, cdOptions, color);
const summaryRow = getRowData('Summary', summary, metrics, color);
if (summaryRow.nameStatus) {
summaryRow.name = Util.getColorStrByStatus(summaryRow.name, summaryRow.nameStatus, color);
}
// no rows if skipped all by skipPercent
if (rows.length) {
rows.push({
innerBorder: true
});
}
rows.push(summaryRow);
const columns = [{
id: 'name',
name: 'Name'
}, ... metrics.map((m) => {
return {
id: m,
name: Util.capitalizeFirstLetter(m),
align: 'right'
};
}), {
id: 'uncoveredLines',
name: 'Uncovered Lines'
}];
return CG({
options: {
silent: cdOptions.silent,
nullPlaceholder: '',
defaultMaxWidth: cdOptions.maxCols
},
columns,
rows
});
};
const getSummaryColumns = (color) => {
const columns = [{
id: 'name',
name: 'Name'
}, {
id: 'pct',
name: 'Coverage %',
align: 'right',
formatter: (v, row, column) => {
if (typeof v === 'number') {
return Util.getColorStrByStatus(Util.PSF(v, 100, 2), row.status, color);
}
return v;
}
}, {
id: 'covered',
name: 'Covered',
align: 'right',
formatter: nFormatter
}, {
id: 'uncovered',
name: 'Uncovered',
align: 'right',
formatter: nFormatter
}, {
id: 'total',
name: 'Total',
align: 'right',
formatter: nFormatter
}];
return columns;
};
const handleConsoleSummaryReport = (reportData, reportOptions, options) => {
const csOptions = {
metrics: [],
... reportOptions
};
const {
summary, name, type
} = reportData;
if (name) {
Util.logInfo(EC.cyan(name));
}
const metrics = Util.getMetrics(csOptions.metrics, type);
const rows = metrics.map((k) => {
return {
... summary[k],
name: Util.capitalizeFirstLetter(k)
};
});
const columns = getSummaryColumns('ansicode');
CG({
columns,
rows
});
};
const handleMarkdownDetailsReport = async (reportData, reportOptions, options) => {
const mdOptions = {
baseUrl: '',
// unicode, html, or empty for no color
color: 'unicode',
skipPercent: 0,
metrics: [],
outputFile: 'coverage-details.md',
... reportOptions
};
const color = Util.normalizeColorType(mdOptions.color);
const baseUrl = mdOptions.baseUrl;
const mdPath = path.resolve(options.outputDir, mdOptions.outputFile);
const metrics = Util.getMetrics(mdOptions.metrics, reportData.type);
let files = reportData.files;
const skipPercent = mdOptions.skipPercent;
if (typeof skipPercent === 'number' && skipPercent > 0) {
files = files.filter((file) => {
const { summary } = file;
for (const k of metrics) {
const percent = summary[k].pct;
if (typeof percent === 'number' && percent < skipPercent) {
return true;
}
}
return false;
});
}
const rows = [];
files.forEach((file) => {
// do NOT add debug file
if (file.debug) {
return;
}
const { sourcePath, summary } = file;
const fileRow = getRowData(sourcePath, summary, metrics, color);
if (fileRow.nameStatus) {
const nameColor = baseUrl && color === 'tex' ? '' : color;
fileRow.name = Util.getColorStrByStatus(fileRow.name, fileRow.nameStatus, nameColor);
}
if (baseUrl) {
fileRow.name = `[${fileRow.name}](${baseUrl + sourcePath})`;
}
fileRow.uncoveredLines = Util.getUncoveredLines(file.data.lines, color);
rows.push(fileRow);
});
const summaryRow = getRowData('Summary', reportData.summary, metrics, color);
if (summaryRow.nameStatus) {
summaryRow.name = Util.getColorStrByStatus(summaryRow.name, summaryRow.nameStatus, color);
}
rows.push(summaryRow);
const columns = [{
id: 'name',
name: 'Name'
}, ... metrics.map((m) => {
return {
id: m,
name: Util.capitalizeFirstLetter(m),
align: 'right'
};
}), {
id: 'uncoveredLines',
name: 'Uncovered Lines'
}];
const markdownGrid = generateMarkdownGrid({
options: {
name: reportData.name
},
columns,
rows
});
await Util.writeFile(mdPath, markdownGrid);
return Util.relativePath(mdPath);
};
const handleMarkdownSummaryReport = async (reportData, reportOptions, options) => {
const msOptions = {
// unicode, html, or empty for no color
color: 'unicode',
metrics: [],
outputFile: 'coverage-summary.md',
... reportOptions
};
const color = Util.normalizeColorType(msOptions.color);
const mdPath = path.resolve(options.outputDir, msOptions.outputFile);
const metrics = Util.getMetrics(msOptions.metrics, reportData.type);
const rows = metrics.map((k) => {
return {
... reportData.summary[k],
name: Util.capitalizeFirstLetter(k)
};
});
const columns = getSummaryColumns(color);
const markdownGrid = generateMarkdownGrid({
options: {
name: reportData.name
},
columns,
rows
});
await Util.writeFile(mdPath, markdownGrid);
return Util.relativePath(mdPath);
};
const handleRawReport = (reportData, reportOptions, options) => {
const rawOptions = {
outputDir: 'raw',
... reportOptions
};
const cacheDir = options.cacheDir;
const rawDir = path.resolve(options.outputDir, rawOptions.outputDir);
// console.log(rawDir, cacheDir);
if (fs.existsSync(rawDir)) {
Util.logError(`Failed to save raw report because the dir already exists: ${Util.relativePath(rawDir)}`);
return;
}
const rawParent = path.dirname(rawDir);
if (!fs.existsSync(rawParent)) {
fs.mkdirSync(rawParent, {
recursive: true
});
}
// just rename the cache folder name
fs.renameSync(cacheDir, rawDir);
};
// ========================================================================================================
const getCoverageResults = async (dataList, sourceCache, options) => {

@@ -583,21 +208,9 @@ // get first and check v8list or istanbul data

const buildInBothReports = {
'codecov': handleCodecovReport,
'codacy': handleCodacyReport,
'console-details': handleConsoleDetailsReport,
'console-summary': handleConsoleSummaryReport,
'markdown-details': handleMarkdownDetailsReport,
'markdown-summary': handleMarkdownSummaryReport,
'raw': handleRawReport
};
const bothGroup = options.reportGroup.both;
if (bothGroup) {
const bothReports = Object.keys(bothGroup);
for (const reportName of bothReports) {
const reportOptions = bothGroup[reportName];
const buildInHandler = buildInBothReports[reportName];
if (options.reportGroup.has('both')) {
const bothGroup = options.reportGroup.get('both');
for (const [reportName, reportOptions] of bothGroup) {
const builtInHandler = bothBuiltInReports[reportName];
const t1 = Date.now();
if (buildInHandler) {
await buildInHandler(coverageResults, reportOptions, options);
if (builtInHandler) {
await builtInHandler(coverageResults, reportOptions, options);
} else {

@@ -604,0 +217,0 @@ await Util.runCustomReporter(reportName, coverageResults, reportOptions, options);

@@ -132,2 +132,5 @@ declare namespace MCR {

metrics?: Array<"bytes" | "statements" | "branches" | "functions" | "lines">;
filter?: string | {
[pattern: string]: boolean;
} | ((file: CoverageFile) => boolean);
}] |

@@ -145,4 +148,8 @@ ['markdown-summary'] | ['markdown-summary', {

color: 'unicode' | 'html' | 'tex' | string;
maxCols?: number;
skipPercent?: number;
metrics?: Array<"bytes" | "statements" | "branches" | "functions" | "lines">;
filter?: string | {
[pattern: string]: boolean;
} | ((file: CoverageFile) => boolean);
/**

@@ -195,4 +202,11 @@ * defaults to `coverage-details.md`

count: number;
/** ignored by special comment which starts with `v8 ignore` */
ignored?: boolean;
/**
* branch only, for example:
* there is only `if` branch but no `else` branch, then `none` will be true, it shows `else path uncovered`
*/
none?: boolean;
/** function only, function name */
name?: boolean;
}

@@ -203,3 +217,5 @@

end: number;
/** ignore type: `next` or `range` */
type: string;
/** n lines for `next` type */
n?: number;

@@ -253,2 +269,3 @@ }

reportPath: string;
version: string;
name: string;

@@ -323,3 +340,7 @@ watermarks: Watermarks;

* */
sourcePath?: ((filePath: string, info: any) => string) | {
sourcePath?: ((filePath: string, info: {
/** the related dist file of current source file */
distFile?: string;
[key: string]: any;
}) => string) | {
[key: string]: string;

@@ -326,0 +347,0 @@ };

@@ -90,10 +90,12 @@ const fs = require('fs');

const istanbulGroup = options.reportGroup.istanbul;
Object.keys(istanbulGroup).forEach((reportName) => {
const t1 = Date.now();
const reportOptions = istanbulGroup[reportName];
const report = istanbulReports.create(reportName, reportOptions);
report.execute(context);
Util.logTime(`┌ [generate] saved report: ${reportName}`, t1);
});
const istanbulGroup = options.reportGroup.get('istanbul');
// already has
if (istanbulGroup) {
for (const [reportName, reportOptions] of istanbulGroup) {
const t1 = Date.now();
const report = istanbulReports.create(reportName, reportOptions);
report.execute(context);
Util.logTime(`┌ [generate] saved report: ${reportName}`, t1);
}
}

@@ -113,2 +115,3 @@ // add watermarks and color

reportPath,
version: Util.version,
name: options.name,

@@ -115,0 +118,0 @@ watermarks: contextOptions.watermarks,

@@ -29,2 +29,18 @@ const Util = {

isNum: function(num) {
if (typeof num !== 'number' || isNaN(num)) {
return false;
}
const isInvalid = function(n) {
if (n === Number.MAX_VALUE || n === Number.MIN_VALUE || n === Number.NEGATIVE_INFINITY || n === Number.POSITIVE_INFINITY) {
return true;
}
return false;
};
if (isInvalid(num)) {
return false;
}
return true;
},
toNum: function(num, toInt) {

@@ -31,0 +47,0 @@ if (typeof (num) !== 'number') {

@@ -0,0 +0,0 @@ const os = require('os');

@@ -11,6 +11,4 @@ const fs = require('fs');

const request = require('./request.js');
const { deflateSync } = require('lz-utils');
const version = require('../../package.json').version;
const acornWalk = require('acorn-walk');
const { findUpSync, supportsColor } = require('../packages/monocart-coverage-vendor.js');

@@ -25,2 +23,4 @@

const Util = {
version,
... Share,

@@ -154,38 +154,2 @@

resolveNodeModule: (id) => {
// for deno npm module
const mp = require.resolve(id);
if (fs.existsSync(mp)) {
return mp;
}
const p = `${it}/dist/${it}.js`;
// root
const cwd = path.resolve('node_modules', p);
if (fs.existsSync(cwd)) {
return cwd;
}
// sub node modules
const sub = path.resolve(__dirname, '../../node_modules', p);
if (fs.existsSync(sub)) {
return sub;
}
// same level dep
const dep = path.resolve(__dirname, '../../../', p);
if (fs.existsSync(dep)) {
return dep;
}
Util.logError(`Not found module: ${p}`);
return cwd;
},
resolvePackage: (p) => {
return path.resolve(__dirname, '../packages', p);
},
getCacheFileInfo: (type, id, cacheDir) => {

@@ -225,72 +189,2 @@ const cacheName = `${type}-${id}.json`;

saveHtmlReport: async (options) => {
const {
inline,
reportData,
jsFiles,
assetsPath,
outputDir,
htmlFile,
reportDataFile
} = options;
// report data
const reportDataCompressed = deflateSync(JSON.stringify(reportData));
const reportDataStr = `window.reportData = '${reportDataCompressed}';`;
// js libs
const jsList = [];
for (const jsFile of jsFiles) {
const jsStr = await Util.readFile(jsFile);
jsList.push({
filename: path.basename(jsFile),
str: jsStr
});
}
// html content
let htmlStr = '';
const EOL = Util.getEOL();
if (inline) {
htmlStr = [
'<script>',
reportDataStr,
... jsList.map((it) => it.str),
'</script>'
].join(EOL);
} else {
await Util.writeFile(path.resolve(outputDir, reportDataFile), reportDataStr);
const assetsDir = path.resolve(outputDir, assetsPath);
const relAssetsDir = Util.relativePath(assetsDir, outputDir);
for (const item of jsList) {
const filePath = path.resolve(assetsDir, item.filename);
if (!fs.existsSync(filePath)) {
await Util.writeFile(filePath, item.str);
}
}
htmlStr = [
`<script src="${reportDataFile}"></script>`,
... jsList.map((it) => `<script src="${relAssetsDir}/${it.filename}"></script>`)
].join(EOL);
}
// html
const htmlPath = path.resolve(outputDir, htmlFile);
const template = Util.getTemplate(path.resolve(__dirname, '../default/template.html'));
const html = Util.replace(template, {
title: reportData.title,
content: htmlStr
});
await Util.writeFile(htmlPath, html);
return Util.relativePath(htmlPath);
},
runCustomReporter: async (reportName, reportData, reportOptions, globalOptions) => {

@@ -492,18 +386,2 @@ let CustomReporter;

getTemplate: function(templatePath) {
if (!Util.templateCache) {
Util.templateCache = {};
}
let template = Util.templateCache[templatePath];
if (!template) {
template = Util.readFileSync(templatePath);
if (template) {
Util.templateCache[templatePath] = template;
} else {
Util.logError(`not found template: ${templatePath}`);
}
}
return template;
},
normalizeColorType: (color) => {

@@ -513,2 +391,8 @@ return `${color}`.trim().toLowerCase();

normalizeMaxCols: (maxCols, min = 1) => {
if (Util.isNum(maxCols)) {
return Math.max(maxCols, min);
}
},
getColorStrByStatus: (str, status, color = '') => {

@@ -554,3 +438,3 @@

'tex': () => {
const texStr = str.replace('%', '\\\\%');
const texStr = str.replace(/%/g, '\\\\%');
if (status === 'low') {

@@ -557,0 +441,0 @@ return `$\\color{red}{\\textsf{${texStr}}}$`;

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

const path = require('path');
const EC = require('eight-colors');
const { minimatch } = require('minimatch');
const { mergeScriptCovs } = require('@bcoe/v8-coverage');
const Util = require('../utils/util.js');

@@ -13,4 +10,7 @@ const { getV8Summary } = require('./v8-summary.js');

const { collectSourceMaps } = require('../converter/collect-source-maps.js');
const version = require('../../package.json').version;
const { minimatch } = require('../packages/monocart-coverage-vendor.js');
const { v8Report } = require('../reports/v8.js');
const { v8JsonReport } = require('../reports/v8-json.js');
const getWrapperSource = (offset, source) => {

@@ -317,64 +317,2 @@ // NO \n because it break line number in mappings

const handleV8JsonReport = async (reportData, reportOptions, options) => {
const v8JsonOptions = {
outputFile: 'coverage-report.json',
... reportOptions
};
// console.log(mergedOptions);
const jsonPath = path.resolve(options.outputDir, v8JsonOptions.outputFile);
await Util.writeFile(jsonPath, JSON.stringify(reportData));
return Util.relativePath(jsonPath);
};
const handleV8HtmlReport = async (reportData, reportOptions, options) => {
// V8 only options, merged with root options
const v8HtmlOptions = {
outputFile: options.outputFile,
inline: options.inline,
assetsPath: options.assetsPath,
metrics: options.metrics,
... reportOptions
};
// add metrics to data for UI
reportData.metrics = v8HtmlOptions.metrics;
const {
outputFile, inline, assetsPath
} = v8HtmlOptions;
// resolve full report path
const reportPath = path.resolve(options.outputDir, outputFile);
const outputDir = path.dirname(reportPath);
const htmlFile = path.basename(reportPath);
// deps
const jsFiles = ['monocart-code-viewer', 'monocart-formatter', 'turbogrid'].map((id) => {
return Util.resolveNodeModule(id);
});
// package app ui
jsFiles.push(Util.resolvePackage('monocart-coverage-app.js'));
// console.log(jsFiles);
const htmlOptions = {
reportData,
jsFiles,
inline,
assetsPath,
outputDir,
htmlFile,
reportDataFile: 'coverage-data.js'
};
const htmlPath = await Util.saveHtmlReport(htmlOptions);
return htmlPath;
};
const saveV8Report = async (v8list, options, istanbulReportPath) => {

@@ -394,4 +332,7 @@

const reportData = {
type: 'v8',
// override with saved file path
reportPath: '',
version: Util.version,
name: options.name,
version,
watermarks,

@@ -404,13 +345,11 @@ summary,

const buildInV8Reports = {
'v8': handleV8HtmlReport,
'v8-json': handleV8JsonReport
'v8': v8Report,
'v8-json': v8JsonReport
};
const outputs = {};
const v8Group = options.reportGroup.v8;
const v8Group = options.reportGroup.get('v8');
// could be no v8 only reports, but have `both` data reports
if (v8Group) {
const v8Reports = Object.keys(v8Group);
for (const reportName of v8Reports) {
const reportOptions = v8Group[reportName];
for (const [reportName, reportOptions] of v8Group) {
const buildInHandler = buildInV8Reports[reportName];

@@ -438,3 +377,5 @@ const t1 = Date.now();

type: 'v8',
// html or json
reportPath,
version: Util.version,
name: options.name,

@@ -441,0 +382,0 @@ watermarks,

{
"name": "monocart-coverage-reports",
"version": "2.9.3",
"version": "2.10.0",
"description": "A code coverage tool to generate native V8 reports or Istanbul reports.",

@@ -57,2 +57,3 @@ "main": "./lib/index.js",

"test-all": "node ./test/test.js && node ./scripts/docs.js",
"test-pr": "node --inspect=9230 ./test/test-pr.js",
"test": "npm run test-unit && npx mcr npm run test-all -c test/mcr.config.mcr.js",

@@ -66,3 +67,2 @@ "test:snap": "cross-env TEST_SNAPSHOT=true npm run test",

"workspaces": [
"packages/*",
"test"

@@ -87,3 +87,2 @@ ],

"console-grid": "^2.2.2",
"diff-sequences": "^29.6.3",
"eight-colors": "^1.3.0",

@@ -94,12 +93,11 @@ "foreground-child": "^3.2.1",

"istanbul-reports": "^3.1.7",
"lz-utils": "^2.0.2",
"minimatch": "9.0.5",
"monocart-code-viewer": "^1.1.4",
"monocart-formatter": "^3.0.0",
"monocart-locator": "^1.0.2",
"turbogrid": "^3.2.0"
"lz-utils": "^2.1.0",
"monocart-locator": "^1.0.2"
},
"devDependencies": {
"async-tick": "^1.0.0",
"convert-source-map": "^2.0.0",
"diff-sequences": "^29.6.3",
"esbuild": "^0.23.0",
"eslint": "~9.7.0",
"eslint": "~9.8.0",
"eslint-config-plus": "^2.0.2",

@@ -109,2 +107,6 @@ "eslint-plugin-html": "^8.1.1",

"find-up": "^7.0.0",
"minimatch": "^9.0.5",
"monocart-code-viewer": "^1.1.4",
"monocart-formatter": "^3.0.0",
"postcss": "^8.4.40",
"starfall-cli": "^2.0.20",

@@ -115,4 +117,6 @@ "stylelint": "^16.7.0",

"tsx": "^4.16.2",
"turbogrid": "^3.2.0",
"vine-ui": "^3.1.16",
"ws": "^8.18.0"
}
}

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

- Support for Native Byte Statistics
- Support processing big data with high performance
- Coverage for Any Runtime Code

@@ -119,3 +120,4 @@ - CSS Coverage Support

- `v8-json`
- [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
- Save `CoverageResults` to a json file
- Preview [coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)

@@ -163,2 +165,3 @@ > Istanbul build-in reports (both V8 and Istanbul data):

- `markdown-details` Save coverage details to a markdown file (defaults to `coverage-details.md`).
- Preview in [runs](https://github.com/cenfun/monocart-coverage-reports/actions/workflows/ci.yml)

@@ -165,0 +168,0 @@ - `raw` only keep all original data, which can be used for other reports input with `inputDir`. see [Merge Coverage Reports](#merge-coverage-reports)

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

- 支持原生的Bytes覆盖率指标
- 支持高性能处理大数据
- 支持任何运行时代码的覆盖率(压缩后的)

@@ -119,3 +120,4 @@ - 支持CSS代码覆盖率(用于分析CSS的冗余代码)

- `v8-json`
- [V8 coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)
- 保存 `CoverageResults` 到一个json文件
- 预览 [coverage-report.json](https://cenfun.github.io/monocart-coverage-reports/v8-and-istanbul/coverage-report.json)

@@ -163,2 +165,3 @@ > 内置Istanbul报告 (V8和Istanbul格式数据都支持):

- `markdown-details` 保存覆盖率详情到markdown文件 (默认是 `coverage-details.md`)
- 预览运行结果 [runs](https://github.com/cenfun/monocart-coverage-reports/actions/workflows/ci.yml)

@@ -165,0 +168,0 @@ - `raw` 只是保存原始覆盖率数据, 用于使用`inputDir`参数来导入多个原始数据进行合并报告。参见 [合并覆盖率报告](#merge-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