import { CliTree, CliTrees, objectPropertiesToCliTrees, writeCliTree } from '@cirrusct/cli-utils'; import { Logger } from '@cirrusct/logging'; import { BuildSpecConfigSettings, createError, MrCommandHandler, MrCommandResults, MrPackage, MrPackageDependency, } from '@cirrusct/mr-core'; import * as chalk from 'chalk'; import * as os from 'os'; import * as Table from 'tty-table'; import { depcheck } from './lib'; import { DepsCommandOptions } from './types'; const getPackageIgnoreDirs = async (mrPackage: MrPackage): Promise => { const buildConfigSettings = mrPackage.config.buildConfig.value; const ignoreMap = {}; if (Array.isArray(buildConfigSettings.exclude)) { buildConfigSettings.exclude.forEach(e => { ignoreMap[e] = e; }); } if (buildConfigSettings.specs) { for (const specName in buildConfigSettings.specs) { if (Array.isArray(buildConfigSettings.specs[specName].exclude)) { buildConfigSettings.specs[specName].exclude.forEach(e => { ignoreMap[e] = e; }); } } } return Object.keys(ignoreMap); }; const writePackageDependencyVersion = (pkg: MrPackage, dependencyName: string, versionRange: string) => { const writer = pkg.createWriter(); writer.setDependencyVersion(dependencyName, versionRange); writer.write(); }; const SemverReleaseTypeLevel = { major: 7, premajor: 6, minor: 5, preminor: 4, patch: 3, prepatch: 2, prerelease: 1, }; const reportDeps = async ( mrPackage: MrPackage, options: DepsCommandOptions, dependencies: MrPackageDependency[], logger: Logger ) => { const header = [ { value: 'Dependency', headerColor: 'cyan', color: 'white', align: 'left', paddingLeft: 2, width: 30, }, { value: 'Current', headerColor: 'cyan', align: 'left', paddingLeft: 2, width: 15, }, { value: 'Latest', headerColor: 'cyan', color: 'white', align: 'left', paddingLeft: 2, width: 15, }, { value: 'Diff', headerColor: 'cyan', color: 'white', align: 'left', paddingLeft: 2, width: 15, }, ]; const rows = []; for (const d of dependencies) { const comparison = await d.getComparisonToLatest(); let diffType: string = comparison.diffType; if (comparison.diffType !== 'none') { let current = d.version; if (comparison.isSatisfied) { current = chalk.green(d.version); } else { switch (comparison.diffType) { case 'patch': current = chalk.greenBright(d.version); diffType = chalk.greenBright(comparison.diffType); break; case 'minor': current = chalk.yellow(d.version); diffType = chalk.yellow(comparison.diffType); break; case 'major': current = chalk.redBright(d.version); diffType = chalk.redBright(comparison.diffType); break; } } rows.push([d.name, current, comparison.latest, diffType]); } } if (rows.length > 0) { const t1 = Table(header, rows, { borderStyle: 1, borderColor: 'blue', paddingBottom: 0, headerAlign: 'center', align: 'center', color: 'white', truncate: '...', }); logger.info(mrPackage.name); logger.write(t1.render() + os.EOL); } else { logger.info( { package: mrPackage.name, }, 'All Dependencies up to date.' ); } }; const reportAndUpdateDeps = async ( mrPackage: MrPackage, options: DepsCommandOptions, dependencies: MrPackageDependency[], logger: Logger ) => { for (const d of dependencies) { const comparison = await d.getComparisonToLatest(); if (comparison.diffType !== 'none') { let current = d.version; if (comparison.isSatisfied) { current = chalk.green(d.version); } else { switch (comparison.diffType) { case 'patch': current = chalk.greenBright(d.version); break; case 'minor': current = chalk.yellow(d.version); break; case 'major': current = chalk.redBright(d.version); break; } } logger.debug( { dependency: d.name, ...comparison, }, 'Dependency Comparison' ); if (options.update) { const updateToLevel = SemverReleaseTypeLevel[options.update]; if (!updateToLevel) { throw createError(`Invalid update level: ${options.update}`); } const diffTypeLevel = SemverReleaseTypeLevel[comparison.diffType]; if (diffTypeLevel <= updateToLevel) { logger.info( { dependency: d.name, declared: comparison.declared, target: comparison.targetRange, diff: comparison.diffType, 'package.json': mrPackage.filePath, }, `Updating Dependency '${d.name}' in package.json for ${mrPackage.name}` ); writePackageDependencyVersion(mrPackage, d.name, comparison.targetRange); } else { logger.debug( { dependency: d.name, declared: comparison.declared, target: comparison.targetRange, diff: comparison.diffType, }, `Skipping Dependency update of ${d.name}. version diff: '${comparison.diffType}' greater than specified option: '${options.update}'` ); } } } } }; const showUsage = async (mrPackage: MrPackage, logger: Logger) => { const ignoreDirs = await getPackageIgnoreDirs(mrPackage); const depCheckResults = await depcheck(mrPackage.path, { ignoreDirs }); logger.info(depCheckResults, 'Usage'); }; export const handleCommand: MrCommandHandler = async ({ options, session, logger, currentPackage, config, }) => { debugger; const includedDeps = currentPackage.getDependencies(options.include); if (options.update) { await reportAndUpdateDeps(currentPackage, options, includedDeps, logger); } else { await reportDeps(currentPackage, options, includedDeps, logger); } if (options.showUsage) { await showUsage(currentPackage, logger); } };