UNPKG

9.39 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
5 * This code may only be used under the BSD style license found at
6 * http://polymer.github.io/LICENSE.txt
7 * The complete set of authors may be found at
8 * http://polymer.github.io/AUTHORS.txt
9 * The complete set of contributors may be found at
10 * http://polymer.github.io/CONTRIBUTORS.txt
11 * Code distributed by Google as part of the polymer project is also
12 * subject to an additional IP rights grant found at
13 * http://polymer.github.io/PATENTS.txt
14 */
15var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
16 return new (P || (P = Promise))(function (resolve, reject) {
17 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
18 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
19 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
20 step((generator = generator.apply(thisArg, _arguments || [])).next());
21 });
22};
23Object.defineProperty(exports, "__esModule", { value: true });
24// Be mindful of adding imports here, as this is on the hot path of all
25// commands.
26const commandLineArgs = require("command-line-args");
27const path_1 = require("path");
28const logging = require("plylog");
29const polymer_project_config_1 = require("polymer-project-config");
30const args_1 = require("./args");
31const analyze_1 = require("./commands/analyze");
32const build_1 = require("./commands/build");
33const help_1 = require("./commands/help");
34const init_1 = require("./commands/init");
35const install_1 = require("./commands/install");
36const lint_1 = require("./commands/lint");
37const serve_1 = require("./commands/serve");
38const test_1 = require("./commands/test");
39const util_1 = require("./util");
40const commandLineCommands = require("command-line-commands");
41const logger = logging.getLogger('cli.main');
42process.on('uncaughtException', (error) => {
43 logger.error(`Uncaught exception: ${error}`);
44 if (error && error.stack) {
45 logger.error(error.stack);
46 }
47 process.exit(1);
48});
49process.on('unhandledRejection', (error) => {
50 logger.error(`Promise rejection: ${error}`);
51 if (error && error.stack) {
52 logger.error(error.stack);
53 }
54 process.exit(1);
55});
56/**
57 * CLI arguments are in "hyphen-case" format, but our configuration is in
58 * "lowerCamelCase". This helper function converts the special
59 * `command-line-args` data format (with its hyphen-case flags) to an easier to
60 * use options object with lowerCamelCase properties.
61 */
62// tslint:disable-next-line: no-any Super hacky scary code.
63function parseCLIArgs(commandOptions) {
64 commandOptions = commandOptions && commandOptions['_all'];
65 const parsedOptions = Object.assign({}, commandOptions);
66 if (commandOptions['extra-dependencies']) {
67 parsedOptions.extraDependencies = commandOptions['extra-dependencies'];
68 }
69 if (commandOptions.fragment) {
70 parsedOptions.fragments = commandOptions.fragment;
71 }
72 return parsedOptions;
73}
74/**
75 * Shallowly copies an object, converting keys from dash-case to camelCase.
76 */
77function objectDashToCamelCase(input) {
78 const output = {};
79 for (const key of Object.keys(input)) {
80 output[util_1.dashToCamelCase(key)] = input[key];
81 }
82 return output;
83}
84class PolymerCli {
85 constructor(args, configOptions) {
86 this.commands = new Map();
87 // If the "--quiet"/"-q" flag is ever present, set our global logging
88 // to quiet mode. Also set the level on the logger we've already created.
89 if (args.indexOf('--quiet') > -1 || args.indexOf('-q') > -1) {
90 logging.setQuiet();
91 }
92 // If the "--verbose"/"-v" flag is ever present, set our global logging
93 // to verbose mode. Also set the level on the logger we've already created.
94 if (args.indexOf('--verbose') > -1 || args.indexOf('-v') > -1) {
95 logging.setVerbose();
96 }
97 this.args = args;
98 logger.debug('got args:', { args: args });
99 if (typeof configOptions !== 'undefined') {
100 this.defaultConfigOptions = configOptions;
101 logger.debug('got default config from constructor argument:', { config: this.defaultConfigOptions });
102 }
103 else {
104 this.defaultConfigOptions =
105 polymer_project_config_1.ProjectConfig.loadOptionsFromFile('polymer.json');
106 if (this.defaultConfigOptions) {
107 logger.debug('got default config from polymer.json file:', { config: this.defaultConfigOptions });
108 }
109 else {
110 logger.debug('no polymer.json file found, no config loaded');
111 }
112 }
113 // This is a quick fix to make sure that "webcomponentsjs" files are
114 // included in every build, since some are imported dynamically in a way
115 // that our analyzer cannot detect.
116 // TODO(fks) 03-07-2017: Remove/refactor when we have a better plan for
117 // support (either here or inside of polymer-project-config).
118 this.defaultConfigOptions = this.defaultConfigOptions || {};
119 this.defaultConfigOptions.extraDependencies =
120 this.defaultConfigOptions.extraDependencies || [];
121 this.defaultConfigOptions.extraDependencies.unshift(`bower_components${path_1.sep}webcomponentsjs${path_1.sep}*.js`);
122 this.addCommand(new analyze_1.AnalyzeCommand());
123 this.addCommand(new build_1.BuildCommand());
124 this.addCommand(new help_1.HelpCommand(this.commands));
125 this.addCommand(new init_1.InitCommand());
126 this.addCommand(new install_1.InstallCommand());
127 this.addCommand(new lint_1.LintCommand());
128 this.addCommand(new serve_1.ServeCommand());
129 this.addCommand(new test_1.TestCommand());
130 }
131 addCommand(command) {
132 logger.debug('adding command', command.name);
133 this.commands.set(command.name, command);
134 command.aliases.forEach((alias) => {
135 logger.debug('adding alias', alias);
136 this.commands.set(alias, command);
137 });
138 }
139 run() {
140 return __awaiter(this, void 0, void 0, function* () {
141 const helpCommand = this.commands.get('help');
142 const commandNames = Array.from(this.commands.keys());
143 let parsedArgs;
144 logger.debug('running...');
145 // If the "--version" flag is ever present, just print
146 // the current version. Useful for globally installed CLIs.
147 if (this.args.indexOf('--version') > -1) {
148 console.log(require('../package.json').version);
149 return Promise.resolve();
150 }
151 try {
152 parsedArgs = commandLineCommands(commandNames, this.args);
153 }
154 catch (error) {
155 // Polymer CLI needs a valid command name to do anything. If the given
156 // command is invalid, run the generalized help command with default
157 // config. This should print the general usage information.
158 if (error.name === 'INVALID_COMMAND') {
159 if (error.command) {
160 logger.warn(`'${error.command}' is not an available command.`);
161 }
162 return helpCommand.run({ command: error.command }, new polymer_project_config_1.ProjectConfig(this.defaultConfigOptions));
163 }
164 // If an unexpected error occurred, propagate it
165 throw error;
166 }
167 const commandName = parsedArgs.command;
168 const commandArgs = parsedArgs.argv;
169 const command = this.commands.get(commandName);
170 if (command == null) {
171 throw new TypeError('command is null');
172 }
173 logger.debug(`command '${commandName}' found, parsing command args:`, { args: commandArgs });
174 const commandDefinitions = args_1.mergeArguments([command.args, args_1.globalArguments]);
175 const commandOptionsRaw = commandLineArgs(commandDefinitions, { argv: commandArgs });
176 const commandOptions = parseCLIArgs(commandOptionsRaw);
177 logger.debug(`command options parsed from args:`, commandOptions);
178 const mergedConfigOptions = Object.assign({}, this.defaultConfigOptions, objectDashToCamelCase(commandOptions));
179 logger.debug(`final config options:`, mergedConfigOptions);
180 const config = new polymer_project_config_1.ProjectConfig(mergedConfigOptions);
181 logger.debug(`final project configuration generated:`, config);
182 // Help is a special argument for displaying help for the given command.
183 // If found, run the help command instead, with the given command name as
184 // an option.
185 if (commandOptions['help']) {
186 logger.debug(`'--help' option found, running 'help' for given command...`);
187 return helpCommand.run({ command: commandName }, config);
188 }
189 logger.debug('Running command...');
190 return command.run(commandOptions, config);
191 });
192 }
193}
194exports.PolymerCli = PolymerCli;
195//# sourceMappingURL=polymer-cli.js.map
\No newline at end of file