return vm.upgradePackageDefinitions(current, options).spread(async (upgraded, latest) => { const {newPkgData, selectedNewDependencies} = await vm.upgradePackageData(pkgData, current, upgraded, latest, options); const output = options.jsonAll ? jph.parse(newPkgData) : options.jsonDeps ? _.pick(jph.parse(newPkgData), 'dependencies', 'devDependencies', 'optionalDependencies') : selectedNewDependencies; // print if (options.json) { // use the selectedNewDependencies dependencies data to generate new package data // INVARIANT: we don't need try-catch here because pkgData has already been parsed as valid JSON, and vm.upgradePackageData simply does a find-and-replace on that printJson(options, output); } else { printUpgrades(options, { current, upgraded: selectedNewDependencies, latest }); } // write // TODO: All this is just to get numUpgraded here. This is repeated in printUpgrades. const deps = Object.keys(upgraded); const satisfied = cint.toObject(deps, dep => cint.keyValue(dep, vm.isSatisfied(latest[dep], current[dep])) ); const isSatisfied = _.propertyOf(satisfied); const filteredUpgraded = options.minimal ? cint.filterObject(upgraded, cint.not(isSatisfied)) : upgraded; const numUpgraded = Object.keys(filteredUpgraded).length; if (numUpgraded > 0) { // if error-level is 2, immediately exit with error code if (options.errorLevel === 2) { programError(options, '\nDependencies not up-to-date'); } // if there is a package file, write the new package data // otherwise, suggest ncu -u if (pkgFile) { if (options.upgrade) { // short-circuit return in order to wait for write operation, but still return the same output return writePackageFile(pkgFile, newPkgData) .then(() => { print(options, `\nRun ${chalk.cyan('npm install')} to install new versions.\n`); return output; }); } else { print(options, `\nRun ${chalk.cyan('ncu -u')} to upgrade ${getPackageFileName(options)}`); } } } return output; });
/** * @param args.current * @param args.upgraded * @param args.latest (optional) */ function printUpgrades(options, args) { // split the deps into satisfied and unsatisfied to display in two separate tables const deps = Object.keys(args.upgraded); const satisfied = cint.toObject(deps, dep => cint.keyValue(dep, vm.isSatisfied(args.latest[dep], args.current[dep])) ); const isSatisfied = _.propertyOf(satisfied); const upgraded = options.minimal ? cint.filterObject(args.upgraded, cint.not(isSatisfied)) : args.upgraded; const numUpgraded = Object.keys(upgraded).length; print(options, ''); // print everything is up-to-date if (numUpgraded === 0) { const smiley = chalk.green.bold(':)'); if (Object.keys(args.current).length === 0) { print(options, 'No dependencies.'); } else if (options.global) { print(options, `All global packages are up-to-date ${smiley}`); } else { print(options, `All dependencies match the ${vm.getVersionTarget(options)} package versions ${smiley}`); } } // print table if (numUpgraded > 0) { // ToDo this code seems wrong, there is parameter mismatch const table = toDependencyTable({ from: args.current, to: upgraded }); print(options, table.toString()); } }
// TODO: printUpgrades and analyzeProjectDependencies need to be refactored. They are tightly coupled and monolithic. /** * @param args.current * @param args.upgraded * @param args.installed (optional) * @param args.latest (optional) * @param args.pkgData * @param args.pkgFile (optional) * @param args.isUpgrade (optional) */ function printUpgrades(args) { // split the deps into satisfied and unsatisfied to display in two separate tables var deps = Object.keys(args.upgraded); var satisfied = cint.toObject(deps, function (dep) { return cint.keyValue(dep, vm.isSatisfied(args.latest[dep], args.current[dep])); }); var isSatisfied = _.propertyOf(satisfied); var satisfiedUpgraded = cint.filterObject(args.upgraded, function (dep) { return isSatisfied(dep) && (!args.latest || !args.installed || args.latest[dep] !== args.installed[dep]); }); var unsatisfiedUpgraded = cint.filterObject(args.upgraded, cint.not(isSatisfied)); var numSatisfied = Object.keys(satisfiedUpgraded).length; var numUnsatisfied = Object.keys(unsatisfiedUpgraded).length; print(''); // print everything is up-to-date if (numSatisfied === 0 && numUnsatisfied === 0) { var smiley = chalk.yellow(':)'); if (options.global) { print('All global packages are up-to-date ' + smiley); } else { print('All dependencies match the ' + getVersionTarget(options) + ' package versions ' + smiley); } } // print unsatisfied table if (numUnsatisfied > 0) { var unsatisfiedTable = toDependencyTable({ from: args.current, to: unsatisfiedUpgraded }, { greatest: options.greatest, newest: options.newest }); print(unsatisfiedTable.toString()); } // print satisfied table if (numSatisfied > 0) { var satisfiedTable = toDependencyTable({ from: args.current, to: satisfiedUpgraded }, { greatest: options.greatest, newest: options.newest }); print((numUnsatisfied > 0 ? '\n' : '') + 'The following dependenc' + (numSatisfied === 1 ? 'y is' : 'ies are') + ' satisfied by ' + (numSatisfied === 1 ? 'its' : 'their') + ' declared version range, but the installed version' + (numSatisfied === 1 ? ' is' : 's are') + ' behind. You can install the latest version' + (numSatisfied === 1 ? '' : 's') + ' without modifying your package file by using ' + chalk.blue(options.packageManager + ' update') + '. If you want to update the dependenc' + (numSatisfied === 1 ? 'y' : 'ies') + ' in your package file anyway, use ' + chalk.cyan('ncu ') + chalk.blue('-a/--upgradeAll') + '.\n'); print(satisfiedTable.toString()); } var numToUpgrade = numUnsatisfied + (options.upgradeAll ? numSatisfied : 0); if (args.pkgFile && numToUpgrade > 0) { if (options.errorLevel >= 2) { programError('Dependencies not up-to-date'); } else if (args.isUpgrade) { var newPkgData = vm.updatePackageData(args.pkgData, args.current, args.upgraded, args.latest, options); writePackageFile(args.pkgFile, newPkgData) .then(function () { print('Upgraded ' + args.pkgFile + '\n'); }); } else { print('\nRun ' + chalk.cyan('ncu') + ' with ' + chalk.blue(numUnsatisfied > 0 ? '-u' : '-a') + ' to upgrade ' + getPackageFileName()); } } print(''); }
/** Creates a new object with only the properties of the given that are not undefined. */ function pruned(obj) { return _.pick(obj, cint.not(_.isUndefined)) }