-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathcli.js
138 lines (120 loc) · 4.08 KB
/
cli.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
"use strict";
// example command script
// - node cli script-name --option1=value1 --option2=value2
const fs = require("fs");
const path = require("path");
const { glob } = require("glob");
const logger = require("./utils/logger");
const commandFile = path.join(__dirname, "./scripts");
const commandFiles = glob.sync([`${commandFile}/**/*.js`]);
process.on("uncaughtException", (error) => {
logger.error(`Uncaught Exception: ${error.message}`);
logger.error(error.stack);
process.exit(1);
});
process.on("unhandledRejection", (reason, promise) => {
logger.error(
`Unhandled Rejection: ${reason instanceof Error ? reason.message : reason}`
);
logger.error(`Promise: ${promise}`);
if (reason instanceof Error) {
logger.error(reason.stack);
}
process.exit(1);
});
/**
* Loads command classes from the specified file paths and returns an object
* mapping command signatures to their respective file paths.
*
* @param {string[]} commandFiles - An array of file paths to the command classes.
* @returns {Object} An object where the keys are command signatures and the values are file paths.
*/
function loadCommands(commandFiles) {
const commands = {};
commandFiles.forEach((filePath) => {
const CommandClass = require(filePath);
const signature = path.basename(filePath, ".js");
commands[signature] = {
signature,
path: filePath,
description: CommandClass.description(),
};
});
return commands;
}
/**
* Logs the available commands to the console.
* It iterates over the keys of the `availableCommands` object and logs each command signature.
*/
function logAvailableCommands() {
logger.success("Available commands:");
const allCommands = Object.values(loadCommands(commandFiles)).map(
(command) => ({
signature: command.signature,
description: command.description,
})
);
logger.table(allCommands);
}
/**
* Parses command-line arguments into a script signature and options object.
*
* @param {string[]} argv - The array of command-line arguments.
* @returns {Object} An object containing the script signature and options.
* @returns {string} return.scriptSignature - The script signature (usually the command to run).
* @returns {Object} return.options - An object containing key-value pairs of options.
*/
function parseArguments(argv) {
const scriptSignature = argv[2];
const args = argv.slice(3);
const options = {};
args.forEach((arg) => {
if (arg.startsWith("--")) {
const [key, value] = arg.slice(2).split("=", 2);
options[key] = value === undefined ? true : value;
}
});
return { scriptSignature, options };
}
/**
* Executes a command script located at the given path with the specified options.
*
* @param {string} commandPath - The path to the command script to execute.
* @param {Object} options - The options to pass to the command script.
* @returns {Promise<void>} - A promise that resolves when the command execution is complete.
*/
async function runCommand(commandPath, options) {
const Command = require(commandPath);
logger.info(`${path.basename(commandFile, '.js')} - ${Command.description()}`);
if (options.help) {
if (Command.help) {
logger.info(Command.help());
} else {
logger.info("No help available for this command");
}
} else {
const commandInstance = new Command();
await commandInstance.handle(options);
}
}
/**
* Parses the command line arguments and extracts the script signature and options.
*
* @param {string[]} process.argv - The array of command line arguments passed to the script.
* @returns {{ scriptSignature: string, options: object }} An object containing the script signature and options.
*/
(async () => {
if (!fs.existsSync("./export")) {
fs.mkdirSync("./export");
}
const availableCommands = loadCommands(commandFiles);
const { scriptSignature, options } = parseArguments(process.argv);
if (scriptSignature) {
const commandDetail = availableCommands[scriptSignature];
if (commandDetail) {
await runCommand(commandDetail.path, options);
}
} else {
logAvailableCommands();
}
})();