forked from blackbaud/skyux-sdk-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
231 lines (188 loc) · 5.88 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
const fs = require('fs');
const path = require('path');
const glob = require('glob');
const logger = require('@blackbaud/skyux-logger');
const generator = require('./lib/utils/certs/generator');
/**
* Returns results of glob.sync from specified directory and our glob pattern.
* @returns {Array} Array of matching patterns
*/
function getGlobs() {
// Look globally and locally for matching glob pattern
const dirs = [
`${process.cwd()}/node_modules/`, // local (where they ran the command from)
`${__dirname}/..`, // global, if scoped package (where this code exists)
`${__dirname}/../..`, // global, if not scoped package
];
let globs = [];
dirs.forEach(dir => {
const legacyPattern = path.join(dir, '*/skyux-builder*/package.json');
const newPattern = path.join(dir, '@skyux-sdk/builder*/package.json');
logger.verbose(`Looking for modules in ${legacyPattern} and ${newPattern}.`);
globs = globs.concat([
...glob.sync(legacyPattern),
...glob.sync(newPattern)
]);
});
return globs;
}
/**
* Iterates over the given modules.
* @param {string} command
* @param {Object} argv
* @param {Array} globs
* @returns {Array} modulesAnswered
*/
function getModulesAnswered(command, argv, globs) {
let modulesCalled = {};
let modulesAnswered = [];
globs.forEach(pkg => {
const dirName = path.dirname(pkg);
let pkgJson = {};
let module;
try {
module = require(dirName);
pkgJson = require(pkg);
} catch (err) {
logger.verbose(`Error loading ${pkg}.`);
}
if (module && typeof module.runCommand === 'function') {
const pkgName = pkgJson.name || dirName;
if (modulesCalled[pkgName]) {
logger.verbose(`Multiple instances were found. Skipping passing the command to ${pkgName} at ${pkg}.`);
} else {
logger.verbose(`Passing the command to ${pkgName} at ${pkg}.`);
modulesCalled[pkgName] = true;
if (module.runCommand(command, argv)) {
modulesAnswered.push(pkgName);
}
}
}
});
return modulesAnswered;
}
/**
* Log fatal error and exit.
* This method is called even for internal commands.
* In those cases, there isn't actually an error.
* @param {string} command
* @param {boolean} isInternalCommand
*/
function invokeCommandError(command, isInternalCommand) {
if (isInternalCommand) {
return;
}
const cwd = process.cwd();
logger.error(`No modules were found that handle the '${command}' command. Please check your syntax. For more information, use the 'help' command.`);
if (cwd.indexOf('skyux-spa') === -1) {
logger.error(`Are you in a SKY UX SPA directory?`);
} else if (!fs.existsSync('./node_modules')) {
logger.error(`The 'node_modules' folder was not found. Did you run 'npm install'?`);
}
process.exit(1);
}
/**
* search for a command in the modules and invoke it if found. If not found,
* log a fatal error.
* @param {string} command
* @param {Object} argv
* @param {boolean} isInternalCommand
*/
function invokeCommand(command, argv, isInternalCommand) {
const globs = getGlobs();
if (globs.length === 0) {
return invokeCommandError(command, isInternalCommand);
}
const modulesAnswered = getModulesAnswered(command, argv, globs);
const modulesAnsweredLength = modulesAnswered.length;
if (modulesAnsweredLength === 0) {
return invokeCommandError(command, isInternalCommand);
}
const modulesAnsweredPlural = modulesAnsweredLength === 1 ? 'module' : 'modules';
logger.verbose(
`Successfully passed the '${command}' command to ${modulesAnsweredLength} ${modulesAnsweredPlural}:`
);
logger.verbose(modulesAnswered.join(', '));
}
/**
* Determines the correct command based on the argv param.
* @param {Object} argv
*/
function getCommand(argv) {
let command = argv._[0] || 'help';
// Allow shorthand "-v" for version
if (argv.v) {
command = 'version';
}
// Allow shorthand "-h" for help
if (argv.h) {
command = 'help';
}
return command;
}
function validateCert(command, argv) {
switch (command) {
case 'serve':
case 'e2e':
return generator.validate(argv);
case 'build':
if (argv.s || argv.serve) {
return generator.validate(argv);
}
break;
}
return true;
}
/**
* Processes an argv object.
* Reads package.json if it exists.
* @name processArgv
* @param [Object] argv
*/
function processArgv(argv) {
const command = getCommand(argv);
let isInternalCommand = true;
logger.info(`SKY UX is processing the '${command}' command.`);
// Don't validate custom sslCert and sslKey
if (!argv.sslCert && !argv.sslKey) {
argv.sslCert = generator.getCertPath();
argv.sslKey = generator.getKeyPath();
// Validate cert for specific scenarios
if (!validateCert(command, argv)) {
logger.warn(`Unable to validate ${argv.sslCert} and ${argv.sslKey}.`);
logger.warn(`You may proceed, but \`skyux ${command}\` may not function properly.`)
logger.warn('Please install the latest SKY UX CLI and run `skyux certs install`.');
}
}
// Catch skyux install certs when they meant skyux certs install
const [ isInstall, isCerts ] = argv['_'];
if (isInstall === 'install' && isCerts === 'certs') {
logger.error('The `skyux install` command is invalid.');
logger.error('Did you mean to run `skyux certs install` instead?');
return;
}
switch (command) {
case 'version':
require('./lib/version').logVersion(argv);
break;
case 'new':
require('./lib/new')(argv);
break;
case 'help':
require('./lib/help')(argv);
break;
case 'install':
require('./lib/install')(argv);
break;
case 'certs':
require('./lib/certs')(argv);
break;
case 'upgrade':
require('./lib/upgrade')(argv);
break;
default:
isInternalCommand = false;
}
invokeCommand(command, argv, isInternalCommand);
}
module.exports = processArgv;