mirror of
https://github.com/pnpm/pnpm.git
synced 2026-02-01 10:42:28 -05:00
feat: outdated command add sort-by option (#8523)
* feat: `outdated` command add `sortField` option Currently, the default sorting result is a combination of multiple rules, including sorting by `packageName`, sorting by `SemverChange`, and sorting by the `current` field. I wanted to set `sortField` to support configuration of `name`/`semver`/`current`, but considering that the other two values do not seem to make much sense except `name`, I will keep the current situation for the time being. * feat: add changeset * fix: format * chore: update test * test: update * fix: update * refactor: rename to sort-by * refactor: outdated * docs: update changeset --------- Co-authored-by: Zoltan Kochan <z@kochan.io>
This commit is contained in:
6
.changeset/bright-jeans-confess.md
Normal file
6
.changeset/bright-jeans-confess.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/plugin-commands-outdated": minor
|
||||
"pnpm": minor
|
||||
---
|
||||
|
||||
`pnpm outdated` command supports a `--sort-by=name` option for sorting outdated dependencies by package name [#8523](https://github.com/pnpm/pnpm/pull/8523).
|
||||
@@ -23,6 +23,7 @@ import renderHelp from 'render-help'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import {
|
||||
DEFAULT_COMPARATORS,
|
||||
NAME_COMPARATOR,
|
||||
type OutdatedWithVersionDiff,
|
||||
} from './utils'
|
||||
import { outdatedRecursive } from './recursive'
|
||||
@@ -40,6 +41,7 @@ export function rcOptionsTypes (): Record<string, unknown> {
|
||||
], allTypes),
|
||||
compatible: Boolean,
|
||||
format: ['table', 'list', 'json'],
|
||||
'sort-by': 'name',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +107,10 @@ For options that may be used with `-r`, see "pnpm help recursive"',
|
||||
description: 'Don\'t check "optionalDependencies"',
|
||||
name: '--no-optional',
|
||||
},
|
||||
{
|
||||
description: 'Specify the sorting method. Currently only `name` is supported.',
|
||||
name: '--sort-by',
|
||||
},
|
||||
OPTIONS.globalDir,
|
||||
...UNIVERSAL_OPTIONS,
|
||||
],
|
||||
@@ -125,6 +131,7 @@ export type OutdatedCommandOptions = {
|
||||
long?: boolean
|
||||
recursive?: boolean
|
||||
format?: 'table' | 'list' | 'json'
|
||||
sortBy?: 'name'
|
||||
} & Pick<Config,
|
||||
| 'allProjects'
|
||||
| 'ca'
|
||||
@@ -216,7 +223,7 @@ export async function handler (
|
||||
}
|
||||
}
|
||||
|
||||
function renderOutdatedTable (outdatedPackages: readonly OutdatedPackage[], opts: { long?: boolean }): string {
|
||||
function renderOutdatedTable (outdatedPackages: readonly OutdatedPackage[], opts: { long?: boolean, sortBy?: 'name' }): string {
|
||||
if (outdatedPackages.length === 0) return ''
|
||||
const columnNames = [
|
||||
'Package',
|
||||
@@ -241,7 +248,7 @@ function renderOutdatedTable (outdatedPackages: readonly OutdatedPackage[], opts
|
||||
|
||||
const data = [
|
||||
columnNames,
|
||||
...sortOutdatedPackages(outdatedPackages)
|
||||
...sortOutdatedPackages(outdatedPackages, { sortBy: opts.sortBy })
|
||||
.map((outdatedPkg) => columnFns.map((fn) => fn(outdatedPkg))),
|
||||
]
|
||||
let detailsColumnMaxWidth = 40
|
||||
@@ -265,9 +272,9 @@ function renderOutdatedTable (outdatedPackages: readonly OutdatedPackage[], opts
|
||||
})
|
||||
}
|
||||
|
||||
function renderOutdatedList (outdatedPackages: readonly OutdatedPackage[], opts: { long?: boolean }): string {
|
||||
function renderOutdatedList (outdatedPackages: readonly OutdatedPackage[], opts: { long?: boolean, sortBy?: 'name' }): string {
|
||||
if (outdatedPackages.length === 0) return ''
|
||||
return sortOutdatedPackages(outdatedPackages)
|
||||
return sortOutdatedPackages(outdatedPackages, { sortBy: opts.sortBy })
|
||||
.map((outdatedPkg) => {
|
||||
let info = `${chalk.bold(renderPackageName(outdatedPkg))}
|
||||
${renderCurrent(outdatedPkg)} ${chalk.grey('=>')} ${renderLatest(outdatedPkg)}`
|
||||
@@ -294,8 +301,8 @@ export interface OutdatedPackageJSONOutput {
|
||||
latestManifest?: PackageManifest
|
||||
}
|
||||
|
||||
function renderOutdatedJSON (outdatedPackages: readonly OutdatedPackage[], opts: { long?: boolean }): string {
|
||||
const outdatedPackagesJSON: Record<string, OutdatedPackageJSONOutput> = sortOutdatedPackages(outdatedPackages)
|
||||
function renderOutdatedJSON (outdatedPackages: readonly OutdatedPackage[], opts: { long?: boolean, sortBy?: 'name' }): string {
|
||||
const outdatedPackagesJSON: Record<string, OutdatedPackageJSONOutput> = sortOutdatedPackages(outdatedPackages, { sortBy: opts.sortBy })
|
||||
.reduce((acc, outdatedPkg) => {
|
||||
acc[outdatedPkg.packageName] = {
|
||||
current: outdatedPkg.current,
|
||||
@@ -312,9 +319,11 @@ function renderOutdatedJSON (outdatedPackages: readonly OutdatedPackage[], opts:
|
||||
return JSON.stringify(outdatedPackagesJSON, null, 2)
|
||||
}
|
||||
|
||||
function sortOutdatedPackages (outdatedPackages: readonly OutdatedPackage[]) {
|
||||
function sortOutdatedPackages (outdatedPackages: readonly OutdatedPackage[], opts?: { sortBy?: 'name' }) {
|
||||
const sortBy = opts?.sortBy
|
||||
const comparators = (sortBy === 'name') ? [NAME_COMPARATOR] : DEFAULT_COMPARATORS
|
||||
return sortWith(
|
||||
DEFAULT_COMPARATORS,
|
||||
comparators,
|
||||
outdatedPackages.map(toOutdatedWithVersionDiff)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,12 +8,13 @@ export interface OutdatedWithVersionDiff extends OutdatedPackage {
|
||||
|
||||
export type Comparator = (o1: OutdatedWithVersionDiff, o2: OutdatedWithVersionDiff) => number
|
||||
|
||||
export const NAME_COMPARATOR: Comparator = (o1, o2) => o1.packageName.localeCompare(o2.packageName)
|
||||
/**
|
||||
* Default comparators used as the argument to `ramda.sortWith()`.
|
||||
*/
|
||||
export const DEFAULT_COMPARATORS: Comparator[] = [
|
||||
sortBySemverChange,
|
||||
(o1, o2) => o1.packageName.localeCompare(o2.packageName), // eslint-disable-line @typescript-eslint/explicit-module-boundary-types
|
||||
NAME_COMPARATOR,
|
||||
(o1, o2) => (o1.current && o2.current) ? o1.current.localeCompare(o2.current) : 0, // eslint-disable-line @typescript-eslint/explicit-module-boundary-types
|
||||
]
|
||||
|
||||
|
||||
@@ -408,3 +408,29 @@ test('pnpm outdated: catalog protocol', async () => {
|
||||
└─────────────┴─────────┴────────┘
|
||||
`)
|
||||
})
|
||||
|
||||
test('pnpm outdated: support --sortField option', async () => {
|
||||
tempDir()
|
||||
|
||||
fs.copyFileSync(path.join(hasOutdatedDepsFixture, 'pnpm-lock.yaml'), path.resolve('pnpm-lock.yaml'))
|
||||
fs.copyFileSync(path.join(hasOutdatedDepsFixture, 'package.json'), path.resolve('package.json'))
|
||||
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...OUTDATED_OPTIONS,
|
||||
dir: hasOutdatedDepsFixture,
|
||||
sortBy: 'name',
|
||||
})
|
||||
|
||||
expect(exitCode).toBe(1)
|
||||
expect(stripAnsi(output)).toBe(`\
|
||||
┌──────────────────────┬──────────────────────┬────────────┐
|
||||
│ Package │ Current │ Latest │
|
||||
├──────────────────────┼──────────────────────┼────────────┤
|
||||
│ @pnpm.e2e/deprecated │ 1.0.0 │ Deprecated │
|
||||
├──────────────────────┼──────────────────────┼────────────┤
|
||||
│ is-negative │ 1.0.0 (wanted 2.1.0) │ 2.1.0 │
|
||||
├──────────────────────┼──────────────────────┼────────────┤
|
||||
│ is-positive (dev) │ 1.0.0 (wanted 3.1.0) │ 3.1.0 │
|
||||
└──────────────────────┴──────────────────────┴────────────┘
|
||||
`)
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ import { install } from '@pnpm/plugin-commands-installation'
|
||||
import { outdated } from '@pnpm/plugin-commands-outdated'
|
||||
import { preparePackages } from '@pnpm/prepare'
|
||||
import stripAnsi from 'strip-ansi'
|
||||
import { DEFAULT_OPTS } from './utils'
|
||||
import { DEFAULT_OPTS, DEFAULT_OUTDATED_OPTS } from './utils'
|
||||
|
||||
test('pnpm recursive outdated', async () => {
|
||||
preparePackages([
|
||||
@@ -50,7 +50,7 @@ test('pnpm recursive outdated', async () => {
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
@@ -75,7 +75,7 @@ test('pnpm recursive outdated', async () => {
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
production: false,
|
||||
@@ -95,7 +95,7 @@ test('pnpm recursive outdated', async () => {
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
long: true,
|
||||
@@ -121,7 +121,7 @@ test('pnpm recursive outdated', async () => {
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
format: 'list',
|
||||
@@ -151,7 +151,7 @@ Dependent: project-2
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
@@ -192,7 +192,7 @@ Dependent: project-2
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
format: 'list',
|
||||
@@ -227,7 +227,7 @@ https://github.com/kevva/is-positive#readme
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
@@ -265,7 +265,7 @@ test('pnpm recursive outdated: format json when there are no outdated dependenci
|
||||
|
||||
const { allProjects, selectedProjectsGraph } = await filterPackagesFromDir(process.cwd(), [])
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
format: 'json',
|
||||
@@ -320,7 +320,7 @@ test('pnpm recursive outdated in workspace with shared lockfile', async () => {
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
@@ -343,7 +343,7 @@ test('pnpm recursive outdated in workspace with shared lockfile', async () => {
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
production: false,
|
||||
@@ -363,7 +363,7 @@ test('pnpm recursive outdated in workspace with shared lockfile', async () => {
|
||||
|
||||
{
|
||||
const { output, exitCode } = await outdated.handler({
|
||||
...DEFAULT_OPTS,
|
||||
...DEFAULT_OUTDATED_OPTS,
|
||||
allProjects,
|
||||
dir: process.cwd(),
|
||||
recursive: true,
|
||||
|
||||
@@ -53,3 +53,8 @@ export const DEFAULT_OPTS = {
|
||||
workspaceConcurrency: 4,
|
||||
virtualStoreDirMaxLength: 120,
|
||||
}
|
||||
|
||||
export const DEFAULT_OUTDATED_OPTS = {
|
||||
...DEFAULT_OPTS,
|
||||
sortBy: 'name' as const,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user