@angular/cli 21.0.0-next.4 → 21.0.0-next.6
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/lib/config/schema.json +146 -44
- package/lib/config/workspace-schema.d.ts +1 -0
- package/lib/config/workspace-schema.js +1 -0
- package/package.json +17 -17
- package/src/command-builder/utilities/json-schema.d.ts +13 -1
- package/src/command-builder/utilities/json-schema.js +179 -100
- package/src/commands/cache/info/cli.js +35 -11
- package/src/commands/mcp/mcp-server.js +2 -0
- package/src/commands/mcp/resources/ai-tutor.md +627 -0
- package/src/commands/mcp/tools/ai-tutor.d.ts +8 -0
- package/src/commands/mcp/tools/ai-tutor.js +61 -0
- package/src/commands/mcp/tools/doc-search.d.ts +1 -0
- package/src/commands/mcp/tools/doc-search.js +17 -4
- package/src/commands/mcp/tools/onpush-zoneless-migration/zoneless-migration.js +55 -33
- package/src/commands/new/cli.js +1 -0
- package/src/commands/version/cli.d.ts +3 -7
- package/src/commands/version/cli.js +44 -49
- package/src/commands/version/version-info.d.ts +18 -10
- package/src/commands/version/version-info.js +23 -48
- package/src/package-managers/discovery.d.ts +23 -0
- package/src/package-managers/discovery.js +109 -0
- package/src/package-managers/error.d.ts +31 -0
- package/src/package-managers/error.js +40 -0
- package/src/package-managers/factory.d.ts +25 -0
- package/src/package-managers/factory.js +122 -0
- package/src/package-managers/host.d.ts +64 -0
- package/src/package-managers/host.js +68 -0
- package/src/package-managers/logger.d.ts +27 -0
- package/src/package-managers/logger.js +9 -0
- package/src/package-managers/package-manager-descriptor.d.ts +204 -0
- package/src/package-managers/package-manager-descriptor.js +146 -0
- package/src/package-managers/package-manager.d.ts +144 -0
- package/src/package-managers/package-manager.js +302 -0
- package/src/package-managers/package-metadata.d.ts +85 -0
- package/src/package-managers/package-metadata.js +9 -0
- package/src/package-managers/package-tree.d.ts +23 -0
- package/src/package-managers/package-tree.js +9 -0
- package/src/package-managers/parsers.d.ts +92 -0
- package/src/package-managers/parsers.js +233 -0
- package/src/package-managers/testing/mock-host.d.ts +26 -0
- package/src/package-managers/testing/mock-host.js +52 -0
- package/src/utilities/package-manager.js +20 -13
- package/src/utilities/version.js +1 -1
|
@@ -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;
|
|
@@ -288,17 +288,17 @@ let PackageManagerUtils = (() => {
|
|
|
288
288
|
: lockfiles.some((lockfile) => filesInRoot.includes(lockfile));
|
|
289
289
|
}
|
|
290
290
|
getConfiguredPackageManager() {
|
|
291
|
-
const getPackageManager = (source) => {
|
|
292
|
-
if (source && (0, core_1.isJsonObject)(source)) {
|
|
293
|
-
const value = source['packageManager'];
|
|
294
|
-
if (typeof value === 'string') {
|
|
295
|
-
return value;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
return undefined;
|
|
299
|
-
};
|
|
300
|
-
let result;
|
|
301
291
|
const { workspace: localWorkspace, globalConfiguration: globalWorkspace } = this.context;
|
|
292
|
+
let result;
|
|
293
|
+
try {
|
|
294
|
+
const packageJsonPath = (0, node_path_1.join)(this.context.root, 'package.json');
|
|
295
|
+
const pkgJson = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, 'utf-8'));
|
|
296
|
+
result = getPackageManager(pkgJson);
|
|
297
|
+
}
|
|
298
|
+
catch { }
|
|
299
|
+
if (result) {
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
302
|
if (localWorkspace) {
|
|
303
303
|
const project = (0, config_1.getProjectByCwd)(localWorkspace);
|
|
304
304
|
if (project) {
|
|
@@ -306,11 +306,18 @@ let PackageManagerUtils = (() => {
|
|
|
306
306
|
}
|
|
307
307
|
result ??= getPackageManager(localWorkspace.extensions['cli']);
|
|
308
308
|
}
|
|
309
|
-
|
|
310
|
-
result = getPackageManager(globalWorkspace.extensions['cli']);
|
|
311
|
-
}
|
|
309
|
+
result ??= getPackageManager(globalWorkspace.extensions['cli']);
|
|
312
310
|
return result;
|
|
313
311
|
}
|
|
314
312
|
};
|
|
315
313
|
})();
|
|
316
314
|
exports.PackageManagerUtils = PackageManagerUtils;
|
|
315
|
+
function getPackageManager(source) {
|
|
316
|
+
if (source && (0, core_1.isJsonObject)(source)) {
|
|
317
|
+
const value = source['packageManager'];
|
|
318
|
+
if (typeof value === 'string') {
|
|
319
|
+
return value.split('@', 1)[0];
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return undefined;
|
|
323
|
+
}
|
package/src/utilities/version.js
CHANGED