frozor-commands
Version:
Easy to use command system for Node.JS!
100 lines (77 loc) • 3.31 kB
JavaScript
const { Command } = require('./Command');
const Collection = require('djs-collection');
class CommandParent extends Command {
/**
* Create a CommandParent instance. This can be used to run sub-commands.
* @param data {object} - Data to instantiate the command and parent with.
* @Param data.children {Array.<Command|CommandParent>} - Command instances to use as subcommands for the parent.
*/
constructor(data) {
if (!data.children || data.children.length === 0) {
throw new Error('Children must be provided to CommandParent');
}
if (!Array.isArray(data.children)) {
throw new TypeError('Expected type Array in data.children');
}
super(data);
let depth = 0;
const children = new Collection();
for (const child of data.children) {
if (!(child instanceof Command)) {
throw new TypeError('Expected type Command in children. Did you forget to instantiate it?');
}
child.parent = this;
for (const name of child.names()) {
children.set(name, child);
}
if (child instanceof CommandParent) {
depth = Math.max(depth, child.depth);
}
}
depth += 1;
this.maxArgs = Number.POSITIVE_INFINITY;
this.depth = depth;
this.children = children;
}
getUsageStatement() {
return `${this.name} [${Array.from(this).map(child => child.name).join('|')}]`;
}
subCommandNotProvided(msg, bot, extra) {
return 'Please provide a sub-command to run.';
}
subCommandFail(subCommand, msg, bot, extra) {
return `Hmm, the sub-command *${subCommand}* doesn't seem to exist.`;
}
/**
* Act on a message's intended action.
* If overriding, use this whenever you want to run a sub-command.
* Don't forget to strip unnecessary args.
* @param action {string} - An action to act upon... this is effectively just a sub-command.
* @param msg {object} - The message to act upon. Requires args property and reply method.
* @param {object} [bot] - The bot to pass.
* @param {object} [extra] - The object to pass.
* @return {Promise} - The children's run result.
*/
act(action, msg, bot, extra) {
if (!this.children.has(action)) {
return msg.reply(this.subCommandFail(action, msg, bot, extra));
}
// Get the child and run it, returning the promise since this is an AsyncFunction
return this.children.get(action).run(msg, bot, extra);
}
async run(msg, bot, extra) {
if (msg.args.length === 0) {
return msg.reply(this.subCommandNotProvided(msg, bot, extra));
}
const subCommand = msg.args[0].toLowerCase();
// Remove the first arg since the next command doesn't care about its own arg.
msg.args = msg.args.slice(1);
return this.act(subCommand, msg, bot, extra);
}
*[Symbol.iterator]() {
for (const command of new Set(this.children.values())) {
yield command;
}
}
}
module.exports = CommandParent;