UNPKG

dependency-cruiser

Version:

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

147 lines (131 loc) 5.54 kB
/* eslint-disable security/detect-object-injection */ import { writeFileSync } from "node:fs"; import figures from "figures"; import chalk from "chalk"; import wrapAndIndent from "../../utl/wrap-and-indent.mjs"; import { PACKAGE_MANIFEST as _PACKAGE_MANIFEST } from "../defaults.mjs"; import { readManifest } from "./environment-helpers.mjs"; import { folderNameArrayToRE } from "./utl.mjs"; const PACKAGE_MANIFEST = `./${_PACKAGE_MANIFEST}`; const EXPERIMENTAL_SCRIPT_DOC = [ { name: "depcruise", headline: "npm run depcruise", description: "validates against the rules in .dependency-cruiser.js and writes the outcome to stdout", }, { name: "depcruise:html", headline: "npm run depcruise:html", description: "validates against the rules in .dependency-cruiser.js and writes it to 'dependency-violation-report.html' with a friendly layout", }, { name: "depcruise:graph", headline: "npm run depcruise:graph", description: "writes a detailed internal graph of your app to 'dependency-graph.html'", }, { name: "depcruise:graph:dev", headline: "npm run depcruise:graph:dev", description: "opens a detailed internal graph of your app in your default browser (uses the 'browser' command line program)", }, { name: "depcruise:graph:archi", headline: "depcruise:graph:archi", description: "writes a high-level internal graph of your app to 'high-level-dependency-graph.html", }, { name: "depcruise:focus", headline: "npm run depcruise:focus <regex>", description: "writes all dependencies to and from modules matching the given <regex> to stdout - in simple text", }, // { // name: "depcruise:text", // headline: "", // description: "", // }, ]; /** * @param {import("./types").IInitConfig} pInitOptions * @return {any} an bunch of key value pairs that can be plonked into a `scripts` attribute in a package.json */ export function compileRunScripts(pInitOptions) { let lReturnValue = {}; if (pInitOptions && (pInitOptions.sourceLocation || []).length > 0) { const lSourceLocations = pInitOptions.sourceLocation.join(" "); const lSourceLocationRE = folderNameArrayToRE(pInitOptions.sourceLocation); const lTestLocations = (pInitOptions.testLocation || []).join(" "); lReturnValue = { depcruise: `depcruise ${lSourceLocations} ${lTestLocations} --config`, "depcruise:graph": `depcruise ${lSourceLocations} --include-only '${lSourceLocationRE}' --config --output-type dot | dot -T svg | depcruise-wrap-stream-in-html > dependency-graph.html`, "depcruise:graph:dev": `depcruise ${lSourceLocations} --include-only '${lSourceLocationRE}' --prefix vscode://file/$(pwd)/ --config --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser`, "depcruise:graph:archi": `depcruise ${lSourceLocations} --include-only '${lSourceLocationRE}' --config --output-type archi | dot -T svg | depcruise-wrap-stream-in-html > high-level-dependency-graph.html`, "depcruise:html": `depcruise ${lSourceLocations} ${lTestLocations} --progress --config --output-type err-html --output-to dependency-violation-report.html`, "depcruise:text": `depcruise ${lSourceLocations} ${lTestLocations} --progress --config --output-type text`, "depcruise:focus": `depcruise ${lSourceLocations} ${lTestLocations} --progress --config --output-type text --focus`, }; } return lReturnValue; } /** * Return the scripts in pAdditionalRunScripts that don't yet exist in * pExistingRunScripts * * @param {any} pAdditionalRunScripts * @param {any} pExistingRunScripts * * @return {any} the scripts in pAdditionalRunScripts that don't yet exist in * pExistingRunScripts */ function filterNewScriptEntries(pExistingRunScripts, pAdditionalRunScripts) { return Object.keys(pAdditionalRunScripts || {}) .filter((pKey) => !pExistingRunScripts[pKey]) .reduce((pAll, pKey) => { pAll[pKey] = pAdditionalRunScripts[pKey]; return pAll; }, {}); } export function addRunScriptsToManifest(pManifest, pAdditionalRunScripts) { const lManifest = { ...(pManifest || {}) }; const lExistingRunScripts = lManifest.scripts || {}; // This could instead simply be done with // {...pAdditionalScriptEntries, ...lManifest} and no logic at all, // but that'd add the new scripts on top, which doesn't feel right // // An alternative would be to sort the keys - but that'd be rude lManifest.scripts = { ...lExistingRunScripts, ...filterNewScriptEntries(lExistingRunScripts, pAdditionalRunScripts), }; return lManifest; } function getSuccessMessage(pDestinationManifestFileName) { const lExplanationIndent = 6; return EXPERIMENTAL_SCRIPT_DOC.reduce((pAll, pScript) => { return `${pAll}${ `\n ${chalk.green(figures.play)} ${pScript.headline}` + `\n${wrapAndIndent(`${pScript.description}`, lExplanationIndent)}\n\n` }`; }, ` ${chalk.green(figures.tick)} Run scripts added to '${pDestinationManifestFileName}':\n`); } export function writeRunScriptsToManifest( pNormalizedInitOptions, pManifest = readManifest(), pDestinationManifestFileName = PACKAGE_MANIFEST ) { const lUpdatedManifest = addRunScriptsToManifest( pManifest, compileRunScripts(pNormalizedInitOptions) ); writeFileSync( pDestinationManifestFileName, JSON.stringify(lUpdatedManifest, null, " "), "utf8" ); process.stdout.write(getSuccessMessage(pDestinationManifestFileName)); }