@angular/cli 18.1.0-next.2 → 18.1.0-next.3

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/cli/index.js CHANGED
@@ -33,18 +33,19 @@ async function default_1(options) {
33
33
  const colorLevels = {
34
34
  info: (s) => s,
35
35
  debug: (s) => s,
36
- warn: (s) => color_1.colors.bold.yellow(s),
37
- error: (s) => color_1.colors.bold.red(s),
38
- fatal: (s) => color_1.colors.bold.red(s),
36
+ warn: (s) => color_1.colors.bold(color_1.colors.yellow(s)),
37
+ error: (s) => color_1.colors.bold(color_1.colors.red(s)),
38
+ fatal: (s) => color_1.colors.bold(color_1.colors.red(s)),
39
39
  };
40
40
  const logger = new core_1.logging.IndentLogger('cli-main-logger');
41
41
  const logInfo = console.log;
42
42
  const logError = console.error;
43
+ const useColor = (0, color_1.supportColor)();
43
44
  const loggerFinished = logger.forEach((entry) => {
44
45
  if (!environment_options_1.ngDebug && entry.level === 'debug') {
45
46
  return;
46
47
  }
47
- const color = color_1.colors.enabled ? colorLevels[entry.level] : node_util_1.stripVTControlCharacters;
48
+ const color = useColor ? colorLevels[entry.level] : node_util_1.stripVTControlCharacters;
48
49
  const message = color(entry.message);
49
50
  switch (entry.level) {
50
51
  case 'warn':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/cli",
3
- "version": "18.1.0-next.2",
3
+ "version": "18.1.0-next.3",
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.1801.0-next.2",
29
- "@angular-devkit/core": "18.1.0-next.2",
30
- "@angular-devkit/schematics": "18.1.0-next.2",
31
- "@inquirer/prompts": "5.0.5",
32
- "@schematics/angular": "18.1.0-next.2",
28
+ "@angular-devkit/architect": "0.1801.0-next.3",
29
+ "@angular-devkit/core": "18.1.0-next.3",
30
+ "@angular-devkit/schematics": "18.1.0-next.3",
31
+ "@inquirer/prompts": "5.0.6",
32
+ "@listr2/prompt-adapter-inquirer": "2.0.12",
33
+ "@schematics/angular": "18.1.0-next.3",
33
34
  "@yarnpkg/lockfile": "1.1.0",
34
- "ansi-colors": "4.1.3",
35
35
  "ini": "4.1.3",
36
36
  "jsonc-parser": "3.2.1",
37
+ "listr2": "8.2.2",
37
38
  "npm-package-arg": "11.0.2",
38
39
  "npm-pick-manifest": "9.0.1",
39
- "ora": "5.4.1",
40
40
  "pacote": "18.0.6",
41
41
  "resolve": "1.22.8",
42
42
  "semver": "7.6.2",
@@ -46,17 +46,17 @@
46
46
  "ng-update": {
47
47
  "migrations": "@schematics/angular/migrations/migration-collection.json",
48
48
  "packageGroup": {
49
- "@angular/cli": "18.1.0-next.2",
50
- "@angular/build": "18.1.0-next.2",
51
- "@angular/ssr": "18.1.0-next.2",
52
- "@angular-devkit/architect": "0.1801.0-next.2",
53
- "@angular-devkit/build-angular": "18.1.0-next.2",
54
- "@angular-devkit/build-webpack": "0.1801.0-next.2",
55
- "@angular-devkit/core": "18.1.0-next.2",
56
- "@angular-devkit/schematics": "18.1.0-next.2"
49
+ "@angular/cli": "18.1.0-next.3",
50
+ "@angular/build": "18.1.0-next.3",
51
+ "@angular/ssr": "18.1.0-next.3",
52
+ "@angular-devkit/architect": "0.1801.0-next.3",
53
+ "@angular-devkit/build-angular": "18.1.0-next.3",
54
+ "@angular-devkit/build-webpack": "0.1801.0-next.3",
55
+ "@angular-devkit/core": "18.1.0-next.3",
56
+ "@angular-devkit/schematics": "18.1.0-next.3"
57
57
  }
58
58
  },
59
- "packageManager": "yarn@4.2.2",
59
+ "packageManager": "yarn@4.3.0",
60
60
  "engines": {
61
61
  "node": "^18.19.1 || ^20.11.1 || >=22.0.0",
62
62
  "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
@@ -6,24 +6,48 @@
6
6
  * Use of this source code is governed by an MIT-style license that can be
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || function (mod) {
26
+ if (mod && mod.__esModule) return mod;
27
+ var result = {};
28
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
29
+ __setModuleDefault(result, mod);
30
+ return result;
31
+ };
9
32
  var __importDefault = (this && this.__importDefault) || function (mod) {
10
33
  return (mod && mod.__esModule) ? mod : { "default": mod };
11
34
  };
12
35
  Object.defineProperty(exports, "__esModule", { value: true });
13
36
  const tools_1 = require("@angular-devkit/schematics/tools");
37
+ const listr2_1 = require("listr2");
14
38
  const module_1 = require("module");
39
+ const node_assert_1 = __importDefault(require("node:assert"));
15
40
  const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
16
41
  const path_1 = require("path");
17
42
  const semver_1 = require("semver");
18
43
  const workspace_schema_1 = require("../../../lib/config/workspace-schema");
19
44
  const schematics_command_module_1 = require("../../command-builder/schematics-command-module");
20
- const color_1 = require("../../utilities/color");
21
45
  const error_1 = require("../../utilities/error");
22
46
  const package_metadata_1 = require("../../utilities/package-metadata");
23
- const prompt_1 = require("../../utilities/prompt");
24
- const spinner_1 = require("../../utilities/spinner");
25
47
  const tty_1 = require("../../utilities/tty");
26
48
  const version_1 = require("../../utilities/version");
49
+ class CommandError extends Error {
50
+ }
27
51
  /**
28
52
  * The set of packages that should have certain versions excluded from consideration
29
53
  * when attempting to find a compatible version for a package.
@@ -66,7 +90,7 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
66
90
  // `ng add @angular/localize -- --package-options`.
67
91
  .strict(false);
68
92
  const collectionName = await this.getCollectionName();
69
- const workflow = await this.getOrCreateWorkflowForBuilder(collectionName);
93
+ const workflow = this.getOrCreateWorkflowForBuilder(collectionName);
70
94
  try {
71
95
  const collection = workflow.engine.createCollection(collectionName);
72
96
  const options = await this.getSchematicOptions(collection, this.schematicName, workflow);
@@ -102,135 +126,181 @@ class AddCommandModule extends schematics_command_module_1.SchematicsCommandModu
102
126
  return this.executeSchematic({ ...options, collection: packageIdentifier.name });
103
127
  }
104
128
  }
105
- const spinner = new spinner_1.Spinner();
106
- spinner.start('Determining package manager...');
107
- const usingYarn = packageManager.name === workspace_schema_1.PackageManager.Yarn;
108
- spinner.info(`Using package manager: ${color_1.colors.grey(packageManager.name)}`);
109
- if (packageIdentifier.name &&
110
- packageIdentifier.type === 'range' &&
111
- packageIdentifier.rawSpec === '*') {
112
- // only package name provided; search for viable version
113
- // plus special cases for packages that did not have peer deps setup
114
- spinner.start('Searching for compatible package version...');
115
- let packageMetadata;
116
- try {
117
- packageMetadata = await (0, package_metadata_1.fetchPackageMetadata)(packageIdentifier.name, logger, {
118
- registry,
119
- usingYarn,
120
- verbose,
121
- });
122
- }
123
- catch (e) {
124
- (0, error_1.assertIsError)(e);
125
- spinner.fail(`Unable to load package information from registry: ${e.message}`);
126
- return 1;
127
- }
128
- // Start with the version tagged as `latest` if it exists
129
- const latestManifest = packageMetadata.tags['latest'];
130
- if (latestManifest) {
131
- packageIdentifier = npm_package_arg_1.default.resolve(latestManifest.name, latestManifest.version);
132
- }
133
- // Adjust the version based on name and peer dependencies
134
- if (latestManifest?.peerDependencies &&
135
- Object.keys(latestManifest.peerDependencies).length === 0) {
136
- spinner.succeed(`Found compatible package version: ${color_1.colors.grey(packageIdentifier.toString())}.`);
137
- }
138
- else if (!latestManifest || (await this.hasMismatchedPeer(latestManifest))) {
139
- // 'latest' is invalid so search for most recent matching package
140
- // Allow prelease versions if the CLI itself is a prerelease
141
- const allowPrereleases = (0, semver_1.prerelease)(version_1.VERSION.full);
142
- const versionExclusions = packageVersionExclusions[packageMetadata.name];
143
- const versionManifests = Object.values(packageMetadata.versions).filter((value) => {
144
- // Prerelease versions are not stable and should not be considered by default
145
- if (!allowPrereleases && (0, semver_1.prerelease)(value.version)) {
146
- return false;
129
+ const taskContext = {
130
+ packageIdentifier,
131
+ executeSchematic: this.executeSchematic.bind(this),
132
+ hasMismatchedPeer: this.hasMismatchedPeer.bind(this),
133
+ };
134
+ const tasks = new listr2_1.Listr([
135
+ {
136
+ title: 'Determining Package Manager',
137
+ task(context, task) {
138
+ context.usingYarn = packageManager.name === workspace_schema_1.PackageManager.Yarn;
139
+ task.output = `Using package manager: ${listr2_1.color.dim(packageManager.name)}`;
140
+ },
141
+ rendererOptions: { persistentOutput: true },
142
+ },
143
+ {
144
+ title: 'Searching for compatible package version',
145
+ enabled: packageIdentifier.type === 'range' && packageIdentifier.rawSpec === '*',
146
+ async task(context, task) {
147
+ (0, node_assert_1.default)(context.packageIdentifier.name, 'Registry package identifiers should always have a name.');
148
+ // only package name provided; search for viable version
149
+ // plus special cases for packages that did not have peer deps setup
150
+ let packageMetadata;
151
+ try {
152
+ packageMetadata = await (0, package_metadata_1.fetchPackageMetadata)(context.packageIdentifier.name, logger, {
153
+ registry,
154
+ usingYarn: context.usingYarn,
155
+ verbose,
156
+ });
147
157
  }
148
- // Deprecated versions should not be used or considered
149
- if (value.deprecated) {
150
- return false;
158
+ catch (e) {
159
+ (0, error_1.assertIsError)(e);
160
+ throw new CommandError(`Unable to load package information from registry: ${e.message}`);
151
161
  }
152
- // Excluded package versions should not be considered
153
- if (versionExclusions &&
154
- (0, semver_1.satisfies)(value.version, versionExclusions, { includePrerelease: true })) {
155
- return false;
162
+ // Start with the version tagged as `latest` if it exists
163
+ const latestManifest = packageMetadata.tags['latest'];
164
+ if (latestManifest) {
165
+ context.packageIdentifier = npm_package_arg_1.default.resolve(latestManifest.name, latestManifest.version);
156
166
  }
157
- return true;
158
- });
159
- // Sort in reverse SemVer order so that the newest compatible version is chosen
160
- versionManifests.sort((a, b) => (0, semver_1.compare)(b.version, a.version, true));
161
- let newIdentifier;
162
- for (const versionManifest of versionManifests) {
163
- if (!(await this.hasMismatchedPeer(versionManifest))) {
164
- newIdentifier = npm_package_arg_1.default.resolve(versionManifest.name, versionManifest.version);
165
- break;
167
+ // Adjust the version based on name and peer dependencies
168
+ if (latestManifest?.peerDependencies &&
169
+ Object.keys(latestManifest.peerDependencies).length === 0) {
170
+ task.output = `Found compatible package version: ${listr2_1.color.blue(latestManifest.version)}.`;
166
171
  }
167
- }
168
- if (!newIdentifier) {
169
- spinner.warn("Unable to find compatible package. Using 'latest' tag.");
170
- }
171
- else {
172
- packageIdentifier = newIdentifier;
173
- spinner.succeed(`Found compatible package version: ${color_1.colors.grey(packageIdentifier.toString())}.`);
174
- }
175
- }
176
- else {
177
- spinner.succeed(`Found compatible package version: ${color_1.colors.grey(packageIdentifier.toString())}.`);
178
- }
179
- }
180
- let collectionName = packageIdentifier.name;
181
- let savePackage;
172
+ else if (!latestManifest || (await context.hasMismatchedPeer(latestManifest))) {
173
+ // 'latest' is invalid so search for most recent matching package
174
+ // Allow prelease versions if the CLI itself is a prerelease
175
+ const allowPrereleases = (0, semver_1.prerelease)(version_1.VERSION.full);
176
+ const versionExclusions = packageVersionExclusions[packageMetadata.name];
177
+ const versionManifests = Object.values(packageMetadata.versions).filter((value) => {
178
+ // Prerelease versions are not stable and should not be considered by default
179
+ if (!allowPrereleases && (0, semver_1.prerelease)(value.version)) {
180
+ return false;
181
+ }
182
+ // Deprecated versions should not be used or considered
183
+ if (value.deprecated) {
184
+ return false;
185
+ }
186
+ // Excluded package versions should not be considered
187
+ if (versionExclusions &&
188
+ (0, semver_1.satisfies)(value.version, versionExclusions, { includePrerelease: true })) {
189
+ return false;
190
+ }
191
+ return true;
192
+ });
193
+ // Sort in reverse SemVer order so that the newest compatible version is chosen
194
+ versionManifests.sort((a, b) => (0, semver_1.compare)(b.version, a.version, true));
195
+ let found = false;
196
+ for (const versionManifest of versionManifests) {
197
+ const mismatch = await context.hasMismatchedPeer(versionManifest);
198
+ if (mismatch) {
199
+ continue;
200
+ }
201
+ context.packageIdentifier = npm_package_arg_1.default.resolve(versionManifest.name, versionManifest.version);
202
+ found = true;
203
+ }
204
+ if (!found) {
205
+ task.output = "Unable to find compatible package. Using 'latest' tag.";
206
+ }
207
+ else {
208
+ task.output = `Found compatible package version: ${listr2_1.color.blue(context.packageIdentifier.toString())}.`;
209
+ }
210
+ }
211
+ else {
212
+ task.output = `Found compatible package version: ${listr2_1.color.blue(context.packageIdentifier.toString())}.`;
213
+ }
214
+ },
215
+ rendererOptions: { persistentOutput: true },
216
+ },
217
+ {
218
+ title: 'Loading package information from registry',
219
+ async task(context, task) {
220
+ let manifest;
221
+ try {
222
+ manifest = await (0, package_metadata_1.fetchPackageManifest)(context.packageIdentifier.toString(), logger, {
223
+ registry,
224
+ verbose,
225
+ usingYarn: context.usingYarn,
226
+ });
227
+ }
228
+ catch (e) {
229
+ (0, error_1.assertIsError)(e);
230
+ throw new CommandError(`Unable to fetch package information for '${context.packageIdentifier}': ${e.message}`);
231
+ }
232
+ context.savePackage = manifest['ng-add']?.save;
233
+ context.collectionName = manifest.name;
234
+ if (await context.hasMismatchedPeer(manifest)) {
235
+ task.output = listr2_1.color.yellow(listr2_1.figures.warning +
236
+ ' Package has unmet peer dependencies. Adding the package may not succeed.');
237
+ }
238
+ },
239
+ rendererOptions: { persistentOutput: true },
240
+ },
241
+ {
242
+ title: 'Confirming installation',
243
+ enabled: !skipConfirmation,
244
+ async task(context, task) {
245
+ if (!(0, tty_1.isTTY)()) {
246
+ task.output =
247
+ `'--skip-confirmation' can be used to bypass installation confirmation. ` +
248
+ `Ensure package name is correct prior to '--skip-confirmation' option usage.`;
249
+ throw new CommandError('No terminal detected');
250
+ }
251
+ const { ListrInquirerPromptAdapter } = await Promise.resolve().then(() => __importStar(require('@listr2/prompt-adapter-inquirer')));
252
+ const { confirm } = await Promise.resolve().then(() => __importStar(require('@inquirer/prompts')));
253
+ const shouldProceed = await task.prompt(ListrInquirerPromptAdapter).run(confirm, {
254
+ message: `The package ${listr2_1.color.blue(context.packageIdentifier.toString())} will be installed and executed.\n` +
255
+ 'Would you like to proceed?',
256
+ default: true,
257
+ theme: { prefix: '' },
258
+ });
259
+ if (!shouldProceed) {
260
+ throw new CommandError('Command aborted');
261
+ }
262
+ },
263
+ rendererOptions: { persistentOutput: true },
264
+ },
265
+ {
266
+ async task(context, task) {
267
+ // Only show if installation will actually occur
268
+ task.title = 'Installing package';
269
+ if (context.savePackage === false) {
270
+ task.title += ' in temporary location';
271
+ // Temporary packages are located in a different directory
272
+ // Hence we need to resolve them using the temp path
273
+ const { success, tempNodeModules } = await packageManager.installTemp(context.packageIdentifier.toString(), registry ? [`--registry="${registry}"`] : undefined);
274
+ const tempRequire = (0, module_1.createRequire)(tempNodeModules + '/');
275
+ (0, node_assert_1.default)(context.collectionName, 'Collection name should always be available');
276
+ const resolvedCollectionPath = tempRequire.resolve((0, path_1.join)(context.collectionName, 'package.json'));
277
+ if (!success) {
278
+ throw new CommandError('Unable to install package');
279
+ }
280
+ context.collectionName = (0, path_1.dirname)(resolvedCollectionPath);
281
+ }
282
+ else {
283
+ const success = await packageManager.install(context.packageIdentifier.toString(), context.savePackage, registry ? [`--registry="${registry}"`] : undefined, undefined);
284
+ if (!success) {
285
+ throw new CommandError('Unable to install package');
286
+ }
287
+ }
288
+ },
289
+ rendererOptions: { bottomBar: Infinity },
290
+ },
291
+ // TODO: Rework schematic execution as a task and insert here
292
+ ]);
182
293
  try {
183
- spinner.start('Loading package information from registry...');
184
- const manifest = await (0, package_metadata_1.fetchPackageManifest)(packageIdentifier.toString(), logger, {
185
- registry,
186
- verbose,
187
- usingYarn,
188
- });
189
- savePackage = manifest['ng-add']?.save;
190
- collectionName = manifest.name;
191
- if (await this.hasMismatchedPeer(manifest)) {
192
- spinner.warn('Package has unmet peer dependencies. Adding the package may not succeed.');
193
- }
194
- else {
195
- spinner.succeed(`Package information loaded.`);
196
- }
294
+ const result = await tasks.run(taskContext);
295
+ (0, node_assert_1.default)(result.collectionName, 'Collection name should always be available');
296
+ return this.executeSchematic({ ...options, collection: result.collectionName });
197
297
  }
198
298
  catch (e) {
199
- (0, error_1.assertIsError)(e);
200
- spinner.fail(`Unable to fetch package information for '${packageIdentifier}': ${e.message}`);
201
- return 1;
202
- }
203
- if (!skipConfirmation) {
204
- const confirmationResponse = await (0, prompt_1.askConfirmation)(`\nThe package ${color_1.colors.blue(packageIdentifier.raw)} will be installed and executed.\n` +
205
- 'Would you like to proceed?', true, false);
206
- if (!confirmationResponse) {
207
- if (!(0, tty_1.isTTY)()) {
208
- logger.error('No terminal detected. ' +
209
- `'--skip-confirmation' can be used to bypass installation confirmation. ` +
210
- `Ensure package name is correct prior to '--skip-confirmation' option usage.`);
211
- }
212
- logger.error('Command aborted.');
213
- return 1;
214
- }
215
- }
216
- if (savePackage === false) {
217
- // Temporary packages are located in a different directory
218
- // Hence we need to resolve them using the temp path
219
- const { success, tempNodeModules } = await packageManager.installTemp(packageIdentifier.raw, registry ? [`--registry="${registry}"`] : undefined);
220
- const tempRequire = (0, module_1.createRequire)(tempNodeModules + '/');
221
- const resolvedCollectionPath = tempRequire.resolve((0, path_1.join)(collectionName, 'package.json'));
222
- if (!success) {
223
- return 1;
224
- }
225
- collectionName = (0, path_1.dirname)(resolvedCollectionPath);
226
- }
227
- else {
228
- const success = await packageManager.install(packageIdentifier.raw, savePackage, registry ? [`--registry="${registry}"`] : undefined);
229
- if (!success) {
299
+ if (e instanceof CommandError) {
230
300
  return 1;
231
301
  }
302
+ throw e;
232
303
  }
233
- return this.executeSchematic({ ...options, collection: collectionName });
234
304
  }
235
305
  async isProjectVersionValid(packageIdentifier) {
236
306
  if (!packageIdentifier.name) {
@@ -35,9 +35,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  const schematics_1 = require("@angular-devkit/schematics");
37
37
  const tools_1 = require("@angular-devkit/schematics/tools");
38
- const child_process_1 = require("child_process");
39
- const fs_1 = require("fs");
40
- const module_1 = require("module");
38
+ const listr2_1 = require("listr2");
39
+ const node_child_process_1 = require("node:child_process");
40
+ const node_fs_1 = require("node:fs");
41
+ const node_module_1 = require("node:module");
41
42
  const npm_package_arg_1 = __importDefault(require("npm-package-arg"));
42
43
  const npm_pick_manifest_1 = __importDefault(require("npm-pick-manifest"));
43
44
  const path = __importStar(require("path"));
@@ -56,6 +57,8 @@ const package_tree_1 = require("../../utilities/package-tree");
56
57
  const prompt_1 = require("../../utilities/prompt");
57
58
  const tty_1 = require("../../utilities/tty");
58
59
  const version_1 = require("../../utilities/version");
60
+ class CommandError extends Error {
61
+ }
59
62
  const ANGULAR_PACKAGES_REGEXP = /^@(?:angular|nguniversal)\//;
60
63
  const UPDATE_SCHEMATIC_COLLECTION = path.join(__dirname, 'schematic/collection.json');
61
64
  class UpdateCommandModule extends command_module_1.CommandModule {
@@ -188,7 +191,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
188
191
  return 1;
189
192
  }
190
193
  }
191
- logger.info(`Using package manager: ${color_1.colors.grey(packageManager.name)}`);
194
+ logger.info(`Using package manager: ${color_1.colors.gray(packageManager.name)}`);
192
195
  logger.info('Collecting installed dependencies...');
193
196
  const rootDependencies = await (0, package_tree_1.getProjectDependencies)(this.context.root);
194
197
  logger.info(`Found ${rootDependencies.size} dependencies.`);
@@ -233,12 +236,12 @@ class UpdateCommandModule extends command_module_1.CommandModule {
233
236
  }
234
237
  catch (e) {
235
238
  if (e instanceof schematics_1.UnsuccessfulWorkflowExecution) {
236
- logger.error(`${color_1.colors.symbols.cross} Migration failed. See above for further details.\n`);
239
+ logger.error(`${color_1.figures.cross} Migration failed. See above for further details.\n`);
237
240
  }
238
241
  else {
239
242
  (0, error_1.assertIsError)(e);
240
243
  const logPath = (0, log_file_1.writeErrorToLogFile)(e);
241
- logger.fatal(`${color_1.colors.symbols.cross} Migration failed: ${e.message}\n` +
244
+ logger.fatal(`${color_1.figures.cross} Migration failed: ${e.message}\n` +
242
245
  ` See "${logPath}" for further details.\n`);
243
246
  }
244
247
  return { success: false, files: workflowSubscription.files };
@@ -308,7 +311,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
308
311
  const { logger } = this.context;
309
312
  for (const migration of migrations) {
310
313
  const { title, description } = getMigrationTitleAndDescription(migration);
311
- logger.info(color_1.colors.cyan(color_1.colors.symbols.pointer) + ' ' + color_1.colors.bold(title));
314
+ logger.info(color_1.colors.cyan(color_1.figures.pointer) + ' ' + color_1.colors.bold(title));
312
315
  if (description) {
313
316
  logger.info(' ' + description);
314
317
  }
@@ -390,14 +393,14 @@ class UpdateCommandModule extends command_module_1.CommandModule {
390
393
  }
391
394
  // Check if it is a package-local location
392
395
  const localMigrations = path.join(packagePath, migrations);
393
- if ((0, fs_1.existsSync)(localMigrations)) {
396
+ if ((0, node_fs_1.existsSync)(localMigrations)) {
394
397
  migrations = localMigrations;
395
398
  }
396
399
  else {
397
400
  // Try to resolve from package location.
398
401
  // This avoids issues with package hoisting.
399
402
  try {
400
- const packageRequire = (0, module_1.createRequire)(packagePath + '/');
403
+ const packageRequire = (0, node_module_1.createRequire)(packagePath + '/');
401
404
  migrations = packageRequire.resolve(migrations, { paths: this.resolvePaths });
402
405
  }
403
406
  catch (e) {
@@ -540,17 +543,45 @@ class UpdateCommandModule extends command_module_1.CommandModule {
540
543
  packages: packagesToUpdate,
541
544
  });
542
545
  if (success) {
546
+ const { root: commandRoot, packageManager } = this.context;
547
+ const installArgs = this.packageManagerForce(options.verbose) ? ['--force'] : [];
548
+ const tasks = new listr2_1.Listr([
549
+ {
550
+ title: 'Cleaning node modules directory',
551
+ async task(_, task) {
552
+ try {
553
+ await node_fs_1.promises.rm(path.join(commandRoot, 'node_modules'), {
554
+ force: true,
555
+ recursive: true,
556
+ maxRetries: 3,
557
+ });
558
+ }
559
+ catch (e) {
560
+ (0, error_1.assertIsError)(e);
561
+ if (e.code === 'ENOENT') {
562
+ task.skip('Cleaning not required. Node modules directory not found.');
563
+ }
564
+ }
565
+ },
566
+ },
567
+ {
568
+ title: 'Installing packages',
569
+ async task() {
570
+ const installationSuccess = await packageManager.installAll(installArgs, commandRoot);
571
+ if (!installationSuccess) {
572
+ throw new CommandError('Unable to install packages');
573
+ }
574
+ },
575
+ },
576
+ ]);
543
577
  try {
544
- await fs_1.promises.rm(path.join(this.context.root, 'node_modules'), {
545
- force: true,
546
- recursive: true,
547
- maxRetries: 3,
548
- });
578
+ await tasks.run();
549
579
  }
550
- catch { }
551
- const installationSuccess = await this.context.packageManager.installAll(this.packageManagerForce(options.verbose) ? ['--force'] : [], this.context.root);
552
- if (!installationSuccess) {
553
- return 1;
580
+ catch (e) {
581
+ if (e instanceof CommandError) {
582
+ return 1;
583
+ }
584
+ throw e;
554
585
  }
555
586
  }
556
587
  if (success && options.createCommits) {
@@ -562,7 +593,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
562
593
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
563
594
  const migrations = global.externalMigrations;
564
595
  if (success && migrations) {
565
- const rootRequire = (0, module_1.createRequire)(this.context.root + '/');
596
+ const rootRequire = (0, node_module_1.createRequire)(this.context.root + '/');
566
597
  for (const migration of migrations) {
567
598
  // Resolve the package from the workspace root, as otherwise it will be resolved from the temp
568
599
  // installed CLI version.
@@ -600,14 +631,14 @@ class UpdateCommandModule extends command_module_1.CommandModule {
600
631
  let migrations;
601
632
  // Check if it is a package-local location
602
633
  const localMigrations = path.join(packagePath, migration.collection);
603
- if ((0, fs_1.existsSync)(localMigrations)) {
634
+ if ((0, node_fs_1.existsSync)(localMigrations)) {
604
635
  migrations = localMigrations;
605
636
  }
606
637
  else {
607
638
  // Try to resolve from package location.
608
639
  // This avoids issues with package hoisting.
609
640
  try {
610
- const packageRequire = (0, module_1.createRequire)(packagePath + '/');
641
+ const packageRequire = (0, node_module_1.createRequire)(packagePath + '/');
611
642
  migrations = packageRequire.resolve(migration.collection);
612
643
  }
613
644
  catch (e) {
@@ -672,11 +703,11 @@ class UpdateCommandModule extends command_module_1.CommandModule {
672
703
  }
673
704
  checkCleanGit() {
674
705
  try {
675
- const topLevel = (0, child_process_1.execSync)('git rev-parse --show-toplevel', {
706
+ const topLevel = (0, node_child_process_1.execSync)('git rev-parse --show-toplevel', {
676
707
  encoding: 'utf8',
677
708
  stdio: 'pipe',
678
709
  });
679
- const result = (0, child_process_1.execSync)('git status --porcelain', { encoding: 'utf8', stdio: 'pipe' });
710
+ const result = (0, node_child_process_1.execSync)('git status --porcelain', { encoding: 'utf8', stdio: 'pipe' });
680
711
  if (result.trim().length === 0) {
681
712
  return true;
682
713
  }
@@ -736,8 +767,8 @@ class UpdateCommandModule extends command_module_1.CommandModule {
736
767
  const packageJsonPath = (0, path_1.join)(pkgLocation, 'package.json');
737
768
  // Get a binary location for this package
738
769
  let binPath;
739
- if ((0, fs_1.existsSync)(packageJsonPath)) {
740
- const content = await fs_1.promises.readFile(packageJsonPath, 'utf-8');
770
+ if ((0, node_fs_1.existsSync)(packageJsonPath)) {
771
+ const content = await node_fs_1.promises.readFile(packageJsonPath, 'utf-8');
741
772
  if (content) {
742
773
  const { bin = {} } = JSON.parse(content);
743
774
  const binKeys = Object.keys(bin);
@@ -749,7 +780,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
749
780
  if (!binPath) {
750
781
  throw new Error(`Cannot locate bin for temporary package: ${packageNameNoVersion}.`);
751
782
  }
752
- const { status, error } = (0, child_process_1.spawnSync)(process.execPath, [binPath, ...args], {
783
+ const { status, error } = (0, node_child_process_1.spawnSync)(process.execPath, [binPath, ...args], {
753
784
  stdio: 'inherit',
754
785
  env: {
755
786
  ...process.env,
@@ -789,7 +820,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
789
820
  if (!(0, tty_1.isTTY)()) {
790
821
  for (const migration of optionalMigrations) {
791
822
  const { title } = getMigrationTitleAndDescription(migration);
792
- logger.info(color_1.colors.cyan(color_1.colors.symbols.pointer) + ' ' + color_1.colors.bold(title));
823
+ logger.info(color_1.colors.cyan(color_1.figures.pointer) + ' ' + color_1.colors.bold(title));
793
824
  logger.info(color_1.colors.gray(` ng update ${packageName} --name ${migration.name}`));
794
825
  logger.info(''); // Extra trailing newline.
795
826
  }
@@ -815,7 +846,7 @@ exports.default = UpdateCommandModule;
815
846
  function hasChangesToCommit() {
816
847
  // List all modified files not covered by .gitignore.
817
848
  // If any files are returned, then there must be something to commit.
818
- return (0, child_process_1.execSync)('git ls-files -m -d -o --exclude-standard').toString() !== '';
849
+ return (0, node_child_process_1.execSync)('git ls-files -m -d -o --exclude-standard').toString() !== '';
819
850
  }
820
851
  /**
821
852
  * Precondition: Must have pending changes to commit, they do not need to be staged.
@@ -824,16 +855,16 @@ function hasChangesToCommit() {
824
855
  */
825
856
  function createCommit(message) {
826
857
  // Stage entire working tree for commit.
827
- (0, child_process_1.execSync)('git add -A', { encoding: 'utf8', stdio: 'pipe' });
858
+ (0, node_child_process_1.execSync)('git add -A', { encoding: 'utf8', stdio: 'pipe' });
828
859
  // Commit with the message passed via stdin to avoid bash escaping issues.
829
- (0, child_process_1.execSync)('git commit --no-verify -F -', { encoding: 'utf8', stdio: 'pipe', input: message });
860
+ (0, node_child_process_1.execSync)('git commit --no-verify -F -', { encoding: 'utf8', stdio: 'pipe', input: message });
830
861
  }
831
862
  /**
832
863
  * @return The Git SHA hash of the HEAD commit. Returns null if unable to retrieve the hash.
833
864
  */
834
865
  function findCurrentGitSha() {
835
866
  try {
836
- return (0, child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf8', stdio: 'pipe' }).trim();
867
+ return (0, node_child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf8', stdio: 'pipe' }).trim();
837
868
  }
838
869
  catch {
839
870
  return null;
@@ -5,6 +5,5 @@
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
- import * as ansiColors from 'ansi-colors';
9
- declare const colors: typeof ansiColors;
10
- export { colors };
8
+ export { color as colors, figures } from 'listr2';
9
+ export declare function supportColor(): boolean;
@@ -6,33 +6,13 @@
6
6
  * Use of this source code is governed by an MIT-style license that can be
7
7
  * found in the LICENSE file at https://angular.dev/license
8
8
  */
9
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- var desc = Object.getOwnPropertyDescriptor(m, k);
12
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
- desc = { enumerable: true, get: function() { return m[k]; } };
14
- }
15
- Object.defineProperty(o, k2, desc);
16
- }) : (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- o[k2] = m[k];
19
- }));
20
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
- Object.defineProperty(o, "default", { enumerable: true, value: v });
22
- }) : function(o, v) {
23
- o["default"] = v;
24
- });
25
- var __importStar = (this && this.__importStar) || function (mod) {
26
- if (mod && mod.__esModule) return mod;
27
- var result = {};
28
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
29
- __setModuleDefault(result, mod);
30
- return result;
31
- };
32
9
  Object.defineProperty(exports, "__esModule", { value: true });
33
- exports.colors = void 0;
34
- const ansiColors = __importStar(require("ansi-colors"));
35
- const tty_1 = require("tty");
10
+ exports.figures = exports.colors = void 0;
11
+ exports.supportColor = supportColor;
12
+ const node_tty_1 = require("node:tty");
13
+ var listr2_1 = require("listr2");
14
+ Object.defineProperty(exports, "colors", { enumerable: true, get: function () { return listr2_1.color; } });
15
+ Object.defineProperty(exports, "figures", { enumerable: true, get: function () { return listr2_1.figures; } });
36
16
  function supportColor() {
37
17
  if (process.env.FORCE_COLOR !== undefined) {
38
18
  // 2 colors: FORCE_COLOR = 0 (Disables colors), depth 1
@@ -52,12 +32,8 @@ function supportColor() {
52
32
  return false;
53
33
  }
54
34
  }
55
- if (process.stdout instanceof tty_1.WriteStream) {
35
+ if (process.stdout instanceof node_tty_1.WriteStream) {
56
36
  return process.stdout.getColorDepth() > 1;
57
37
  }
58
38
  return false;
59
39
  }
60
- // Create a separate instance to prevent unintended global changes to the color configuration
61
- const colors = ansiColors.create();
62
- exports.colors = colors;
63
- colors.enabled = supportColor();
@@ -25,7 +25,6 @@ const path_1 = require("path");
25
25
  const workspace_schema_1 = require("../../lib/config/workspace-schema");
26
26
  const config_1 = require("./config");
27
27
  const memoize_1 = require("./memoize");
28
- const spinner_1 = require("./spinner");
29
28
  class PackageManagerUtils {
30
29
  context;
31
30
  constructor(context) {
@@ -133,8 +132,6 @@ class PackageManagerUtils {
133
132
  }
134
133
  async run(args, options = {}) {
135
134
  const { cwd = process.cwd(), silent = false } = options;
136
- const spinner = new spinner_1.Spinner();
137
- spinner.start('Installing packages...');
138
135
  return new Promise((resolve) => {
139
136
  const bufferedOutput = [];
140
137
  const childProcess = (0, child_process_1.spawn)(this.name, args, {
@@ -144,13 +141,10 @@ class PackageManagerUtils {
144
141
  cwd,
145
142
  }).on('close', (code) => {
146
143
  if (code === 0) {
147
- spinner.succeed('Packages successfully installed.');
148
144
  resolve(true);
149
145
  }
150
146
  else {
151
- spinner.stop();
152
147
  bufferedOutput.forEach(({ stream, data }) => stream.write(data));
153
- spinner.fail('Packages installation failed, see above.');
154
148
  resolve(false);
155
149
  }
156
150
  });
@@ -25,5 +25,5 @@ class Version {
25
25
  }
26
26
  }
27
27
  // TODO(bazel): Convert this to use build-time version stamping after flipping the build script to use bazel
28
- // export const VERSION = new Version('18.1.0-next.2');
28
+ // export const VERSION = new Version('18.1.0-next.3');
29
29
  exports.VERSION = new Version(JSON.parse((0, fs_1.readFileSync)((0, path_1.resolve)(__dirname, '../../package.json'), 'utf-8')).version);
@@ -1,20 +0,0 @@
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
- export declare class Spinner {
9
- private readonly spinner;
10
- /** When false, only fail messages will be displayed. */
11
- enabled: boolean;
12
- constructor(text?: string);
13
- set text(text: string);
14
- succeed(text?: string): void;
15
- info(text?: string): void;
16
- fail(text?: string): void;
17
- warn(text?: string): void;
18
- stop(): void;
19
- start(text?: string): void;
20
- }
@@ -1,55 +0,0 @@
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
- var __importDefault = (this && this.__importDefault) || function (mod) {
10
- return (mod && mod.__esModule) ? mod : { "default": mod };
11
- };
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.Spinner = void 0;
14
- const ora_1 = __importDefault(require("ora"));
15
- const color_1 = require("./color");
16
- class Spinner {
17
- spinner;
18
- /** When false, only fail messages will be displayed. */
19
- enabled = true;
20
- constructor(text) {
21
- this.spinner = (0, ora_1.default)({
22
- text,
23
- // The below 2 options are needed because otherwise CTRL+C will be delayed
24
- // when the underlying process is sync.
25
- hideCursor: false,
26
- discardStdin: false,
27
- });
28
- }
29
- set text(text) {
30
- this.spinner.text = text;
31
- }
32
- succeed(text) {
33
- if (this.enabled) {
34
- this.spinner.succeed(text);
35
- }
36
- }
37
- info(text) {
38
- this.spinner.info(text);
39
- }
40
- fail(text) {
41
- this.spinner.fail(text && color_1.colors.redBright(text));
42
- }
43
- warn(text) {
44
- this.spinner.warn(text && color_1.colors.yellowBright(text));
45
- }
46
- stop() {
47
- this.spinner.stop();
48
- }
49
- start(text) {
50
- if (this.enabled) {
51
- this.spinner.start(text);
52
- }
53
- }
54
- }
55
- exports.Spinner = Spinner;