UNPKG

@ui5/cli

Version:
174 lines (162 loc) 5.83 kB
// Tree import baseMiddleware from "../middlewares/base.js"; import chalk from "chalk"; const tree = { command: "tree", aliases: ["ls", "list"], describe: "Outputs the dependency tree of the current project to stdout. " + "It takes all relevant parameters of ui5 build into account.", middlewares: [baseMiddleware] }; tree.builder = function(cli) { return cli .option("flat", { describe: "Output a flat list of all dependencies instead of a tree hierarchy", type: "boolean", default: false }) .option("level", { describe: "Limit the number of levels shown in the tree hierarchy", type: "number" }) .option("framework-version", { describe: "Overrides the framework version defined by the project. " + "Takes the same value as the version part of \"ui5 use\"", type: "string" }) .option("cache-mode", { describe: "Cache mode to use when consuming SNAPSHOT versions of framework dependencies. " + "The 'Default' behavior is to invalidate the cache after 9 hours. 'Force' uses the cache only and " + "does not create any requests. 'Off' invalidates any existing cache and updates from the repository", type: "string", default: "Default", choices: ["Default", "Force", "Off"] }); }; tree.handler = async function(argv) { let startTime; let elapsedTime; if (argv.perf) { startTime = process.hrtime(); } const {graphFromStaticFile, graphFromPackageDependencies} = await import("@ui5/project/graph"); let graph; if (argv.dependencyDefinition) { graph = await graphFromStaticFile({ filePath: argv.dependencyDefinition, versionOverride: argv.frameworkVersion, cacheMode: argv.cacheMode, }); } else { graph = await graphFromPackageDependencies({ rootConfigPath: argv.config, versionOverride: argv.frameworkVersion, cacheMode: argv.cacheMode, workspaceConfigPath: argv.workspaceConfig, workspaceName: argv.workspace === false ? null : argv.workspace, }); } if (argv.perf) { elapsedTime = await getElapsedTime(startTime); } let requestedLevels; if (argv.level !== undefined && isNaN(argv.level)) { throw new Error(`The provided 'level' option is not a number`); } else if (argv.level !== undefined) { requestedLevels = argv.level; } else { requestedLevels = Infinity; } const projects = new Map(); const indentWidth = 4; await graph.traverseBreadthFirst(async ({project, dependencies}) => { projects.set(project.getName(), { render: function(level, connectorIndices, lastChild, renderDeps = true) { let baseString = " ".repeat(level * indentWidth); connectorIndices.forEach((idx) => { baseString = `${baseString.slice(0, idx)}${baseString.slice(idx + 1)}`; }); const connectorString = lastChild ? "╰─" : "├─"; let name = chalk.bold(project.getName()); if (project.isFrameworkProject()) { name = chalk.blue(name); } process.stdout.write( `${baseString}${connectorString} ${name} ` + `${project.getNamespace() ? chalk.inverse(project.getNamespace()) + " " : ""}` + chalk.dim(`(${project.getVersion()}, ${project.getType()}) `) + chalk.dim.italic(`${project.getRootPath()}`) ); process.stdout.write("\n"); const lastIdx = dependencies.length - 1; const newConnectorIndices = [...connectorIndices]; if (!lastChild) { newConnectorIndices.push(level * indentWidth); } if (level >= requestedLevels) { const msg = chalk.dim.italic(`Dependencies below Level ${level} are hidden`); let nextBaseString = " ".repeat((level + 1) * indentWidth); newConnectorIndices.forEach((idx) => { nextBaseString = `${nextBaseString.slice(0, idx)}${nextBaseString.slice(idx + 1)}`; }); process.stdout.write(`${nextBaseString}╰─ ${msg}`); process.stdout.write("\n"); return; } if (renderDeps) { dependencies.forEach((dep, i) => { projects.get(dep).render(level + 1, newConnectorIndices, i === lastIdx); }); } } }); }); process.stdout.write(chalk.bold.underline(`Dependencies (${projects.size}):`)); process.stdout.write("\n"); if (argv.flat) { // Iterate over list of projects, rendering each individually // We need to transform the map into an array in order to know the index // for determining whether we are rendering the last entry (lastChild param) Array.from(projects.values()).forEach(({render: renderProject}, idx, arr) => { renderProject(0, [], idx == arr.length -1, false); }); } else { // Recursively render the tree, starting with the first entry of the map projects.values().next().value.render(0, [], true); } process.stdout.write("\n"); const extensionNames = graph.getExtensionNames(); const extensionCount = extensionNames.length; process.stdout.write(chalk.bold.underline(`Extensions (${extensionCount}):`)); process.stdout.write("\n"); if (extensionCount) { const lastIdx = extensionCount - 1; extensionNames.forEach((extensionName, idx) => { const extension = graph.getExtension(extensionName); const connectorString = idx === lastIdx ? "╰─" : "├─"; process.stdout.write( `${connectorString} ${extensionName} ` + chalk.dim(`(${extension.getVersion()}, ${extension.getType()}) `) + chalk.dim.italic(`${extension.getRootPath()}`)); process.stdout.write("\n"); }); } else { process.stdout.write(chalk.italic(`None`)); process.stdout.write("\n"); } if (argv.perf) { process.stderr.write("\n"); process.stderr.write(chalk.blue( `Dependency graph generation took ${chalk.bold(elapsedTime)}`)); process.stderr.write("\n"); } }; async function getElapsedTime(startTime) { const timeDiff = process.hrtime(startTime); const {default: prettyHrtime} = await import("pretty-hrtime"); return prettyHrtime(timeDiff); } export default tree;