@angular/cli 8.0.0-rc.1 → 8.0.0

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Configures the gathering of Angular CLI usage metrics. See
3
- * https://next.angular.io/cli/usage-analytics-gathering.
3
+ * https://v8.angular.io/cli/usage-analytics-gathering.
4
4
  */
5
5
  export interface Schema {
6
6
  /**
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "http://json-schema.org/schema",
3
3
  "$id": "ng-cli://commands/analytics.json",
4
- "description": "Configures the gathering of Angular CLI usage metrics. See https://next.angular.io/cli/usage-analytics-gathering.",
4
+ "description": "Configures the gathering of Angular CLI usage metrics. See https://v8.angular.io/cli/usage-analytics-gathering.",
5
5
  "$longDescription": "",
6
6
 
7
7
  "$aliases": [],
@@ -10,6 +10,7 @@ export interface Schema {
10
10
  /**
11
11
  * A named build target, as specified in the "configurations" section of angular.json.
12
12
  * Each named target is accompanied by a configuration of option defaults for that target.
13
+ * Setting this explicitly overrides the "--prod" flag
13
14
  */
14
15
  configuration?: string;
15
16
  /**
@@ -17,13 +18,14 @@ export interface Schema {
17
18
  */
18
19
  help?: HelpUnion;
19
20
  /**
21
+ * Shorthand for "--configuration=production".
20
22
  * When true, sets the build configuration to the production target.
21
- * All builds make use of bundling and limited tree-shaking. A production build also runs
22
- * limited dead code elimination.
23
+ * By default, the production target is set up in the workspace configuration such that all
24
+ * builds make use of bundling, limited tree-shaking, and also limited dead code elimination.
23
25
  */
24
26
  prod?: boolean;
25
27
  /**
26
- * The name of the project to build. Can be an app or a library.
28
+ * The name of the project to build. Can be an application or a library.
27
29
  */
28
30
  project?: string;
29
31
  }
@@ -70,7 +70,7 @@ const validCliPaths = new Map([
70
70
  * by the path. For example, a path of "a[3].foo.bar[2]" would give you a fragment array of
71
71
  * ["a", 3, "foo", "bar", 2].
72
72
  * @param path The JSON string to parse.
73
- * @returns {string[]} The fragments for the string.
73
+ * @returns {(string|number)[]} The fragments for the string.
74
74
  * @private
75
75
  */
76
76
  function parseJsonPath(path) {
@@ -87,11 +87,14 @@ function parseJsonPath(path) {
87
87
  }
88
88
  result.push(match[1]);
89
89
  if (match[2]) {
90
- const indices = match[2].slice(1, -1).split('][');
90
+ const indices = match[2]
91
+ .slice(1, -1)
92
+ .split('][')
93
+ .map(x => /^\d$/.test(x) ? +x : x.replace(/\"|\'/g, ''));
91
94
  result.push(...indices);
92
95
  }
93
96
  }
94
- return result.filter(fragment => !!fragment);
97
+ return result.filter(fragment => fragment != null);
95
98
  }
96
99
  function getValueFromPath(root, path) {
97
100
  const fragments = parseJsonPath(path);
@@ -7,21 +7,21 @@
7
7
  "properties": {
8
8
  "project": {
9
9
  "type": "string",
10
- "description": "The name of the project to build. Can be an app or a library.",
10
+ "description": "The name of the project to build. Can be an application or a library.",
11
11
  "$default": {
12
12
  "$source": "argv",
13
13
  "index": 0
14
14
  }
15
15
  },
16
16
  "configuration": {
17
- "description": "A named build target, as specified in the \"configurations\" section of angular.json.\nEach named target is accompanied by a configuration of option defaults for that target.",
17
+ "description": "A named build target, as specified in the \"configurations\" section of angular.json.\nEach named target is accompanied by a configuration of option defaults for that target.\nSetting this explicitly overrides the \"--prod\" flag",
18
18
  "type": "string",
19
19
  "aliases": [
20
20
  "c"
21
21
  ]
22
22
  },
23
23
  "prod": {
24
- "description": "When true, sets the build configuration to the production target.\nAll builds make use of bundling and limited tree-shaking. A production build also runs limited dead code elimination.",
24
+ "description": "Shorthand for \"--configuration=production\".\nWhen true, sets the build configuration to the production target.\nBy default, the production target is set up in the workspace configuration such that all builds make use of bundling, limited tree-shaking, and also limited dead code elimination.",
25
25
  "type": "boolean"
26
26
  }
27
27
  }
package/commands/e2e.d.ts CHANGED
@@ -5,6 +5,7 @@ export interface Schema {
5
5
  /**
6
6
  * A named build target, as specified in the "configurations" section of angular.json.
7
7
  * Each named target is accompanied by a configuration of option defaults for that target.
8
+ * Setting this explicitly overrides the "--prod" flag
8
9
  */
9
10
  configuration?: string;
10
11
  /**
@@ -12,13 +13,14 @@ export interface Schema {
12
13
  */
13
14
  help?: HelpUnion;
14
15
  /**
16
+ * Shorthand for "--configuration=production".
15
17
  * When true, sets the build configuration to the production target.
16
- * All builds make use of bundling and limited tree-shaking. A production build also runs
17
- * limited dead code elimination.
18
+ * By default, the production target is set up in the workspace configuration such that all
19
+ * builds make use of bundling, limited tree-shaking, and also limited dead code elimination.
18
20
  */
19
21
  prod?: boolean;
20
22
  /**
21
- * The name of the project to build. Can be an app or a library.
23
+ * The name of the project to build. Can be an application or a library.
22
24
  */
23
25
  project?: string;
24
26
  }
@@ -7,15 +7,16 @@
7
7
  * found in the LICENSE file at https://angular.io/license
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- // tslint:disable:no-global-tslint-disable no-any
11
10
  const core_1 = require("@angular-devkit/core");
12
11
  const schematic_command_1 = require("../models/schematic-command");
13
12
  const json_schema_1 = require("../utilities/json-schema");
14
13
  class GenerateCommand extends schematic_command_1.SchematicCommand {
15
14
  async initialize(options) {
16
- await super.initialize(options);
17
15
  // Fill up the schematics property of the command description.
18
16
  const [collectionName, schematicName] = this.parseSchematicInfo(options);
17
+ this.collectionName = collectionName;
18
+ this.schematicName = schematicName;
19
+ await super.initialize(options);
19
20
  const collection = this.getCollection(collectionName);
20
21
  const subcommands = {};
21
22
  const schematicNames = schematicName ? [schematicName] : collection.listSchematicNames();
@@ -45,13 +46,12 @@ class GenerateCommand extends schematic_command_1.SchematicCommand {
45
46
  });
46
47
  }
47
48
  async run(options) {
48
- const [collectionName, schematicName] = this.parseSchematicInfo(options);
49
- if (!schematicName || !collectionName) {
49
+ if (!this.schematicName || !this.collectionName) {
50
50
  return this.printHelp(options);
51
51
  }
52
52
  return this.runSchematic({
53
- collectionName,
54
- schematicName,
53
+ collectionName: this.collectionName,
54
+ schematicName: this.schematicName,
55
55
  schematicOptions: options['--'] || [],
56
56
  debug: !!options.debug || false,
57
57
  dryRun: !!options.dryRun || false,
@@ -11,6 +11,7 @@ import { Schema as NewCommandSchema } from './new';
11
11
  export declare class NewCommand extends SchematicCommand<NewCommandSchema> {
12
12
  readonly allowMissingWorkspace = true;
13
13
  schematicName: string;
14
+ initialize(options: NewCommandSchema & Arguments): Promise<void>;
14
15
  run(options: NewCommandSchema & Arguments): Promise<number | void>;
15
16
  private parseCollectionName;
16
17
  }
@@ -14,20 +14,22 @@ class NewCommand extends schematic_command_1.SchematicCommand {
14
14
  this.allowMissingWorkspace = true;
15
15
  this.schematicName = 'ng-new';
16
16
  }
17
- async run(options) {
18
- let collectionName;
17
+ async initialize(options) {
19
18
  if (options.collection) {
20
- collectionName = options.collection;
19
+ this.collectionName = options.collection;
21
20
  }
22
21
  else {
23
- collectionName = this.parseCollectionName(options);
22
+ this.collectionName = this.parseCollectionName(options);
24
23
  }
24
+ return super.initialize(options);
25
+ }
26
+ async run(options) {
25
27
  // Register the version of the CLI in the registry.
26
28
  const packageJson = require('../package.json');
27
29
  const version = packageJson.version;
28
30
  this._workflow.registry.addSmartDefaultProvider('ng-cli-version', () => version);
29
31
  return this.runSchematic({
30
- collectionName: collectionName,
32
+ collectionName: this.collectionName,
31
33
  schematicName: this.schematicName,
32
34
  schematicOptions: options['--'] || [],
33
35
  debug: !!options.debug,
@@ -9,6 +9,7 @@ export interface Schema {
9
9
  /**
10
10
  * A named build target, as specified in the "configurations" section of angular.json.
11
11
  * Each named target is accompanied by a configuration of option defaults for that target.
12
+ * Setting this explicitly overrides the "--prod" flag
12
13
  */
13
14
  configuration?: string;
14
15
  /**
@@ -16,13 +17,14 @@ export interface Schema {
16
17
  */
17
18
  help?: HelpUnion;
18
19
  /**
20
+ * Shorthand for "--configuration=production".
19
21
  * When true, sets the build configuration to the production target.
20
- * All builds make use of bundling and limited tree-shaking. A production build also runs
21
- * limited dead code elimination.
22
+ * By default, the production target is set up in the workspace configuration such that all
23
+ * builds make use of bundling, limited tree-shaking, and also limited dead code elimination.
22
24
  */
23
25
  prod?: boolean;
24
26
  /**
25
- * The name of the project to build. Can be an app or a library.
27
+ * The name of the project to build. Can be an application or a library.
26
28
  */
27
29
  project?: string;
28
30
  }
@@ -5,6 +5,7 @@ export interface Schema {
5
5
  /**
6
6
  * A named build target, as specified in the "configurations" section of angular.json.
7
7
  * Each named target is accompanied by a configuration of option defaults for that target.
8
+ * Setting this explicitly overrides the "--prod" flag
8
9
  */
9
10
  configuration?: string;
10
11
  /**
@@ -12,13 +13,14 @@ export interface Schema {
12
13
  */
13
14
  help?: HelpUnion;
14
15
  /**
16
+ * Shorthand for "--configuration=production".
15
17
  * When true, sets the build configuration to the production target.
16
- * All builds make use of bundling and limited tree-shaking. A production build also runs
17
- * limited dead code elimination.
18
+ * By default, the production target is set up in the workspace configuration such that all
19
+ * builds make use of bundling, limited tree-shaking, and also limited dead code elimination.
18
20
  */
19
21
  prod?: boolean;
20
22
  /**
21
- * The name of the project to build. Can be an app or a library.
23
+ * The name of the project to build. Can be an application or a library.
22
24
  */
23
25
  project?: string;
24
26
  }
@@ -3,8 +3,7 @@ import { SchematicCommand } from '../models/schematic-command';
3
3
  import { Schema as UpdateCommandSchema } from './update';
4
4
  export declare class UpdateCommand extends SchematicCommand<UpdateCommandSchema> {
5
5
  readonly allowMissingWorkspace = true;
6
- collectionName: string;
7
- schematicName: string;
8
- parseArguments(schematicOptions: string[], schema: Option[]): Promise<Arguments>;
6
+ parseArguments(_schematicOptions: string[], _schema: Option[]): Promise<Arguments>;
9
7
  run(options: UpdateCommandSchema & Arguments): Promise<number | void>;
8
+ checkCleanGit(): boolean;
10
9
  }
@@ -7,55 +7,234 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  * Use of this source code is governed by an MIT-style license that can be
8
8
  * found in the LICENSE file at https://angular.io/license
9
9
  */
10
- const core_1 = require("@angular-devkit/core");
10
+ const child_process_1 = require("child_process");
11
+ const path = require("path");
12
+ const semver = require("semver");
11
13
  const schematic_command_1 = require("../models/schematic-command");
12
14
  const find_up_1 = require("../utilities/find-up");
13
15
  const package_manager_1 = require("../utilities/package-manager");
16
+ const package_metadata_1 = require("../utilities/package-metadata");
17
+ const package_tree_1 = require("../utilities/package-tree");
18
+ const npa = require('npm-package-arg');
19
+ const oldConfigFileNames = [
20
+ '.angular-cli.json',
21
+ 'angular-cli.json',
22
+ ];
14
23
  class UpdateCommand extends schematic_command_1.SchematicCommand {
15
24
  constructor() {
16
25
  super(...arguments);
17
26
  this.allowMissingWorkspace = true;
18
- this.collectionName = '@schematics/update';
19
- this.schematicName = 'update';
20
27
  }
21
- async parseArguments(schematicOptions, schema) {
22
- const args = await super.parseArguments(schematicOptions, schema);
23
- const maybeArgsLeftovers = args['--'];
24
- if (maybeArgsLeftovers
25
- && maybeArgsLeftovers.length == 1
26
- && maybeArgsLeftovers[0] == '@angular/cli'
27
- && args.migrateOnly === undefined
28
- && args.from === undefined) {
29
- // Check for a 1.7 angular-cli.json file.
30
- const oldConfigFileNames = [
31
- core_1.normalize('.angular-cli.json'),
32
- core_1.normalize('angular-cli.json'),
33
- ];
34
- const oldConfigFilePath = find_up_1.findUp(oldConfigFileNames, process.cwd())
35
- || find_up_1.findUp(oldConfigFileNames, __dirname);
36
- if (oldConfigFilePath) {
37
- args.migrateOnly = true;
38
- args.from = '1.0.0';
39
- }
40
- }
41
- // Move `--` to packages.
42
- if (args.packages == undefined && args['--']) {
43
- args.packages = args['--'];
44
- delete args['--'];
45
- }
46
- return args;
28
+ async parseArguments(_schematicOptions, _schema) {
29
+ return {};
47
30
  }
31
+ // tslint:disable-next-line:no-big-function
48
32
  async run(options) {
33
+ const packages = [];
34
+ for (const request of options['--'] || []) {
35
+ try {
36
+ const packageIdentifier = npa(request);
37
+ // only registry identifiers are supported
38
+ if (!packageIdentifier.registry) {
39
+ this.logger.error(`Package '${request}' is not a registry package identifer.`);
40
+ return 1;
41
+ }
42
+ if (packages.some(v => v.name === packageIdentifier.name)) {
43
+ this.logger.error(`Duplicate package '${packageIdentifier.name}' specified.`);
44
+ return 1;
45
+ }
46
+ // If next option is used and no specifier supplied, use next tag
47
+ if (options.next && !packageIdentifier.rawSpec) {
48
+ packageIdentifier.fetchSpec = 'next';
49
+ }
50
+ packages.push(packageIdentifier);
51
+ }
52
+ catch (e) {
53
+ this.logger.error(e.message);
54
+ return 1;
55
+ }
56
+ }
57
+ if (options.all && packages.length > 0) {
58
+ this.logger.error('Cannot specify packages when using the "all" option.');
59
+ return 1;
60
+ }
61
+ else if (options.all && options.migrateOnly) {
62
+ this.logger.error('Cannot use "all" option with "migrate-only" option.');
63
+ return 1;
64
+ }
65
+ else if (!options.migrateOnly && (options.from || options.to)) {
66
+ this.logger.error('Can only use "from" or "to" options with "migrate-only" option.');
67
+ return 1;
68
+ }
69
+ // If not asking for status then check for a clean git repository.
70
+ // This allows the user to easily reset any changes from the update.
71
+ if ((packages.length !== 0 || options.all) && !this.checkCleanGit()) {
72
+ this.logger.error('Repository is not clean. Please commit or stash any changes before updating.');
73
+ return 2;
74
+ }
49
75
  const packageManager = package_manager_1.getPackageManager(this.workspace.root);
76
+ this.logger.info(`Using package manager: '${packageManager}'`);
77
+ // Special handling for Angular CLI 1.x migrations
78
+ if (options.migrateOnly === undefined && options.from === undefined) {
79
+ if (!options.all && packages.length === 1 && packages[0].name === '@angular/cli') {
80
+ const oldConfigFilePath = find_up_1.findUp(oldConfigFileNames, process.cwd());
81
+ if (oldConfigFilePath) {
82
+ options.migrateOnly = true;
83
+ options.from = '1.0.0';
84
+ }
85
+ }
86
+ }
87
+ this.logger.info('Collecting installed dependencies...');
88
+ const packageTree = await package_tree_1.readPackageTree(this.workspace.root);
89
+ const rootDependencies = package_tree_1.findNodeDependencies(packageTree);
90
+ this.logger.info(`Found ${Object.keys(rootDependencies).length} dependencies.`);
91
+ if (options.all || packages.length === 0) {
92
+ // Either update all packages or show status
93
+ return this.runSchematic({
94
+ collectionName: '@schematics/update',
95
+ schematicName: 'update',
96
+ dryRun: !!options.dryRun,
97
+ showNothingDone: false,
98
+ additionalOptions: {
99
+ force: options.force || false,
100
+ next: options.next || false,
101
+ packageManager,
102
+ packages: options.all ? Object.keys(rootDependencies) : [],
103
+ },
104
+ });
105
+ }
106
+ if (options.migrateOnly) {
107
+ if (!options.from) {
108
+ this.logger.error('"from" option is required when using the "migrate-only" option.');
109
+ return 1;
110
+ }
111
+ else if (packages.length !== 1) {
112
+ this.logger.error('A single package must be specified when using the "migrate-only" option.');
113
+ return 1;
114
+ }
115
+ if (options.next) {
116
+ this.logger.warn('"next" option has no effect when using "migrate-only" option.');
117
+ }
118
+ const packageName = packages[0].name;
119
+ let packageNode = rootDependencies[packageName];
120
+ if (typeof packageNode === 'string') {
121
+ this.logger.error('Package found in package.json but is not installed.');
122
+ return 1;
123
+ }
124
+ else if (!packageNode) {
125
+ // Allow running migrations on transitively installed dependencies
126
+ // There can technically be nested multiple versions
127
+ // TODO: If multiple, this should find all versions and ask which one to use
128
+ const child = packageTree.children.find(c => c.name === packageName);
129
+ if (child) {
130
+ // A link represents a symlinked package so use the actual in this case
131
+ packageNode = child.isLink ? child.target : child;
132
+ }
133
+ if (!packageNode) {
134
+ this.logger.error('Package is not installed.');
135
+ return 1;
136
+ }
137
+ }
138
+ const updateMetadata = packageNode.package['ng-update'];
139
+ let migrations = updateMetadata && updateMetadata.migrations;
140
+ if (migrations === undefined) {
141
+ this.logger.error('Package does not provide migrations.');
142
+ return 1;
143
+ }
144
+ else if (typeof migrations !== 'string') {
145
+ this.logger.error('Package contains a malformed migrations field.');
146
+ return 1;
147
+ }
148
+ // if not non-relative, add package name
149
+ if (migrations.startsWith('.') || migrations.startsWith('/')) {
150
+ migrations = path.join(packageName, migrations);
151
+ }
152
+ return this.runSchematic({
153
+ collectionName: '@schematics/update',
154
+ schematicName: 'migrate',
155
+ dryRun: !!options.dryRun,
156
+ force: false,
157
+ showNothingDone: false,
158
+ additionalOptions: {
159
+ package: packageName,
160
+ collection: migrations,
161
+ from: options.from,
162
+ to: options.to || packageNode.package.version,
163
+ },
164
+ });
165
+ }
166
+ const requests = [];
167
+ // Validate packages actually are part of the workspace
168
+ for (const pkg of packages) {
169
+ const node = rootDependencies[pkg.name];
170
+ if (!node) {
171
+ this.logger.error(`Package '${pkg.name}' is not a dependency.`);
172
+ return 1;
173
+ }
174
+ // If a specific version is requested and matches the installed version, skip.
175
+ if (pkg.type === 'version' &&
176
+ typeof node === 'object' &&
177
+ node.package.version === pkg.fetchSpec) {
178
+ this.logger.info(`Package '${pkg.name}' is already at '${pkg.fetchSpec}'.`);
179
+ continue;
180
+ }
181
+ requests.push(pkg);
182
+ }
183
+ if (requests.length === 0) {
184
+ return 0;
185
+ }
186
+ this.logger.info('Fetching dependency metadata from registry...');
187
+ for (const requestIdentifier of requests) {
188
+ let metadata;
189
+ try {
190
+ // Metadata requests are internally cached; multiple requests for same name
191
+ // does not result in additional network traffic
192
+ metadata = await package_metadata_1.fetchPackageMetadata(requestIdentifier.name, this.logger);
193
+ }
194
+ catch (e) {
195
+ this.logger.error(`Error fetching metadata for '${requestIdentifier.name}': ` + e.message);
196
+ return 1;
197
+ }
198
+ // Try to find a package version based on the user requested package specifier
199
+ // registry specifier types are either version, range, or tag
200
+ let manifest;
201
+ if (requestIdentifier.type === 'version') {
202
+ manifest = metadata.versions.get(requestIdentifier.fetchSpec);
203
+ }
204
+ else if (requestIdentifier.type === 'range') {
205
+ const maxVersion = semver.maxSatisfying(Array.from(metadata.versions.keys()), requestIdentifier.fetchSpec);
206
+ if (maxVersion) {
207
+ manifest = metadata.versions.get(maxVersion);
208
+ }
209
+ }
210
+ else if (requestIdentifier.type === 'tag') {
211
+ manifest = metadata.tags[requestIdentifier.fetchSpec];
212
+ }
213
+ if (!manifest) {
214
+ this.logger.error(`Package specified by '${requestIdentifier.raw}' does not exist within the registry.`);
215
+ return 1;
216
+ }
217
+ }
50
218
  return this.runSchematic({
51
- collectionName: this.collectionName,
52
- schematicName: this.schematicName,
53
- schematicOptions: options['--'],
219
+ collectionName: '@schematics/update',
220
+ schematicName: 'update',
54
221
  dryRun: !!options.dryRun,
55
- force: false,
56
222
  showNothingDone: false,
57
- additionalOptions: { packageManager },
223
+ additionalOptions: {
224
+ force: options.force || false,
225
+ packageManager,
226
+ packages: requests.map(p => p.toString()),
227
+ },
58
228
  });
59
229
  }
230
+ checkCleanGit() {
231
+ try {
232
+ const result = child_process_1.execSync('git status --porcelain', { encoding: 'utf8', stdio: 'pipe' });
233
+ return result.trim().length === 0;
234
+ }
235
+ catch (_a) {
236
+ return true;
237
+ }
238
+ }
60
239
  }
61
240
  exports.UpdateCommand = UpdateCommand;
@@ -1,7 +1,9 @@
1
- Perform a basic update to v7 of the core framework and CLI by running the following command.
1
+ Perform a basic update to the current stable release of the core framework and CLI by running the following command.
2
2
 
3
3
  ```
4
4
  ng update @angular/cli @angular/core
5
5
  ```
6
6
 
7
+ To update to the next beta or pre-release version, use the `--next=true` option.
8
+
7
9
  For detailed information and guidance on updating your application, see the interactive [Angular Update Guide](https://update.angular.io/).
@@ -2,10 +2,41 @@
2
2
  * Updates your application and its dependencies. See https://update.angular.io/
3
3
  */
4
4
  export interface Schema {
5
+ /**
6
+ * Whether to update all packages in package.json.
7
+ */
8
+ all?: boolean;
9
+ /**
10
+ * If false, will error out if installed packages are incompatible with the update.
11
+ */
12
+ force?: boolean;
13
+ /**
14
+ * Version from which to migrate from. Only available with a single package being updated,
15
+ * and only on migration only.
16
+ */
17
+ from?: string;
5
18
  /**
6
19
  * Shows a help message for this command in the console.
7
20
  */
8
21
  help?: HelpUnion;
22
+ /**
23
+ * Only perform a migration, does not update the installed version.
24
+ */
25
+ migrateOnly?: boolean;
26
+ /**
27
+ * Use the largest version, including beta and RCs.
28
+ */
29
+ next?: boolean;
30
+ /**
31
+ * The names of package(s) to update.
32
+ */
33
+ packages?: string[];
34
+ /**
35
+ * Version up to which to apply migrations. Only available with a single package being
36
+ * updated, and only on migrations only. Requires from to be specified. Default to the
37
+ * installed version detected.
38
+ */
39
+ to?: string;
9
40
  }
10
41
  /**
11
42
  * Shows a help message for this command in the console.
@@ -13,6 +13,48 @@
13
13
  "allOf": [
14
14
  {
15
15
  "$ref": "./definitions.json#/definitions/base"
16
+ },
17
+ {
18
+ "type": "object",
19
+ "properties": {
20
+ "packages": {
21
+ "description": "The names of package(s) to update.",
22
+ "type": "array",
23
+ "items": {
24
+ "type": "string"
25
+ },
26
+ "$default": {
27
+ "$source": "argv"
28
+ }
29
+ },
30
+ "force": {
31
+ "description": "If false, will error out if installed packages are incompatible with the update.",
32
+ "default": false,
33
+ "type": "boolean"
34
+ },
35
+ "all": {
36
+ "description": "Whether to update all packages in package.json.",
37
+ "default": false,
38
+ "type": "boolean"
39
+ },
40
+ "next": {
41
+ "description": "Use the largest version, including beta and RCs.",
42
+ "default": false,
43
+ "type": "boolean"
44
+ },
45
+ "migrateOnly": {
46
+ "description": "Only perform a migration, does not update the installed version.",
47
+ "type": "boolean"
48
+ },
49
+ "from": {
50
+ "description": "Version from which to migrate from. Only available with a single package being updated, and only on migration only.",
51
+ "type": "string"
52
+ },
53
+ "to": {
54
+ "description": "Version up to which to apply migrations. Only available with a single package being updated, and only on migrations only. Requires from to be specified. Default to the installed version detected.",
55
+ "type": "string"
56
+ }
57
+ }
16
58
  }
17
59
  ]
18
60
  }
@@ -26,6 +26,7 @@ class VersionCommand extends command_1.Command {
26
26
  const patterns = [
27
27
  /^@angular\/.*/,
28
28
  /^@angular-devkit\/.*/,
29
+ /^@bazel\/.*/,
29
30
  /^@ngtools\/.*/,
30
31
  /^@nguniversal\/.*/,
31
32
  /^@schematics\/.*/,
@@ -14,6 +14,12 @@ class Xi18nCommand extends architect_command_1.ArchitectCommand {
14
14
  this.target = 'extract-i18n';
15
15
  }
16
16
  async run(options) {
17
+ const version = process.version.substr(1).split('.');
18
+ if (Number(version[0]) === 12 && Number(version[1]) === 0) {
19
+ this.logger.error('Due to a defect in Node.js 12.0, the command is not supported on this Node.js version. '
20
+ + 'Please upgrade to Node.js 12.1 or later.');
21
+ return 1;
22
+ }
17
23
  return this.runArchitectTarget(options);
18
24
  }
19
25
  }
@@ -5,6 +5,7 @@ export interface Schema {
5
5
  /**
6
6
  * A named build target, as specified in the "configurations" section of angular.json.
7
7
  * Each named target is accompanied by a configuration of option defaults for that target.
8
+ * Setting this explicitly overrides the "--prod" flag
8
9
  */
9
10
  configuration?: string;
10
11
  /**
@@ -12,13 +13,14 @@ export interface Schema {
12
13
  */
13
14
  help?: HelpUnion;
14
15
  /**
16
+ * Shorthand for "--configuration=production".
15
17
  * When true, sets the build configuration to the production target.
16
- * All builds make use of bundling and limited tree-shaking. A production build also runs
17
- * limited dead code elimination.
18
+ * By default, the production target is set up in the workspace configuration such that all
19
+ * builds make use of bundling, limited tree-shaking, and also limited dead code elimination.
18
20
  */
19
21
  prod?: boolean;
20
22
  /**
21
- * The name of the project to build. Can be an app or a library.
23
+ * The name of the project to build. Can be an application or a library.
22
24
  */
23
25
  project?: string;
24
26
  }
@@ -16,6 +16,7 @@ const os = require("os");
16
16
  const ua = require("universal-analytics");
17
17
  const uuid_1 = require("uuid");
18
18
  const config_1 = require("../utilities/config");
19
+ const tty_1 = require("../utilities/tty");
19
20
  const analyticsDebug = debug('ng:analytics'); // Generate analytics, including settings and users.
20
21
  const analyticsLogDebug = debug('ng:analytics:log'); // Actual logs of events.
21
22
  const BYTES_PER_MEGABYTES = 1024 * 1024;
@@ -309,7 +310,7 @@ exports.setAnalyticsConfig = setAnalyticsConfig;
309
310
  */
310
311
  async function promptGlobalAnalytics(force = false) {
311
312
  analyticsDebug('prompting global analytics.');
312
- if (force || (process.stdout.isTTY && process.stdin.isTTY)) {
313
+ if (force || tty_1.isTTY()) {
313
314
  const answers = await inquirer.prompt([
314
315
  {
315
316
  type: 'confirm',
@@ -353,7 +354,7 @@ async function promptProjectAnalytics(force = false) {
353
354
  if (!config || !configPath) {
354
355
  throw new Error(`Could not find a local workspace. Are you in a project?`);
355
356
  }
356
- if (force || (process.stdout.isTTY && process.stdin.isTTY)) {
357
+ if (force || tty_1.isTTY()) {
357
358
  const answers = await inquirer.prompt([
358
359
  {
359
360
  type: 'confirm',
@@ -389,7 +390,7 @@ function hasGlobalAnalyticsConfiguration() {
389
390
  const analyticsConfig = globalWorkspace
390
391
  && globalWorkspace.getCli()
391
392
  && globalWorkspace.getCli()['analytics'];
392
- if (analyticsConfig !== undefined) {
393
+ if (analyticsConfig !== null && analyticsConfig !== undefined) {
393
394
  return true;
394
395
  }
395
396
  }
@@ -176,7 +176,9 @@ class ArchitectCommand extends command_1.Command {
176
176
  const builderDesc = await this._architectHost.resolveBuilder(builderConf);
177
177
  const targetOptionArray = await json_schema_1.parseJsonSchemaToOptions(this._registry, builderDesc.optionSchema);
178
178
  const overrides = parser_1.parseArguments(targetOptions, targetOptionArray, this.logger);
179
- if (overrides['--']) {
179
+ const allowAdditionalProperties = typeof builderDesc.optionSchema === 'object'
180
+ && builderDesc.optionSchema.additionalProperties;
181
+ if (overrides['--'] && !allowAdditionalProperties) {
180
182
  (overrides['--'] || []).forEach(additional => {
181
183
  this.logger.fatal(`Unknown option: '${additional.split(/=/)[0]}'`);
182
184
  });
@@ -188,7 +190,10 @@ class ArchitectCommand extends command_1.Command {
188
190
  return this.runBepTarget(this.description.name, target, overrides, commandOptions.buildEventLog);
189
191
  }
190
192
  else {
191
- const run = await this._architect.scheduleTarget(target, overrides, { logger: this.logger });
193
+ const run = await this._architect.scheduleTarget(target, overrides, {
194
+ logger: this.logger,
195
+ analytics: analytics_1.isPackageNameSafeForAnalytics(builderConf) ? this.analytics : undefined,
196
+ });
192
197
  const result = await run.output.toPromise();
193
198
  await run.stop();
194
199
  return result.success ? 0 : 1;
@@ -35,6 +35,7 @@ export declare abstract class SchematicCommand<T extends (BaseSchematicSchema &
35
35
  private _host;
36
36
  private _workspace;
37
37
  protected _workflow: NodeWorkflow;
38
+ private readonly defaultCollectionName;
38
39
  protected collectionName: string;
39
40
  protected schematicName?: string;
40
41
  constructor(context: CommandContext, description: CommandDescription, logger: logging.Logger);
@@ -17,6 +17,7 @@ const workspace_loader_1 = require("../models/workspace-loader");
17
17
  const config_1 = require("../utilities/config");
18
18
  const json_schema_1 = require("../utilities/json-schema");
19
19
  const package_manager_1 = require("../utilities/package-manager");
20
+ const tty_1 = require("../utilities/tty");
20
21
  const analytics_1 = require("./analytics");
21
22
  const command_1 = require("./command");
22
23
  const parser_1 = require("./parser");
@@ -32,7 +33,8 @@ class SchematicCommand extends command_1.Command {
32
33
  this.allowPrivateSchematics = false;
33
34
  this.allowAdditionalArgs = false;
34
35
  this._host = new node_1.NodeJsSyncHost();
35
- this.collectionName = '@schematics/angular';
36
+ this.defaultCollectionName = '@schematics/angular';
37
+ this.collectionName = this.defaultCollectionName;
36
38
  }
37
39
  async initialize(options) {
38
40
  await this._loadWorkspace();
@@ -172,35 +174,10 @@ class SchematicCommand extends command_1.Command {
172
174
  };
173
175
  }
174
176
  else {
175
- return {
176
- ...context,
177
- analytics: new core_1.analytics.NoopAnalytics(),
178
- };
177
+ return context;
179
178
  }
180
179
  });
181
180
  workflow.engineHost.registerOptionsTransform(tools_1.validateOptionsWithSchema(workflow.registry));
182
- // This needs to be the last transform as it reports the flags to analytics (if enabled).
183
- workflow.engineHost.registerOptionsTransform(async (schematic, options, context) => {
184
- const analytics = context && context.analytics;
185
- if (!schematic.schemaJson || !context || !analytics) {
186
- return options;
187
- }
188
- const collectionName = context.schematic.collection.description.name;
189
- const schematicName = context.schematic.description.name;
190
- if (!analytics_1.isPackageNameSafeForAnalytics(collectionName)) {
191
- return options;
192
- }
193
- const args = await json_schema_1.parseJsonSchemaToOptions(this._workflow.registry, schematic.schemaJson);
194
- const dimensions = [];
195
- for (const option of args) {
196
- const ua = option.userAnalytics;
197
- if (option.name in options && ua) {
198
- dimensions[ua] = options[option.name];
199
- }
200
- }
201
- analytics.event('schematics', collectionName + ':' + schematicName, { dimensions });
202
- return options;
203
- });
204
181
  if (options.defaults) {
205
182
  workflow.registry.addPreTransform(core_1.schema.transforms.addUndefinedDefaults);
206
183
  }
@@ -227,7 +204,7 @@ class SchematicCommand extends command_1.Command {
227
204
  }
228
205
  return undefined;
229
206
  });
230
- if (options.interactive !== false && process.stdout.isTTY) {
207
+ if (options.interactive !== false && tty_1.isTTY()) {
231
208
  workflow.registry.usePromptProvider((definitions) => {
232
209
  const questions = definitions.map(definition => {
233
210
  const question = {
@@ -292,7 +269,7 @@ class SchematicCommand extends command_1.Command {
292
269
  return value;
293
270
  }
294
271
  }
295
- return this.collectionName;
272
+ return this.defaultCollectionName;
296
273
  }
297
274
  async runSchematic(options) {
298
275
  const { schematicOptions, debug, dryRun } = options;
@@ -309,7 +286,7 @@ class SchematicCommand extends command_1.Command {
309
286
  collectionName = schematic.collection.description.name;
310
287
  schematicName = schematic.description.name;
311
288
  // TODO: Remove warning check when 'targets' is default
312
- if (collectionName !== this.collectionName) {
289
+ if (collectionName !== this.defaultCollectionName) {
313
290
  const [ast, configPath] = config_1.getWorkspaceRaw('local');
314
291
  if (ast) {
315
292
  const projectsKeyValue = ast.properties.find(p => p.key.value === 'projects');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@angular/cli",
3
- "version": "8.0.0-rc.1",
3
+ "version": "8.0.0",
4
4
  "description": "CLI tool for Angular",
5
5
  "main": "lib/cli/index.js",
6
6
  "bin": {
@@ -28,11 +28,11 @@
28
28
  },
29
29
  "homepage": "https://github.com/angular/angular-cli",
30
30
  "dependencies": {
31
- "@angular-devkit/architect": "0.800.0-rc.1",
32
- "@angular-devkit/core": "8.0.0-rc.1",
33
- "@angular-devkit/schematics": "8.0.0-rc.1",
34
- "@schematics/angular": "8.0.0-rc.1",
35
- "@schematics/update": "0.800.0-rc.1",
31
+ "@angular-devkit/architect": "0.800.0",
32
+ "@angular-devkit/core": "8.0.0",
33
+ "@angular-devkit/schematics": "8.0.0",
34
+ "@schematics/angular": "8.0.0",
35
+ "@schematics/update": "0.800.0",
36
36
  "@yarnpkg/lockfile": "1.1.0",
37
37
  "debug": "^4.1.1",
38
38
  "ini": "1.3.5",
@@ -40,6 +40,7 @@
40
40
  "npm-package-arg": "6.1.0",
41
41
  "open": "6.2.0",
42
42
  "pacote": "9.5.0",
43
+ "read-package-tree": "5.2.2",
43
44
  "semver": "6.0.0",
44
45
  "symbol-observable": "1.2.0",
45
46
  "universal-analytics": "^0.4.20",
@@ -48,10 +49,10 @@
48
49
  "ng-update": {
49
50
  "migrations": "@schematics/angular/migrations/migration-collection.json",
50
51
  "packageGroup": {
51
- "@angular/cli": "8.0.0-rc.1",
52
- "@angular-devkit/build-angular": "0.800.0-rc.1",
53
- "@angular-devkit/build-ng-packagr": "0.800.0-rc.1",
54
- "@angular-devkit/build-webpack": "0.800.0-rc.1"
52
+ "@angular/cli": "8.0.0",
53
+ "@angular-devkit/build-angular": "0.800.0",
54
+ "@angular-devkit/build-ng-packagr": "0.800.0",
55
+ "@angular-devkit/build-webpack": "0.800.0"
55
56
  }
56
57
  },
57
58
  "engines": {
@@ -6,5 +6,4 @@
6
6
  * found in the LICENSE file at https://angular.io/license
7
7
  */
8
8
  import { logging } from '@angular-devkit/core';
9
- export declare type NpmInstall = (packageName: string, logger: logging.Logger, packageManager: string, projectRoot: string, save?: boolean) => Promise<void>;
10
9
  export default function (packageName: string, logger: logging.Logger, packageManager: string, projectRoot: string, save?: boolean): Promise<void>;
@@ -15,14 +15,14 @@ async function default_1(packageName, logger, packageManager, projectRoot, save
15
15
  case 'cnpm':
16
16
  case 'pnpm':
17
17
  case 'npm':
18
- installArgs.push('install', '--silent');
18
+ installArgs.push('install');
19
19
  break;
20
20
  case 'yarn':
21
21
  installArgs.push('add');
22
22
  break;
23
23
  default:
24
24
  packageManager = 'npm';
25
- installArgs.push('install', '--quiet');
25
+ installArgs.push('install');
26
26
  break;
27
27
  }
28
28
  logger.info(core_1.terminal.green(`Installing packages for tooling via ${packageManager}.`));
@@ -32,6 +32,7 @@ async function default_1(packageName, logger, packageManager, projectRoot, save
32
32
  if (!save) {
33
33
  installArgs.push('--no-save');
34
34
  }
35
+ installArgs.push('--quiet');
35
36
  await new Promise((resolve, reject) => {
36
37
  child_process_1.spawn(packageManager, installArgs, { stdio: 'inherit', shell: true })
37
38
  .on('close', (code) => {
@@ -40,9 +41,7 @@ async function default_1(packageName, logger, packageManager, projectRoot, save
40
41
  resolve();
41
42
  }
42
43
  else {
43
- const message = 'Package install failed, see above.';
44
- logger.info(core_1.terminal.red(message));
45
- reject(message);
44
+ reject('Package install failed, see above.');
46
45
  }
47
46
  });
48
47
  });
@@ -15,6 +15,8 @@ export interface PackageIdentifier {
15
15
  scope: string | null;
16
16
  registry: boolean;
17
17
  raw: string;
18
+ fetchSpec: string;
19
+ rawSpec: string;
18
20
  }
19
21
  export interface PackageManifest {
20
22
  name: string;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google Inc. 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.io/license
7
+ */
8
+ export interface PackageTreeNodeBase {
9
+ name: string;
10
+ path: string;
11
+ realpath: string;
12
+ error?: Error;
13
+ id: number;
14
+ isLink: boolean;
15
+ package: {
16
+ name: string;
17
+ version: string;
18
+ dependencies?: Record<string, string>;
19
+ devDependencies?: Record<string, string>;
20
+ peerDependencies?: Record<string, string>;
21
+ 'ng-update'?: {
22
+ migrations?: string;
23
+ };
24
+ };
25
+ children: PackageTreeNode[];
26
+ }
27
+ export interface PackageTreeActual extends PackageTreeNodeBase {
28
+ isLink: false;
29
+ parent?: PackageTreeActual;
30
+ }
31
+ export interface PackageTreeLink extends PackageTreeNodeBase {
32
+ isLink: true;
33
+ parent: null;
34
+ target: PackageTreeActual;
35
+ }
36
+ export declare type PackageTreeNode = PackageTreeActual | PackageTreeLink;
37
+ export declare function readPackageTree(path: string): Promise<PackageTreeNode>;
38
+ export declare function findNodeDependencies(root: PackageTreeNode, node?: PackageTreeNode): Record<string, string | PackageTreeActual | undefined>;
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ function readPackageTree(path) {
4
+ const rpt = require('read-package-tree');
5
+ return new Promise((resolve, reject) => {
6
+ rpt(path, (e, data) => {
7
+ if (e) {
8
+ reject(e);
9
+ }
10
+ else {
11
+ resolve(data);
12
+ }
13
+ });
14
+ });
15
+ }
16
+ exports.readPackageTree = readPackageTree;
17
+ function findNodeDependencies(root, node = root) {
18
+ const actual = node.isLink ? node.target : node;
19
+ const rawDeps = {
20
+ ...actual.package.dependencies,
21
+ ...actual.package.devDependencies,
22
+ ...actual.package.peerDependencies,
23
+ };
24
+ return Object.entries(rawDeps).reduce((deps, [name, version]) => {
25
+ const depNode = root.children.find(child => {
26
+ return child.name === name && !child.isLink && child.parent === node;
27
+ });
28
+ deps[name] = depNode || version;
29
+ return deps;
30
+ }, {});
31
+ }
32
+ exports.findNodeDependencies = findNodeDependencies;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @license
3
+ * Copyright Google Inc. 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.io/license
7
+ */
8
+ export declare function isTTY(): boolean;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * @license
5
+ * Copyright Google Inc. All Rights Reserved.
6
+ *
7
+ * Use of this source code is governed by an MIT-style license that can be
8
+ * found in the LICENSE file at https://angular.io/license
9
+ */
10
+ function isTTY() {
11
+ const force = process.env['NG_FORCE_TTY'];
12
+ if (force !== undefined) {
13
+ return !(force === '0' || force.toUpperCase() === 'FALSE');
14
+ }
15
+ return !!process.stdout.isTTY && !!process.stdin.isTTY;
16
+ }
17
+ exports.isTTY = isTTY;