@angular/cli 20.2.1 → 21.0.0-next.1

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.
@@ -51,7 +51,6 @@
51
51
  "type": "string",
52
52
  "enum": [
53
53
  "npm",
54
- "cnpm",
55
54
  "yarn",
56
55
  "pnpm",
57
56
  "bun"
@@ -118,7 +117,6 @@
118
117
  "type": "string",
119
118
  "enum": [
120
119
  "npm",
121
- "cnpm",
122
120
  "yarn",
123
121
  "pnpm",
124
122
  "bun"
@@ -1007,7 +1005,8 @@
1007
1005
  "css",
1008
1006
  "scss",
1009
1007
  "sass",
1010
- "less"
1008
+ "less",
1009
+ "tailwind"
1011
1010
  ]
1012
1011
  },
1013
1012
  "skipTests": {
@@ -1769,7 +1768,8 @@
1769
1768
  "css",
1770
1769
  "scss",
1771
1770
  "sass",
1772
- "less"
1771
+ "less",
1772
+ "tailwind"
1773
1773
  ]
1774
1774
  },
1775
1775
  "skipTests": {
@@ -1800,7 +1800,6 @@
1800
1800
  "npm",
1801
1801
  "yarn",
1802
1802
  "pnpm",
1803
- "cnpm",
1804
1803
  "bun"
1805
1804
  ]
1806
1805
  },
@@ -4377,6 +4376,10 @@
4377
4376
  "type": "string"
4378
4377
  },
4379
4378
  "description": "A list of global setup and configuration files that are included before the test files. The application's polyfills are always included before these files. The Angular Testbed is also initialized prior to the execution of these files."
4379
+ },
4380
+ "progress": {
4381
+ "type": "boolean",
4382
+ "description": "Log progress to the console while building. Defaults to the build target's progress value."
4380
4383
  }
4381
4384
  },
4382
4385
  "additionalProperties": false,
@@ -67,7 +67,6 @@ export declare enum Environment {
67
67
  */
68
68
  export declare enum PackageManager {
69
69
  Bun = "bun",
70
- Cnpm = "cnpm",
71
70
  Npm = "npm",
72
71
  Pnpm = "pnpm",
73
72
  Yarn = "yarn"
@@ -196,7 +195,8 @@ export declare enum SchematicsAngularApplicationStyle {
196
195
  Css = "css",
197
196
  Less = "less",
198
197
  Sass = "sass",
199
- Scss = "scss"
198
+ Scss = "scss",
199
+ Tailwind = "tailwind"
200
200
  }
201
201
  /**
202
202
  * Sets the view encapsulation mode for the application's components. This determines how
@@ -20,7 +20,6 @@ var Environment;
20
20
  var PackageManager;
21
21
  (function (PackageManager) {
22
22
  PackageManager["Bun"] = "bun";
23
- PackageManager["Cnpm"] = "cnpm";
24
23
  PackageManager["Npm"] = "npm";
25
24
  PackageManager["Pnpm"] = "pnpm";
26
25
  PackageManager["Yarn"] = "yarn";
@@ -36,6 +35,7 @@ var SchematicsAngularApplicationStyle;
36
35
  SchematicsAngularApplicationStyle["Less"] = "less";
37
36
  SchematicsAngularApplicationStyle["Sass"] = "sass";
38
37
  SchematicsAngularApplicationStyle["Scss"] = "scss";
38
+ SchematicsAngularApplicationStyle["Tailwind"] = "tailwind";
39
39
  })(SchematicsAngularApplicationStyle || (exports.SchematicsAngularApplicationStyle = SchematicsAngularApplicationStyle = {}));
40
40
  /**
41
41
  * Sets the view encapsulation mode for the application's components. This determines how
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/cli",
3
- "version": "20.2.1",
3
+ "version": "21.0.0-next.1",
4
4
  "description": "CLI tool for Angular",
5
5
  "main": "lib/cli/index.js",
6
6
  "bin": {
@@ -25,18 +25,18 @@
25
25
  },
26
26
  "homepage": "https://github.com/angular/angular-cli",
27
27
  "dependencies": {
28
- "@angular-devkit/architect": "0.2002.1",
29
- "@angular-devkit/core": "20.2.1",
30
- "@angular-devkit/schematics": "20.2.1",
31
- "@inquirer/prompts": "7.8.2",
32
- "@listr2/prompt-adapter-inquirer": "3.0.1",
33
- "@modelcontextprotocol/sdk": "1.17.3",
34
- "@schematics/angular": "20.2.1",
28
+ "@angular-devkit/architect": "0.2100.0-next.1",
29
+ "@angular-devkit/core": "21.0.0-next.1",
30
+ "@angular-devkit/schematics": "21.0.0-next.1",
31
+ "@inquirer/prompts": "7.8.4",
32
+ "@listr2/prompt-adapter-inquirer": "3.0.2",
33
+ "@modelcontextprotocol/sdk": "1.17.4",
34
+ "@schematics/angular": "21.0.0-next.1",
35
35
  "@yarnpkg/lockfile": "1.1.0",
36
- "algoliasearch": "5.35.0",
36
+ "algoliasearch": "5.36.0",
37
37
  "ini": "5.0.0",
38
38
  "jsonc-parser": "3.3.1",
39
- "listr2": "9.0.1",
39
+ "listr2": "9.0.2",
40
40
  "npm-package-arg": "13.0.0",
41
41
  "pacote": "21.0.0",
42
42
  "resolve": "1.22.10",
@@ -47,14 +47,14 @@
47
47
  "ng-update": {
48
48
  "migrations": "@schematics/angular/migrations/migration-collection.json",
49
49
  "packageGroup": {
50
- "@angular/cli": "20.2.1",
51
- "@angular/build": "20.2.1",
52
- "@angular/ssr": "20.2.1",
53
- "@angular-devkit/architect": "0.2002.1",
54
- "@angular-devkit/build-angular": "20.2.1",
55
- "@angular-devkit/build-webpack": "0.2002.1",
56
- "@angular-devkit/core": "20.2.1",
57
- "@angular-devkit/schematics": "20.2.1"
50
+ "@angular/cli": "21.0.0-next.1",
51
+ "@angular/build": "21.0.0-next.1",
52
+ "@angular/ssr": "21.0.0-next.1",
53
+ "@angular-devkit/architect": "0.2100.0-next.1",
54
+ "@angular-devkit/build-angular": "21.0.0-next.1",
55
+ "@angular-devkit/build-webpack": "0.2100.0-next.1",
56
+ "@angular-devkit/core": "21.0.0-next.1",
57
+ "@angular-devkit/schematics": "21.0.0-next.1"
58
58
  }
59
59
  },
60
60
  "packageManager": "pnpm@10.15.0",
@@ -15,6 +15,7 @@ interface AddCommandArgs extends SchematicsCommandArgs {
15
15
  'skip-confirmation'?: boolean;
16
16
  }
17
17
  export default class AddCommandModule extends SchematicsCommandModule implements CommandModuleImplementation<AddCommandArgs> {
18
+ #private;
18
19
  command: string;
19
20
  describe: string;
20
21
  longDescriptionPath: string;
@@ -23,11 +24,16 @@ export default class AddCommandModule extends SchematicsCommandModule implements
23
24
  private rootRequire;
24
25
  builder(argv: Argv): Promise<Argv<AddCommandArgs>>;
25
26
  run(options: Options<AddCommandArgs> & OtherOptions): Promise<number | void>;
27
+ private determinePackageManagerTask;
28
+ private findCompatiblePackageVersionTask;
29
+ private loadPackageInfoTask;
30
+ private confirmInstallationTask;
31
+ private installPackageTask;
26
32
  private isProjectVersionValid;
27
33
  private getCollectionName;
28
34
  private isPackageInstalled;
29
35
  private executeSchematic;
30
36
  private findProjectVersion;
31
- private hasMismatchedPeer;
37
+ private getPeerDependencyConflicts;
32
38
  }
33
39
  export {};
@@ -69,6 +69,7 @@ const packageVersionExclusions = {
69
69
  // @angular/material@7.x versions have unbounded peer dependency ranges (>=7.0.0).
70
70
  '@angular/material': '7.x',
71
71
  };
72
+ const DEFAULT_CONFLICT_DISPLAY_LIMIT = 5;
72
73
  class AddCommandModule extends schematics_command_module_1.SchematicsCommandModule {
73
74
  command = 'add <collection>';
74
75
  describe = 'Adds support for an external library to your project.';
@@ -76,6 +77,7 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
76
77
  allowPrivateSchematics = true;
77
78
  schematicName = 'ng-add';
78
79
  rootRequire = (0, node_module_1.createRequire)(this.context.root + '/');
80
+ #projectVersionCache = new Map();
79
81
  async builder(argv) {
80
82
  const localYargs = (await super.builder(argv))
81
83
  .positional('collection', {
@@ -116,10 +118,10 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
116
118
  }
117
119
  return localYargs;
118
120
  }
119
- // eslint-disable-next-line max-lines-per-function
120
121
  async run(options) {
121
- const { logger, packageManager } = this.context;
122
- const { verbose, registry, collection, skipConfirmation } = options;
122
+ this.#projectVersionCache.clear();
123
+ const { logger } = this.context;
124
+ const { collection, skipConfirmation } = options;
123
125
  let packageIdentifier;
124
126
  try {
125
127
  packageIdentifier = (0, npm_package_arg_1.default)(collection);
@@ -142,180 +144,226 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
142
144
  const taskContext = {
143
145
  packageIdentifier,
144
146
  executeSchematic: this.executeSchematic.bind(this),
145
- hasMismatchedPeer: this.hasMismatchedPeer.bind(this),
147
+ getPeerDependencyConflicts: this.getPeerDependencyConflicts.bind(this),
148
+ dryRun: options.dryRun,
146
149
  };
147
150
  const tasks = new listr2_1.Listr([
148
151
  {
149
152
  title: 'Determining Package Manager',
150
- task(context, task) {
151
- context.usingYarn = packageManager.name === workspace_schema_1.PackageManager.Yarn;
152
- task.output = `Using package manager: ${listr2_1.color.dim(packageManager.name)}`;
153
- },
153
+ task: (context, task) => this.determinePackageManagerTask(context, task),
154
154
  rendererOptions: { persistentOutput: true },
155
155
  },
156
156
  {
157
157
  title: 'Searching for compatible package version',
158
158
  enabled: packageIdentifier.type === 'range' && packageIdentifier.rawSpec === '*',
159
- async task(context, task) {
160
- (0, node_assert_1.default)(context.packageIdentifier.name, 'Registry package identifiers should always have a name.');
161
- // only package name provided; search for viable version
162
- // plus special cases for packages that did not have peer deps setup
163
- let packageMetadata;
164
- try {
165
- packageMetadata = await (0, package_metadata_1.fetchPackageMetadata)(context.packageIdentifier.name, logger, {
166
- registry,
167
- usingYarn: context.usingYarn,
168
- verbose,
169
- });
170
- }
171
- catch (e) {
172
- (0, error_1.assertIsError)(e);
173
- throw new CommandError(`Unable to load package information from registry: ${e.message}`);
174
- }
175
- // Start with the version tagged as `latest` if it exists
176
- const latestManifest = packageMetadata.tags['latest'];
177
- if (latestManifest) {
178
- context.packageIdentifier = npm_package_arg_1.default.resolve(latestManifest.name, latestManifest.version);
179
- }
180
- // Adjust the version based on name and peer dependencies
181
- if (latestManifest?.peerDependencies &&
182
- Object.keys(latestManifest.peerDependencies).length === 0) {
183
- task.output = `Found compatible package version: ${listr2_1.color.blue(latestManifest.version)}.`;
184
- }
185
- else if (!latestManifest || (await context.hasMismatchedPeer(latestManifest))) {
186
- // 'latest' is invalid so search for most recent matching package
187
- // Allow prelease versions if the CLI itself is a prerelease
188
- const allowPrereleases = (0, semver_1.prerelease)(version_1.VERSION.full);
189
- const versionExclusions = packageVersionExclusions[packageMetadata.name];
190
- const versionManifests = Object.values(packageMetadata.versions).filter((value) => {
191
- // Prerelease versions are not stable and should not be considered by default
192
- if (!allowPrereleases && (0, semver_1.prerelease)(value.version)) {
193
- return false;
194
- }
195
- // Deprecated versions should not be used or considered
196
- if (value.deprecated) {
197
- return false;
198
- }
199
- // Excluded package versions should not be considered
200
- if (versionExclusions &&
201
- (0, semver_1.satisfies)(value.version, versionExclusions, { includePrerelease: true })) {
202
- return false;
203
- }
204
- return true;
205
- });
206
- // Sort in reverse SemVer order so that the newest compatible version is chosen
207
- versionManifests.sort((a, b) => (0, semver_1.compare)(b.version, a.version, true));
208
- let found = false;
209
- for (const versionManifest of versionManifests) {
210
- const mismatch = await context.hasMismatchedPeer(versionManifest);
211
- if (mismatch) {
212
- continue;
213
- }
214
- context.packageIdentifier = npm_package_arg_1.default.resolve(versionManifest.name, versionManifest.version);
215
- found = true;
216
- break;
217
- }
218
- if (!found) {
219
- task.output = "Unable to find compatible package. Using 'latest' tag.";
220
- }
221
- else {
222
- task.output = `Found compatible package version: ${listr2_1.color.blue(context.packageIdentifier.toString())}.`;
223
- }
224
- }
225
- else {
226
- task.output = `Found compatible package version: ${listr2_1.color.blue(context.packageIdentifier.toString())}.`;
227
- }
228
- },
159
+ task: (context, task) => this.findCompatiblePackageVersionTask(context, task, options),
229
160
  rendererOptions: { persistentOutput: true },
230
161
  },
231
162
  {
232
163
  title: 'Loading package information from registry',
233
- async task(context, task) {
234
- let manifest;
235
- try {
236
- manifest = await (0, package_metadata_1.fetchPackageManifest)(context.packageIdentifier.toString(), logger, {
237
- registry,
238
- verbose,
239
- usingYarn: context.usingYarn,
240
- });
241
- }
242
- catch (e) {
243
- (0, error_1.assertIsError)(e);
244
- throw new CommandError(`Unable to fetch package information for '${context.packageIdentifier}': ${e.message}`);
245
- }
246
- context.savePackage = manifest['ng-add']?.save;
247
- context.collectionName = manifest.name;
248
- if (await context.hasMismatchedPeer(manifest)) {
249
- task.output = listr2_1.color.yellow(listr2_1.figures.warning +
250
- ' Package has unmet peer dependencies. Adding the package may not succeed.');
251
- }
252
- },
164
+ task: (context, task) => this.loadPackageInfoTask(context, task, options),
253
165
  rendererOptions: { persistentOutput: true },
254
166
  },
255
167
  {
256
168
  title: 'Confirming installation',
257
- enabled: !skipConfirmation,
258
- async task(context, task) {
259
- if (!(0, tty_1.isTTY)()) {
260
- task.output =
261
- `'--skip-confirmation' can be used to bypass installation confirmation. ` +
262
- `Ensure package name is correct prior to '--skip-confirmation' option usage.`;
263
- throw new CommandError('No terminal detected');
264
- }
265
- const { ListrInquirerPromptAdapter } = await Promise.resolve().then(() => __importStar(require('@listr2/prompt-adapter-inquirer')));
266
- const { confirm } = await Promise.resolve().then(() => __importStar(require('@inquirer/prompts')));
267
- const shouldProceed = await task.prompt(ListrInquirerPromptAdapter).run(confirm, {
268
- message: `The package ${listr2_1.color.blue(context.packageIdentifier.toString())} will be installed and executed.\n` +
269
- 'Would you like to proceed?',
270
- default: true,
271
- theme: { prefix: '' },
272
- });
273
- if (!shouldProceed) {
274
- throw new CommandError('Command aborted');
275
- }
276
- },
169
+ enabled: !skipConfirmation && !options.dryRun,
170
+ task: (context, task) => this.confirmInstallationTask(context, task),
277
171
  rendererOptions: { persistentOutput: true },
278
172
  },
279
173
  {
280
- async task(context, task) {
281
- // Only show if installation will actually occur
282
- task.title = 'Installing package';
283
- if (context.savePackage === false) {
284
- task.title += ' in temporary location';
285
- // Temporary packages are located in a different directory
286
- // Hence we need to resolve them using the temp path
287
- const { success, tempNodeModules } = await packageManager.installTemp(context.packageIdentifier.toString(), registry ? [`--registry="${registry}"`] : undefined);
288
- const tempRequire = (0, node_module_1.createRequire)(tempNodeModules + '/');
289
- (0, node_assert_1.default)(context.collectionName, 'Collection name should always be available');
290
- const resolvedCollectionPath = tempRequire.resolve((0, node_path_1.join)(context.collectionName, 'package.json'));
291
- if (!success) {
292
- throw new CommandError('Unable to install package');
293
- }
294
- context.collectionName = (0, node_path_1.dirname)(resolvedCollectionPath);
295
- }
296
- else {
297
- const success = await packageManager.install(context.packageIdentifier.toString(), context.savePackage, registry ? [`--registry="${registry}"`] : undefined, undefined);
298
- if (!success) {
299
- throw new CommandError('Unable to install package');
300
- }
174
+ title: 'Installing package',
175
+ skip: (context) => {
176
+ if (context.dryRun) {
177
+ return `Skipping package installation. Would install package ${listr2_1.color.blue(context.packageIdentifier.toString())}.`;
301
178
  }
179
+ return false;
302
180
  },
181
+ task: (context, task) => this.installPackageTask(context, task, options),
303
182
  rendererOptions: { bottomBar: Infinity },
304
183
  },
305
184
  // TODO: Rework schematic execution as a task and insert here
306
- ]);
185
+ ], {
186
+ /* options */
187
+ });
307
188
  try {
308
189
  const result = await tasks.run(taskContext);
309
190
  (0, node_assert_1.default)(result.collectionName, 'Collection name should always be available');
191
+ if (options.dryRun) {
192
+ logger.info('The package schematic would be executed next.');
193
+ return;
194
+ }
310
195
  return this.executeSchematic({ ...options, collection: result.collectionName });
311
196
  }
312
197
  catch (e) {
313
198
  if (e instanceof CommandError) {
199
+ logger.error(e.message);
314
200
  return 1;
315
201
  }
316
202
  throw e;
317
203
  }
318
204
  }
205
+ determinePackageManagerTask(context, task) {
206
+ const { packageManager } = this.context;
207
+ context.usingYarn = packageManager.name === workspace_schema_1.PackageManager.Yarn;
208
+ task.output = `Using package manager: ${listr2_1.color.dim(packageManager.name)}`;
209
+ }
210
+ async findCompatiblePackageVersionTask(context, task, options) {
211
+ const { logger } = this.context;
212
+ const { verbose, registry } = options;
213
+ (0, node_assert_1.default)(context.packageIdentifier.name, 'Registry package identifiers should always have a name.');
214
+ // only package name provided; search for viable version
215
+ // plus special cases for packages that did not have peer deps setup
216
+ let packageMetadata;
217
+ try {
218
+ packageMetadata = await (0, package_metadata_1.fetchPackageMetadata)(context.packageIdentifier.name, logger, {
219
+ registry,
220
+ usingYarn: context.usingYarn,
221
+ verbose,
222
+ });
223
+ }
224
+ catch (e) {
225
+ (0, error_1.assertIsError)(e);
226
+ throw new CommandError(`Unable to load package information from registry: ${e.message}`);
227
+ }
228
+ const rejectionReasons = [];
229
+ // Start with the version tagged as `latest` if it exists
230
+ const latestManifest = packageMetadata.tags['latest'];
231
+ if (latestManifest) {
232
+ const latestConflicts = await this.getPeerDependencyConflicts(latestManifest);
233
+ if (latestConflicts) {
234
+ // 'latest' is invalid so search for most recent matching package
235
+ rejectionReasons.push(...latestConflicts);
236
+ }
237
+ else {
238
+ context.packageIdentifier = npm_package_arg_1.default.resolve(latestManifest.name, latestManifest.version);
239
+ task.output = `Found compatible package version: ${listr2_1.color.blue(latestManifest.version)}.`;
240
+ return;
241
+ }
242
+ }
243
+ // Allow prelease versions if the CLI itself is a prerelease
244
+ const allowPrereleases = !!(0, semver_1.prerelease)(version_1.VERSION.full);
245
+ const versionManifests = this.#getPotentialVersionManifests(packageMetadata, allowPrereleases);
246
+ let found = false;
247
+ for (const versionManifest of versionManifests) {
248
+ // Already checked the 'latest' version
249
+ if (latestManifest?.version === versionManifest.version) {
250
+ continue;
251
+ }
252
+ const conflicts = await this.getPeerDependencyConflicts(versionManifest);
253
+ if (conflicts) {
254
+ if (options.verbose || rejectionReasons.length < DEFAULT_CONFLICT_DISPLAY_LIMIT) {
255
+ rejectionReasons.push(...conflicts);
256
+ }
257
+ continue;
258
+ }
259
+ context.packageIdentifier = npm_package_arg_1.default.resolve(versionManifest.name, versionManifest.version);
260
+ found = true;
261
+ break;
262
+ }
263
+ if (!found) {
264
+ let message = `Unable to find compatible package. Using 'latest' tag.`;
265
+ if (rejectionReasons.length > 0) {
266
+ message +=
267
+ '\nThis is often because of incompatible peer dependencies.\n' +
268
+ 'These versions were rejected due to the following conflicts:\n' +
269
+ rejectionReasons
270
+ .slice(0, options.verbose ? undefined : DEFAULT_CONFLICT_DISPLAY_LIMIT)
271
+ .map((r) => ` - ${r}`)
272
+ .join('\n');
273
+ }
274
+ task.output = message;
275
+ }
276
+ else {
277
+ task.output = `Found compatible package version: ${listr2_1.color.blue(context.packageIdentifier.toString())}.`;
278
+ }
279
+ }
280
+ #getPotentialVersionManifests(packageMetadata, allowPrereleases) {
281
+ const versionExclusions = packageVersionExclusions[packageMetadata.name];
282
+ const versionManifests = Object.values(packageMetadata.versions).filter((value) => {
283
+ // Prerelease versions are not stable and should not be considered by default
284
+ if (!allowPrereleases && (0, semver_1.prerelease)(value.version)) {
285
+ return false;
286
+ }
287
+ // Deprecated versions should not be used or considered
288
+ if (value.deprecated) {
289
+ return false;
290
+ }
291
+ // Excluded package versions should not be considered
292
+ if (versionExclusions &&
293
+ (0, semver_1.satisfies)(value.version, versionExclusions, { includePrerelease: true })) {
294
+ return false;
295
+ }
296
+ return true;
297
+ });
298
+ // Sort in reverse SemVer order so that the newest compatible version is chosen
299
+ return versionManifests.sort((a, b) => (0, semver_1.compare)(b.version, a.version, true));
300
+ }
301
+ async loadPackageInfoTask(context, task, options) {
302
+ const { logger } = this.context;
303
+ const { verbose, registry } = options;
304
+ let manifest;
305
+ try {
306
+ manifest = await (0, package_metadata_1.fetchPackageManifest)(context.packageIdentifier.toString(), logger, {
307
+ registry,
308
+ verbose,
309
+ usingYarn: context.usingYarn,
310
+ });
311
+ }
312
+ catch (e) {
313
+ (0, error_1.assertIsError)(e);
314
+ throw new CommandError(`Unable to fetch package information for '${context.packageIdentifier}': ${e.message}`);
315
+ }
316
+ context.savePackage = manifest['ng-add']?.save;
317
+ context.collectionName = manifest.name;
318
+ if (await this.getPeerDependencyConflicts(manifest)) {
319
+ task.output = listr2_1.color.yellow(listr2_1.figures.warning +
320
+ ' Package has unmet peer dependencies. Adding the package may not succeed.');
321
+ }
322
+ }
323
+ async confirmInstallationTask(context, task) {
324
+ if (!(0, tty_1.isTTY)()) {
325
+ task.output =
326
+ `'--skip-confirmation' can be used to bypass installation confirmation. ` +
327
+ `Ensure package name is correct prior to '--skip-confirmation' option usage.`;
328
+ throw new CommandError('No terminal detected');
329
+ }
330
+ const { ListrInquirerPromptAdapter } = await Promise.resolve().then(() => __importStar(require('@listr2/prompt-adapter-inquirer')));
331
+ const { confirm } = await Promise.resolve().then(() => __importStar(require('@inquirer/prompts')));
332
+ const shouldProceed = await task.prompt(ListrInquirerPromptAdapter).run(confirm, {
333
+ message: `The package ${listr2_1.color.blue(context.packageIdentifier.toString())} will be installed and executed.\n` +
334
+ 'Would you like to proceed?',
335
+ default: true,
336
+ theme: { prefix: '' },
337
+ });
338
+ if (!shouldProceed) {
339
+ throw new CommandError('Command aborted');
340
+ }
341
+ }
342
+ async installPackageTask(context, task, options) {
343
+ const { packageManager } = this.context;
344
+ const { registry } = options;
345
+ // Only show if installation will actually occur
346
+ task.title = 'Installing package';
347
+ if (context.savePackage === false) {
348
+ task.title += ' in temporary location';
349
+ // Temporary packages are located in a different directory
350
+ // Hence we need to resolve them using the temp path
351
+ const { success, tempNodeModules } = await packageManager.installTemp(context.packageIdentifier.toString(), registry ? [`--registry="${registry}"`] : undefined);
352
+ const tempRequire = (0, node_module_1.createRequire)(tempNodeModules + '/');
353
+ (0, node_assert_1.default)(context.collectionName, 'Collection name should always be available');
354
+ const resolvedCollectionPath = tempRequire.resolve((0, node_path_1.join)(context.collectionName, 'package.json'));
355
+ if (!success) {
356
+ throw new CommandError('Unable to install package');
357
+ }
358
+ context.collectionName = (0, node_path_1.dirname)(resolvedCollectionPath);
359
+ }
360
+ else {
361
+ const success = await packageManager.install(context.packageIdentifier.toString(), context.savePackage, registry ? [`--registry="${registry}"`] : undefined, undefined);
362
+ if (!success) {
363
+ throw new CommandError('Unable to install package');
364
+ }
365
+ }
366
+ }
319
367
  async isProjectVersionValid(packageIdentifier) {
320
368
  if (!packageIdentifier.name) {
321
369
  return false;
@@ -397,6 +445,10 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
397
445
  }
398
446
  }
399
447
  async findProjectVersion(name) {
448
+ const cachedVersion = this.#projectVersionCache.get(name);
449
+ if (cachedVersion !== undefined) {
450
+ return cachedVersion;
451
+ }
400
452
  const { logger, root } = this.context;
401
453
  let installedPackage;
402
454
  try {
@@ -406,6 +458,7 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
406
458
  if (installedPackage) {
407
459
  try {
408
460
  const installed = await (0, package_metadata_1.fetchPackageManifest)((0, node_path_1.dirname)(installedPackage), logger);
461
+ this.#projectVersionCache.set(name, installed.version);
409
462
  return installed.version;
410
463
  }
411
464
  catch { }
@@ -418,44 +471,50 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
418
471
  if (projectManifest) {
419
472
  const version = projectManifest.dependencies?.[name] || projectManifest.devDependencies?.[name];
420
473
  if (version) {
474
+ this.#projectVersionCache.set(name, version);
421
475
  return version;
422
476
  }
423
477
  }
478
+ this.#projectVersionCache.set(name, null);
424
479
  return null;
425
480
  }
426
- async hasMismatchedPeer(manifest) {
427
- for (const peer in manifest.peerDependencies) {
481
+ async getPeerDependencyConflicts(manifest) {
482
+ if (!manifest.peerDependencies) {
483
+ return false;
484
+ }
485
+ const checks = Object.entries(manifest.peerDependencies).map(async ([peer, range]) => {
428
486
  let peerIdentifier;
429
487
  try {
430
- peerIdentifier = npm_package_arg_1.default.resolve(peer, manifest.peerDependencies[peer]);
488
+ peerIdentifier = npm_package_arg_1.default.resolve(peer, range);
431
489
  }
432
490
  catch {
433
491
  this.context.logger.warn(`Invalid peer dependency ${peer} found in package.`);
434
- continue;
492
+ return null;
435
493
  }
436
- if (peerIdentifier.type === 'version' || peerIdentifier.type === 'range') {
437
- try {
438
- const version = await this.findProjectVersion(peer);
439
- if (!version) {
440
- continue;
441
- }
442
- const options = { includePrerelease: true };
443
- if (!(0, semver_1.intersects)(version, peerIdentifier.rawSpec, options) &&
444
- !(0, semver_1.satisfies)(version, peerIdentifier.rawSpec, options)) {
445
- return true;
446
- }
494
+ if (peerIdentifier.type !== 'version' && peerIdentifier.type !== 'range') {
495
+ // type === 'tag' | 'file' | 'directory' | 'remote' | 'git'
496
+ // Cannot accurately compare these as the tag/location may have changed since install.
497
+ return null;
498
+ }
499
+ try {
500
+ const version = await this.findProjectVersion(peer);
501
+ if (!version) {
502
+ return null;
447
503
  }
448
- catch {
449
- // Not found or invalid so ignore
450
- continue;
504
+ const options = { includePrerelease: true };
505
+ if (!(0, semver_1.intersects)(version, peerIdentifier.rawSpec, options) &&
506
+ !(0, semver_1.satisfies)(version, peerIdentifier.rawSpec, options)) {
507
+ return (`Package "${manifest.name}@${manifest.version}" has an incompatible peer dependency to "` +
508
+ `${peer}@${peerIdentifier.rawSpec}" (requires "${version}" in project).`);
451
509
  }
452
510
  }
453
- else {
454
- // type === 'tag' | 'file' | 'directory' | 'remote' | 'git'
455
- // Cannot accurately compare these as the tag/location may have changed since install
511
+ catch {
512
+ // Not found or invalid so ignore
456
513
  }
457
- }
458
- return false;
514
+ return null;
515
+ });
516
+ const conflicts = (await Promise.all(checks)).filter((result) => !!result);
517
+ return conflicts.length > 0 && conflicts;
459
518
  }
460
519
  }
461
520
  exports.default = AddCommandModule;
@@ -45,7 +45,6 @@ export type Schema = {
45
45
  */
46
46
  export declare enum PackageManager {
47
47
  Bun = "bun",
48
- Cnpm = "cnpm",
49
48
  Npm = "npm",
50
49
  Pnpm = "pnpm",
51
50
  Yarn = "yarn"
@@ -9,7 +9,6 @@ exports.PackageManager = void 0;
9
9
  var PackageManager;
10
10
  (function (PackageManager) {
11
11
  PackageManager["Bun"] = "bun";
12
- PackageManager["Cnpm"] = "cnpm";
13
12
  PackageManager["Npm"] = "npm";
14
13
  PackageManager["Pnpm"] = "pnpm";
15
14
  PackageManager["Yarn"] = "yarn";
@@ -57,7 +57,7 @@
57
57
  "description": "The preferred package manager configuration files to use for registry settings.",
58
58
  "type": "string",
59
59
  "default": "npm",
60
- "enum": ["npm", "yarn", "cnpm", "pnpm", "bun"]
60
+ "enum": ["npm", "yarn", "pnpm", "bun"]
61
61
  }
62
62
  },
63
63
  "required": []
@@ -22,4 +22,4 @@ class Version {
22
22
  this.patch = patch;
23
23
  }
24
24
  }
25
- exports.VERSION = new Version('20.2.1');
25
+ exports.VERSION = new Version('21.0.0-next.1');