UNPKG

dependency-cruiser

Version:

Validate and visualize dependencies. With your rules. JavaScript, TypeScript, CoffeeScript. ES6, CommonJS, AMD.

169 lines (148 loc) 5.08 kB
import { EOL } from "node:os"; import chalk from "chalk"; import figures from "figures"; import { findRuleByName } from "../graph-utl/rule-set.mjs"; import wrapAndIndent from "../utl/wrap-and-indent.mjs"; import { formatPercentage, formatViolation as _formatViolation, } from "./utl/index.mjs"; const SEVERITY2CHALK = { error: chalk.red, warn: chalk.yellow, info: chalk.cyan, ignore: chalk.gray, }; const EXTRA_PATH_INFORMATION_INDENT = 6; function formatExtraPathInformation(pExtra) { return EOL.concat( wrapAndIndent( pExtra.join(` ${figures.arrowRight} ${EOL}`), EXTRA_PATH_INFORMATION_INDENT ) ); } function formatModuleViolation(pViolation) { return chalk.bold(pViolation.from); } function formatDependencyViolation(pViolation) { return `${chalk.bold(pViolation.from)} ${figures.arrowRight} ${chalk.bold( pViolation.to )}`; } function formatCycleViolation(pViolation) { return `${chalk.bold(pViolation.from)} ${ figures.arrowRight } ${formatExtraPathInformation(pViolation.cycle)}`; } function formatReachabilityViolation(pViolation) { return `${chalk.bold(pViolation.from)} ${figures.arrowRight} ${chalk.bold( pViolation.to )}${formatExtraPathInformation(pViolation.via)}`; } function formatInstabilityViolation(pViolation) { return `${formatDependencyViolation(pViolation)}${EOL}${wrapAndIndent( chalk.dim( `instability: ${formatPercentage(pViolation.metrics.from.instability)} ${ figures.arrowRight } ${formatPercentage(pViolation.metrics.to.instability)}` ), EXTRA_PATH_INFORMATION_INDENT )}`; } function formatViolation(pViolation) { const lViolationType2Formatter = { module: formatModuleViolation, dependency: formatDependencyViolation, cycle: formatCycleViolation, reachability: formatReachabilityViolation, instability: formatInstabilityViolation, }; const lFormattedViolators = _formatViolation( pViolation, lViolationType2Formatter, formatDependencyViolation ); return ( `${SEVERITY2CHALK[pViolation.rule.severity](pViolation.rule.severity)} ${ pViolation.rule.name }: ${lFormattedViolators}` + `${ pViolation.comment ? `${EOL}${wrapAndIndent(chalk.dim(pViolation.comment))}${EOL}` : "" }` ); } function formatMeta(pMeta) { return `${pMeta.error} errors, ${pMeta.warn} warnings`; } function sumMeta(pMeta) { return pMeta.error + pMeta.warn + pMeta.info; } function formatSummary(pSummary) { let lMessage = `${EOL}${figures.cross} ${sumMeta( pSummary )} dependency violations (${formatMeta(pSummary)}). ${ pSummary.totalCruised } modules, ${pSummary.totalDependenciesCruised} dependencies cruised.${EOL}`; return pSummary.error > 0 ? chalk.red(lMessage) : lMessage; } function addExplanation(pRuleSet, pLong) { return pLong ? (pViolation) => ({ ...pViolation, comment: findRuleByName(pRuleSet, pViolation.rule.name)?.comment ?? "-", }) : (pViolation) => pViolation; } function formatIgnoreWarning(pNumberOfIgnoredViolations) { if (pNumberOfIgnoredViolations > 0) { return chalk.yellow( `${figures.warning} ${pNumberOfIgnoredViolations} known violations ignored. Run with --no-ignore-known to see them.${EOL}` ); } return ""; } function report(pResults, pLong) { const lNonIgnorableViolations = pResults.summary.violations.filter( (pViolation) => pViolation.rule.severity !== "ignore" ); if (lNonIgnorableViolations.length === 0) { return `${EOL}${chalk.green( figures.tick )} no dependency violations found (${ pResults.summary.totalCruised } modules, ${ pResults.summary.totalDependenciesCruised } dependencies cruised)${EOL}${formatIgnoreWarning( pResults.summary.ignore )}${EOL}`; } return lNonIgnorableViolations .reverse() .map(addExplanation(pResults.summary.ruleSetUsed, pLong)) .reduce((pAll, pThis) => `${pAll} ${formatViolation(pThis)}${EOL}`, EOL) .concat(formatSummary(pResults.summary)) .concat(formatIgnoreWarning(pResults.summary.ignore)) .concat(EOL); } /** * Returns the results of a cruise in a text only format, reminiscent of how eslint * prints to stdout: * - for each violation a message stating the violation name and the to and from * - a summary with total number of errors and warnings found, and the total * number of files cruised * @param {import("../../types/cruise-result.js").ICruiseResult} pResults - * @param {any} pOptions - An object with options; * {boolean} long - whether or not to include an explanation * (/ comment) which each violation * @returns {import("../../types/dependency-cruiser.js").IReporterOutput} - output: the formatted text in a string * exitCode: the number of errors found */ export default function error(pResults, pOptions) { return { output: report(pResults, (pOptions || {}).long), exitCode: pResults.summary.error, }; }