1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | const core_1 = require("@angular-devkit/core");
|
11 | const debug = require("debug");
|
12 | const fs_1 = require("fs");
|
13 | const path_1 = require("path");
|
14 | const json_schema_1 = require("../utilities/json-schema");
|
15 | const analytics_1 = require("./analytics");
|
16 | const command_1 = require("./command");
|
17 | const parser = require("./parser");
|
18 | const analyticsDebug = debug('ng:analytics:commands');
|
19 |
|
20 | const standardCommands = {
|
21 | 'add': '../commands/add.json',
|
22 | 'analytics': '../commands/analytics.json',
|
23 | 'build': '../commands/build.json',
|
24 | 'deploy': '../commands/deploy.json',
|
25 | 'config': '../commands/config.json',
|
26 | 'doc': '../commands/doc.json',
|
27 | 'e2e': '../commands/e2e.json',
|
28 | 'make-this-awesome': '../commands/easter-egg.json',
|
29 | 'generate': '../commands/generate.json',
|
30 | 'get': '../commands/deprecated.json',
|
31 | 'set': '../commands/deprecated.json',
|
32 | 'help': '../commands/help.json',
|
33 | 'lint': '../commands/lint.json',
|
34 | 'new': '../commands/new.json',
|
35 | 'run': '../commands/run.json',
|
36 | 'serve': '../commands/serve.json',
|
37 | 'test': '../commands/test.json',
|
38 | 'update': '../commands/update.json',
|
39 | 'version': '../commands/version.json',
|
40 | 'xi18n': '../commands/xi18n.json',
|
41 | };
|
42 |
|
43 |
|
44 |
|
45 |
|
46 | async function _createAnalytics(workspace, skipPrompt = false) {
|
47 | let config = await analytics_1.getGlobalAnalytics();
|
48 |
|
49 | if (workspace && config) {
|
50 | const skipAnalytics = skipPrompt ||
|
51 | (process.env['NG_CLI_ANALYTICS'] &&
|
52 | (process.env['NG_CLI_ANALYTICS'].toLowerCase() === 'false' ||
|
53 | process.env['NG_CLI_ANALYTICS'] === '0'));
|
54 |
|
55 |
|
56 |
|
57 | if (!skipAnalytics && !(await analytics_1.hasWorkspaceAnalyticsConfiguration())) {
|
58 | await analytics_1.promptProjectAnalytics();
|
59 | }
|
60 | config = await analytics_1.getWorkspaceAnalytics();
|
61 | }
|
62 | const maybeSharedAnalytics = await analytics_1.getSharedAnalytics();
|
63 | if (config && maybeSharedAnalytics) {
|
64 | return new core_1.analytics.MultiAnalytics([config, maybeSharedAnalytics]);
|
65 | }
|
66 | else if (config) {
|
67 | return config;
|
68 | }
|
69 | else if (maybeSharedAnalytics) {
|
70 | return maybeSharedAnalytics;
|
71 | }
|
72 | else {
|
73 | return new core_1.analytics.NoopAnalytics();
|
74 | }
|
75 | }
|
76 | async function loadCommandDescription(name, path, registry) {
|
77 | const schemaPath = path_1.resolve(__dirname, path);
|
78 | const schemaContent = fs_1.readFileSync(schemaPath, 'utf-8');
|
79 | const schema = core_1.json.parseJson(schemaContent, core_1.JsonParseMode.Loose, { path: schemaPath });
|
80 | if (!core_1.isJsonObject(schema)) {
|
81 | throw new Error('Invalid command JSON loaded from ' + JSON.stringify(schemaPath));
|
82 | }
|
83 | return json_schema_1.parseJsonSchemaToCommandDescription(name, schemaPath, registry, schema);
|
84 | }
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 | async function runCommand(args, logger, workspace, commands = standardCommands, options = {}) {
|
94 |
|
95 | const registry = new core_1.schema.CoreSchemaRegistry([]);
|
96 | registry.registerUriHandler((uri) => {
|
97 | if (uri.startsWith('ng-cli://')) {
|
98 | const content = fs_1.readFileSync(path_1.join(__dirname, '..', uri.substr('ng-cli://'.length)), 'utf-8');
|
99 | return Promise.resolve(JSON.parse(content));
|
100 | }
|
101 | else {
|
102 | return null;
|
103 | }
|
104 | });
|
105 | let commandName = undefined;
|
106 | for (let i = 0; i < args.length; i++) {
|
107 | const arg = args[i];
|
108 | if (!arg.startsWith('-')) {
|
109 | commandName = arg;
|
110 | args.splice(i, 1);
|
111 | break;
|
112 | }
|
113 | }
|
114 | let description = null;
|
115 |
|
116 | if (!commandName) {
|
117 | if (args.length === 1 && args[0] === '--version') {
|
118 | commandName = 'version';
|
119 | }
|
120 | else {
|
121 | commandName = 'help';
|
122 | }
|
123 | if (!(commandName in commands)) {
|
124 | logger.error(core_1.tags.stripIndent `
|
125 | The "${commandName}" command seems to be disabled.
|
126 | This is an issue with the CLI itself. If you see this comment, please report it and
|
127 | provide your repository.
|
128 | `);
|
129 | return 1;
|
130 | }
|
131 | }
|
132 | if (commandName in commands) {
|
133 | description = await loadCommandDescription(commandName, commands[commandName], registry);
|
134 | }
|
135 | else {
|
136 | const commandNames = Object.keys(commands);
|
137 |
|
138 | if (commandName.length === 1) {
|
139 | commandNames.sort((a, b) => {
|
140 | const aMatch = a[0] === commandName;
|
141 | const bMatch = b[0] === commandName;
|
142 | if (aMatch && !bMatch) {
|
143 | return -1;
|
144 | }
|
145 | else if (!aMatch && bMatch) {
|
146 | return 1;
|
147 | }
|
148 | else {
|
149 | return 0;
|
150 | }
|
151 | });
|
152 | }
|
153 | for (const name of commandNames) {
|
154 | const aliasDesc = await loadCommandDescription(name, commands[name], registry);
|
155 | const aliases = aliasDesc.aliases;
|
156 | if (aliases && aliases.some(alias => alias === commandName)) {
|
157 | commandName = name;
|
158 | description = aliasDesc;
|
159 | break;
|
160 | }
|
161 | }
|
162 | }
|
163 | if (!description) {
|
164 | const commandsDistance = {};
|
165 | const name = commandName;
|
166 | const allCommands = Object.keys(commands).sort((a, b) => {
|
167 | if (!(a in commandsDistance)) {
|
168 | commandsDistance[a] = core_1.strings.levenshtein(a, name);
|
169 | }
|
170 | if (!(b in commandsDistance)) {
|
171 | commandsDistance[b] = core_1.strings.levenshtein(b, name);
|
172 | }
|
173 | return commandsDistance[a] - commandsDistance[b];
|
174 | });
|
175 | logger.error(core_1.tags.stripIndent `
|
176 | The specified command ("${commandName}") is invalid. For a list of available options,
|
177 | run "ng help".
|
178 |
|
179 | Did you mean "${allCommands[0]}"?
|
180 | `);
|
181 | return 1;
|
182 | }
|
183 | try {
|
184 | const parsedOptions = parser.parseArguments(args, description.options, logger);
|
185 | command_1.Command.setCommandMap(async () => {
|
186 | const map = {};
|
187 | for (const [name, path] of Object.entries(commands)) {
|
188 | map[name] = await loadCommandDescription(name, path, registry);
|
189 | }
|
190 | return map;
|
191 | });
|
192 | const analytics = options.analytics ||
|
193 | (await _createAnalytics(!!workspace.configFile, description.name === 'update'));
|
194 | const context = { workspace, analytics };
|
195 | const command = new description.impl(context, description, logger);
|
196 |
|
197 | let analyticsFlushPromise = Promise.resolve();
|
198 | setInterval(() => {
|
199 | analyticsFlushPromise = analyticsFlushPromise.then(() => analytics.flush());
|
200 | }, 1000);
|
201 | const result = await command.validateAndRun(parsedOptions);
|
202 |
|
203 | await analyticsFlushPromise.then(() => analytics.flush());
|
204 | return result;
|
205 | }
|
206 | catch (e) {
|
207 | if (e instanceof parser.ParseArgumentException) {
|
208 | logger.fatal('Cannot parse arguments. See below for the reasons.');
|
209 | logger.fatal(' ' + e.comments.join('\n '));
|
210 | return 1;
|
211 | }
|
212 | else {
|
213 | throw e;
|
214 | }
|
215 | }
|
216 | }
|
217 | exports.runCommand = runCommand;
|