Skip to content

Commit 104c907

Browse files
committed
feat(@angular/cli): enhance ng version output with more details
The `ng version` command output is enhanced to provide more comprehensive diagnostic information, making it easier for developers to inspect their environment. These changes include: - The Angular Framework version is now displayed prominently in the header section for quick reference. - The package table now includes a "Requested Version" column, showing the version specified in the workspace `package.json`. This helps in quickly identifying any discrepancies between requested and installed versions. - The columns in the package table have been reordered to `Package`, `Installed Version`, `Requested Version` to prioritize the most critical information and improve the logical flow.
1 parent ae746a6 commit 104c907

File tree

2 files changed

+72
-30
lines changed

2 files changed

+72
-30
lines changed

packages/angular/cli/src/commands/version/cli.ts

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import type { Argv } from 'yargs';
1010
import { CommandModule, CommandModuleImplementation } from '../../command-builder/command-module';
1111
import { colors } from '../../utilities/color';
1212
import { RootCommands } from '../command-config';
13-
import { gatherVersionInfo } from './version-info';
13+
import { PackageVersionInfo, gatherVersionInfo } from './version-info';
1414

1515
/**
1616
* The Angular CLI logo, displayed as ASCII art.
@@ -67,6 +67,7 @@ export default class VersionCommandModule
6767

6868
const {
6969
cli: { version: ngCliVersion },
70+
framework,
7071
system: {
7172
node: { version: nodeVersion, unsupported: unsupportedNodeVersion },
7273
os: { platform: os, architecture: arch },
@@ -75,8 +76,13 @@ export default class VersionCommandModule
7576
packages,
7677
} = versionInfo;
7778

78-
const headerInfo = [
79-
{ label: 'Angular CLI', value: ngCliVersion },
79+
const headerInfo = [{ label: 'Angular CLI', value: ngCliVersion }];
80+
81+
if (framework.version) {
82+
headerInfo.push({ label: 'Angular', value: framework.version });
83+
}
84+
85+
headerInfo.push(
8086
{
8187
label: 'Node.js',
8288
value: `${nodeVersion}${unsupportedNodeVersion ? colors.yellow(' (Unsupported)') : ''}`,
@@ -86,7 +92,7 @@ export default class VersionCommandModule
8692
value: `${packageManagerName} ${packageManagerVersion ?? '<error>'}`,
8793
},
8894
{ label: 'Operating System', value: `${os} ${arch}` },
89-
];
95+
);
9096

9197
const maxHeaderLabelLength = Math.max(...headerInfo.map((l) => l.label.length));
9298

@@ -113,38 +119,56 @@ export default class VersionCommandModule
113119
* @param versions A map of package names to their versions.
114120
* @returns A string containing the formatted package table.
115121
*/
116-
private formatPackageTable(versions: Record<string, string>): string {
122+
private formatPackageTable(versions: Record<string, PackageVersionInfo>): string {
117123
const versionKeys = Object.keys(versions);
118124
if (versionKeys.length === 0) {
119125
return '';
120126
}
121127

122-
const nameHeader = 'Package';
123-
const versionHeader = 'Version';
128+
const headers = {
129+
name: 'Package',
130+
installed: 'Installed Version',
131+
requested: 'Requested Version',
132+
};
124133

125-
const maxNameLength = Math.max(nameHeader.length, ...versionKeys.map((key) => key.length));
126-
const maxVersionLength = Math.max(
127-
versionHeader.length,
128-
...versionKeys.map((key) => versions[key].length),
134+
const maxNameLength = Math.max(headers.name.length, ...versionKeys.map((key) => key.length));
135+
const maxInstalledLength = Math.max(
136+
headers.installed.length,
137+
...versionKeys.map((key) => versions[key].installed.length),
138+
);
139+
const maxRequestedLength = Math.max(
140+
headers.requested.length,
141+
...versionKeys.map((key) => versions[key].requested.length),
129142
);
130143

131144
const tableRows = versionKeys
132145
.map((module) => {
146+
const { requested, installed } = versions[module];
133147
const name = module.padEnd(maxNameLength);
134-
const version = versions[module];
135-
const coloredVersion = version === '<error>' ? colors.red(version) : colors.cyan(version);
136-
const padding = ' '.repeat(maxVersionLength - version.length);
137148

138-
return `│ ${name}${coloredVersion}${padding} │`;
149+
const coloredInstalled =
150+
installed === '<error>' ? colors.red(installed) : colors.cyan(installed);
151+
const installedPadding = ' '.repeat(maxInstalledLength - installed.length);
152+
153+
return `│ ${name}${coloredInstalled}${installedPadding}${requested.padEnd(
154+
maxRequestedLength,
155+
)} │`;
139156
})
140157
.sort();
141158

142-
const top = `┌─${'─'.repeat(maxNameLength)}─┬─${'─'.repeat(maxVersionLength)}─┐`;
143-
const header = `│ ${nameHeader.padEnd(maxNameLength)}${versionHeader.padEnd(
144-
maxVersionLength,
145-
)} │`;
146-
const separator = `├─${'─'.repeat(maxNameLength)}─┼─${'─'.repeat(maxVersionLength)}─┤`;
147-
const bottom = `└─${'─'.repeat(maxNameLength)}─┴─${'─'.repeat(maxVersionLength)}─┘`;
159+
const top = `┌─${'─'.repeat(maxNameLength)}─┬─${'─'.repeat(
160+
maxInstalledLength,
161+
)}─┬─${'─'.repeat(maxRequestedLength)}─┐`;
162+
const header =
163+
`│ ${headers.name.padEnd(maxNameLength)} │ ` +
164+
`${headers.installed.padEnd(maxInstalledLength)} │ ` +
165+
`${headers.requested.padEnd(maxRequestedLength)} │`;
166+
const separator = `├─${'─'.repeat(maxNameLength)}─┼─${'─'.repeat(
167+
maxInstalledLength,
168+
)}─┼─${'─'.repeat(maxRequestedLength)}─┤`;
169+
const bottom = `└─${'─'.repeat(maxNameLength)}─┴─${'─'.repeat(
170+
maxInstalledLength,
171+
)}─┴─${'─'.repeat(maxRequestedLength)}─┘`;
148172

149173
return [top, header, separator, ...tableRows, bottom].join('\n');
150174
}

packages/angular/cli/src/commands/version/version-info.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,24 @@ interface PartialPackageInfo {
1919
devDependencies?: Record<string, string>;
2020
}
2121

22+
/**
23+
* An object containing version information for a single package.
24+
*/
25+
export interface PackageVersionInfo {
26+
requested: string;
27+
installed: string;
28+
}
29+
2230
/**
2331
* An object containing all the version information that will be displayed by the command.
2432
*/
2533
export interface VersionInfo {
2634
cli: {
2735
version: string;
2836
};
37+
framework: {
38+
version: string | undefined;
39+
};
2940
system: {
3041
node: {
3142
version: string;
@@ -40,7 +51,7 @@ export interface VersionInfo {
4051
version: string | undefined;
4152
};
4253
};
43-
packages: Record<string, string>;
54+
packages: Record<string, PackageVersionInfo>;
4455
}
4556

4657
/**
@@ -84,24 +95,31 @@ export function gatherVersionInfo(context: {
8495
const [nodeMajor] = process.versions.node.split('.').map((part) => Number(part));
8596
const unsupportedNodeVersion = !SUPPORTED_NODE_MAJORS.includes(nodeMajor);
8697

87-
const packageNames = new Set(
88-
Object.keys({
89-
...workspacePackage?.dependencies,
90-
...workspacePackage?.devDependencies,
91-
}),
92-
);
98+
const allDependencies = {
99+
...workspacePackage?.dependencies,
100+
...workspacePackage?.devDependencies,
101+
};
102+
const packageNames = new Set(Object.keys(allDependencies));
93103

94-
const packages: Record<string, string> = {};
104+
const packages: Record<string, PackageVersionInfo> = {};
95105
for (const name of packageNames) {
96106
if (PACKAGE_PATTERNS.some((p) => p.test(name))) {
97-
packages[name] = getVersion(name, workspaceRequire);
107+
packages[name] = {
108+
requested: allDependencies[name] ?? 'error',
109+
installed: getVersion(name, workspaceRequire),
110+
};
98111
}
99112
}
100113

114+
const angularCoreVersion = packages['@angular/core'];
115+
101116
return {
102117
cli: {
103118
version: VERSION.full,
104119
},
120+
framework: {
121+
version: angularCoreVersion?.installed,
122+
},
105123
system: {
106124
node: {
107125
version: process.versions.node,

0 commit comments

Comments
 (0)