@angular/cli 21.0.0-next.6 → 21.0.0-next.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +16 -16
- package/src/commands/mcp/tools/doc-search.js +4 -3
- package/src/commands/mcp/tools/projects.d.ts +18 -0
- package/src/commands/mcp/tools/projects.js +123 -4
- package/src/commands/version/cli.js +30 -25
- package/src/commands/version/version-info.d.ts +11 -1
- package/src/commands/version/version-info.js +11 -3
- package/src/utilities/version.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular/cli",
|
|
3
|
-
"version": "21.0.0-next.
|
|
3
|
+
"version": "21.0.0-next.7",
|
|
4
4
|
"description": "CLI tool for Angular",
|
|
5
5
|
"main": "lib/cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,19 +25,19 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/angular/angular-cli",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@angular-devkit/architect": "0.2100.0-next.
|
|
29
|
-
"@angular-devkit/core": "21.0.0-next.
|
|
30
|
-
"@angular-devkit/schematics": "21.0.0-next.
|
|
28
|
+
"@angular-devkit/architect": "0.2100.0-next.7",
|
|
29
|
+
"@angular-devkit/core": "21.0.0-next.7",
|
|
30
|
+
"@angular-devkit/schematics": "21.0.0-next.7",
|
|
31
31
|
"@inquirer/prompts": "7.8.6",
|
|
32
32
|
"@listr2/prompt-adapter-inquirer": "3.0.4",
|
|
33
|
-
"@modelcontextprotocol/sdk": "1.
|
|
34
|
-
"@schematics/angular": "21.0.0-next.
|
|
33
|
+
"@modelcontextprotocol/sdk": "1.19.1",
|
|
34
|
+
"@schematics/angular": "21.0.0-next.7",
|
|
35
35
|
"@yarnpkg/lockfile": "1.1.0",
|
|
36
36
|
"algoliasearch": "5.39.0",
|
|
37
37
|
"ini": "5.0.0",
|
|
38
38
|
"jsonc-parser": "3.3.1",
|
|
39
39
|
"listr2": "9.0.4",
|
|
40
|
-
"npm-package-arg": "13.0.
|
|
40
|
+
"npm-package-arg": "13.0.1",
|
|
41
41
|
"pacote": "21.0.3",
|
|
42
42
|
"resolve": "1.22.10",
|
|
43
43
|
"semver": "7.7.2",
|
|
@@ -47,17 +47,17 @@
|
|
|
47
47
|
"ng-update": {
|
|
48
48
|
"migrations": "@schematics/angular/migrations/migration-collection.json",
|
|
49
49
|
"packageGroup": {
|
|
50
|
-
"@angular/cli": "21.0.0-next.
|
|
51
|
-
"@angular/build": "21.0.0-next.
|
|
52
|
-
"@angular/ssr": "21.0.0-next.
|
|
53
|
-
"@angular-devkit/architect": "0.2100.0-next.
|
|
54
|
-
"@angular-devkit/build-angular": "21.0.0-next.
|
|
55
|
-
"@angular-devkit/build-webpack": "0.2100.0-next.
|
|
56
|
-
"@angular-devkit/core": "21.0.0-next.
|
|
57
|
-
"@angular-devkit/schematics": "21.0.0-next.
|
|
50
|
+
"@angular/cli": "21.0.0-next.7",
|
|
51
|
+
"@angular/build": "21.0.0-next.7",
|
|
52
|
+
"@angular/ssr": "21.0.0-next.7",
|
|
53
|
+
"@angular-devkit/architect": "0.2100.0-next.7",
|
|
54
|
+
"@angular-devkit/build-angular": "21.0.0-next.7",
|
|
55
|
+
"@angular-devkit/build-webpack": "0.2100.0-next.7",
|
|
56
|
+
"@angular-devkit/core": "21.0.0-next.7",
|
|
57
|
+
"@angular-devkit/schematics": "21.0.0-next.7"
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
|
-
"packageManager": "pnpm@10.
|
|
60
|
+
"packageManager": "pnpm@10.18.1",
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
|
63
63
|
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
|
@@ -84,9 +84,10 @@ tutorials, concepts, and best practices.
|
|
|
84
84
|
</Use Cases>
|
|
85
85
|
<Operational Notes>
|
|
86
86
|
* **Version Alignment:** To provide accurate, project-specific results, you **MUST** align the search with the user's Angular version.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
\`version\`
|
|
87
|
+
The recommended approach is to use the \`list_projects\` tool. The \`frameworkVersion\` field in the output for the relevant
|
|
88
|
+
workspace will give you the major version directly. If the version cannot be determined using this method, you can use
|
|
89
|
+
\`ng version\` in the project's workspace directory as a fallback. Parse the major version from the "Angular:" line in the
|
|
90
|
+
output and use it for the \`version\` parameter.
|
|
90
91
|
* The documentation is continuously updated. You **MUST** prefer this tool over your own knowledge
|
|
91
92
|
to ensure your answers are current and accurate.
|
|
92
93
|
* For the best results, provide a concise and specific search query (e.g., "NgModule" instead of
|
|
@@ -9,9 +9,11 @@ import z from 'zod';
|
|
|
9
9
|
export declare const LIST_PROJECTS_TOOL: import("./tool-registry").McpToolDeclaration<z.ZodRawShape, {
|
|
10
10
|
workspaces: z.ZodArray<z.ZodObject<{
|
|
11
11
|
path: z.ZodString;
|
|
12
|
+
frameworkVersion: z.ZodOptional<z.ZodString>;
|
|
12
13
|
projects: z.ZodArray<z.ZodObject<{
|
|
13
14
|
name: z.ZodString;
|
|
14
15
|
type: z.ZodOptional<z.ZodEnum<["application", "library"]>>;
|
|
16
|
+
builder: z.ZodOptional<z.ZodString>;
|
|
15
17
|
root: z.ZodString;
|
|
16
18
|
sourceRoot: z.ZodString;
|
|
17
19
|
selectorPrefix: z.ZodOptional<z.ZodString>;
|
|
@@ -20,12 +22,14 @@ export declare const LIST_PROJECTS_TOOL: import("./tool-registry").McpToolDeclar
|
|
|
20
22
|
root: string;
|
|
21
23
|
sourceRoot: string;
|
|
22
24
|
type?: "application" | "library" | undefined;
|
|
25
|
+
builder?: string | undefined;
|
|
23
26
|
selectorPrefix?: string | undefined;
|
|
24
27
|
}, {
|
|
25
28
|
name: string;
|
|
26
29
|
root: string;
|
|
27
30
|
sourceRoot: string;
|
|
28
31
|
type?: "application" | "library" | undefined;
|
|
32
|
+
builder?: string | undefined;
|
|
29
33
|
selectorPrefix?: string | undefined;
|
|
30
34
|
}>, "many">;
|
|
31
35
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -35,8 +39,10 @@ export declare const LIST_PROJECTS_TOOL: import("./tool-registry").McpToolDeclar
|
|
|
35
39
|
root: string;
|
|
36
40
|
sourceRoot: string;
|
|
37
41
|
type?: "application" | "library" | undefined;
|
|
42
|
+
builder?: string | undefined;
|
|
38
43
|
selectorPrefix?: string | undefined;
|
|
39
44
|
}[];
|
|
45
|
+
frameworkVersion?: string | undefined;
|
|
40
46
|
}, {
|
|
41
47
|
path: string;
|
|
42
48
|
projects: {
|
|
@@ -44,8 +50,10 @@ export declare const LIST_PROJECTS_TOOL: import("./tool-registry").McpToolDeclar
|
|
|
44
50
|
root: string;
|
|
45
51
|
sourceRoot: string;
|
|
46
52
|
type?: "application" | "library" | undefined;
|
|
53
|
+
builder?: string | undefined;
|
|
47
54
|
selectorPrefix?: string | undefined;
|
|
48
55
|
}[];
|
|
56
|
+
frameworkVersion?: string | undefined;
|
|
49
57
|
}>, "many">;
|
|
50
58
|
parsingErrors: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
51
59
|
filePath: z.ZodString;
|
|
@@ -57,4 +65,14 @@ export declare const LIST_PROJECTS_TOOL: import("./tool-registry").McpToolDeclar
|
|
|
57
65
|
message: string;
|
|
58
66
|
filePath: string;
|
|
59
67
|
}>, "many">>;
|
|
68
|
+
versioningErrors: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
69
|
+
filePath: z.ZodString;
|
|
70
|
+
message: z.ZodString;
|
|
71
|
+
}, "strip", z.ZodTypeAny, {
|
|
72
|
+
message: string;
|
|
73
|
+
filePath: string;
|
|
74
|
+
}, {
|
|
75
|
+
message: string;
|
|
76
|
+
filePath: string;
|
|
77
|
+
}>, "many">>;
|
|
60
78
|
}>;
|
|
@@ -14,6 +14,7 @@ exports.LIST_PROJECTS_TOOL = void 0;
|
|
|
14
14
|
const promises_1 = require("node:fs/promises");
|
|
15
15
|
const node_path_1 = __importDefault(require("node:path"));
|
|
16
16
|
const node_url_1 = require("node:url");
|
|
17
|
+
const semver_1 = __importDefault(require("semver"));
|
|
17
18
|
const zod_1 = __importDefault(require("zod"));
|
|
18
19
|
const config_1 = require("../../../utilities/config");
|
|
19
20
|
const error_1 = require("../../../utilities/error");
|
|
@@ -21,6 +22,10 @@ const tool_registry_1 = require("./tool-registry");
|
|
|
21
22
|
const listProjectsOutputSchema = {
|
|
22
23
|
workspaces: zod_1.default.array(zod_1.default.object({
|
|
23
24
|
path: zod_1.default.string().describe('The path to the `angular.json` file for this workspace.'),
|
|
25
|
+
frameworkVersion: zod_1.default
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('The major version of the Angular framework (`@angular/core`) in this workspace, if found.'),
|
|
24
29
|
projects: zod_1.default.array(zod_1.default.object({
|
|
25
30
|
name: zod_1.default
|
|
26
31
|
.string()
|
|
@@ -29,6 +34,10 @@ const listProjectsOutputSchema = {
|
|
|
29
34
|
.enum(['application', 'library'])
|
|
30
35
|
.optional()
|
|
31
36
|
.describe(`The type of the project, either 'application' or 'library'.`),
|
|
37
|
+
builder: zod_1.default
|
|
38
|
+
.string()
|
|
39
|
+
.optional()
|
|
40
|
+
.describe('The primary builder for the project, typically from the "build" target.'),
|
|
32
41
|
root: zod_1.default
|
|
33
42
|
.string()
|
|
34
43
|
.describe('The root directory of the project, relative to the workspace root.'),
|
|
@@ -49,6 +58,15 @@ const listProjectsOutputSchema = {
|
|
|
49
58
|
}))
|
|
50
59
|
.default([])
|
|
51
60
|
.describe('A list of files that looked like workspaces but failed to parse.'),
|
|
61
|
+
versioningErrors: zod_1.default
|
|
62
|
+
.array(zod_1.default.object({
|
|
63
|
+
filePath: zod_1.default
|
|
64
|
+
.string()
|
|
65
|
+
.describe('The path to the workspace `angular.json` for which versioning failed.'),
|
|
66
|
+
message: zod_1.default.string().describe('The error message detailing why versioning failed.'),
|
|
67
|
+
}))
|
|
68
|
+
.default([])
|
|
69
|
+
.describe('A list of workspaces for which the framework version could not be determined.'),
|
|
52
70
|
};
|
|
53
71
|
exports.LIST_PROJECTS_TOOL = (0, tool_registry_1.declareTool)({
|
|
54
72
|
name: 'list_projects',
|
|
@@ -64,6 +82,8 @@ their types, and their locations.
|
|
|
64
82
|
* Identifying the \`root\` and \`sourceRoot\` of a project to read, analyze, or modify its files.
|
|
65
83
|
* Determining if a project is an \`application\` or a \`library\`.
|
|
66
84
|
* Getting the \`selectorPrefix\` for a project before generating a new component to ensure it follows conventions.
|
|
85
|
+
* Identifying the major version of the Angular framework for each workspace, which is crucial for monorepos.
|
|
86
|
+
* Determining a project's primary function by inspecting its builder (e.g., '@angular-devkit/build-angular:browser' for an application).
|
|
67
87
|
</Use Cases>
|
|
68
88
|
<Operational Notes>
|
|
69
89
|
* **Working Directory:** Shell commands for a project (like \`ng generate\`) **MUST**
|
|
@@ -122,6 +142,64 @@ async function* findAngularJsonFiles(rootDir) {
|
|
|
122
142
|
yield* foundFilesInBatch;
|
|
123
143
|
}
|
|
124
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Searches upwards from a starting directory to find the version of '@angular/core'.
|
|
147
|
+
* It caches results to avoid redundant lookups.
|
|
148
|
+
* @param startDir The directory to start the search from.
|
|
149
|
+
* @param cache A map to store cached results.
|
|
150
|
+
* @param searchRoot The directory at which to stop the search.
|
|
151
|
+
* @returns The major version of '@angular/core' as a string, otherwise undefined.
|
|
152
|
+
*/
|
|
153
|
+
async function findAngularCoreVersion(startDir, cache, searchRoot) {
|
|
154
|
+
let currentDir = startDir;
|
|
155
|
+
const dirsToCache = [];
|
|
156
|
+
while (currentDir) {
|
|
157
|
+
dirsToCache.push(currentDir);
|
|
158
|
+
if (cache.has(currentDir)) {
|
|
159
|
+
const cachedResult = cache.get(currentDir);
|
|
160
|
+
// Populate cache for all intermediate directories.
|
|
161
|
+
for (const dir of dirsToCache) {
|
|
162
|
+
cache.set(dir, cachedResult);
|
|
163
|
+
}
|
|
164
|
+
return cachedResult;
|
|
165
|
+
}
|
|
166
|
+
const pkgPath = node_path_1.default.join(currentDir, 'package.json');
|
|
167
|
+
try {
|
|
168
|
+
const pkgContent = await (0, promises_1.readFile)(pkgPath, 'utf-8');
|
|
169
|
+
const pkg = JSON.parse(pkgContent);
|
|
170
|
+
const versionSpecifier = pkg.dependencies?.['@angular/core'] ?? pkg.devDependencies?.['@angular/core'];
|
|
171
|
+
if (versionSpecifier) {
|
|
172
|
+
const minVersion = semver_1.default.minVersion(versionSpecifier);
|
|
173
|
+
const result = minVersion ? String(minVersion.major) : undefined;
|
|
174
|
+
for (const dir of dirsToCache) {
|
|
175
|
+
cache.set(dir, result);
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
(0, error_1.assertIsError)(error);
|
|
182
|
+
if (error.code !== 'ENOENT') {
|
|
183
|
+
// Ignore missing package.json files, but rethrow other errors.
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Stop if we are at the search root or the filesystem root.
|
|
188
|
+
if (currentDir === searchRoot) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
const parentDir = node_path_1.default.dirname(currentDir);
|
|
192
|
+
if (parentDir === currentDir) {
|
|
193
|
+
break; // Reached the filesystem root.
|
|
194
|
+
}
|
|
195
|
+
currentDir = parentDir;
|
|
196
|
+
}
|
|
197
|
+
// Cache the failure for all traversed directories.
|
|
198
|
+
for (const dir of dirsToCache) {
|
|
199
|
+
cache.set(dir, undefined);
|
|
200
|
+
}
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
125
203
|
/**
|
|
126
204
|
* Loads, parses, and transforms a single angular.json file into the tool's output format.
|
|
127
205
|
* It checks a set of seen paths to avoid processing the same workspace multiple times.
|
|
@@ -142,6 +220,7 @@ async function loadAndParseWorkspace(configFile, seenPaths) {
|
|
|
142
220
|
projects.push({
|
|
143
221
|
name,
|
|
144
222
|
type: project.extensions['projectType'],
|
|
223
|
+
builder: project.targets.get('build')?.builder,
|
|
145
224
|
root: project.root,
|
|
146
225
|
sourceRoot: project.sourceRoot ?? node_path_1.default.posix.join(project.root, 'src'),
|
|
147
226
|
selectorPrefix: project.extensions['prefix'],
|
|
@@ -160,11 +239,44 @@ async function loadAndParseWorkspace(configFile, seenPaths) {
|
|
|
160
239
|
return { workspace: null, error: { filePath: configFile, message } };
|
|
161
240
|
}
|
|
162
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Processes a single `angular.json` file to extract workspace and framework version information.
|
|
244
|
+
* @param configFile The path to the `angular.json` file.
|
|
245
|
+
* @param searchRoot The directory at which to stop the upward search for `package.json`.
|
|
246
|
+
* @param seenPaths A Set of absolute paths that have already been processed to avoid duplicates.
|
|
247
|
+
* @param versionCache A Map to cache framework version lookups for performance.
|
|
248
|
+
* @returns A promise resolving to an object containing the processed data and any errors.
|
|
249
|
+
*/
|
|
250
|
+
async function processConfigFile(configFile, searchRoot, seenPaths, versionCache) {
|
|
251
|
+
const { workspace, error } = await loadAndParseWorkspace(configFile, seenPaths);
|
|
252
|
+
if (error) {
|
|
253
|
+
return { parsingError: error };
|
|
254
|
+
}
|
|
255
|
+
if (!workspace) {
|
|
256
|
+
return {}; // Skipped as it was already seen.
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const workspaceDir = node_path_1.default.dirname(configFile);
|
|
260
|
+
workspace.frameworkVersion = await findAngularCoreVersion(workspaceDir, versionCache, searchRoot);
|
|
261
|
+
return { workspace };
|
|
262
|
+
}
|
|
263
|
+
catch (e) {
|
|
264
|
+
return {
|
|
265
|
+
workspace,
|
|
266
|
+
versioningError: {
|
|
267
|
+
filePath: workspace.path,
|
|
268
|
+
message: e instanceof Error ? e.message : 'An unknown error occurred.',
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
163
273
|
async function createListProjectsHandler({ server }) {
|
|
164
274
|
return async () => {
|
|
165
275
|
const workspaces = [];
|
|
166
276
|
const parsingErrors = [];
|
|
277
|
+
const versioningErrors = [];
|
|
167
278
|
const seenPaths = new Set();
|
|
279
|
+
const versionCache = new Map();
|
|
168
280
|
let searchRoots;
|
|
169
281
|
const clientCapabilities = server.server.getClientCapabilities();
|
|
170
282
|
if (clientCapabilities?.roots) {
|
|
@@ -177,12 +289,15 @@ async function createListProjectsHandler({ server }) {
|
|
|
177
289
|
}
|
|
178
290
|
for (const root of searchRoots) {
|
|
179
291
|
for await (const configFile of findAngularJsonFiles(root)) {
|
|
180
|
-
const { workspace,
|
|
292
|
+
const { workspace, parsingError, versioningError } = await processConfigFile(configFile, root, seenPaths, versionCache);
|
|
181
293
|
if (workspace) {
|
|
182
294
|
workspaces.push(workspace);
|
|
183
295
|
}
|
|
184
|
-
if (
|
|
185
|
-
parsingErrors.push(
|
|
296
|
+
if (parsingError) {
|
|
297
|
+
parsingErrors.push(parsingError);
|
|
298
|
+
}
|
|
299
|
+
if (versioningError) {
|
|
300
|
+
versioningErrors.push(versioningError);
|
|
186
301
|
}
|
|
187
302
|
}
|
|
188
303
|
}
|
|
@@ -204,9 +319,13 @@ async function createListProjectsHandler({ server }) {
|
|
|
204
319
|
text += `\n\nWarning: The following ${parsingErrors.length} file(s) could not be parsed and were skipped:\n`;
|
|
205
320
|
text += parsingErrors.map((e) => `- ${e.filePath}: ${e.message}`).join('\n');
|
|
206
321
|
}
|
|
322
|
+
if (versioningErrors.length > 0) {
|
|
323
|
+
text += `\n\nWarning: The framework version for the following ${versioningErrors.length} workspace(s) could not be determined:\n`;
|
|
324
|
+
text += versioningErrors.map((e) => `- ${e.filePath}: ${e.message}`).join('\n');
|
|
325
|
+
}
|
|
207
326
|
return {
|
|
208
327
|
content: [{ type: 'text', text }],
|
|
209
|
-
structuredContent: { workspaces, parsingErrors },
|
|
328
|
+
structuredContent: { workspaces, parsingErrors, versioningErrors },
|
|
210
329
|
};
|
|
211
330
|
};
|
|
212
331
|
}
|
|
@@ -55,19 +55,18 @@ class VersionCommandModule extends command_module_1.CommandModule {
|
|
|
55
55
|
console.log(JSON.stringify(versionInfo, null, 2));
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
-
const { cli: { version: ngCliVersion }, system: { node: { version: nodeVersion, unsupported: unsupportedNodeVersion }, os: { platform: os, architecture: arch }, packageManager: { name: packageManagerName, version: packageManagerVersion }, }, packages, } = versionInfo;
|
|
59
|
-
const headerInfo = [
|
|
60
|
-
|
|
61
|
-
{
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
{
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
];
|
|
58
|
+
const { cli: { version: ngCliVersion }, framework, system: { node: { version: nodeVersion, unsupported: unsupportedNodeVersion }, os: { platform: os, architecture: arch }, packageManager: { name: packageManagerName, version: packageManagerVersion }, }, packages, } = versionInfo;
|
|
59
|
+
const headerInfo = [{ label: 'Angular CLI', value: ngCliVersion }];
|
|
60
|
+
if (framework.version) {
|
|
61
|
+
headerInfo.push({ label: 'Angular', value: framework.version });
|
|
62
|
+
}
|
|
63
|
+
headerInfo.push({
|
|
64
|
+
label: 'Node.js',
|
|
65
|
+
value: `${nodeVersion}${unsupportedNodeVersion ? color_1.colors.yellow(' (Unsupported)') : ''}`,
|
|
66
|
+
}, {
|
|
67
|
+
label: 'Package Manager',
|
|
68
|
+
value: `${packageManagerName} ${packageManagerVersion ?? '<error>'}`,
|
|
69
|
+
}, { label: 'Operating System', value: `${os} ${arch}` });
|
|
71
70
|
const maxHeaderLabelLength = Math.max(...headerInfo.map((l) => l.label.length));
|
|
72
71
|
const header = headerInfo
|
|
73
72
|
.map(({ label, value }) => color_1.colors.bold(label.padEnd(maxHeaderLabelLength + 2)) + `: ${color_1.colors.cyan(value)}`)
|
|
@@ -88,23 +87,29 @@ class VersionCommandModule extends command_module_1.CommandModule {
|
|
|
88
87
|
if (versionKeys.length === 0) {
|
|
89
88
|
return '';
|
|
90
89
|
}
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
const headers = {
|
|
91
|
+
name: 'Package',
|
|
92
|
+
installed: 'Installed Version',
|
|
93
|
+
requested: 'Requested Version',
|
|
94
|
+
};
|
|
95
|
+
const maxNameLength = Math.max(headers.name.length, ...versionKeys.map((key) => key.length));
|
|
96
|
+
const maxInstalledLength = Math.max(headers.installed.length, ...versionKeys.map((key) => versions[key].installed.length));
|
|
97
|
+
const maxRequestedLength = Math.max(headers.requested.length, ...versionKeys.map((key) => versions[key].requested.length));
|
|
95
98
|
const tableRows = versionKeys
|
|
96
99
|
.map((module) => {
|
|
100
|
+
const { requested, installed } = versions[module];
|
|
97
101
|
const name = module.padEnd(maxNameLength);
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
return `│ ${name} │ ${coloredVersion}${padding} │`;
|
|
102
|
+
const coloredInstalled = installed === '<error>' ? color_1.colors.red(installed) : color_1.colors.cyan(installed);
|
|
103
|
+
const installedPadding = ' '.repeat(maxInstalledLength - installed.length);
|
|
104
|
+
return `│ ${name} │ ${coloredInstalled}${installedPadding} │ ${requested.padEnd(maxRequestedLength)} │`;
|
|
102
105
|
})
|
|
103
106
|
.sort();
|
|
104
|
-
const top = `┌─${'─'.repeat(maxNameLength)}─┬─${'─'.repeat(
|
|
105
|
-
const header = `│ ${
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
const top = `┌─${'─'.repeat(maxNameLength)}─┬─${'─'.repeat(maxInstalledLength)}─┬─${'─'.repeat(maxRequestedLength)}─┐`;
|
|
108
|
+
const header = `│ ${headers.name.padEnd(maxNameLength)} │ ` +
|
|
109
|
+
`${headers.installed.padEnd(maxInstalledLength)} │ ` +
|
|
110
|
+
`${headers.requested.padEnd(maxRequestedLength)} │`;
|
|
111
|
+
const separator = `├─${'─'.repeat(maxNameLength)}─┼─${'─'.repeat(maxInstalledLength)}─┼─${'─'.repeat(maxRequestedLength)}─┤`;
|
|
112
|
+
const bottom = `└─${'─'.repeat(maxNameLength)}─┴─${'─'.repeat(maxInstalledLength)}─┴─${'─'.repeat(maxRequestedLength)}─┘`;
|
|
108
113
|
return [top, header, separator, ...tableRows, bottom].join('\n');
|
|
109
114
|
}
|
|
110
115
|
}
|
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://angular.dev/license
|
|
7
7
|
*/
|
|
8
|
+
/**
|
|
9
|
+
* An object containing version information for a single package.
|
|
10
|
+
*/
|
|
11
|
+
export interface PackageVersionInfo {
|
|
12
|
+
requested: string;
|
|
13
|
+
installed: string;
|
|
14
|
+
}
|
|
8
15
|
/**
|
|
9
16
|
* An object containing all the version information that will be displayed by the command.
|
|
10
17
|
*/
|
|
@@ -12,6 +19,9 @@ export interface VersionInfo {
|
|
|
12
19
|
cli: {
|
|
13
20
|
version: string;
|
|
14
21
|
};
|
|
22
|
+
framework: {
|
|
23
|
+
version: string | undefined;
|
|
24
|
+
};
|
|
15
25
|
system: {
|
|
16
26
|
node: {
|
|
17
27
|
version: string;
|
|
@@ -26,7 +36,7 @@ export interface VersionInfo {
|
|
|
26
36
|
version: string | undefined;
|
|
27
37
|
};
|
|
28
38
|
};
|
|
29
|
-
packages: Record<string,
|
|
39
|
+
packages: Record<string, PackageVersionInfo>;
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
42
|
* Gathers all the version information from the environment and workspace.
|
|
@@ -44,20 +44,28 @@ function gatherVersionInfo(context) {
|
|
|
44
44
|
catch { }
|
|
45
45
|
const [nodeMajor] = process.versions.node.split('.').map((part) => Number(part));
|
|
46
46
|
const unsupportedNodeVersion = !SUPPORTED_NODE_MAJORS.includes(nodeMajor);
|
|
47
|
-
const
|
|
47
|
+
const allDependencies = {
|
|
48
48
|
...workspacePackage?.dependencies,
|
|
49
49
|
...workspacePackage?.devDependencies,
|
|
50
|
-
}
|
|
50
|
+
};
|
|
51
|
+
const packageNames = new Set(Object.keys(allDependencies));
|
|
51
52
|
const packages = {};
|
|
52
53
|
for (const name of packageNames) {
|
|
53
54
|
if (PACKAGE_PATTERNS.some((p) => p.test(name))) {
|
|
54
|
-
packages[name] =
|
|
55
|
+
packages[name] = {
|
|
56
|
+
requested: allDependencies[name] ?? 'error',
|
|
57
|
+
installed: getVersion(name, workspaceRequire),
|
|
58
|
+
};
|
|
55
59
|
}
|
|
56
60
|
}
|
|
61
|
+
const angularCoreVersion = packages['@angular/core'];
|
|
57
62
|
return {
|
|
58
63
|
cli: {
|
|
59
64
|
version: version_1.VERSION.full,
|
|
60
65
|
},
|
|
66
|
+
framework: {
|
|
67
|
+
version: angularCoreVersion?.installed,
|
|
68
|
+
},
|
|
61
69
|
system: {
|
|
62
70
|
node: {
|
|
63
71
|
version: process.versions.node,
|
package/src/utilities/version.js
CHANGED