fix: dynamically calculate column widths in interactive update table (#10585)

* fix: dynamically calculate column widths in interactive update table

* test: implement copilot suggestions

* style: change order of functions

close #10316
This commit is contained in:
Ryo Matsukawa
2026-02-13 15:13:29 +09:00
committed by Zoltan Kochan
parent f503627e5d
commit add108086a
3 changed files with 44 additions and 2 deletions

View File

@@ -0,0 +1,6 @@
---
"@pnpm/plugin-commands-installation": patch
"pnpm": patch
---
Fixed `pnpm update --interactive` table breaking with long version strings (e.g., prerelease versions like `7.0.0-dev.20251209.1`) by dynamically calculating column widths instead of using hardcoded values [#10316](https://github.com/pnpm/pnpm/issues/10316).

View File

@@ -1,3 +1,4 @@
import { stripVTControlCharacters } from 'util'
import colorizeSemverDiff from '@pnpm/colorize-semver-diff'
import { type OutdatedPackage } from '@pnpm/outdated'
import semverDiff from '@pnpm/semver-diff'
@@ -148,8 +149,8 @@ function alignColumns (rows: string[][]): string[] {
columns:
{
0: { width: 50, truncate: 100 },
1: { width: 15, alignment: 'right' },
3: { width: 15 },
1: { width: getColumnWidth(rows, 1, 15), alignment: 'right' },
3: { width: getColumnWidth(rows, 3, 15) },
4: { paddingLeft: 2 },
5: { paddingLeft: 2 },
},
@@ -157,3 +158,10 @@ function alignColumns (rows: string[][]): string[] {
}
).split('\n')
}
function getColumnWidth (rows: string[][], columnIndex: number, minWidth: number): number {
return rows.reduce((max, row) => {
if (row[columnIndex] == null) return max
return Math.max(max, stripVTControlCharacters(row[columnIndex]).length)
}, minWidth)
}

View File

@@ -139,3 +139,31 @@ test('getUpdateChoices()', () => {
},
])
})
test('getUpdateChoices() handles long version strings without wrapping', () => {
const choices = getUpdateChoices([
{
alias: '@typescript/native-preview',
belongsTo: 'devDependencies' as const,
current: '7.0.0-dev.20251209.1',
latestManifest: {
name: '@typescript/native-preview',
version: '7.0.0-dev.20251214.1',
homepage: 'https://github.com/nicolo-ribaudo/tc39-proposal-structs',
},
packageName: '@typescript/native-preview',
wanted: '7.0.0-dev.20251209.1',
},
], false)
const dataRow = choices[0].choices[1] as { message: string; value: string; name: string }
expect(dataRow).toStrictEqual({
message: expect.stringContaining('7.0.0-dev.20251209.1'),
value: '@typescript/native-preview',
name: '@typescript/native-preview',
})
// The rendered message must be a single line (no wrapping)
expect(dataRow.message).not.toContain('\n')
// Both current and target versions must appear in the output
expect(dataRow.message).toContain('7.0.0-dev.20251214.1')
})