UNPKG

4.2 kBJavaScriptView Raw
1/*
2 * Copyright 2018 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12
13/* eslint-disable global-require, no-console */
14
15'use strict';
16
17const yargs = require('yargs');
18const camelcase = require('camelcase');
19
20const MIN_MSG = 'You need at least one command.';
21
22// fix for #189: strip debug options from NODE_OPTIONS env variable
23if (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
30function 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 * Adds the default logging options.
63 * @param argv Yargs
64 * @returns {Yargs} the args
65 */
66function 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
84class 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 // hack to check if command is valid in non-strict mode
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
149module.exports = CLI;