UNPKG

3.83 kBJavaScriptView Raw
1/*eslint no-process-exit: 0 */
2const _ = require('lodash');
3const colors = require('colors/safe');
4const updateNotifier = require('update-notifier');
5
6const {
7 DEBUG,
8 LAMBDA_VERSION,
9 UPDATE_NOTIFICATION_INTERVAL
10} = require('./constants');
11const commands = require('./commands');
12const utils = require('./utils');
13const leven = require('leven');
14
15const commandSuggestion = command => {
16 const availableCommands = Object.keys(commands);
17 // the lower the score, the more identical the words
18 const suggestion = _.sortBy(
19 availableCommands.map(c => {
20 return { command: c, score: leven(command, c) };
21 }),
22 'score'
23 )[0];
24
25 // after some brief testing, ~3 is a reasonable threshold for a typo vs an unrelated word
26 if (suggestion.score <= 3) {
27 return suggestion.command;
28 } else {
29 return null;
30 }
31};
32
33module.exports = argv => {
34 if (!utils.isValidNodeVersion()) {
35 console.error(
36 colors.red(
37 `Requires node version >= ${LAMBDA_VERSION}, found ${
38 process.versions.node
39 }. Please upgrade node.`
40 )
41 );
42 process.exit(1);
43 }
44
45 const pkg = require('../package.json');
46 const notifier = updateNotifier({
47 pkg: pkg,
48 updateCheckInterval: UPDATE_NOTIFICATION_INTERVAL
49 });
50 if (notifier.update && notifier.update.latest !== pkg.version) {
51 notifier.notify({ isGlobal: true });
52 }
53
54 if (DEBUG) {
55 console.log('running in:', process.cwd());
56 console.log('raw argv:', argv);
57 console.log('\n--------------------------------------------------\n\n');
58 }
59
60 argv = argv.slice(2); // strip path, zapier.js
61
62 let [args, argOpts] = utils.argParse(argv);
63 global.argOpts = argOpts;
64
65 // when `zapier invitees --help`, swap to `zapier help invitees`
66 if (argOpts.help || args.length === 0) {
67 args = ['help'].concat(args);
68 }
69
70 const command = args[0];
71 args = args.slice(1);
72
73 // create the context, logs thread through this
74 const context = utils.createContext({ command, args, argOpts });
75
76 if (command === 'help' && (argOpts.version || argOpts.v)) {
77 utils.printVersionInfo(context);
78 return;
79 }
80
81 let commandFunc = commands[command];
82 if (!commandFunc) {
83 let message = [`\`zapier ${command}\` is not a command!`];
84 const suggestion = commandSuggestion(command);
85 if (suggestion) {
86 message.push(`Did you mean \`zapier ${suggestion}\`?`);
87 } else {
88 message.push(
89 'Run `zapier help` to see a full list of available commands.'
90 );
91 }
92
93 context.line(message.join(' '));
94
95 return;
96 }
97
98 const { valid, reason } = utils.isValidAppInstall(command);
99 if (!valid) {
100 console.error(colors.red(reason));
101 process.exit(1);
102 }
103
104 const spec = {
105 argsSpec: commandFunc.argsSpec,
106 argOptsSpec: _.extend({}, utils.globalArgOptsSpec, commandFunc.argOptsSpec)
107 };
108 const errors = utils.enforceArgSpec(spec, args, argOpts);
109 if (errors.length) {
110 context.line();
111 context.line(
112 colors.red(
113 'Errors running command `' + ['zapier'].concat(argv).join(' ') + '`:'
114 )
115 );
116 context.line();
117 errors.forEach(error => context.line(colors.red(`!!! ${error}`)));
118 context.line();
119 context.line(`For more information, run \`zapier help ${command}\`.`);
120 context.line();
121 process.exit(1);
122 }
123
124 commandFunc(context, ...args).catch(err => {
125 utils.endSpinner(false);
126
127 if (DEBUG || global.argOpts.debug) {
128 context.line();
129 context.line(err.stack);
130 context.line();
131 context.line(colors.red('Error!'));
132 } else {
133 context.line();
134 context.line();
135 context.line(colors.red('Error!') + ' ' + colors.red(err.message));
136 context.line(
137 colors.grey(
138 '(Use --debug flag and run this command again to get more details.)'
139 )
140 );
141 }
142 process.exit(1);
143 });
144};