From c809ad4439d64fcf2579305dd795fb65830fb08d Mon Sep 17 00:00:00 2001 From: Zoltan Kochan Date: Sun, 25 Aug 2019 02:12:23 +0300 Subject: [PATCH] feat(cli): "multi outdated" prints one package only once Every package is printed once, dependent workspace packages are grouped in the last columnt. --- packages/pnpm/src/cmd/outdated.ts | 1 + packages/pnpm/src/cmd/recursive/outdated.ts | 53 +++++++++++++++------ packages/pnpm/test/recursive/outdated.ts | 28 +++++++---- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/packages/pnpm/src/cmd/outdated.ts b/packages/pnpm/src/cmd/outdated.ts index 45f52fe66c..04964ed3a7 100644 --- a/packages/pnpm/src/cmd/outdated.ts +++ b/packages/pnpm/src/cmd/outdated.ts @@ -132,6 +132,7 @@ export async function outdatedDependenciesOfWorkspacePackages ( wantedLockfile, } return { + manifest, outdatedPackages: args.length ? await outdatedForPackages(args, optsForOutdated) : await outdated(optsForOutdated), diff --git a/packages/pnpm/src/cmd/recursive/outdated.ts b/packages/pnpm/src/cmd/recursive/outdated.ts index c3384b5a57..5503312924 100644 --- a/packages/pnpm/src/cmd/recursive/outdated.ts +++ b/packages/pnpm/src/cmd/recursive/outdated.ts @@ -1,10 +1,17 @@ import { getLockfileImporterId } from '@pnpm/lockfile-file' import { DependenciesField, PackageJson, Registries } from '@pnpm/types' import chalk from 'chalk' +import R = require('ramda') import stripColor = require('strip-color') import table = require('text-table') import { outdatedDependenciesOfWorkspacePackages } from '../outdated' +const DEP_PRIORITY: Record = { + optionalDependencies: 0, + dependencies: 1, + devDependencies: 2, +} + export default async ( pkgs: Array<{path: string, manifest: PackageJson}>, args: string[], @@ -35,45 +42,61 @@ export default async ( userAgent: string, }, ) => { - const outdatedPkgs = [] as Array<{ + const outdatedByNameAndType = {} as Record, latest?: string, - prefix: string, + packageName: string, + wanted: string, }> if (opts.lockfileDirectory) { const outdatedPackagesByProject = await outdatedDependenciesOfWorkspacePackages(pkgs, args, opts) - for (let { prefix, outdatedPackages } of outdatedPackagesByProject) { - outdatedPackages.forEach((outdatedPkg: any) => outdatedPkgs.push({ ...outdatedPkg, prefix })) // tslint:disable-line:no-any + for (let { prefix, outdatedPackages, manifest } of outdatedPackagesByProject) { + outdatedPackages.forEach((outdatedPkg) => { + const key = JSON.stringify([outdatedPkg.packageName, outdatedPkg.belongsTo]) + if (!outdatedByNameAndType[key]) { + outdatedByNameAndType[key] = { ...outdatedPkg, dependentPkgs: [] } + } + outdatedByNameAndType[key].dependentPkgs.push({ location: prefix, manifest }) + }) } } else { await Promise.all(pkgs.map(async ({ manifest, path }) => { const { outdatedPackages } = ( await outdatedDependenciesOfWorkspacePackages([{ manifest, path }], args, { ...opts, lockfileDirectory: path }) )[0] - outdatedPackages.forEach((outdatedPkg: any) => // tslint:disable-line:no-any - outdatedPkgs.push({ - ...outdatedPkg, - prefix: getLockfileImporterId(opts.prefix, path), - })) + outdatedPackages.forEach((outdatedPkg) => { + const key = JSON.stringify([outdatedPkg.packageName, outdatedPkg.belongsTo]) + if (!outdatedByNameAndType[key]) { + outdatedByNameAndType[key] = { ...outdatedPkg, dependentPkgs: [] } + } + outdatedByNameAndType[key].dependentPkgs.push({ location: getLockfileImporterId(opts.prefix, path), manifest }) + }) })) } - const columnNames = ['', 'Package', 'Current', 'Wanted', 'Latest', 'Belongs To'].map((txt) => chalk.underline(txt)) + const columnNames = ['Package', 'Current', 'Wanted', 'Latest', 'Belongs To', 'Dependents'].map((txt) => chalk.underline(txt)) console.log( table([ columnNames, - ...outdatedPkgs - .sort((o1, o2) => o1.prefix.localeCompare(o2.prefix)) + ...R.sortWith( + [ + (o1, o2) => o1.packageName.localeCompare(o2.packageName), + (o1, o2) => DEP_PRIORITY[o1.belongsTo] - DEP_PRIORITY[o2.belongsTo], + ], + (Object.values(outdatedByNameAndType)), + ) .map((outdatedPkg) => [ - outdatedPkg.prefix, chalk.yellow(outdatedPkg.packageName), outdatedPkg.current || 'missing', chalk.green(outdatedPkg.wanted), chalk.magenta(outdatedPkg.latest || ''), outdatedPkg.belongsTo, + outdatedPkg.dependentPkgs + .map(({ manifest, location }) => manifest.name || location) + .sort() + .join(', '), ]), ], { stringLength: (s: string) => stripColor(s).length, diff --git a/packages/pnpm/test/recursive/outdated.ts b/packages/pnpm/test/recursive/outdated.ts index 46b714c226..17e8703fc2 100644 --- a/packages/pnpm/test/recursive/outdated.ts +++ b/packages/pnpm/test/recursive/outdated.ts @@ -12,7 +12,7 @@ const test = promisifyTape(tape) const testOnly = promisifyTape(tape.only) test('pnpm recursive outdated', async (t: tape.Test) => { - const projects = preparePackages(t, [ + preparePackages(t, [ { name: 'project-1', version: '1.0.0', @@ -29,6 +29,17 @@ test('pnpm recursive outdated', async (t: tape.Test) => { 'is-negative': '1.0.0', }, }, + { + name: 'project-3', + version: '1.0.0', + + dependencies: { + 'is-positive': '1.0.0', + }, + devDependencies: { + 'is-negative': '1.0.0', + }, + }, ]) await execPnpm('recursive', 'install') @@ -38,10 +49,11 @@ test('pnpm recursive outdated', async (t: tape.Test) => { t.equal(result.status, 0) - t.equal(normalizeNewline(result.stdout.toString()), ' ' + stripIndents` - Package Current Wanted Latest Belongs To - project-1 is-positive 1.0.0 1.0.0 3.1.0 dependencies - project-2 is-negative 1.0.0 1.0.0 2.1.0 dependencies + t.equal(normalizeNewline(result.stdout.toString()), stripIndents` + Package Current Wanted Latest Belongs To Dependents + is-negative 1.0.0 1.0.0 2.1.0 dependencies project-2 + is-negative 1.0.0 1.0.0 2.1.0 devDependencies project-3 + is-positive 1.0.0 1.0.0 3.1.0 dependencies project-1, project-3 ` + '\n') } @@ -50,9 +62,9 @@ test('pnpm recursive outdated', async (t: tape.Test) => { t.equal(result.status, 0) - t.equal(normalizeNewline(result.stdout.toString()), ' ' + stripIndents` - Package Current Wanted Latest Belongs To - project-1 is-positive 1.0.0 1.0.0 3.1.0 dependencies + t.equal(normalizeNewline(result.stdout.toString()), stripIndents` + Package Current Wanted Latest Belongs To Dependents + is-positive 1.0.0 1.0.0 3.1.0 dependencies project-1, project-3 ` + '\n') } })