@angular/cli 14.0.0-next.7 → 14.0.0-rc.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.
- package/lib/config/schema.json +18 -0
- package/lib/config/workspace-schema.d.ts +12 -0
- package/package.json +17 -17
- package/src/analytics/analytics.d.ts +1 -1
- package/src/analytics/analytics.js +22 -20
- package/src/command-builder/architect-base-command-module.d.ts +9 -2
- package/src/command-builder/architect-base-command-module.js +65 -3
- package/src/command-builder/architect-command-module.d.ts +4 -1
- package/src/command-builder/architect-command-module.js +37 -11
- package/src/command-builder/command-module.d.ts +1 -1
- package/src/command-builder/command-module.js +21 -7
- package/src/command-builder/command-runner.js +41 -30
- package/src/command-builder/schematics-command-module.d.ts +0 -3
- package/src/command-builder/schematics-command-module.js +21 -23
- package/src/command-builder/utilities/command.d.ts +1 -1
- package/src/command-builder/utilities/normalize-options-middleware.d.ts +18 -0
- package/src/command-builder/utilities/normalize-options-middleware.js +59 -0
- package/src/command-builder/utilities/schematic-engine-host.d.ts +2 -2
- package/src/command-builder/utilities/schematic-engine-host.js +33 -18
- package/src/commands/analytics/settings/cli.js +2 -2
- package/src/commands/cache/settings/cli.d.ts +2 -2
- package/src/commands/cache/settings/cli.js +2 -2
- package/src/commands/cache/utilities.d.ts +1 -1
- package/src/commands/cache/utilities.js +7 -8
- package/src/commands/completion/cli.d.ts +16 -0
- package/src/commands/completion/cli.js +61 -0
- package/src/commands/completion/long-description.md +5 -0
- package/src/commands/config/cli.js +15 -14
- package/src/commands/deploy/cli.d.ts +2 -1
- package/src/commands/deploy/cli.js +27 -13
- package/src/commands/e2e/cli.d.ts +2 -1
- package/src/commands/e2e/cli.js +14 -13
- package/src/commands/lint/cli.d.ts +2 -1
- package/src/commands/lint/cli.js +6 -9
- package/src/commands/new/cli.js +7 -2
- package/src/commands/run/cli.d.ts +2 -0
- package/src/commands/run/cli.js +24 -0
- package/src/commands/update/cli.js +3 -2
- package/src/utilities/completion.d.ts +22 -0
- package/src/utilities/completion.js +219 -0
- package/src/utilities/config.d.ts +4 -3
- package/src/utilities/config.js +11 -5
- package/src/utilities/environment-options.d.ts +1 -0
- package/src/utilities/environment-options.js +8 -1
- package/src/utilities/json-file.js +1 -0
- package/src/utilities/memoize.d.ts +15 -0
- package/src/utilities/memoize.js +69 -0
- package/src/utilities/package-manager.js +13 -2
- package/src/utilities/prompt.d.ts +2 -0
- package/src/utilities/prompt.js +18 -1
|
@@ -71,25 +71,23 @@ class ConfigCommandModule extends command_module_1.CommandModule {
|
|
|
71
71
|
return 0;
|
|
72
72
|
}
|
|
73
73
|
async set(options) {
|
|
74
|
-
var _a
|
|
74
|
+
var _a;
|
|
75
75
|
if (!((_a = options.jsonPath) === null || _a === void 0 ? void 0 : _a.trim())) {
|
|
76
76
|
throw new command_module_1.CommandModuleError('Invalid Path.');
|
|
77
77
|
}
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
['cli.cache.environment', undefined],
|
|
88
|
-
['cli.cache.path', undefined],
|
|
78
|
+
const validGlobalCliPaths = new Set([
|
|
79
|
+
'cli.warnings.versionMismatch',
|
|
80
|
+
'cli.defaultCollection',
|
|
81
|
+
'cli.schematicCollections',
|
|
82
|
+
'cli.packageManager',
|
|
83
|
+
'cli.analytics',
|
|
84
|
+
'cli.analyticsSharing.tracking',
|
|
85
|
+
'cli.analyticsSharing.uuid',
|
|
86
|
+
'cli.completion.prompted',
|
|
89
87
|
]);
|
|
90
88
|
if (options.global &&
|
|
91
89
|
!options.jsonPath.startsWith('schematics.') &&
|
|
92
|
-
!
|
|
90
|
+
!validGlobalCliPaths.has(options.jsonPath)) {
|
|
93
91
|
throw new command_module_1.CommandModuleError('Invalid Path.');
|
|
94
92
|
}
|
|
95
93
|
const [config, configPath] = (0, config_1.getWorkspaceRaw)(options.global ? 'global' : 'local');
|
|
@@ -97,7 +95,10 @@ class ConfigCommandModule extends command_module_1.CommandModule {
|
|
|
97
95
|
if (!config || !configPath) {
|
|
98
96
|
throw new command_module_1.CommandModuleError('Confguration file cannot be found.');
|
|
99
97
|
}
|
|
100
|
-
const
|
|
98
|
+
const normalizeUUIDValue = (v) => (v === '' ? (0, uuid_1.v4)() : `${v}`);
|
|
99
|
+
const value = options.jsonPath === 'cli.analyticsSharing.uuid'
|
|
100
|
+
? normalizeUUIDValue(options.value)
|
|
101
|
+
: options.value;
|
|
101
102
|
const modified = config.modify(parseJsonPath(options.jsonPath), normalizeValue(value));
|
|
102
103
|
if (!modified) {
|
|
103
104
|
logger.error('Value cannot be found.');
|
|
@@ -5,10 +5,11 @@
|
|
|
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.io/license
|
|
7
7
|
*/
|
|
8
|
+
import { MissingTargetChoice } from '../../command-builder/architect-base-command-module';
|
|
8
9
|
import { ArchitectCommandModule } from '../../command-builder/architect-command-module';
|
|
9
10
|
import { CommandModuleImplementation } from '../../command-builder/command-module';
|
|
10
11
|
export declare class DeployCommandModule extends ArchitectCommandModule implements CommandModuleImplementation {
|
|
11
|
-
|
|
12
|
+
missingTargetChoices: MissingTargetChoice[];
|
|
12
13
|
multiTarget: boolean;
|
|
13
14
|
command: string;
|
|
14
15
|
longDescriptionPath: string;
|
|
@@ -8,24 +8,38 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.DeployCommandModule = void 0;
|
|
11
|
-
const core_1 = require("@angular-devkit/core");
|
|
12
11
|
const path_1 = require("path");
|
|
13
12
|
const architect_command_module_1 = require("../../command-builder/architect-command-module");
|
|
14
13
|
class DeployCommandModule extends architect_command_module_1.ArchitectCommandModule {
|
|
15
14
|
constructor() {
|
|
16
15
|
super(...arguments);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
16
|
+
// The below choices should be kept in sync with the list in https://angular.io/guide/deployment
|
|
17
|
+
this.missingTargetChoices = [
|
|
18
|
+
{
|
|
19
|
+
name: 'Amazon S3',
|
|
20
|
+
value: '@jefiozie/ngx-aws-deploy',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'Azure',
|
|
24
|
+
value: '@azure/ng-deploy',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Firebase',
|
|
28
|
+
value: '@angular/fire',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'Netlify',
|
|
32
|
+
value: '@netlify-builder/deploy',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'NPM',
|
|
36
|
+
value: 'ngx-deploy-npm',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'GitHub Pages',
|
|
40
|
+
value: 'angular-cli-ghpages',
|
|
41
|
+
},
|
|
42
|
+
];
|
|
29
43
|
this.multiTarget = false;
|
|
30
44
|
this.command = 'deploy [project]';
|
|
31
45
|
this.longDescriptionPath = (0, path_1.join)(__dirname, 'long-description.md');
|
|
@@ -5,11 +5,12 @@
|
|
|
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.io/license
|
|
7
7
|
*/
|
|
8
|
+
import { MissingTargetChoice } from '../../command-builder/architect-base-command-module';
|
|
8
9
|
import { ArchitectCommandModule } from '../../command-builder/architect-command-module';
|
|
9
10
|
import { CommandModuleImplementation } from '../../command-builder/command-module';
|
|
10
11
|
export declare class E2eCommandModule extends ArchitectCommandModule implements CommandModuleImplementation {
|
|
12
|
+
missingTargetChoices: MissingTargetChoice[];
|
|
11
13
|
multiTarget: boolean;
|
|
12
|
-
missingErrorTarget: string;
|
|
13
14
|
command: string;
|
|
14
15
|
aliases: string[];
|
|
15
16
|
describe: string;
|
package/src/commands/e2e/cli.js
CHANGED
|
@@ -8,24 +8,25 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.E2eCommandModule = void 0;
|
|
11
|
-
const core_1 = require("@angular-devkit/core");
|
|
12
11
|
const architect_command_module_1 = require("../../command-builder/architect-command-module");
|
|
13
12
|
class E2eCommandModule extends architect_command_module_1.ArchitectCommandModule {
|
|
14
13
|
constructor() {
|
|
15
14
|
super(...arguments);
|
|
15
|
+
this.missingTargetChoices = [
|
|
16
|
+
{
|
|
17
|
+
name: 'Cypress',
|
|
18
|
+
value: '@cypress/schematic',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'Nightwatch',
|
|
22
|
+
value: '@nightwatch/schematics',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
name: 'WebdriverIO',
|
|
26
|
+
value: '@wdio/schematics',
|
|
27
|
+
},
|
|
28
|
+
];
|
|
16
29
|
this.multiTarget = true;
|
|
17
|
-
this.missingErrorTarget = core_1.tags.stripIndents `
|
|
18
|
-
Cannot find "e2e" target for the specified project.
|
|
19
|
-
|
|
20
|
-
You should add a package that implements end-to-end testing capabilities.
|
|
21
|
-
|
|
22
|
-
For example:
|
|
23
|
-
Cypress: ng add @cypress/schematic
|
|
24
|
-
Nightwatch: ng add @nightwatch/schematics
|
|
25
|
-
WebdriverIO: ng add @wdio/schematics
|
|
26
|
-
|
|
27
|
-
More options will be added to the list as they become available.
|
|
28
|
-
`;
|
|
29
30
|
this.command = 'e2e [project]';
|
|
30
31
|
this.aliases = ['e'];
|
|
31
32
|
this.describe = 'Builds and serves an Angular application, then runs end-to-end tests.';
|
|
@@ -5,10 +5,11 @@
|
|
|
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.io/license
|
|
7
7
|
*/
|
|
8
|
+
import { MissingTargetChoice } from '../../command-builder/architect-base-command-module';
|
|
8
9
|
import { ArchitectCommandModule } from '../../command-builder/architect-command-module';
|
|
9
10
|
import { CommandModuleImplementation } from '../../command-builder/command-module';
|
|
10
11
|
export declare class LintCommandModule extends ArchitectCommandModule implements CommandModuleImplementation {
|
|
11
|
-
|
|
12
|
+
missingTargetChoices: MissingTargetChoice[];
|
|
12
13
|
multiTarget: boolean;
|
|
13
14
|
command: string;
|
|
14
15
|
longDescriptionPath: string;
|
package/src/commands/lint/cli.js
CHANGED
|
@@ -8,20 +8,17 @@
|
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
exports.LintCommandModule = void 0;
|
|
11
|
-
const core_1 = require("@angular-devkit/core");
|
|
12
11
|
const path_1 = require("path");
|
|
13
12
|
const architect_command_module_1 = require("../../command-builder/architect-command-module");
|
|
14
13
|
class LintCommandModule extends architect_command_module_1.ArchitectCommandModule {
|
|
15
14
|
constructor() {
|
|
16
15
|
super(...arguments);
|
|
17
|
-
this.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
ng add @angular-eslint/schematics
|
|
24
|
-
`;
|
|
16
|
+
this.missingTargetChoices = [
|
|
17
|
+
{
|
|
18
|
+
name: 'ESLint',
|
|
19
|
+
value: '@angular-eslint/schematics',
|
|
20
|
+
},
|
|
21
|
+
];
|
|
25
22
|
this.multiTarget = true;
|
|
26
23
|
this.command = 'lint [project]';
|
|
27
24
|
this.longDescriptionPath = (0, path_1.join)(__dirname, 'long-description.md');
|
package/src/commands/new/cli.js
CHANGED
|
@@ -39,9 +39,14 @@ class NewCommandModule extends schematics_command_module_1.SchematicsCommandModu
|
|
|
39
39
|
var _a;
|
|
40
40
|
// Register the version of the CLI in the registry.
|
|
41
41
|
const collectionName = (_a = options.collection) !== null && _a !== void 0 ? _a : (await this.getCollectionFromConfig());
|
|
42
|
-
const workflow = await this.getOrCreateWorkflowForExecution(collectionName, options);
|
|
43
|
-
workflow.registry.addSmartDefaultProvider('ng-cli-version', () => version_1.VERSION.full);
|
|
44
42
|
const { dryRun, force, interactive, defaults, collection, ...schematicOptions } = options;
|
|
43
|
+
const workflow = await this.getOrCreateWorkflowForExecution(collectionName, {
|
|
44
|
+
dryRun,
|
|
45
|
+
force,
|
|
46
|
+
interactive,
|
|
47
|
+
defaults,
|
|
48
|
+
});
|
|
49
|
+
workflow.registry.addSmartDefaultProvider('ng-cli-version', () => version_1.VERSION.full);
|
|
45
50
|
// Compatibility check for NPM 7
|
|
46
51
|
if (collectionName === '@schematics/angular' &&
|
|
47
52
|
!schematicOptions.skipInstall &&
|
|
@@ -20,4 +20,6 @@ export declare class RunCommandModule extends ArchitectBaseCommandModule<RunComm
|
|
|
20
20
|
builder(argv: Argv): Promise<Argv<RunCommandArgs>>;
|
|
21
21
|
run(options: Options<RunCommandArgs> & OtherOptions): Promise<number>;
|
|
22
22
|
protected makeTargetSpecifier(options?: Options<RunCommandArgs>): Target | undefined;
|
|
23
|
+
/** @returns a sorted list of target specifiers to be used for auto completion. */
|
|
24
|
+
private getTargetChoices;
|
|
23
25
|
}
|
package/src/commands/run/cli.js
CHANGED
|
@@ -19,11 +19,15 @@ class RunCommandModule extends architect_base_command_module_1.ArchitectBaseComm
|
|
|
19
19
|
this.longDescriptionPath = (0, path_1.join)(__dirname, 'long-description.md');
|
|
20
20
|
}
|
|
21
21
|
async builder(argv) {
|
|
22
|
+
const { jsonHelp, getYargsCompletions, help } = this.context.args.options;
|
|
22
23
|
const localYargs = argv
|
|
23
24
|
.positional('target', {
|
|
24
25
|
describe: 'The Architect target to run.',
|
|
25
26
|
type: 'string',
|
|
26
27
|
demandOption: true,
|
|
28
|
+
// Show only in when using --help and auto completion because otherwise comma seperated configuration values will be invalid.
|
|
29
|
+
// Also, hide choices from JSON help so that we don't display them in AIO.
|
|
30
|
+
choices: (getYargsCompletions || help) && !jsonHelp ? this.getTargetChoices() : undefined,
|
|
27
31
|
})
|
|
28
32
|
.strict();
|
|
29
33
|
const target = this.makeTargetSpecifier();
|
|
@@ -54,6 +58,26 @@ class RunCommandModule extends architect_base_command_module_1.ArchitectBaseComm
|
|
|
54
58
|
configuration,
|
|
55
59
|
};
|
|
56
60
|
}
|
|
61
|
+
/** @returns a sorted list of target specifiers to be used for auto completion. */
|
|
62
|
+
getTargetChoices() {
|
|
63
|
+
if (!this.context.workspace) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const targets = [];
|
|
67
|
+
for (const [projectName, project] of this.context.workspace.projects) {
|
|
68
|
+
for (const [targetName, target] of project.targets) {
|
|
69
|
+
const currentTarget = `${projectName}:${targetName}`;
|
|
70
|
+
targets.push(currentTarget);
|
|
71
|
+
if (!target.configurations) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
for (const configName of Object.keys(target.configurations)) {
|
|
75
|
+
targets.push(`${currentTarget}:${configName}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return targets.sort();
|
|
80
|
+
}
|
|
57
81
|
}
|
|
58
82
|
exports.RunCommandModule = RunCommandModule;
|
|
59
83
|
RunCommandModule.scope = command_module_1.CommandScope.In;
|
|
@@ -67,7 +67,8 @@ class UpdateCommandModule extends command_module_1.CommandModule {
|
|
|
67
67
|
return localYargs
|
|
68
68
|
.positional('packages', {
|
|
69
69
|
description: 'The names of package(s) to update.',
|
|
70
|
-
|
|
70
|
+
type: 'string',
|
|
71
|
+
array: true,
|
|
71
72
|
})
|
|
72
73
|
.option('force', {
|
|
73
74
|
description: 'Ignore peer dependency version mismatches. ' +
|
|
@@ -656,7 +657,7 @@ class UpdateCommandModule extends command_module_1.CommandModule {
|
|
|
656
657
|
* @returns the version to install or null when there is no update to install.
|
|
657
658
|
*/
|
|
658
659
|
async checkCLIVersion(packagesToUpdate, verbose = false, next = false) {
|
|
659
|
-
const { version } = await (0, package_metadata_1.fetchPackageManifest)(`@angular/cli@${this.getCLIUpdateRunnerVersion(
|
|
660
|
+
const { version } = await (0, package_metadata_1.fetchPackageManifest)(`@angular/cli@${this.getCLIUpdateRunnerVersion(packagesToUpdate, next)}`, this.context.logger, {
|
|
660
661
|
verbose,
|
|
661
662
|
usingYarn: this.context.packageManager.name === workspace_schema_1.PackageManager.Yarn,
|
|
662
663
|
});
|
|
@@ -0,0 +1,22 @@
|
|
|
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.io/license
|
|
7
|
+
*/
|
|
8
|
+
import { logging } from '@angular-devkit/core';
|
|
9
|
+
/**
|
|
10
|
+
* Checks if it is appropriate to prompt the user to setup autocompletion. If not, does nothing. If
|
|
11
|
+
* so prompts and sets up autocompletion for the user. Returns an exit code if the program should
|
|
12
|
+
* terminate, otherwise returns `undefined`.
|
|
13
|
+
* @returns an exit code if the program should terminate, undefined otherwise.
|
|
14
|
+
*/
|
|
15
|
+
export declare function considerSettingUpAutocompletion(command: string, logger: logging.Logger): Promise<number | undefined>;
|
|
16
|
+
/**
|
|
17
|
+
* Sets up autocompletion for the user's terminal. This attempts to find the configuration file for
|
|
18
|
+
* the current shell (`.bashrc`, `.zshrc`, etc.) and append a command which enables autocompletion
|
|
19
|
+
* for the Angular CLI. Supports only Bash and Zsh. Returns whether or not it was successful.
|
|
20
|
+
* @return The full path of the configuration file modified.
|
|
21
|
+
*/
|
|
22
|
+
export declare function initializeAutocomplete(): Promise<string>;
|
|
@@ -0,0 +1,219 @@
|
|
|
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.io/license
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.initializeAutocomplete = exports.considerSettingUpAutocompletion = void 0;
|
|
34
|
+
const core_1 = require("@angular-devkit/core");
|
|
35
|
+
const fs_1 = require("fs");
|
|
36
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const process_1 = require("process");
|
|
38
|
+
const color_1 = require("../utilities/color");
|
|
39
|
+
const config_1 = require("../utilities/config");
|
|
40
|
+
const environment_options_1 = require("../utilities/environment-options");
|
|
41
|
+
const tty_1 = require("../utilities/tty");
|
|
42
|
+
/**
|
|
43
|
+
* Checks if it is appropriate to prompt the user to setup autocompletion. If not, does nothing. If
|
|
44
|
+
* so prompts and sets up autocompletion for the user. Returns an exit code if the program should
|
|
45
|
+
* terminate, otherwise returns `undefined`.
|
|
46
|
+
* @returns an exit code if the program should terminate, undefined otherwise.
|
|
47
|
+
*/
|
|
48
|
+
async function considerSettingUpAutocompletion(command, logger) {
|
|
49
|
+
// Check if we should prompt the user to setup autocompletion.
|
|
50
|
+
const completionConfig = await getCompletionConfig();
|
|
51
|
+
if (!(await shouldPromptForAutocompletionSetup(command, completionConfig))) {
|
|
52
|
+
return undefined; // Already set up or prompted previously, nothing to do.
|
|
53
|
+
}
|
|
54
|
+
// Prompt the user and record their response.
|
|
55
|
+
const shouldSetupAutocompletion = await promptForAutocompletion();
|
|
56
|
+
if (!shouldSetupAutocompletion) {
|
|
57
|
+
// User rejected the prompt and doesn't want autocompletion.
|
|
58
|
+
logger.info(`
|
|
59
|
+
Ok, you won't be prompted again. Should you change your mind, the following command will set up autocompletion for you:
|
|
60
|
+
|
|
61
|
+
${color_1.colors.yellow(`ng completion`)}
|
|
62
|
+
`.trim());
|
|
63
|
+
// Save configuration to remember that the user was prompted and avoid prompting again.
|
|
64
|
+
await setCompletionConfig({ ...completionConfig, prompted: true });
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
// User accepted the prompt, set up autocompletion.
|
|
68
|
+
let rcFile;
|
|
69
|
+
try {
|
|
70
|
+
rcFile = await initializeAutocomplete();
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
// Failed to set up autocompeletion, log the error and abort.
|
|
74
|
+
logger.error(err.message);
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
// Notify the user autocompletion was set up successfully.
|
|
78
|
+
logger.info(`
|
|
79
|
+
Appended \`source <(ng completion script)\` to \`${rcFile}\`. Restart your terminal or run the following to autocomplete \`ng\` commands:
|
|
80
|
+
|
|
81
|
+
${color_1.colors.yellow(`source <(ng completion script)`)}
|
|
82
|
+
`.trim());
|
|
83
|
+
// Save configuration to remember that the user was prompted.
|
|
84
|
+
await setCompletionConfig({ ...completionConfig, prompted: true });
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
exports.considerSettingUpAutocompletion = considerSettingUpAutocompletion;
|
|
88
|
+
async function getCompletionConfig() {
|
|
89
|
+
var _a;
|
|
90
|
+
const wksp = await (0, config_1.getWorkspace)('global');
|
|
91
|
+
return (_a = wksp === null || wksp === void 0 ? void 0 : wksp.getCli()) === null || _a === void 0 ? void 0 : _a['completion'];
|
|
92
|
+
}
|
|
93
|
+
async function setCompletionConfig(config) {
|
|
94
|
+
var _a;
|
|
95
|
+
var _b;
|
|
96
|
+
const wksp = await (0, config_1.getWorkspace)('global');
|
|
97
|
+
if (!wksp) {
|
|
98
|
+
throw new Error(`Could not find global workspace`);
|
|
99
|
+
}
|
|
100
|
+
(_a = (_b = wksp.extensions)['cli']) !== null && _a !== void 0 ? _a : (_b['cli'] = {});
|
|
101
|
+
const cli = wksp.extensions['cli'];
|
|
102
|
+
if (!core_1.json.isJsonObject(cli)) {
|
|
103
|
+
throw new Error(`Invalid config found at ${wksp.filePath}. \`extensions.cli\` should be an object.`);
|
|
104
|
+
}
|
|
105
|
+
cli.completion = config;
|
|
106
|
+
await wksp.save();
|
|
107
|
+
}
|
|
108
|
+
async function shouldPromptForAutocompletionSetup(command, config) {
|
|
109
|
+
// Force whether or not to prompt for autocomplete to give an easy path for e2e testing to skip.
|
|
110
|
+
if (environment_options_1.forceAutocomplete !== undefined) {
|
|
111
|
+
return environment_options_1.forceAutocomplete;
|
|
112
|
+
}
|
|
113
|
+
// Don't prompt on `ng update` or `ng completion`.
|
|
114
|
+
if (command === 'update' || command === 'completion') {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
// Non-interactive and continuous integration systems don't care about autocompletion.
|
|
118
|
+
if (!(0, tty_1.isTTY)()) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
// Skip prompt if the user has already been prompted.
|
|
122
|
+
if (config === null || config === void 0 ? void 0 : config.prompted) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
// `$HOME` variable is necessary to find RC files to modify.
|
|
126
|
+
const home = process_1.env['HOME'];
|
|
127
|
+
if (!home) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
// Get possible RC files for the current shell.
|
|
131
|
+
const shell = process_1.env['SHELL'];
|
|
132
|
+
if (!shell) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
const rcFiles = getShellRunCommandCandidates(shell, home);
|
|
136
|
+
if (!rcFiles) {
|
|
137
|
+
return false; // Unknown shell.
|
|
138
|
+
}
|
|
139
|
+
// Check each RC file if they already use `ng completion script` in any capacity and don't prompt.
|
|
140
|
+
for (const rcFile of rcFiles) {
|
|
141
|
+
const contents = await fs_1.promises.readFile(rcFile, 'utf-8').catch(() => undefined);
|
|
142
|
+
if (contents === null || contents === void 0 ? void 0 : contents.includes('ng completion script')) {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
async function promptForAutocompletion() {
|
|
149
|
+
// Dynamically load `inquirer` so users don't have to pay the cost of parsing and executing it for
|
|
150
|
+
// the 99% of builds that *don't* prompt for autocompletion.
|
|
151
|
+
const { prompt } = await Promise.resolve().then(() => __importStar(require('inquirer')));
|
|
152
|
+
const { autocomplete } = await prompt([
|
|
153
|
+
{
|
|
154
|
+
name: 'autocomplete',
|
|
155
|
+
type: 'confirm',
|
|
156
|
+
message: `
|
|
157
|
+
Would you like to enable autocompletion? This will set up your terminal so pressing TAB while typing
|
|
158
|
+
Angular CLI commands will show possible options and autocomplete arguments. (Enabling autocompletion
|
|
159
|
+
will modify configuration files in your home directory.)
|
|
160
|
+
`
|
|
161
|
+
.split('\n')
|
|
162
|
+
.join(' ')
|
|
163
|
+
.trim(),
|
|
164
|
+
default: true,
|
|
165
|
+
},
|
|
166
|
+
]);
|
|
167
|
+
return autocomplete;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Sets up autocompletion for the user's terminal. This attempts to find the configuration file for
|
|
171
|
+
* the current shell (`.bashrc`, `.zshrc`, etc.) and append a command which enables autocompletion
|
|
172
|
+
* for the Angular CLI. Supports only Bash and Zsh. Returns whether or not it was successful.
|
|
173
|
+
* @return The full path of the configuration file modified.
|
|
174
|
+
*/
|
|
175
|
+
async function initializeAutocomplete() {
|
|
176
|
+
var _a, _b;
|
|
177
|
+
// Get the currently active `$SHELL` and `$HOME` environment variables.
|
|
178
|
+
const shell = process_1.env['SHELL'];
|
|
179
|
+
if (!shell) {
|
|
180
|
+
throw new Error('`$SHELL` environment variable not set. Angular CLI autocompletion only supports Bash or' +
|
|
181
|
+
" Zsh. If you're on Windows, Cmd and Powershell don't support command autocompletion," +
|
|
182
|
+
' but Git Bash or Windows Subsystem for Linux should work, so please try again in one of' +
|
|
183
|
+
' those environments.');
|
|
184
|
+
}
|
|
185
|
+
const home = process_1.env['HOME'];
|
|
186
|
+
if (!home) {
|
|
187
|
+
throw new Error('`$HOME` environment variable not set. Setting up autocompletion modifies configuration files' +
|
|
188
|
+
' in the home directory and must be set.');
|
|
189
|
+
}
|
|
190
|
+
// Get all the files we can add `ng completion` to which apply to the user's `$SHELL`.
|
|
191
|
+
const runCommandCandidates = getShellRunCommandCandidates(shell, home);
|
|
192
|
+
if (!runCommandCandidates) {
|
|
193
|
+
throw new Error(`Unknown \`$SHELL\` environment variable value (${shell}). Angular CLI autocompletion only supports Bash or Zsh.`);
|
|
194
|
+
}
|
|
195
|
+
// Get the first file that already exists or fallback to a new file of the first candidate.
|
|
196
|
+
const candidates = await Promise.allSettled(runCommandCandidates.map((rcFile) => fs_1.promises.access(rcFile).then(() => rcFile)));
|
|
197
|
+
const rcFile = (_b = (_a = candidates.find((result) => result.status === 'fulfilled')) === null || _a === void 0 ? void 0 : _a.value) !== null && _b !== void 0 ? _b : runCommandCandidates[0];
|
|
198
|
+
// Append Angular autocompletion setup to RC file.
|
|
199
|
+
try {
|
|
200
|
+
await fs_1.promises.appendFile(rcFile, '\n\n# Load Angular CLI autocompletion.\nsource <(ng completion script)\n');
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
throw new Error(`Failed to append autocompletion setup to \`${rcFile}\`:\n${err.message}`);
|
|
204
|
+
}
|
|
205
|
+
return rcFile;
|
|
206
|
+
}
|
|
207
|
+
exports.initializeAutocomplete = initializeAutocomplete;
|
|
208
|
+
/** Returns an ordered list of possible candidates of RC files used by the given shell. */
|
|
209
|
+
function getShellRunCommandCandidates(shell, home) {
|
|
210
|
+
if (shell.toLowerCase().includes('bash')) {
|
|
211
|
+
return ['.bashrc', '.bash_profile', '.profile'].map((file) => path.join(home, file));
|
|
212
|
+
}
|
|
213
|
+
else if (shell.toLowerCase().includes('zsh')) {
|
|
214
|
+
return ['.zshrc', '.zsh_profile', '.profile'].map((file) => path.join(home, file));
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
return undefined;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -10,14 +10,15 @@ import { PackageManager } from '../../lib/config/workspace-schema';
|
|
|
10
10
|
import { JSONFile } from './json-file';
|
|
11
11
|
export declare const workspaceSchemaPath: string;
|
|
12
12
|
export declare class AngularWorkspace {
|
|
13
|
-
private workspace;
|
|
13
|
+
private readonly workspace;
|
|
14
14
|
readonly filePath: string;
|
|
15
15
|
readonly basePath: string;
|
|
16
16
|
constructor(workspace: workspaces.WorkspaceDefinition, filePath: string);
|
|
17
17
|
get extensions(): Record<string, json.JsonValue | undefined>;
|
|
18
18
|
get projects(): workspaces.ProjectDefinitionCollection;
|
|
19
|
-
getCli(): Record<string, any
|
|
20
|
-
getProjectCli(projectName: string): Record<string, any
|
|
19
|
+
getCli(): Record<string, any> | undefined;
|
|
20
|
+
getProjectCli(projectName: string): Record<string, any> | undefined;
|
|
21
|
+
save(): Promise<void>;
|
|
21
22
|
static load(workspaceFilePath: string): Promise<AngularWorkspace>;
|
|
22
23
|
}
|
|
23
24
|
export declare function getWorkspace(level?: 'local' | 'global'): Promise<AngularWorkspace | undefined>;
|
package/src/utilities/config.js
CHANGED
|
@@ -134,12 +134,15 @@ class AngularWorkspace {
|
|
|
134
134
|
// Temporary helper functions to support refactoring
|
|
135
135
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
136
|
getCli() {
|
|
137
|
-
return this.workspace.extensions['cli']
|
|
137
|
+
return this.workspace.extensions['cli'];
|
|
138
138
|
}
|
|
139
139
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
140
140
|
getProjectCli(projectName) {
|
|
141
141
|
const project = this.workspace.projects.get(projectName);
|
|
142
|
-
return
|
|
142
|
+
return project === null || project === void 0 ? void 0 : project.extensions['cli'];
|
|
143
|
+
}
|
|
144
|
+
save() {
|
|
145
|
+
return core_1.workspaces.writeWorkspace(this.workspace, createWorkspaceHost(), this.filePath);
|
|
143
146
|
}
|
|
144
147
|
static async load(workspaceFilePath) {
|
|
145
148
|
const result = await core_1.workspaces.readWorkspace(workspaceFilePath, createWorkspaceHost(), core_1.workspaces.WorkspaceFormat.JSON);
|
|
@@ -152,10 +155,13 @@ async function getWorkspace(level = 'local') {
|
|
|
152
155
|
if (cachedWorkspaces.has(level)) {
|
|
153
156
|
return cachedWorkspaces.get(level);
|
|
154
157
|
}
|
|
155
|
-
|
|
158
|
+
let configPath = level === 'local' ? projectFilePath() : globalFilePath();
|
|
156
159
|
if (!configPath) {
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
if (level === 'local') {
|
|
161
|
+
cachedWorkspaces.set(level, undefined);
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
configPath = createGlobalSettings();
|
|
159
165
|
}
|
|
160
166
|
try {
|
|
161
167
|
const workspace = await AngularWorkspace.load(configPath);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* found in the LICENSE file at https://angular.io/license
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.ngDebug = exports.disableVersionCheck = exports.isCI = exports.analyticsShareDisabled = exports.analyticsDisabled = void 0;
|
|
10
|
+
exports.forceAutocomplete = exports.ngDebug = exports.disableVersionCheck = exports.isCI = exports.analyticsShareDisabled = exports.analyticsDisabled = void 0;
|
|
11
11
|
function isPresent(variable) {
|
|
12
12
|
return typeof variable === 'string' && variable !== '';
|
|
13
13
|
}
|
|
@@ -17,8 +17,15 @@ function isDisabled(variable) {
|
|
|
17
17
|
function isEnabled(variable) {
|
|
18
18
|
return isPresent(variable) && (variable === '1' || variable.toLowerCase() === 'true');
|
|
19
19
|
}
|
|
20
|
+
function optional(variable) {
|
|
21
|
+
if (!isPresent(variable)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
return isEnabled(variable);
|
|
25
|
+
}
|
|
20
26
|
exports.analyticsDisabled = isDisabled(process.env['NG_CLI_ANALYTICS']);
|
|
21
27
|
exports.analyticsShareDisabled = isDisabled(process.env['NG_CLI_ANALYTICS_SHARE']);
|
|
22
28
|
exports.isCI = isEnabled(process.env['CI']);
|
|
23
29
|
exports.disableVersionCheck = isEnabled(process.env['NG_DISABLE_VERSION_CHECK']);
|
|
24
30
|
exports.ngDebug = isEnabled(process.env['NG_DEBUG']);
|
|
31
|
+
exports.forceAutocomplete = optional(process.env['NG_FORCE_AUTOCOMPLETE']);
|