@angular/cli 14.0.0-rc.0 → 14.0.0-rc.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 +1 -1
- package/lib/config/schema.json +33 -1
- package/lib/init.js +1 -1
- package/package.json +11 -11
- package/src/command-builder/command-module.js +1 -6
- package/src/command-builder/schematics-command-module.js +37 -8
- package/src/commands/completion/cli.js +7 -0
- package/src/commands/completion/long-description.md +69 -4
- package/src/commands/doc/cli.js +2 -2
- package/src/commands/update/cli.js +21 -7
- package/src/utilities/completion.d.ts +8 -0
- package/src/utilities/completion.js +64 -1
- package/src/utilities/package-manager.js +8 -13
package/lib/cli/index.js
CHANGED
|
@@ -73,7 +73,7 @@ async function default_1(options) {
|
|
|
73
73
|
// Log nothing.
|
|
74
74
|
}
|
|
75
75
|
else {
|
|
76
|
-
logger.fatal(
|
|
76
|
+
logger.fatal(`An unexpected error occurred: ${'toString' in err ? err.toString() : JSON.stringify(err)}`);
|
|
77
77
|
}
|
|
78
78
|
return 1;
|
|
79
79
|
}
|
package/lib/config/schema.json
CHANGED
|
@@ -742,6 +742,9 @@
|
|
|
742
742
|
"path": {
|
|
743
743
|
"type": "string",
|
|
744
744
|
"format": "path",
|
|
745
|
+
"$default": {
|
|
746
|
+
"$source": "workingDirectory"
|
|
747
|
+
},
|
|
745
748
|
"description": "The path at which to create the class, relative to the workspace root.",
|
|
746
749
|
"visible": false
|
|
747
750
|
},
|
|
@@ -773,6 +776,9 @@
|
|
|
773
776
|
"path": {
|
|
774
777
|
"type": "string",
|
|
775
778
|
"format": "path",
|
|
779
|
+
"$default": {
|
|
780
|
+
"$source": "workingDirectory"
|
|
781
|
+
},
|
|
776
782
|
"description": "The path at which to create the component file, relative to the current workspace. Default is a folder with the same name as the component in the project root.",
|
|
777
783
|
"visible": false
|
|
778
784
|
},
|
|
@@ -929,6 +935,9 @@
|
|
|
929
935
|
"path": {
|
|
930
936
|
"type": "string",
|
|
931
937
|
"format": "path",
|
|
938
|
+
"$default": {
|
|
939
|
+
"$source": "workingDirectory"
|
|
940
|
+
},
|
|
932
941
|
"description": "The path at which to create the interface that defines the directive, relative to the workspace root.",
|
|
933
942
|
"visible": false
|
|
934
943
|
},
|
|
@@ -1012,6 +1021,9 @@
|
|
|
1012
1021
|
"path": {
|
|
1013
1022
|
"type": "string",
|
|
1014
1023
|
"format": "path",
|
|
1024
|
+
"$default": {
|
|
1025
|
+
"$source": "workingDirectory"
|
|
1026
|
+
},
|
|
1015
1027
|
"description": "The path at which to create the enum definition, relative to the current workspace.",
|
|
1016
1028
|
"visible": false
|
|
1017
1029
|
},
|
|
@@ -1057,6 +1069,9 @@
|
|
|
1057
1069
|
"path": {
|
|
1058
1070
|
"type": "string",
|
|
1059
1071
|
"format": "path",
|
|
1072
|
+
"$default": {
|
|
1073
|
+
"$source": "workingDirectory"
|
|
1074
|
+
},
|
|
1060
1075
|
"description": "The path at which to create the interface that defines the guard, relative to the current workspace.",
|
|
1061
1076
|
"visible": false
|
|
1062
1077
|
},
|
|
@@ -1106,6 +1121,9 @@
|
|
|
1106
1121
|
"path": {
|
|
1107
1122
|
"type": "string",
|
|
1108
1123
|
"format": "path",
|
|
1124
|
+
"$default": {
|
|
1125
|
+
"$source": "workingDirectory"
|
|
1126
|
+
},
|
|
1109
1127
|
"description": "The path at which to create the interceptor, relative to the workspace root.",
|
|
1110
1128
|
"visible": false
|
|
1111
1129
|
},
|
|
@@ -1147,6 +1165,9 @@
|
|
|
1147
1165
|
"path": {
|
|
1148
1166
|
"type": "string",
|
|
1149
1167
|
"format": "path",
|
|
1168
|
+
"$default": {
|
|
1169
|
+
"$source": "workingDirectory"
|
|
1170
|
+
},
|
|
1150
1171
|
"description": "The path at which to create the interface, relative to the workspace root.",
|
|
1151
1172
|
"visible": false
|
|
1152
1173
|
},
|
|
@@ -1236,6 +1257,9 @@
|
|
|
1236
1257
|
"path": {
|
|
1237
1258
|
"type": "string",
|
|
1238
1259
|
"format": "path",
|
|
1260
|
+
"$default": {
|
|
1261
|
+
"$source": "workingDirectory"
|
|
1262
|
+
},
|
|
1239
1263
|
"description": "The path at which to create the pipe, relative to the workspace root.",
|
|
1240
1264
|
"visible": false
|
|
1241
1265
|
},
|
|
@@ -1466,6 +1490,9 @@
|
|
|
1466
1490
|
"path": {
|
|
1467
1491
|
"type": "string",
|
|
1468
1492
|
"format": "path",
|
|
1493
|
+
"$default": {
|
|
1494
|
+
"$source": "workingDirectory"
|
|
1495
|
+
},
|
|
1469
1496
|
"description": "The path at which to create the interface that defines the resolver, relative to the current workspace.",
|
|
1470
1497
|
"visible": false
|
|
1471
1498
|
},
|
|
@@ -1495,7 +1522,9 @@
|
|
|
1495
1522
|
},
|
|
1496
1523
|
"path": {
|
|
1497
1524
|
"type": "string",
|
|
1498
|
-
"
|
|
1525
|
+
"$default": {
|
|
1526
|
+
"$source": "workingDirectory"
|
|
1527
|
+
},
|
|
1499
1528
|
"description": "The path at which to create the service, relative to the workspace root.",
|
|
1500
1529
|
"visible": false
|
|
1501
1530
|
},
|
|
@@ -1528,6 +1557,9 @@
|
|
|
1528
1557
|
"path": {
|
|
1529
1558
|
"type": "string",
|
|
1530
1559
|
"format": "path",
|
|
1560
|
+
"$default": {
|
|
1561
|
+
"$source": "workingDirectory"
|
|
1562
|
+
},
|
|
1531
1563
|
"description": "The path at which to create the worker file, relative to the current workspace.",
|
|
1532
1564
|
"visible": false
|
|
1533
1565
|
},
|
package/lib/init.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular/cli",
|
|
3
|
-
"version": "14.0.0-rc.
|
|
3
|
+
"version": "14.0.0-rc.3",
|
|
4
4
|
"description": "CLI tool for Angular",
|
|
5
5
|
"main": "lib/cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://github.com/angular/angular-cli",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@angular-devkit/architect": "0.1400.0-rc.
|
|
29
|
-
"@angular-devkit/core": "14.0.0-rc.
|
|
30
|
-
"@angular-devkit/schematics": "14.0.0-rc.
|
|
31
|
-
"@schematics/angular": "14.0.0-rc.
|
|
28
|
+
"@angular-devkit/architect": "0.1400.0-rc.3",
|
|
29
|
+
"@angular-devkit/core": "14.0.0-rc.3",
|
|
30
|
+
"@angular-devkit/schematics": "14.0.0-rc.3",
|
|
31
|
+
"@schematics/angular": "14.0.0-rc.3",
|
|
32
32
|
"@yarnpkg/lockfile": "1.1.0",
|
|
33
33
|
"ansi-colors": "4.1.1",
|
|
34
34
|
"debug": "4.3.4",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"ng-update": {
|
|
50
50
|
"migrations": "@schematics/angular/migrations/migration-collection.json",
|
|
51
51
|
"packageGroup": {
|
|
52
|
-
"@angular/cli": "14.0.0-rc.
|
|
53
|
-
"@angular-devkit/architect": "0.1400.0-rc.
|
|
54
|
-
"@angular-devkit/build-angular": "14.0.0-rc.
|
|
55
|
-
"@angular-devkit/build-webpack": "0.1400.0-rc.
|
|
56
|
-
"@angular-devkit/core": "14.0.0-rc.
|
|
57
|
-
"@angular-devkit/schematics": "14.0.0-rc.
|
|
52
|
+
"@angular/cli": "14.0.0-rc.3",
|
|
53
|
+
"@angular-devkit/architect": "0.1400.0-rc.3",
|
|
54
|
+
"@angular-devkit/build-angular": "14.0.0-rc.3",
|
|
55
|
+
"@angular-devkit/build-webpack": "0.1400.0-rc.3",
|
|
56
|
+
"@angular-devkit/core": "14.0.0-rc.3",
|
|
57
|
+
"@angular-devkit/schematics": "14.0.0-rc.3"
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"engines": {
|
|
@@ -148,9 +148,8 @@ class CommandModule {
|
|
|
148
148
|
* **Note:** This method should be called from the command bundler method.
|
|
149
149
|
*/
|
|
150
150
|
addSchemaOptionsToCommand(localYargs, options) {
|
|
151
|
-
const workingDir = (0, core_1.normalize)(path.relative(this.context.root, process.cwd()));
|
|
152
151
|
for (const option of options) {
|
|
153
|
-
const { default: defaultVal, positional, deprecated, description, alias, userAnalytics, type, hidden, name, choices,
|
|
152
|
+
const { default: defaultVal, positional, deprecated, description, alias, userAnalytics, type, hidden, name, choices, } = option;
|
|
154
153
|
const sharedOptions = {
|
|
155
154
|
alias,
|
|
156
155
|
hidden,
|
|
@@ -160,10 +159,6 @@ class CommandModule {
|
|
|
160
159
|
// This should only be done when `--help` is used otherwise default will override options set in angular.json.
|
|
161
160
|
...(this.context.args.options.help ? { default: defaultVal } : {}),
|
|
162
161
|
};
|
|
163
|
-
// Special case for schematics
|
|
164
|
-
if (workingDir && format === 'path' && name === 'path' && hidden) {
|
|
165
|
-
sharedOptions.default = workingDir;
|
|
166
|
-
}
|
|
167
162
|
if (positional === undefined) {
|
|
168
163
|
localYargs = localYargs.option(core_1.strings.dasherize(name), {
|
|
169
164
|
type,
|
|
@@ -40,6 +40,7 @@ exports.SchematicsCommandModule = exports.DEFAULT_SCHEMATICS_COLLECTION = void 0
|
|
|
40
40
|
const core_1 = require("@angular-devkit/core");
|
|
41
41
|
const schematics_1 = require("@angular-devkit/schematics");
|
|
42
42
|
const tools_1 = require("@angular-devkit/schematics/tools");
|
|
43
|
+
const path_1 = require("path");
|
|
43
44
|
const config_1 = require("../utilities/config");
|
|
44
45
|
const memoize_1 = require("../utilities/memoize");
|
|
45
46
|
const tty_1 = require("../utilities/tty");
|
|
@@ -119,8 +120,10 @@ class SchematicsCommandModule extends command_module_1.CommandModule {
|
|
|
119
120
|
engineHostCreator: (options) => new schematic_engine_host_1.SchematicEngineHost(options.resolvePaths),
|
|
120
121
|
});
|
|
121
122
|
workflow.registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults);
|
|
122
|
-
workflow.registry.addSmartDefaultProvider('projectName', () => this.getProjectName());
|
|
123
123
|
workflow.registry.useXDeprecatedProvider((msg) => logger.warn(msg));
|
|
124
|
+
workflow.registry.addSmartDefaultProvider('projectName', () => this.getProjectName());
|
|
125
|
+
const workingDir = (0, core_1.normalize)((0, path_1.relative)(this.context.root, process.cwd()));
|
|
126
|
+
workflow.registry.addSmartDefaultProvider('workingDirectory', () => workingDir === '' ? undefined : workingDir);
|
|
124
127
|
let shouldReportAnalytics = true;
|
|
125
128
|
workflow.engineHost.registerOptionsTransform(async (schematic, options) => {
|
|
126
129
|
var _a;
|
|
@@ -134,6 +137,28 @@ class SchematicsCommandModule extends command_module_1.CommandModule {
|
|
|
134
137
|
schematic.name.replace(/\//g, '_'),
|
|
135
138
|
]);
|
|
136
139
|
}
|
|
140
|
+
// TODO: The below should be removed in version 15 when we change 1P schematics to use the `workingDirectory smart default`.
|
|
141
|
+
// Handle `"format": "path"` options.
|
|
142
|
+
const schema = schematic === null || schematic === void 0 ? void 0 : schematic.schemaJson;
|
|
143
|
+
if (!options || !schema || !(0, core_1.isJsonObject)(schema)) {
|
|
144
|
+
return options;
|
|
145
|
+
}
|
|
146
|
+
if (!('path' in options && options['path'] === undefined)) {
|
|
147
|
+
return options;
|
|
148
|
+
}
|
|
149
|
+
const properties = schema === null || schema === void 0 ? void 0 : schema['properties'];
|
|
150
|
+
if (!properties || !(0, core_1.isJsonObject)(properties)) {
|
|
151
|
+
return options;
|
|
152
|
+
}
|
|
153
|
+
const property = properties['path'];
|
|
154
|
+
if (!property || !(0, core_1.isJsonObject)(property)) {
|
|
155
|
+
return options;
|
|
156
|
+
}
|
|
157
|
+
if (property['format'] === 'path' && !property['$default']) {
|
|
158
|
+
options['path'] = workingDir || undefined;
|
|
159
|
+
this.context.logger.warn(`The 'path' option in '${schematic === null || schematic === void 0 ? void 0 : schematic.schema}' is using deprecated behaviour.` +
|
|
160
|
+
`'workingDirectory' smart default provider should be used instead.`);
|
|
161
|
+
}
|
|
137
162
|
return options;
|
|
138
163
|
});
|
|
139
164
|
if (options.interactive !== false && (0, tty_1.isTTY)()) {
|
|
@@ -209,16 +234,20 @@ class SchematicsCommandModule extends command_module_1.CommandModule {
|
|
|
209
234
|
}
|
|
210
235
|
async getSchematicCollections() {
|
|
211
236
|
var _a;
|
|
237
|
+
// Resolve relative collections from the location of `angular.json`
|
|
238
|
+
const resolveRelativeCollection = (collectionName) => collectionName.charAt(0) === '.'
|
|
239
|
+
? (0, path_1.resolve)(this.context.root, collectionName)
|
|
240
|
+
: collectionName;
|
|
212
241
|
const getSchematicCollections = (configSection) => {
|
|
213
242
|
if (!configSection) {
|
|
214
243
|
return undefined;
|
|
215
244
|
}
|
|
216
245
|
const { schematicCollections, defaultCollection } = configSection;
|
|
217
246
|
if (Array.isArray(schematicCollections)) {
|
|
218
|
-
return new Set(schematicCollections);
|
|
247
|
+
return new Set(schematicCollections.map((c) => resolveRelativeCollection(c)));
|
|
219
248
|
}
|
|
220
249
|
else if (typeof defaultCollection === 'string') {
|
|
221
|
-
return new Set([defaultCollection]);
|
|
250
|
+
return new Set([resolveRelativeCollection(defaultCollection)]);
|
|
222
251
|
}
|
|
223
252
|
return undefined;
|
|
224
253
|
};
|
|
@@ -275,11 +304,11 @@ class SchematicsCommandModule extends command_module_1.CommandModule {
|
|
|
275
304
|
if (err instanceof schematics_1.UnsuccessfulWorkflowExecution) {
|
|
276
305
|
// "See above" because we already printed the error.
|
|
277
306
|
logger.fatal('The Schematic workflow failed. See above.');
|
|
278
|
-
return 1;
|
|
279
307
|
}
|
|
280
308
|
else {
|
|
281
|
-
|
|
309
|
+
logger.fatal(err.message);
|
|
282
310
|
}
|
|
311
|
+
return 1;
|
|
283
312
|
}
|
|
284
313
|
finally {
|
|
285
314
|
unsubscribe();
|
|
@@ -299,9 +328,9 @@ class SchematicsCommandModule extends command_module_1.CommandModule {
|
|
|
299
328
|
if (typeof defaultProjectName === 'string' && defaultProjectName) {
|
|
300
329
|
if (!this.defaultProjectDeprecationWarningShown) {
|
|
301
330
|
logger.warn(core_1.tags.oneLine `
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
331
|
+
DEPRECATED: The 'defaultProject' workspace option has been deprecated.
|
|
332
|
+
The project to use will be determined from the current working directory.
|
|
333
|
+
`);
|
|
305
334
|
this.defaultProjectDeprecationWarningShown = true;
|
|
306
335
|
}
|
|
307
336
|
return defaultProjectName;
|
|
@@ -41,6 +41,13 @@ Appended \`source <(ng completion script)\` to \`${rcFile}\`. Restart your termi
|
|
|
41
41
|
|
|
42
42
|
${color_1.colors.yellow('source <(ng completion script)')}
|
|
43
43
|
`.trim());
|
|
44
|
+
if ((await (0, completion_1.hasGlobalCliInstall)()) === false) {
|
|
45
|
+
this.context.logger.warn('Setup completed successfully, but there does not seem to be a global install of the' +
|
|
46
|
+
' Angular CLI. For autocompletion to work, the CLI will need to be on your `$PATH`, which' +
|
|
47
|
+
' is typically done with the `-g` flag in `npm install -g @angular/cli`.' +
|
|
48
|
+
'\n\n' +
|
|
49
|
+
'For more information, see https://angular.io/cli/completion#global-install');
|
|
50
|
+
}
|
|
44
51
|
return 0;
|
|
45
52
|
}
|
|
46
53
|
}
|
|
@@ -1,5 +1,70 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
Setting up autocompletion configures your terminal, so pressing the `<TAB>` key while in the middle
|
|
2
|
+
of typing will display various commands and options available to you. This makes it very easy to
|
|
3
|
+
discover and use CLI commands without lots of memorization.
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+

|
|
8
|
+
|
|
9
|
+
## Automated setup
|
|
10
|
+
|
|
11
|
+
The CLI should prompt and ask to set up autocompletion for you the first time you use it (v14+).
|
|
12
|
+
Simply answer "Yes" and the CLI will take care of the rest.
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
$ ng serve
|
|
16
|
+
? Would you like to enable autocompletion? This will set up your terminal so pressing TAB while typing Angular CLI commands will show possible options and autocomplete arguments. (Enabling autocompletion will modify configuration files in your home directory.) Yes
|
|
17
|
+
Appended `source <(ng completion script)` to `/home/my-username/.bashrc`. Restart your terminal or run:
|
|
18
|
+
|
|
19
|
+
source <(ng completion script)
|
|
20
|
+
|
|
21
|
+
to autocomplete `ng` commands.
|
|
22
|
+
|
|
23
|
+
# Serve output...
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If you already refused the prompt, it won't ask again. But you can run `ng completion` to
|
|
27
|
+
do the same thing automatically.
|
|
28
|
+
|
|
29
|
+
This modifies your terminal environment to load Angular CLI autocompletion, but can't update your
|
|
30
|
+
current terminal session. Either restart it or run `source <(ng completion script)` directly to
|
|
31
|
+
enable autocompletion in your current session.
|
|
32
|
+
|
|
33
|
+
Test it out by typing `ng ser<TAB>` and it should autocomplete to `ng serve`. Ambiguous arguments
|
|
34
|
+
will show all possible options and their documentation, such as `ng generate <TAB>`.
|
|
35
|
+
|
|
36
|
+
## Manual setup
|
|
37
|
+
|
|
38
|
+
Some users may have highly customized terminal setups, possibly with configuration files checked
|
|
39
|
+
into source control with an opinionated structure. `ng completion` only ever appends Angular's setup
|
|
40
|
+
to an existing configuration file for your current shell, or creates one if none exists. If you want
|
|
41
|
+
more control over exactly where this configuration lives, you can manually set it up by having your
|
|
42
|
+
shell run at startup:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
source <(ng completion script)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This is equivalent to what `ng completion` will automatically set up, and gives power users more
|
|
49
|
+
flexibility in their environments when desired.
|
|
50
|
+
|
|
51
|
+
## Platform support
|
|
52
|
+
|
|
53
|
+
Angular CLI supports autocompletion for the Bash and Zsh shells on MacOS and Linux operating
|
|
54
|
+
systems.
|
|
55
|
+
|
|
56
|
+
Windows does not support autocompletion in native shells, such as Cmd and Powershell. However,
|
|
57
|
+
the Angular CLI supports Git Bash and
|
|
58
|
+
[Windows Subsystem for Linux](https://docs.microsoft.com/en-us/windows/wsl/) using Bash or Zsh.
|
|
59
|
+
|
|
60
|
+
## Global install
|
|
61
|
+
|
|
62
|
+
Autocompletion works by configuring your terminal to invoke the Angular CLI on startup to load the
|
|
63
|
+
setup script. This means the terminal must be able to find and execute the Angular CLI, typically
|
|
64
|
+
through a global install that places the binary on the user's `$PATH`. If you get
|
|
65
|
+
`command not found: ng`, make sure the CLI is installed globally which you can do with the `-g`
|
|
66
|
+
flag:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install -g @angular/cli
|
|
70
|
+
```
|
package/src/commands/doc/cli.js
CHANGED
|
@@ -93,8 +93,8 @@ class DocCommandModule extends command_module_1.CommandModule {
|
|
|
93
93
|
catch { }
|
|
94
94
|
}
|
|
95
95
|
await (0, open_1.default)(options.search
|
|
96
|
-
? `https://${domain}/
|
|
97
|
-
: `https://${domain}/
|
|
96
|
+
? `https://${domain}/docs?search=${options.keyword}`
|
|
97
|
+
: `https://${domain}/api?query=${options.keyword}`);
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
exports.DocCommandModule = DocCommandModule;
|
|
@@ -122,7 +122,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
|
|
|
122
122
|
alias: ['C'],
|
|
123
123
|
default: false,
|
|
124
124
|
})
|
|
125
|
-
.check(({ packages,
|
|
125
|
+
.check(({ packages, 'allow-dirty': allowDirty, 'migrate-only': migrateOnly }) => {
|
|
126
126
|
const { logger } = this.context;
|
|
127
127
|
// This allows the user to easily reset any changes from the update.
|
|
128
128
|
if ((packages === null || packages === void 0 ? void 0 : packages.length) && !this.checkCleanGit()) {
|
|
@@ -137,9 +137,6 @@ class UpdateCommandModule extends command_module_1.CommandModule {
|
|
|
137
137
|
if ((packages === null || packages === void 0 ? void 0 : packages.length) !== 1) {
|
|
138
138
|
throw new command_module_1.CommandModuleError(`A single package must be specified when using the 'migrate-only' option.`);
|
|
139
139
|
}
|
|
140
|
-
if (next) {
|
|
141
|
-
logger.warn(`'next' option has no effect when using 'migrate-only' option.`);
|
|
142
|
-
}
|
|
143
140
|
}
|
|
144
141
|
return true;
|
|
145
142
|
})
|
|
@@ -513,7 +510,23 @@ class UpdateCommandModule extends command_module_1.CommandModule {
|
|
|
513
510
|
});
|
|
514
511
|
}
|
|
515
512
|
catch { }
|
|
516
|
-
|
|
513
|
+
let forceInstall = options.force;
|
|
514
|
+
// npm 7+ can fail due to it incorrectly resolving peer dependencies that have valid SemVer
|
|
515
|
+
// ranges during an update. Update will set correct versions of dependencies within the
|
|
516
|
+
// package.json file. The force option is set to workaround these errors.
|
|
517
|
+
// Example error:
|
|
518
|
+
// npm ERR! Conflicting peer dependency: @angular/compiler-cli@14.0.0-rc.0
|
|
519
|
+
// npm ERR! node_modules/@angular/compiler-cli
|
|
520
|
+
// npm ERR! peer @angular/compiler-cli@"^14.0.0 || ^14.0.0-rc" from @angular-devkit/build-angular@14.0.0-rc.0
|
|
521
|
+
// npm ERR! node_modules/@angular-devkit/build-angular
|
|
522
|
+
// npm ERR! dev @angular-devkit/build-angular@"~14.0.0-rc.0" from the root project
|
|
523
|
+
if (this.context.packageManager.name === workspace_schema_1.PackageManager.Npm &&
|
|
524
|
+
this.context.packageManager.version &&
|
|
525
|
+
semver.gte(this.context.packageManager.version, '7.0.0', { includePrerelease: true })) {
|
|
526
|
+
logVerbose('NPM 7+ detected -- enabling force option for package installation');
|
|
527
|
+
forceInstall = true;
|
|
528
|
+
}
|
|
529
|
+
const installationSuccess = await this.context.packageManager.installAll(forceInstall ? ['--force'] : [], this.context.root);
|
|
517
530
|
if (!installationSuccess) {
|
|
518
531
|
return 1;
|
|
519
532
|
}
|
|
@@ -584,8 +597,9 @@ class UpdateCommandModule extends command_module_1.CommandModule {
|
|
|
584
597
|
}
|
|
585
598
|
}
|
|
586
599
|
const result = await this.executeMigrations(workflow, migration.package, migrations, migration.from, migration.to, options.createCommits);
|
|
587
|
-
|
|
588
|
-
|
|
600
|
+
// A non-zero value is a failure for the package's migrations
|
|
601
|
+
if (result !== 0) {
|
|
602
|
+
return result;
|
|
589
603
|
}
|
|
590
604
|
}
|
|
591
605
|
}
|
|
@@ -20,3 +20,11 @@ export declare function considerSettingUpAutocompletion(command: string, logger:
|
|
|
20
20
|
* @return The full path of the configuration file modified.
|
|
21
21
|
*/
|
|
22
22
|
export declare function initializeAutocomplete(): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Returns whether the user has a global CLI install or `undefined` if this can't be determined.
|
|
25
|
+
* Execution from `npx` is *not* considered a global CLI install.
|
|
26
|
+
*
|
|
27
|
+
* This does *not* mean the current execution is from a global CLI install, only that a global
|
|
28
|
+
* install exists on the system.
|
|
29
|
+
*/
|
|
30
|
+
export declare function hasGlobalCliInstall(): Promise<boolean | undefined>;
|
|
@@ -30,8 +30,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
30
30
|
return result;
|
|
31
31
|
};
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
-
exports.initializeAutocomplete = exports.considerSettingUpAutocompletion = void 0;
|
|
33
|
+
exports.hasGlobalCliInstall = exports.initializeAutocomplete = exports.considerSettingUpAutocompletion = void 0;
|
|
34
34
|
const core_1 = require("@angular-devkit/core");
|
|
35
|
+
const child_process_1 = require("child_process");
|
|
35
36
|
const fs_1 = require("fs");
|
|
36
37
|
const path = __importStar(require("path"));
|
|
37
38
|
const process_1 = require("process");
|
|
@@ -80,6 +81,13 @@ Appended \`source <(ng completion script)\` to \`${rcFile}\`. Restart your termi
|
|
|
80
81
|
|
|
81
82
|
${color_1.colors.yellow(`source <(ng completion script)`)}
|
|
82
83
|
`.trim());
|
|
84
|
+
if ((await hasGlobalCliInstall()) === false) {
|
|
85
|
+
logger.warn('Setup completed successfully, but there does not seem to be a global install of the' +
|
|
86
|
+
' Angular CLI. For autocompletion to work, the CLI will need to be on your `$PATH`, which' +
|
|
87
|
+
' is typically done with the `-g` flag in `npm install -g @angular/cli`.' +
|
|
88
|
+
'\n\n' +
|
|
89
|
+
'For more information, see https://angular.io/cli/completion#global-install');
|
|
90
|
+
}
|
|
83
91
|
// Save configuration to remember that the user was prompted.
|
|
84
92
|
await setCompletionConfig({ ...completionConfig, prompted: true });
|
|
85
93
|
return undefined;
|
|
@@ -136,6 +144,11 @@ async function shouldPromptForAutocompletionSetup(command, config) {
|
|
|
136
144
|
if (!rcFiles) {
|
|
137
145
|
return false; // Unknown shell.
|
|
138
146
|
}
|
|
147
|
+
// Don't prompt if the user is missing a global CLI install. Autocompletion won't work after setup
|
|
148
|
+
// anyway and could be annoying for users running one-off commands via `npx` or using `npm start`.
|
|
149
|
+
if ((await hasGlobalCliInstall()) === false) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
139
152
|
// Check each RC file if they already use `ng completion script` in any capacity and don't prompt.
|
|
140
153
|
for (const rcFile of rcFiles) {
|
|
141
154
|
const contents = await fs_1.promises.readFile(rcFile, 'utf-8').catch(() => undefined);
|
|
@@ -217,3 +230,53 @@ function getShellRunCommandCandidates(shell, home) {
|
|
|
217
230
|
return undefined;
|
|
218
231
|
}
|
|
219
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* Returns whether the user has a global CLI install or `undefined` if this can't be determined.
|
|
235
|
+
* Execution from `npx` is *not* considered a global CLI install.
|
|
236
|
+
*
|
|
237
|
+
* This does *not* mean the current execution is from a global CLI install, only that a global
|
|
238
|
+
* install exists on the system.
|
|
239
|
+
*/
|
|
240
|
+
async function hasGlobalCliInstall() {
|
|
241
|
+
var _a;
|
|
242
|
+
// List all binaries with the `ng` name on the user's `$PATH`.
|
|
243
|
+
const proc = (0, child_process_1.execFile)('which', ['-a', 'ng']);
|
|
244
|
+
let stdout = '';
|
|
245
|
+
(_a = proc.stdout) === null || _a === void 0 ? void 0 : _a.addListener('data', (content) => {
|
|
246
|
+
stdout += content;
|
|
247
|
+
});
|
|
248
|
+
const exitCode = await new Promise((resolve) => {
|
|
249
|
+
proc.addListener('exit', (exitCode) => {
|
|
250
|
+
resolve(exitCode);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
switch (exitCode) {
|
|
254
|
+
case 0:
|
|
255
|
+
// Successfully listed all `ng` binaries on the `$PATH`. Look for at least one line which is a
|
|
256
|
+
// global install. We can't easily identify global installs, but local installs are typically
|
|
257
|
+
// placed in `node_modules/.bin` by NPM / Yarn. `npx` also currently caches files at
|
|
258
|
+
// `~/.npm/_npx/*/node_modules/.bin/`, so the same logic applies.
|
|
259
|
+
const lines = stdout.split('\n').filter((line) => line !== '');
|
|
260
|
+
const hasGlobalInstall = lines.some((line) => {
|
|
261
|
+
// A binary is a local install if it is a direct child of a `node_modules/.bin/` directory.
|
|
262
|
+
const parent = path.parse(path.parse(line).dir);
|
|
263
|
+
const grandparent = path.parse(parent.dir);
|
|
264
|
+
const localInstall = grandparent.base === 'node_modules' && parent.base === '.bin';
|
|
265
|
+
return !localInstall;
|
|
266
|
+
});
|
|
267
|
+
return hasGlobalInstall;
|
|
268
|
+
case 1:
|
|
269
|
+
// No instances of `ng` on the user's `$PATH`.
|
|
270
|
+
return false;
|
|
271
|
+
case null:
|
|
272
|
+
// `which` was killed by a signal and did not exit gracefully. Maybe it hung or something else
|
|
273
|
+
// went very wrong, so treat this as inconclusive.
|
|
274
|
+
return undefined;
|
|
275
|
+
default:
|
|
276
|
+
// `which` returns exit code 2 if an invalid option is specified and `-a` doesn't appear to be
|
|
277
|
+
// supported on all systems. Other exit codes mean unknown errors occurred. Can't tell whether
|
|
278
|
+
// CLI is globally installed, so treat this as inconclusive.
|
|
279
|
+
return undefined;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
exports.hasGlobalCliInstall = hasGlobalCliInstall;
|
|
@@ -61,24 +61,20 @@ class PackageManagerUtils {
|
|
|
61
61
|
/** Install a single package. */
|
|
62
62
|
async install(packageName, save = true, extraArgs = [], cwd) {
|
|
63
63
|
const packageManagerArgs = this.getArguments();
|
|
64
|
-
const installArgs = [
|
|
65
|
-
packageManagerArgs.install,
|
|
66
|
-
packageName,
|
|
67
|
-
packageManagerArgs.silent,
|
|
68
|
-
];
|
|
64
|
+
const installArgs = [packageManagerArgs.install, packageName];
|
|
69
65
|
if (save === 'devDependencies') {
|
|
70
66
|
installArgs.push(packageManagerArgs.saveDev);
|
|
71
67
|
}
|
|
72
|
-
return this.run([...installArgs, ...extraArgs], cwd);
|
|
68
|
+
return this.run([...installArgs, ...extraArgs], { cwd, silent: true });
|
|
73
69
|
}
|
|
74
70
|
/** Install all packages. */
|
|
75
71
|
async installAll(extraArgs = [], cwd) {
|
|
76
72
|
const packageManagerArgs = this.getArguments();
|
|
77
|
-
const installArgs = [
|
|
73
|
+
const installArgs = [];
|
|
78
74
|
if (packageManagerArgs.installAll) {
|
|
79
75
|
installArgs.push(packageManagerArgs.installAll);
|
|
80
76
|
}
|
|
81
|
-
return this.run([...installArgs, ...extraArgs], cwd);
|
|
77
|
+
return this.run([...installArgs, ...extraArgs], { cwd, silent: true });
|
|
82
78
|
}
|
|
83
79
|
/** Install a single package temporary. */
|
|
84
80
|
async installTemp(packageName, extraArgs) {
|
|
@@ -123,7 +119,6 @@ class PackageManagerUtils {
|
|
|
123
119
|
switch (this.name) {
|
|
124
120
|
case workspace_schema_1.PackageManager.Yarn:
|
|
125
121
|
return {
|
|
126
|
-
silent: '--silent',
|
|
127
122
|
saveDev: '--dev',
|
|
128
123
|
install: 'add',
|
|
129
124
|
prefix: '--modules-folder',
|
|
@@ -131,7 +126,6 @@ class PackageManagerUtils {
|
|
|
131
126
|
};
|
|
132
127
|
case workspace_schema_1.PackageManager.Pnpm:
|
|
133
128
|
return {
|
|
134
|
-
silent: '--silent',
|
|
135
129
|
saveDev: '--save-dev',
|
|
136
130
|
install: 'add',
|
|
137
131
|
installAll: 'install',
|
|
@@ -140,7 +134,6 @@ class PackageManagerUtils {
|
|
|
140
134
|
};
|
|
141
135
|
default:
|
|
142
136
|
return {
|
|
143
|
-
silent: '--quiet',
|
|
144
137
|
saveDev: '--save-dev',
|
|
145
138
|
install: 'install',
|
|
146
139
|
installAll: 'install',
|
|
@@ -149,14 +142,16 @@ class PackageManagerUtils {
|
|
|
149
142
|
};
|
|
150
143
|
}
|
|
151
144
|
}
|
|
152
|
-
async run(args,
|
|
145
|
+
async run(args, options = {}) {
|
|
146
|
+
const { cwd = process.cwd(), silent = false } = options;
|
|
153
147
|
const spinner = new spinner_1.Spinner();
|
|
154
148
|
spinner.start('Installing packages...');
|
|
155
149
|
return new Promise((resolve) => {
|
|
156
150
|
var _a, _b;
|
|
157
151
|
const bufferedOutput = [];
|
|
158
152
|
const childProcess = (0, child_process_1.spawn)(this.name, args, {
|
|
159
|
-
|
|
153
|
+
// Always pipe stderr to allow for failures to be reported
|
|
154
|
+
stdio: silent ? ['ignore', 'ignore', 'pipe'] : 'pipe',
|
|
160
155
|
shell: true,
|
|
161
156
|
cwd,
|
|
162
157
|
}).on('close', (code) => {
|