@angular/cli 21.0.0-next.5 → 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.
Files changed (37) hide show
  1. package/lib/config/schema.json +140 -43
  2. package/lib/config/workspace-schema.d.ts +1 -0
  3. package/lib/config/workspace-schema.js +1 -0
  4. package/package.json +17 -17
  5. package/src/command-builder/utilities/json-schema.d.ts +13 -1
  6. package/src/command-builder/utilities/json-schema.js +179 -100
  7. package/src/commands/cache/info/cli.js +35 -11
  8. package/src/commands/mcp/tools/doc-search.js +4 -3
  9. package/src/commands/mcp/tools/projects.d.ts +18 -0
  10. package/src/commands/mcp/tools/projects.js +123 -4
  11. package/src/commands/version/cli.d.ts +3 -7
  12. package/src/commands/version/cli.js +49 -49
  13. package/src/commands/version/version-info.d.ts +28 -10
  14. package/src/commands/version/version-info.js +33 -50
  15. package/src/package-managers/discovery.d.ts +23 -0
  16. package/src/package-managers/discovery.js +109 -0
  17. package/src/package-managers/error.d.ts +31 -0
  18. package/src/package-managers/error.js +40 -0
  19. package/src/package-managers/factory.d.ts +25 -0
  20. package/src/package-managers/factory.js +122 -0
  21. package/src/package-managers/host.d.ts +64 -0
  22. package/src/package-managers/host.js +68 -0
  23. package/src/package-managers/logger.d.ts +27 -0
  24. package/src/package-managers/logger.js +9 -0
  25. package/src/package-managers/package-manager-descriptor.d.ts +204 -0
  26. package/src/package-managers/package-manager-descriptor.js +146 -0
  27. package/src/package-managers/package-manager.d.ts +144 -0
  28. package/src/package-managers/package-manager.js +302 -0
  29. package/src/package-managers/package-metadata.d.ts +85 -0
  30. package/src/package-managers/package-metadata.js +9 -0
  31. package/src/package-managers/package-tree.d.ts +23 -0
  32. package/src/package-managers/package-tree.js +9 -0
  33. package/src/package-managers/parsers.d.ts +92 -0
  34. package/src/package-managers/parsers.js +233 -0
  35. package/src/package-managers/testing/mock-host.d.ts +26 -0
  36. package/src/package-managers/testing/mock-host.js +52 -0
  37. package/src/utilities/version.js +1 -1
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ /**
9
+ * @fileoverview
10
+ * This file defines the interfaces for representing a project's installed
11
+ * package dependency tree.
12
+ */
13
+ /**
14
+ * Represents a package that is installed in the project's node_modules.
15
+ */
16
+ export interface InstalledPackage {
17
+ /** The name of the package. */
18
+ readonly name: string;
19
+ /** The installed version of the package. */
20
+ readonly version: string;
21
+ /** The absolute path to the package's directory on disk, if available. */
22
+ readonly path?: string;
23
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,92 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ /**
9
+ * @fileoverview This file contains the parser functions that are used to
10
+ * interpret the output of various package manager commands. Separating these
11
+ * into their own file improves modularity and allows for focused testing.
12
+ */
13
+ import { Logger } from './logger';
14
+ import { PackageManifest, PackageMetadata } from './package-metadata';
15
+ import { InstalledPackage } from './package-tree';
16
+ /**
17
+ * Parses the output of `npm list` or a compatible command.
18
+ *
19
+ * The expected JSON structure is:
20
+ * ```json
21
+ * {
22
+ * "dependencies": {
23
+ * "@angular/cli": {
24
+ * "version": "18.0.0",
25
+ * "path": "/path/to/project/node_modules/@angular/cli", // path is optional
26
+ * ... (other package.json properties)
27
+ * }
28
+ * }
29
+ * }
30
+ * ```
31
+ *
32
+ * @param stdout The standard output of the command.
33
+ * @param logger An optional logger instance.
34
+ * @returns A map of package names to their installed package details.
35
+ */
36
+ export declare function parseNpmLikeDependencies(stdout: string, logger?: Logger): Map<string, InstalledPackage>;
37
+ /**
38
+ * Parses the output of `yarn list` (classic).
39
+ *
40
+ * The expected output is a JSON stream (JSONL), where each line is a JSON object.
41
+ * The relevant object has a `type` of `'tree'`.
42
+ * Yarn classic does not provide a path, so the `path` property will be `undefined`.
43
+ *
44
+ * ```json
45
+ * {"type":"tree","data":{"trees":[{"name":"@angular/cli@18.0.0","children":[]}]}}
46
+ * ```
47
+ *
48
+ * @param stdout The standard output of the command.
49
+ * @param logger An optional logger instance.
50
+ * @returns A map of package names to their installed package details.
51
+ */
52
+ export declare function parseYarnClassicDependencies(stdout: string, logger?: Logger): Map<string, InstalledPackage>;
53
+ /**
54
+ * Parses the output of `yarn list` (modern).
55
+ *
56
+ * The expected JSON structure is a single object.
57
+ * Yarn modern does not provide a path, so the `path` property will be `undefined`.
58
+ *
59
+ * ```json
60
+ * {
61
+ * "trees": [
62
+ * { "name": "@angular/cli@18.0.0", "children": [] }
63
+ * ]
64
+ * }
65
+ * ```
66
+ *
67
+ * @param stdout The standard output of the command.
68
+ * @param logger An optional logger instance.
69
+ * @returns A map of package names to their installed package details.
70
+ */
71
+ export declare function parseYarnModernDependencies(stdout: string, logger?: Logger): Map<string, InstalledPackage>;
72
+ /**
73
+ * Parses the output of `npm view` or a compatible command to get a package manifest.
74
+ * @param stdout The standard output of the command.
75
+ * @param logger An optional logger instance.
76
+ * @returns The package manifest object.
77
+ */
78
+ export declare function parseNpmLikeManifest(stdout: string, logger?: Logger): PackageManifest | null;
79
+ /**
80
+ * Parses the output of `npm view` or a compatible command to get package metadata.
81
+ * @param stdout The standard output of the command.
82
+ * @param logger An optional logger instance.
83
+ * @returns The package metadata object.
84
+ */
85
+ export declare function parseNpmLikeMetadata(stdout: string, logger?: Logger): PackageMetadata | null;
86
+ /**
87
+ * Parses the output of `yarn info` (classic).
88
+ * @param stdout The standard output of the command.
89
+ * @param logger An optional logger instance.
90
+ * @returns The package manifest object.
91
+ */
92
+ export declare function parseYarnLegacyManifest(stdout: string, logger?: Logger): PackageManifest | null;
@@ -0,0 +1,233 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.parseNpmLikeDependencies = parseNpmLikeDependencies;
11
+ exports.parseYarnClassicDependencies = parseYarnClassicDependencies;
12
+ exports.parseYarnModernDependencies = parseYarnModernDependencies;
13
+ exports.parseNpmLikeManifest = parseNpmLikeManifest;
14
+ exports.parseNpmLikeMetadata = parseNpmLikeMetadata;
15
+ exports.parseYarnLegacyManifest = parseYarnLegacyManifest;
16
+ const MAX_LOG_LENGTH = 1024;
17
+ function logStdout(stdout, logger) {
18
+ if (!logger) {
19
+ return;
20
+ }
21
+ let output = stdout;
22
+ if (output.length > MAX_LOG_LENGTH) {
23
+ output = `${output.slice(0, MAX_LOG_LENGTH)}... (truncated)`;
24
+ }
25
+ logger.debug(` stdout:\n${output}`);
26
+ }
27
+ /**
28
+ * Parses the output of `npm list` or a compatible command.
29
+ *
30
+ * The expected JSON structure is:
31
+ * ```json
32
+ * {
33
+ * "dependencies": {
34
+ * "@angular/cli": {
35
+ * "version": "18.0.0",
36
+ * "path": "/path/to/project/node_modules/@angular/cli", // path is optional
37
+ * ... (other package.json properties)
38
+ * }
39
+ * }
40
+ * }
41
+ * ```
42
+ *
43
+ * @param stdout The standard output of the command.
44
+ * @param logger An optional logger instance.
45
+ * @returns A map of package names to their installed package details.
46
+ */
47
+ function parseNpmLikeDependencies(stdout, logger) {
48
+ logger?.debug(`Parsing npm-like dependency list...`);
49
+ logStdout(stdout, logger);
50
+ const dependencies = new Map();
51
+ if (!stdout) {
52
+ logger?.debug(' stdout is empty. No dependencies found.');
53
+ return dependencies;
54
+ }
55
+ let data = JSON.parse(stdout);
56
+ if (Array.isArray(data)) {
57
+ // pnpm returns an array of projects.
58
+ data = data[0];
59
+ }
60
+ const dependencyMaps = [data.dependencies, data.devDependencies, data.unsavedDependencies].filter((d) => !!d);
61
+ if (dependencyMaps.length === 0) {
62
+ logger?.debug(' `dependencies` property not found. No dependencies found.');
63
+ return dependencies;
64
+ }
65
+ for (const dependencyMap of dependencyMaps) {
66
+ for (const [name, info] of Object.entries(dependencyMap)) {
67
+ dependencies.set(name, {
68
+ name,
69
+ version: info.version,
70
+ path: info.path,
71
+ });
72
+ }
73
+ }
74
+ logger?.debug(` Found ${dependencies.size} dependencies.`);
75
+ return dependencies;
76
+ }
77
+ /**
78
+ * Parses the output of `yarn list` (classic).
79
+ *
80
+ * The expected output is a JSON stream (JSONL), where each line is a JSON object.
81
+ * The relevant object has a `type` of `'tree'`.
82
+ * Yarn classic does not provide a path, so the `path` property will be `undefined`.
83
+ *
84
+ * ```json
85
+ * {"type":"tree","data":{"trees":[{"name":"@angular/cli@18.0.0","children":[]}]}}
86
+ * ```
87
+ *
88
+ * @param stdout The standard output of the command.
89
+ * @param logger An optional logger instance.
90
+ * @returns A map of package names to their installed package details.
91
+ */
92
+ function parseYarnClassicDependencies(stdout, logger) {
93
+ logger?.debug(`Parsing yarn classic dependency list...`);
94
+ logStdout(stdout, logger);
95
+ const dependencies = new Map();
96
+ if (!stdout) {
97
+ logger?.debug(' stdout is empty. No dependencies found.');
98
+ return dependencies;
99
+ }
100
+ for (const line of stdout.split('\n')) {
101
+ if (!line) {
102
+ continue;
103
+ }
104
+ const json = JSON.parse(line);
105
+ if (json.type === 'tree' && json.data?.trees) {
106
+ for (const info of json.data.trees) {
107
+ const name = info.name.split('@')[0];
108
+ const version = info.name.split('@').pop();
109
+ dependencies.set(name, {
110
+ name,
111
+ version,
112
+ });
113
+ }
114
+ }
115
+ }
116
+ logger?.debug(` Found ${dependencies.size} dependencies.`);
117
+ return dependencies;
118
+ }
119
+ /**
120
+ * Parses the output of `yarn list` (modern).
121
+ *
122
+ * The expected JSON structure is a single object.
123
+ * Yarn modern does not provide a path, so the `path` property will be `undefined`.
124
+ *
125
+ * ```json
126
+ * {
127
+ * "trees": [
128
+ * { "name": "@angular/cli@18.0.0", "children": [] }
129
+ * ]
130
+ * }
131
+ * ```
132
+ *
133
+ * @param stdout The standard output of the command.
134
+ * @param logger An optional logger instance.
135
+ * @returns A map of package names to their installed package details.
136
+ */
137
+ function parseYarnModernDependencies(stdout, logger) {
138
+ logger?.debug(`Parsing yarn modern dependency list...`);
139
+ logStdout(stdout, logger);
140
+ const dependencies = new Map();
141
+ if (!stdout) {
142
+ logger?.debug(' stdout is empty. No dependencies found.');
143
+ return dependencies;
144
+ }
145
+ // Modern yarn `list` command outputs a single JSON object with a `trees` property.
146
+ // Each line is not a separate JSON object.
147
+ try {
148
+ const data = JSON.parse(stdout);
149
+ for (const info of data.trees) {
150
+ const name = info.name.split('@')[0];
151
+ const version = info.name.split('@').pop();
152
+ dependencies.set(name, {
153
+ name,
154
+ version,
155
+ });
156
+ }
157
+ }
158
+ catch (e) {
159
+ logger?.debug(` Failed to parse as single JSON object: ${e}. Falling back to line-by-line parsing.`);
160
+ // Fallback for older versions of yarn berry that might still output json lines
161
+ for (const line of stdout.split('\n')) {
162
+ if (!line) {
163
+ continue;
164
+ }
165
+ try {
166
+ const json = JSON.parse(line);
167
+ if (json.type === 'tree' && json.data?.trees) {
168
+ for (const info of json.data.trees) {
169
+ const name = info.name.split('@')[0];
170
+ const version = info.name.split('@').pop();
171
+ dependencies.set(name, {
172
+ name,
173
+ version,
174
+ });
175
+ }
176
+ }
177
+ }
178
+ catch (innerError) {
179
+ logger?.debug(` Ignoring non-JSON line: ${innerError}`);
180
+ // Ignore lines that are not valid JSON.
181
+ }
182
+ }
183
+ }
184
+ logger?.debug(` Found ${dependencies.size} dependencies.`);
185
+ return dependencies;
186
+ }
187
+ /**
188
+ * Parses the output of `npm view` or a compatible command to get a package manifest.
189
+ * @param stdout The standard output of the command.
190
+ * @param logger An optional logger instance.
191
+ * @returns The package manifest object.
192
+ */
193
+ function parseNpmLikeManifest(stdout, logger) {
194
+ logger?.debug(`Parsing npm-like manifest...`);
195
+ logStdout(stdout, logger);
196
+ if (!stdout) {
197
+ logger?.debug(' stdout is empty. No manifest found.');
198
+ return null;
199
+ }
200
+ return JSON.parse(stdout);
201
+ }
202
+ /**
203
+ * Parses the output of `npm view` or a compatible command to get package metadata.
204
+ * @param stdout The standard output of the command.
205
+ * @param logger An optional logger instance.
206
+ * @returns The package metadata object.
207
+ */
208
+ function parseNpmLikeMetadata(stdout, logger) {
209
+ logger?.debug(`Parsing npm-like metadata...`);
210
+ logStdout(stdout, logger);
211
+ if (!stdout) {
212
+ logger?.debug(' stdout is empty. No metadata found.');
213
+ return null;
214
+ }
215
+ return JSON.parse(stdout);
216
+ }
217
+ /**
218
+ * Parses the output of `yarn info` (classic).
219
+ * @param stdout The standard output of the command.
220
+ * @param logger An optional logger instance.
221
+ * @returns The package manifest object.
222
+ */
223
+ function parseYarnLegacyManifest(stdout, logger) {
224
+ logger?.debug(`Parsing yarn classic manifest...`);
225
+ logStdout(stdout, logger);
226
+ if (!stdout) {
227
+ logger?.debug(' stdout is empty. No manifest found.');
228
+ return null;
229
+ }
230
+ const data = JSON.parse(stdout);
231
+ // Yarn classic wraps the manifest in a `data` property.
232
+ return data.data ?? data;
233
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google LLC All Rights Reserved.
4
+ *
5
+ * Use of this source code is governed by an MIT-style license that can be
6
+ * found in the LICENSE file at https://angular.dev/license
7
+ */
8
+ import { Stats } from 'node:fs';
9
+ import { Host } from '../host';
10
+ /**
11
+ * A mock `Host` implementation for testing.
12
+ * This class allows for simulating a file system in memory.
13
+ */
14
+ export declare class MockHost implements Host {
15
+ private readonly fs;
16
+ constructor(files?: Record<string, string[] | true>);
17
+ stat(path: string): Promise<Stats>;
18
+ readdir(path: string): Promise<string[]>;
19
+ runCommand(): Promise<{
20
+ stdout: string;
21
+ stderr: string;
22
+ }>;
23
+ createTempDirectory(): Promise<string>;
24
+ deleteDirectory(): Promise<void>;
25
+ writeFile(): Promise<void>;
26
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ /**
3
+ * @license
4
+ * Copyright Google LLC All Rights Reserved.
5
+ *
6
+ * Use of this source code is governed by an MIT-style license that can be
7
+ * found in the LICENSE file at https://angular.dev/license
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.MockHost = void 0;
11
+ /**
12
+ * A mock `Host` implementation for testing.
13
+ * This class allows for simulating a file system in memory.
14
+ */
15
+ class MockHost {
16
+ fs = new Map();
17
+ constructor(files = {}) {
18
+ // Normalize paths to use forward slashes for consistency in tests.
19
+ for (const [path, content] of Object.entries(files)) {
20
+ this.fs.set(path.replace(/\\/g, '/'), content);
21
+ }
22
+ }
23
+ stat(path) {
24
+ const content = this.fs.get(path.replace(/\\/g, '/'));
25
+ if (content === undefined) {
26
+ return Promise.reject(new Error(`File not found: ${path}`));
27
+ }
28
+ // A `true` value signifies a directory in our mock file system.
29
+ return Promise.resolve({ isDirectory: () => content === true });
30
+ }
31
+ readdir(path) {
32
+ const content = this.fs.get(path.replace(/\\/g, '/'));
33
+ if (content === true || content === undefined) {
34
+ // This should be a directory with a file list.
35
+ return Promise.reject(new Error(`Directory not found or not a directory: ${path}`));
36
+ }
37
+ return Promise.resolve(content);
38
+ }
39
+ runCommand() {
40
+ throw new Error('Method not implemented.');
41
+ }
42
+ createTempDirectory() {
43
+ throw new Error('Method not implemented.');
44
+ }
45
+ deleteDirectory() {
46
+ throw new Error('Method not implemented.');
47
+ }
48
+ writeFile() {
49
+ throw new Error('Method not implemented.');
50
+ }
51
+ }
52
+ exports.MockHost = MockHost;
@@ -22,4 +22,4 @@ class Version {
22
22
  this.patch = patch;
23
23
  }
24
24
  }
25
- exports.VERSION = new Version('21.0.0-next.5');
25
+ exports.VERSION = new Version('21.0.0-next.7');