1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | 'use strict';
|
16 |
|
17 | const yargs = require('yargs');
|
18 | const camelcase = require('camelcase');
|
19 |
|
20 | const MIN_MSG = 'You need at least one command.';
|
21 |
|
22 |
|
23 | if (process.env.NODE_OPTIONS) {
|
24 | process.env.NODE_OPTIONS = process.env.NODE_OPTIONS
|
25 | .split(' ')
|
26 | .filter((opt) => opt.indexOf('--inspect') === -1)
|
27 | .join(' ');
|
28 | }
|
29 |
|
30 | function envAwareStrict(args, aliases) {
|
31 | const specialKeys = ['$0', '--', '_'];
|
32 | const illegalEnv = ['saveConfig', 'add'];
|
33 |
|
34 | const hlxEnv = {};
|
35 | Object
|
36 | .keys(process.env)
|
37 | .filter((key) => key.startsWith('HLX_'))
|
38 | .forEach((key) => {
|
39 | hlxEnv[camelcase(key.substring(4))] = key;
|
40 | });
|
41 |
|
42 | illegalEnv.forEach((key) => {
|
43 | if (key in hlxEnv) {
|
44 | throw new Error(`${hlxEnv[key]} is not allowed in environment.`);
|
45 | }
|
46 | });
|
47 |
|
48 | const unknown = [];
|
49 | Object.keys(args).forEach((key) => {
|
50 | if (specialKeys.indexOf(key) === -1 && !(key in hlxEnv) && !(key in aliases)) {
|
51 | unknown.push(key);
|
52 | }
|
53 | });
|
54 |
|
55 | if (unknown.length > 0) {
|
56 | return unknown.length === 1 ? `Unknown argument: ${unknown[0]}` : `Unknown arguments: ${unknown.join(', ')}`;
|
57 | }
|
58 | return true;
|
59 | }
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 | function logArgs(argv) {
|
67 | return argv
|
68 | .option('log-file', {
|
69 | alias: 'logFile',
|
70 | describe: 'Log file (use "-" for stdout)',
|
71 | type: 'string',
|
72 | array: true,
|
73 | default: '-',
|
74 | })
|
75 | .option('log-level', {
|
76 | alias: 'logLevel',
|
77 | describe: 'Log level',
|
78 | type: 'string',
|
79 | choices: ['silly', 'debug', 'verbose', 'info', 'warn', 'error'],
|
80 | default: 'info',
|
81 | });
|
82 | }
|
83 |
|
84 | class CLI {
|
85 | constructor() {
|
86 | this._commands = {
|
87 | demo: require('./demo.js')(),
|
88 | up: require('./up.js')(),
|
89 | build: require('./build.js')(),
|
90 | package: require('./package.js')(),
|
91 | deploy: require('./deploy.js')(),
|
92 | perf: require('./perf.js')(),
|
93 | publish: require('./publish.js')(),
|
94 | clean: require('./clean.js')(),
|
95 | auth: require('./auth.js')(),
|
96 | hack: require('./hack.js')(),
|
97 | };
|
98 | this._failFn = (message, err, argv) => {
|
99 | const msg = err && err.message ? err.message : message;
|
100 | if (msg) {
|
101 | console.error(msg);
|
102 | }
|
103 | if (msg === MIN_MSG || /.*Unknown argument.*/.test(msg) || /.*Not enough non-option arguments:.*/.test(msg)) {
|
104 | console.error('\n%s', argv.help());
|
105 | }
|
106 | process.exit(1);
|
107 | };
|
108 | }
|
109 |
|
110 | withCommandExecutor(name, exec) {
|
111 | this._commands[name].executor = exec;
|
112 | return this;
|
113 | }
|
114 |
|
115 | onFail(fn) {
|
116 | this._failFn = fn;
|
117 | return this;
|
118 | }
|
119 |
|
120 | run(args) {
|
121 | const argv = yargs();
|
122 | Object.values(this._commands).forEach((cmd) => argv.command(cmd));
|
123 |
|
124 | const ret = logArgs(argv)
|
125 | .scriptName('hlx')
|
126 | .usage('Usage: $0 <command> [options]')
|
127 | .parserConfiguration({ 'camel-case-expansion': false })
|
128 | .env('HLX')
|
129 | .check(envAwareStrict)
|
130 | .showHelpOnFail(true)
|
131 | .fail(this._failFn)
|
132 | .exitProcess(args.indexOf('--get-yargs-completions') > -1)
|
133 | .demandCommand(1, MIN_MSG)
|
134 | .epilogue('for more information, find our manual at https://github.com/adobe/helix-cli')
|
135 | .help()
|
136 | .completion()
|
137 | .parse(args);
|
138 |
|
139 |
|
140 | const cmd = ret._[0];
|
141 | if (cmd && !(cmd in this._commands)) {
|
142 | console.error('Unknown command: %s\n', cmd);
|
143 | argv.showHelp();
|
144 | process.exit(1);
|
145 | }
|
146 | }
|
147 | }
|
148 |
|
149 | module.exports = CLI;
|