dependency-cruiser
Version:
Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.
175 lines (154 loc) • 5.29 kB
JavaScript
import meta from "../meta.js";
import errorHtmlUtl from "./error-html/utl.mjs";
const { aggregateViolations, determineTo, determineFromExtras } = errorHtmlUtl;
const REPORT_DEFAULTS = {
showTitle: true,
title: "## Forbidden dependency check - results",
showSummary: true,
showSummaryHeader: true,
summaryHeader: "### :chart_with_upwards_trend: Summary",
showStatsSummary: true,
showRulesSummary: true,
includeIgnoredInSummary: true,
showDetails: true,
includeIgnoredInDetails: true,
showDetailsHeader: true,
detailsHeader: "### :fire: All violations",
collapseDetails: true,
collapsedMessage: "Violations found - click to expand",
noViolationsMessage:
":revolving_hearts: No violations found. Get gummy bears to celebrate.",
showFooter: true,
footer: `---\n[dependency-cruiser@${
meta.version
}](https://www.github.com/sverweij/dependency-cruiser) / ${new Date().toISOString()}`,
};
/**
*
* @param {import("../../types/shared-types.js").SeverityType} pSeverity
*/
function severity2Icon(pSeverity) {
const lSeverity2IconMap = {
error: ":exclamation:",
info: ":grey_exclamation:",
ignore: ":see_no_evil:",
};
// eslint-disable-next-line security/detect-object-injection
return lSeverity2IconMap[pSeverity] || ":warning:";
}
/**
*
* @param {import("../../types/cruise-result.js").ISummary} pSummary
*/
function formatStatsSummary(pSummary) {
const lSpacerLength = 4;
const lSpacer = " ".repeat(lSpacerLength);
return `**${pSummary.totalCruised}** modules${lSpacer}**${pSummary.totalDependenciesCruised}** dependencies${lSpacer}**${pSummary.error}** errors${lSpacer}**${pSummary.warn}** warnings${lSpacer}**${pSummary.info}** informational${lSpacer}**${pSummary.ignore}** ignored\n`;
}
/**
*
* @param {import("../../types/cruise-result.js").ICruiseResult} pCruiseResult
* @param {Boolean} pIncludeIgnoredInSummary
* @return {string}
*/
function formatRulesSummary(pCruiseResult, pIncludeIgnoredInSummary) {
const lTableHead =
"|rule|violations|ignored|explanation\n|:---|:---:|:---:|:---|\n";
return aggregateViolations(
pCruiseResult.summary.violations,
pCruiseResult.summary.ruleSetUsed
)
.filter(
(pRule) =>
pRule.count > 0 || (pIncludeIgnoredInSummary && pRule.ignoredCount > 0)
)
.reduce(
(pAll, pRule) =>
`${pAll}|${severity2Icon(pRule.severity)} _${pRule.name}_|**${
pRule.count
}**|**${pRule.ignoredCount}**|${pRule.comment}|\n`,
lTableHead
);
}
/**
*
* @param {import("../../types/cruise-result.js").IViolation[]} pViolations
* @param {boolean} pIncludeIgnoredInDetails
* @return {string}
*/
function formatViolations(pViolations, pIncludeIgnoredInDetails) {
const lTableHead = "|violated rule|module|to|\n|:---|:---|:---|\n";
return pViolations
.filter(
(pViolation) =>
pViolation.rule.severity !== "ignore" || pIncludeIgnoredInDetails
)
.reduce((pAll, pViolation) => {
const lFromExtras = determineFromExtras(pViolation);
const lTo = determineTo(pViolation);
return `${pAll}|${severity2Icon(pViolation.rule.severity)} _${
pViolation.rule.name
}_|${pViolation.from}${lFromExtras}|${lTo}|\n`;
}, lTableHead);
}
/**
*
* @param {import("../../types/cruise-result.js").ICruiseResult} pResults
* @param {import("../../types/reporter-options.js").IMarkdownReporterOptions} pOptions
*/
// eslint-disable-next-line complexity, max-statements
function report(pResults, pOptions) {
const lOptions = { ...REPORT_DEFAULTS, ...(pOptions || {}) };
let lReturnValue = "";
if (lOptions.showTitle) {
lReturnValue += `${lOptions.title}\n\n`;
}
if (lOptions.showSummary) {
if (lOptions.showSummaryHeader) {
lReturnValue += `${lOptions.summaryHeader}\n\n`;
}
lReturnValue += `${formatStatsSummary(pResults.summary)}\n\n`;
if (pResults.summary.violations.length > 0 && lOptions.showRulesSummary) {
lReturnValue += `${formatRulesSummary(
pResults,
lOptions.includeIgnoredInSummary
)}\n\n`;
}
}
if (lOptions.showDetails) {
if (pResults.summary.violations.length > 0) {
if (lOptions.showDetailsHeader) {
lReturnValue += `${lOptions.detailsHeader}\n\n`;
}
if (lOptions.collapseDetails) {
lReturnValue += `<details><summary>${lOptions.collapsedMessage}</summary>\n\n`;
}
lReturnValue += `${formatViolations(
pResults.summary.violations,
lOptions.includeIgnoredInDetails
)}\n\n`;
if (lOptions.collapseDetails) {
lReturnValue += "</details>\n\n";
}
} else {
lReturnValue += `${lOptions.noViolationsMessage}\n\n`;
}
}
if (lOptions.showFooter) {
lReturnValue += `${lOptions.footer}\n\n`;
}
return lReturnValue;
}
/**
* Returns the violations from a cruise in markdown format
*
* @param {import("../../types/cruise-result.js").ICruiseResult} pResults
* @param {import("../../types/reporter-options.js").IMarkdownReporterOptions} pOptions
* @returns {import("../../types/dependency-cruiser.js").IReporterOutput}
*/
export default function markdown(pResults, pOptions) {
return {
output: report(pResults, pOptions),
exitCode: 0,
};
}