6
6
* found in the LICENSE file at https://angular.dev/license
7
7
*/
8
8
9
- import nodeModule from 'node:module' ;
10
- import { resolve } from 'node:path' ;
11
- import { Argv } from 'yargs' ;
9
+ import type { Argv } from 'yargs' ;
12
10
import { CommandModule , CommandModuleImplementation } from '../../command-builder/command-module' ;
13
11
import { colors } from '../../utilities/color' ;
14
12
import { RootCommands } from '../command-config' ;
15
-
16
- interface PartialPackageInfo {
17
- name : string ;
18
- version : string ;
19
- dependencies ?: Record < string , string > ;
20
- devDependencies ?: Record < string , string > ;
21
- }
13
+ import { VersionInfo , gatherVersionInfo } from './version-info' ;
22
14
23
15
/**
24
- * Major versions of Node.js that are officially supported by Angular .
16
+ * The Angular CLI logo, displayed as ASCII art .
25
17
*/
26
- const SUPPORTED_NODE_MAJORS = [ 20 , 22 , 24 ] ;
27
-
28
- const PACKAGE_PATTERNS = [
29
- / ^ @ a n g u l a r \/ .* / ,
30
- / ^ @ a n g u l a r - d e v k i t \/ .* / ,
31
- / ^ @ n g t o o l s \/ .* / ,
32
- / ^ @ s c h e m a t i c s \/ .* / ,
33
- / ^ r x j s $ / ,
34
- / ^ t y p e s c r i p t $ / ,
35
- / ^ n g - p a c k a g r $ / ,
36
- / ^ w e b p a c k $ / ,
37
- / ^ z o n e \. j s $ / ,
38
- ] ;
18
+ const ASCII_ART = `
19
+ _ _ ____ _ ___
20
+ / \\ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
21
+ / △ \\ | '_ \\ / _\` | | | | |/ _\` | '__| | | | | | |
22
+ / ___ \\| | | | (_| | |_| | | (_| | | | |___| |___ | |
23
+ /_/ \\_\\_| |_|\\__, |\\__,_|_|\\__,_|_| \\____|_____|___|
24
+ |___/
25
+ `
26
+ . split ( '\n' )
27
+ . map ( ( x ) => colors . red ( x ) )
28
+ . join ( '\n' ) ;
39
29
30
+ /**
31
+ * The command-line module for the `ng version` command.
32
+ */
40
33
export default class VersionCommandModule
41
34
extends CommandModule
42
35
implements CommandModuleImplementation
@@ -46,146 +39,108 @@ export default class VersionCommandModule
46
39
describe = 'Outputs Angular CLI version.' ;
47
40
longDescriptionPath ?: string | undefined ;
48
41
42
+ /**
43
+ * Builds the command-line options for the `ng version` command.
44
+ * @param localYargs The `yargs` instance to configure.
45
+ * @returns The configured `yargs` instance.
46
+ */
49
47
builder ( localYargs : Argv ) : Argv {
50
48
return localYargs ;
51
49
}
52
50
51
+ /**
52
+ * The main execution logic for the `ng version` command.
53
+ */
53
54
async run ( ) : Promise < void > {
54
- const { packageManager, logger, root } = this . context ;
55
- const localRequire = nodeModule . createRequire ( resolve ( __filename , '../../../' ) ) ;
56
- // Trailing slash is used to allow the path to be treated as a directory
57
- const workspaceRequire = nodeModule . createRequire ( root + '/' ) ;
58
-
59
- const cliPackage : PartialPackageInfo = localRequire ( './package.json' ) ;
60
- let workspacePackage : PartialPackageInfo | undefined ;
61
- try {
62
- workspacePackage = workspaceRequire ( './package.json' ) ;
63
- } catch { }
64
-
65
- const [ nodeMajor ] = process . versions . node . split ( '.' ) . map ( ( part ) => Number ( part ) ) ;
66
- const unsupportedNodeVersion = ! SUPPORTED_NODE_MAJORS . includes ( nodeMajor ) ;
67
-
68
- const packageNames = new Set (
69
- Object . keys ( {
70
- ...cliPackage . dependencies ,
71
- ...cliPackage . devDependencies ,
72
- ...workspacePackage ?. dependencies ,
73
- ...workspacePackage ?. devDependencies ,
74
- } ) ,
75
- ) ;
76
-
77
- const versions : Record < string , string > = { } ;
78
- for ( const name of packageNames ) {
79
- if ( PACKAGE_PATTERNS . some ( ( p ) => p . test ( name ) ) ) {
80
- versions [ name ] = this . getVersion ( name , workspaceRequire , localRequire ) ;
81
- }
82
- }
55
+ const { logger } = this . context ;
56
+ const versionInfo = gatherVersionInfo ( this . context ) ;
57
+ const {
58
+ ngCliVersion,
59
+ nodeVersion,
60
+ unsupportedNodeVersion,
61
+ packageManagerName,
62
+ packageManagerVersion,
63
+ os,
64
+ arch,
65
+ versions,
66
+ } = versionInfo ;
67
+
68
+ const header = `
69
+ Angular CLI: ${ ngCliVersion }
70
+ Node: ${ nodeVersion } ${ unsupportedNodeVersion ? ' (Unsupported)' : '' }
71
+ Package Manager: ${ packageManagerName } ${ packageManagerVersion ?? '<error>' }
72
+ OS: ${ os } ${ arch }
73
+ ` . replace ( / ^ { 6 } / gm, '' ) ;
83
74
84
- const ngCliVersion = cliPackage . version ;
85
- let angularCoreVersion = '' ;
86
- const angularSameAsCore : string [ ] = [ ] ;
87
-
88
- if ( workspacePackage ) {
89
- // Filter all angular versions that are the same as core.
90
- angularCoreVersion = versions [ '@angular/core' ] ;
91
- if ( angularCoreVersion ) {
92
- for ( const [ name , version ] of Object . entries ( versions ) ) {
93
- if ( version === angularCoreVersion && name . startsWith ( '@angular/' ) ) {
94
- angularSameAsCore . push ( name . replace ( / ^ @ a n g u l a r \/ / , '' ) ) ;
95
- delete versions [ name ] ;
96
- }
97
- }
75
+ const angularPackages = this . formatAngularPackages ( versionInfo ) ;
76
+ const packageTable = this . formatPackageTable ( versions ) ;
98
77
99
- // Make sure we list them in alphabetical order.
100
- angularSameAsCore . sort ( ) ;
101
- }
102
- }
103
-
104
- const namePad = ' ' . repeat (
105
- Object . keys ( versions ) . sort ( ( a , b ) => b . length - a . length ) [ 0 ] . length + 3 ,
106
- ) ;
107
- const asciiArt = `
108
- _ _ ____ _ ___
109
- / \\ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
110
- / △ \\ | '_ \\ / _\` | | | | |/ _\` | '__| | | | | | |
111
- / ___ \\| | | | (_| | |_| | | (_| | | | |___| |___ | |
112
- /_/ \\_\\_| |_|\\__, |\\__,_|_|\\__,_|_| \\____|_____|___|
113
- |___/
114
- `
115
- . split ( '\n' )
116
- . map ( ( x ) => colors . red ( x ) )
117
- . join ( '\n' ) ;
118
-
119
- logger . info ( asciiArt ) ;
120
- logger . info (
121
- `
122
- Angular CLI: ${ ngCliVersion }
123
- Node: ${ process . versions . node } ${ unsupportedNodeVersion ? ' (Unsupported)' : '' }
124
- Package Manager: ${ packageManager . name } ${ packageManager . version ?? '<error>' }
125
- OS: ${ process . platform } ${ process . arch }
126
-
127
- Angular: ${ angularCoreVersion }
128
- ... ${ angularSameAsCore
129
- . reduce < string [ ] > ( ( acc , name ) => {
130
- // Perform a simple word wrap around 60.
131
- if ( acc . length == 0 ) {
132
- return [ name ] ;
133
- }
134
- const line = acc [ acc . length - 1 ] + ', ' + name ;
135
- if ( line . length > 60 ) {
136
- acc . push ( name ) ;
137
- } else {
138
- acc [ acc . length - 1 ] = line ;
139
- }
140
-
141
- return acc ;
142
- } , [ ] )
143
- . join ( '\n... ' ) }
144
-
145
- Package${ namePad . slice ( 7 ) } Version
146
- -------${ namePad . replace ( / / g, '-' ) } ------------------
147
- ${ Object . keys ( versions )
148
- . map ( ( module ) => `${ module } ${ namePad . slice ( module . length ) } ${ versions [ module ] } ` )
149
- . sort ( )
150
- . join ( '\n' ) }
151
- ` . replace ( / ^ { 6 } / gm, '' ) ,
152
- ) ;
78
+ logger . info ( [ ASCII_ART , header , angularPackages , packageTable ] . join ( '\n\n' ) ) ;
153
79
154
80
if ( unsupportedNodeVersion ) {
155
81
logger . warn (
156
- `Warning: The current version of Node (${ process . versions . node } ) is not supported by Angular.` ,
82
+ `Warning: The current version of Node (${ nodeVersion } ) is not supported by Angular.` ,
157
83
) ;
158
84
}
159
85
}
160
86
161
- private getVersion (
162
- moduleName : string ,
163
- workspaceRequire : NodeRequire ,
164
- localRequire : NodeRequire ,
165
- ) : string {
166
- let packageInfo : PartialPackageInfo | undefined ;
167
- let cliOnly = false ;
168
-
169
- // Try to find the package in the workspace
170
- try {
171
- packageInfo = workspaceRequire ( `${ moduleName } /package.json` ) ;
172
- } catch { }
173
-
174
- // If not found, try to find within the CLI
175
- if ( ! packageInfo ) {
176
- try {
177
- packageInfo = localRequire ( `${ moduleName } /package.json` ) ;
178
- cliOnly = true ;
179
- } catch { }
87
+ /**
88
+ * Formats the Angular packages section of the version output.
89
+ * @param versionInfo An object containing the version information.
90
+ * @returns A string containing the formatted Angular packages information.
91
+ */
92
+ private formatAngularPackages ( versionInfo : VersionInfo ) : string {
93
+ const { angularCoreVersion, angularSameAsCore } = versionInfo ;
94
+ if ( ! angularCoreVersion ) {
95
+ return 'Angular: <error>' ;
180
96
}
181
97
182
- // If found, attempt to get the version
183
- if ( packageInfo ) {
184
- try {
185
- return packageInfo . version + ( cliOnly ? ' (cli-only)' : '' ) ;
186
- } catch { }
98
+ const wrappedPackages = angularSameAsCore
99
+ . reduce < string [ ] > ( ( acc , name ) => {
100
+ if ( acc . length === 0 ) {
101
+ return [ name ] ;
102
+ }
103
+ const line = acc [ acc . length - 1 ] + ', ' + name ;
104
+ if ( line . length > 60 ) {
105
+ acc . push ( name ) ;
106
+ } else {
107
+ acc [ acc . length - 1 ] = line ;
108
+ }
109
+
110
+ return acc ;
111
+ } , [ ] )
112
+ . join ( '\n... ' ) ;
113
+
114
+ return `Angular: ${ angularCoreVersion } \n... ${ wrappedPackages } ` ;
115
+ }
116
+
117
+ /**
118
+ * Formats the package table section of the version output.
119
+ * @param versions A map of package names to their versions.
120
+ * @returns A string containing the formatted package table.
121
+ */
122
+ private formatPackageTable ( versions : Record < string , string > ) : string {
123
+ const versionKeys = Object . keys ( versions ) ;
124
+ if ( versionKeys . length === 0 ) {
125
+ return '' ;
187
126
}
188
127
189
- return '<error>' ;
128
+ const header = 'Package' ;
129
+ const maxNameLength = Math . max ( ...versionKeys . map ( ( key ) => key . length ) ) ;
130
+ const namePad = ' ' . repeat ( Math . max ( 0 , maxNameLength - header . length ) + 3 ) ;
131
+
132
+ const tableHeader = `${ header } ${ namePad } Version` ;
133
+ const separator = '-' . repeat ( tableHeader . length ) ;
134
+
135
+ const tableRows = versionKeys
136
+ . map ( ( module ) => {
137
+ const padding = ' ' . repeat ( maxNameLength - module . length + 3 ) ;
138
+
139
+ return `${ module } ${ padding } ${ versions [ module ] } ` ;
140
+ } )
141
+ . sort ( )
142
+ . join ( '\n' ) ;
143
+
144
+ return `${ tableHeader } \n${ separator } \n${ tableRows } ` ;
190
145
}
191
146
}
0 commit comments