djs-message-commands
Version:
Build easy, safe, and testable message commands for discord.js
264 lines (263 loc) • 9.38 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageCommandBuilder = void 0;
const builders_1 = require("@discordjs/builders");
const _1 = require("./");
class MessageCommandBuilder {
/**
* The name of the command.
*/
name;
/**
* The description of the command.
*/
description;
/**
* Any aliases the command may be executed with.
*/
aliases;
/**
* The options/arguments that can be supplied to this command.
*/
options;
/**
* The role IDs permitted to execute this command.
*/
roleIds;
/**
* The permissions permitted to execute this command.
*/
permissions;
constructor(data) {
this.name = data?.name ?? "No name implemented";
this.description = data?.description ?? "No description implemented";
this.aliases = data?.aliases ?? [];
this.options = data?.options ?? [];
this.roleIds = data?.roleIds ?? [];
this.permissions = data?.permissions ?? [];
}
/**
* Sets the name of the command. Cannot be empty.
* @param name The name of the command.
* @returns The builder instance.
*/
setName(name) {
if (name === "") {
throw new Error("Command name must be at least one character long.");
}
this.name = name;
return this;
}
/**
* Sets the description of the command. Cannot be empty.
* @param description The description of the command.
* @returns The builder instance.
*/
setDescription(description) {
if (description === "") {
throw new Error("Command description must be at least one character long.");
}
this.description = description;
return this;
}
/**
* Sets any aliases you wish to supply for the command.
* @param aliases The aliases of the command.
* @returns The builder instance.
*/
setAliases(aliases) {
if (aliases.length <= 0) {
throw new Error("There must be at least one alias provided in the array.");
}
if (aliases.some(a => a === "")) {
throw new Error("Aliases must be at least one character long.");
}
this.aliases = aliases;
return this;
}
/**
* Sets the roles allowed to execute this command. If a role doesn't exist in the guild, it will be ignored.
* @param ids The role IDs permitted to execute this command.
* @returns The builder instance.
*/
setRoles(ids) {
if (ids.length <= 0) {
throw new Error("There must be at least one role ID provided in the array.");
}
this.roleIds = ids;
return this;
}
/**
* Sets the permissions allowed to execute this command.
* @param permissions The permissions required to execute this command.
* @returns The builder instance.
*/
setPermissions(permissions) {
if (permissions.length <= 0) {
throw new Error("There must be at least one permission provided in the array.");
}
this.permissions = permissions;
return this;
}
/**
* Adds a choice-able string option to the command.
* @param composer A function that returns an instance of the option.
* @returns The builder instance.
*/
addStringOption(composer) {
const option = composer(new _1.MessageCommandStringOption());
this.options.push(option);
return this;
}
/**
* Adds a choice-able number option to the command.
* @param composer A function that returns an instance of the option.
* @returns The builder instance.
*/
addNumberOption(composer) {
const option = composer(new _1.MessageCommandNumberOption());
this.options.push(option);
return this;
}
/**
* Adds a boolean option to the command.
* @param composer A function that returns an instance of the option.
* @returns The builder instance.
*/
addBooleanOption(composer) {
const option = composer(new _1.MessageCommandBooleanOption());
this.options.push(option);
return this;
}
/**
* Adds a member mentionable option to the command.
* @param composer A function that returns an instance of the option.
* @returns The builder instance.
*/
addMemberOption(composer) {
const option = composer(new _1.MessageCommandMemberOption());
this.options.push(option);
return this;
}
/**
* Adds a channel mentionable option to the command.
* @param composer A function that returns an instance of the option.
* @returns The builder instance.
*/
addChannelOption(composer) {
const option = composer(new _1.MessageCommandChannelOption());
this.options.push(option);
return this;
}
/**
* Adds a role mentionable option to the command.
* @param composer A function that returns an instance of the option.
* @returns The builder instance.
*/
addRoleOption(composer) {
const option = composer(new _1.MessageCommandRoleOption());
this.options.push(option);
return this;
}
/**
* A utility method to convert the command into a regular expression. Useful for debugging.
* @param prefix The guild's message prefix.
* @returns The command's builder converted to RegExp.
*/
toRegex(prefix) {
const aliases = this.aliases.length > 0 ? `|${this.aliases.join("|")}` : "";
let regex = `${prefix}(${this.name}${aliases})`;
for (const option of this.options) {
regex += `\\s+`;
if (option instanceof _1.MessageCommandOptionChoiceable) {
if (option.choices.length <= 0) {
switch (option.type) {
case "text" /* STRING */:
regex += `\"(.+)\"`;
break;
case "number" /* NUMBER */:
regex += `(\\d+)`;
break;
}
}
else {
regex += `\"(${option.choices.map(c => c[1]).join("|")})\"`;
}
continue;
}
switch (option.type) {
case "true/false" /* BOOLEAN */:
regex += `(true|false)`;
break;
case "member" /* MEMBER */:
regex += `<@!?(\\d{17,19})>`;
break;
case "channel" /* CHANNEL */:
regex += `<#(\\d{17,19})>`;
break;
case "role" /* ROLE */:
regex += `<@&(\\d{17,19})>`;
}
}
return new RegExp(`^${regex}$`, "gm");
}
/**
* Validates the message with the command. This checks for permissions, roles, and arguments supplied to the command.
* @param message The message to validate.
* @returns The parsed options and potential errors.
*/
validate(message) {
let errors;
const parsedOptions = [];
const args = message.content.trim().split(/\s+/).slice(1);
for (const perm of this.permissions) {
if (!message.member.permissions.has(perm)) {
if (!errors)
errors = [];
errors.push({
message: `Missing permission: ${perm}`,
type: "MISSING_PERMISSIONS",
});
}
}
for (const id of this.roleIds) {
if (!message.guild.roles.cache.has(id)) {
continue;
}
if (!message.member.roles.cache.has(id)) {
if (!errors)
errors = [];
errors.push({
message: `Missing role: ${(0, builders_1.roleMention)(id)}`,
type: "MISSING_ROLES",
});
}
}
if (args.length === this.options.length) {
for (let i = 0; i < this.options.length; i++) {
const option = this.options[i];
const result = option.validate(args[i]);
if (result === undefined) {
if (!errors)
errors = [];
errors.push({
message: `Invalid option type: ${option.name} in ${this.name}`,
type: "INVALID_ARG_TYPE",
});
continue;
}
parsedOptions.push(result);
}
}
else {
if (!errors)
errors = [];
errors.push({
message: `Missing arguments -> Expected: ${this.options.length}, Got: ${args.length}`,
type: "MISSING_ARGS",
});
}
return [errors, parsedOptions];
}
}
exports.MessageCommandBuilder = MessageCommandBuilder;