Archived
Working slash command registration
This commit is contained in:
1 parent
b5e6cf5d00
commit
b1b981e3ac
6 files changed
+111
-58
No files matched your search
+9
-5
@@ -75,7 +75,7 @@ export class Bot extends EventEmitter {
|
||||
* @param {string} [token] - app token from Discord Developer Portal
|
||||
* @returns *Promise<boolean>*
|
||||
*/
|
||||
async start(port?: number): Promise<boolean> {
|
||||
async start(port?: number, register?: boolean): Promise<boolean> {
|
||||
try {
|
||||
console.log(`\nBot name: ${this.name}`);
|
||||
console.log(`Prefix: ${this.commands.prefix} \n`);
|
||||
@@ -102,16 +102,20 @@ export class Bot extends EventEmitter {
|
||||
process.stdout.write("Connecting to Discord... ");
|
||||
this.client.login(this.token);
|
||||
this.client.on("ready", async () => {
|
||||
if (register === undefined || register === true) {
|
||||
console.log("✔");
|
||||
process.stdout.write("Registering commands... ");
|
||||
this.commands.list.map(async (c) => {
|
||||
await axios.post(
|
||||
await axios.put(
|
||||
`https://discord.com/api/v8/applications/${this.applicationId}/commands`,
|
||||
c.toCommandObject(),
|
||||
this.commands.list.map((c) =>
|
||||
!c.guilds ? c.toCommandObject() : {}
|
||||
),
|
||||
{ headers: { Authorization: `Bot ${this.token}` } }
|
||||
);
|
||||
});
|
||||
console.log("✔\n");
|
||||
} else {
|
||||
console.log("✔\n");
|
||||
}
|
||||
this.emit("READY");
|
||||
});
|
||||
this.client.on("message", async (m) => {
|
||||
|
||||
+59
-19
@@ -6,19 +6,19 @@ import {
|
||||
ParameterResolvable,
|
||||
} from "./types.js";
|
||||
import { MissingParameterError, PermissionsError } from "./errors.js";
|
||||
import { Parameter, ProcessArgument } from "./Parameter.js";
|
||||
import { Parameter } from "./Parameter.js";
|
||||
|
||||
//CLASSES
|
||||
export class Command {
|
||||
name: string;
|
||||
parameters: Parameter[];
|
||||
aliases: string[];
|
||||
keywords: string[];
|
||||
parameters?: Parameter[];
|
||||
aliases?: string[];
|
||||
keywords?: string[];
|
||||
description: string;
|
||||
usage: string;
|
||||
usage?: string;
|
||||
permissionCheck: PermissionCheckTypes;
|
||||
permissions: Permissions;
|
||||
guilds: Guild[];
|
||||
permissions?: Permissions;
|
||||
guilds?: Guild[];
|
||||
visible: boolean;
|
||||
private function: (
|
||||
message?: Message,
|
||||
@@ -41,7 +41,9 @@ export class Command {
|
||||
*/
|
||||
constructor(options: CommandBuilder) {
|
||||
this.name = options.name.split(" ").join("_");
|
||||
this.parameters = options.parameters || [];
|
||||
this.parameters = options.parameters
|
||||
? options.parameters.map((p) => new Parameter(p))
|
||||
: undefined;
|
||||
this.aliases = Command.processPhrase(options.aliases);
|
||||
this.keywords = Command.processPhrase(options.keywords);
|
||||
this.description = options.description || "No description";
|
||||
@@ -50,13 +52,18 @@ export class Command {
|
||||
options.permissionCheck == "ALL" || options.permissionCheck == "ANY"
|
||||
? options.permissionCheck
|
||||
: "ANY";
|
||||
this.permissions = new Permissions(options.permissions || undefined);
|
||||
this.guilds = options.guilds || [];
|
||||
this.permissions = options.permissions
|
||||
? new Permissions(options.permissions)
|
||||
: undefined;
|
||||
this.guilds = options.guilds;
|
||||
this.visible = options.visible != undefined ? options.visible : true;
|
||||
this.function = options.function;
|
||||
/*if (!new RegExp("^[w-]{1,32}$").test(this.name)) {
|
||||
if (!/^[\w-]{1,32}$/.test(this.name)) {
|
||||
throw new Error(`Incorrect command name: ${this.name}`);
|
||||
}*/
|
||||
}
|
||||
if (this.description.length > 100) {
|
||||
throw new Error("Command description is too long");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,17 +76,18 @@ export class Command {
|
||||
const memberPermissions: Readonly<Permissions> =
|
||||
message?.member?.permissions || new Permissions();
|
||||
if (
|
||||
this.permissionCheck == "ALL"
|
||||
!this.permissions ||
|
||||
(this.permissionCheck == "ALL"
|
||||
? memberPermissions.has(this.permissions, true)
|
||||
: memberPermissions.any(this.permissions, true)
|
||||
: memberPermissions.any(this.permissions, true))
|
||||
) {
|
||||
let inputArguments: ParameterResolvable[] = cmdParams || [];
|
||||
if (this.parameters.length > 0) {
|
||||
if (this.parameters) {
|
||||
this.parameters.map((a, i) => {
|
||||
if (!inputArguments[i] && !a.optional) {
|
||||
throw new MissingParameterError(a);
|
||||
} else if (inputArguments[i]) {
|
||||
inputArguments[i] = ProcessArgument(
|
||||
inputArguments[i] = Parameter.process(
|
||||
inputArguments[i] as string,
|
||||
a.type
|
||||
);
|
||||
@@ -98,14 +106,45 @@ export class Command {
|
||||
}
|
||||
|
||||
toCommandObject() {
|
||||
let options: any[] = [];
|
||||
if (this.parameters) {
|
||||
options = this.parameters.map((p) => {
|
||||
let type = 3;
|
||||
if (!/^[\w-]{1,32}$/.test(p.name)) {
|
||||
throw new Error(
|
||||
`Failed to register ${p.name} parameter for ${this.name}: The option name is incorrect`
|
||||
);
|
||||
}
|
||||
if ((p.description || "No description").length > 100) {
|
||||
throw new Error(
|
||||
`Failed to register ${p.name} parameter for ${this.name}: The description is too long`
|
||||
);
|
||||
}
|
||||
if (p.type == "boolean") type = 5;
|
||||
else if (p.type == "user") type = 6;
|
||||
else if (p.type == "channel") type = 7;
|
||||
else if (p.type == "role") type = 8;
|
||||
else if (p.type == "mentionable") type = 9;
|
||||
else if (p.type == "number") type = 10;
|
||||
return {
|
||||
name: p.name,
|
||||
description: p.description || "No description",
|
||||
required: !p.optional,
|
||||
type: type,
|
||||
choices: p.choices || [],
|
||||
};
|
||||
});
|
||||
}
|
||||
return {
|
||||
name: this.name,
|
||||
description: this.description,
|
||||
options: [],
|
||||
options: options,
|
||||
};
|
||||
}
|
||||
|
||||
private static processPhrase(phrase?: string | string[]): string[] {
|
||||
private static processPhrase(
|
||||
phrase?: string | string[]
|
||||
): string[] | undefined {
|
||||
if (Array.isArray(phrase)) {
|
||||
const buff = phrase.map((p) => {
|
||||
return p.split(" ").join("_");
|
||||
@@ -121,12 +160,13 @@ export class Command {
|
||||
buff.push(phrase.split(" ").join("_"));
|
||||
return buff;
|
||||
} else {
|
||||
return [];
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
private generateUsageFromArguments(): string {
|
||||
let usageTemplate: string = "";
|
||||
this.parameters &&
|
||||
this.parameters.map((e) => {
|
||||
usageTemplate += `[${e.name} (${e.type}${
|
||||
e.optional ? ", optional" : ""
|
||||
|
||||
@@ -32,6 +32,7 @@ export class CommandManager {
|
||||
if (c.name == phrase) {
|
||||
command = c;
|
||||
}
|
||||
c.aliases &&
|
||||
c.aliases.map((a) => {
|
||||
if (a == phrase) {
|
||||
command = c;
|
||||
@@ -39,6 +40,7 @@ export class CommandManager {
|
||||
});
|
||||
break;
|
||||
case "NO_PREFIX":
|
||||
c.keywords &&
|
||||
c.keywords.map((k) => {
|
||||
if (k == phrase) {
|
||||
command = c;
|
||||
@@ -49,11 +51,13 @@ export class CommandManager {
|
||||
if (c.name == phrase) {
|
||||
command = c;
|
||||
}
|
||||
c.aliases &&
|
||||
c.aliases.map((a) => {
|
||||
if (a == phrase) {
|
||||
command = c;
|
||||
}
|
||||
});
|
||||
c.keywords &&
|
||||
c.keywords.map((k) => {
|
||||
if (k == phrase) {
|
||||
command = c;
|
||||
@@ -82,6 +86,7 @@ export class CommandManager {
|
||||
`The name "${command.name}" has already been registered as ${nameOccurrence.type} in the "${nameOccurrence.command.name}" command.`
|
||||
);
|
||||
}
|
||||
command.aliases &&
|
||||
command.aliases.map((a, i, ar) => {
|
||||
const aliasOccurrence: PhraseOccurrenceData | null =
|
||||
this.findPhraseOccurrence(a);
|
||||
@@ -93,8 +98,9 @@ export class CommandManager {
|
||||
}
|
||||
});
|
||||
this.list.map((c) => {
|
||||
command.keywords &&
|
||||
command.keywords.map((k, i, a) => {
|
||||
if (c.keywords.indexOf(k) != -1) {
|
||||
if (c.keywords && c.keywords.indexOf(k) != -1) {
|
||||
console.warn(
|
||||
`[⚠ WARN] The name "${k}" is already a registered KEYWORD for the "${c.name}" command. It will be removed from the "${command.name}" command`
|
||||
);
|
||||
@@ -159,7 +165,7 @@ export class CommandManager {
|
||||
command: c,
|
||||
type: "NAME",
|
||||
};
|
||||
} else if (c.aliases.indexOf(phrase || "") != -1) {
|
||||
} else if (c.aliases && c.aliases.indexOf(phrase || "") != -1) {
|
||||
returnValue = {
|
||||
command: c,
|
||||
type: "ALIAS",
|
||||
|
||||
+7
-4
@@ -16,7 +16,7 @@ export class HelpMessage extends Command {
|
||||
description: params.description,
|
||||
parameters: [
|
||||
{
|
||||
name: "Command name",
|
||||
name: "command_name",
|
||||
description:
|
||||
"Name of the command that you want to get details about",
|
||||
optional: true,
|
||||
@@ -45,7 +45,10 @@ export class HelpMessage extends Command {
|
||||
`${cmdManager.prefix}${cmd.name} ${cmd.usage}`,
|
||||
false
|
||||
);
|
||||
if (cmd.permissions.toArray(false).length > 0) {
|
||||
if (
|
||||
cmd.permissions &&
|
||||
cmd.permissions.toArray(false).length > 0
|
||||
) {
|
||||
let permList: string = "";
|
||||
cmd.permissions.toArray(false).map((p) => {
|
||||
permList += p + "\n";
|
||||
@@ -56,14 +59,14 @@ export class HelpMessage extends Command {
|
||||
false
|
||||
);
|
||||
}
|
||||
if (cmd.aliases.length > 0) {
|
||||
if (cmd.aliases && cmd.aliases.length > 0) {
|
||||
let aList: string = "";
|
||||
cmd.aliases.map((a) => {
|
||||
aList += a + "\n";
|
||||
});
|
||||
helpMsg.addField("Aliases:", aList, false);
|
||||
}
|
||||
if (cmd.keywords.length > 0) {
|
||||
if (cmd.keywords && cmd.keywords.length > 0) {
|
||||
let kwrdList: string = "";
|
||||
cmd.keywords.map((k) => {
|
||||
kwrdList += k + "\n";
|
||||
|
||||
+26
-26
@@ -1,35 +1,35 @@
|
||||
import { ParameterType, ParameterResolvable, Choice } from "./types.js";
|
||||
export interface Parameter {
|
||||
export interface ParameterSchema {
|
||||
name: string;
|
||||
description?: string;
|
||||
optional: boolean;
|
||||
type: ParameterType;
|
||||
choices?: Choice[];
|
||||
}
|
||||
export const ProcessArgument = (
|
||||
a: string,
|
||||
type: ParameterType
|
||||
): ParameterResolvable => {
|
||||
switch (type) {
|
||||
/* case "TEXT":
|
||||
return a;
|
||||
case "NUMBER":
|
||||
const numF = parseFloat(a);
|
||||
if (isNaN(numF)) {
|
||||
throw new ParameterTypeError(a, type);
|
||||
} else {
|
||||
return numF;
|
||||
export class Parameter {
|
||||
name: string;
|
||||
description: string;
|
||||
optional: boolean;
|
||||
type: ParameterType;
|
||||
choices?: Choice[];
|
||||
|
||||
constructor(options: ParameterSchema) {
|
||||
this.name = options.name;
|
||||
this.description = options.description || "No description";
|
||||
this.optional = options.optional;
|
||||
this.type = options.type;
|
||||
this.choices = options.choices;
|
||||
if (!/^[\w-]{1,32}$/.test(this.name)) {
|
||||
throw new Error(
|
||||
`Parameter name ${this.name} doesn't match the pattern`
|
||||
);
|
||||
}
|
||||
case "TRUE/FALSE":
|
||||
if (a.toLowerCase() == "true") {
|
||||
return true;
|
||||
} else if (a.toLowerCase() == "false") {
|
||||
return false;
|
||||
} else {
|
||||
throw new ParameterTypeError(a, type);
|
||||
}*/
|
||||
default:
|
||||
return a;
|
||||
//throw new TypeError("Invalied type specified");
|
||||
if (this.description.length > 100) {
|
||||
throw new Error(`Parameter ${this.name}: Description too long`);
|
||||
}
|
||||
};
|
||||
return;
|
||||
}
|
||||
static process(a: string, type: ParameterType): ParameterResolvable {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -8,7 +8,7 @@ import {
|
||||
TextChannel,
|
||||
VoiceChannel,
|
||||
} from "discord.js";
|
||||
import { Parameter } from "./Parameter.js";
|
||||
import { ParameterSchema } from "./Parameter.js";
|
||||
import { PermissionResolvable, Message, MessageEmbed } from "discord.js";
|
||||
import type { Command } from "./Command.js";
|
||||
|
||||
@@ -24,7 +24,7 @@ export type GetMode = "ALL" | "PREFIX" | "NO_PREFIX";
|
||||
export type PermissionCheckTypes = "ALL" | "ANY";
|
||||
export interface CommandBuilder {
|
||||
name: string;
|
||||
parameters?: Parameter[];
|
||||
parameters?: ParameterSchema[];
|
||||
aliases?: string[] | string;
|
||||
keywords?: string[] | string;
|
||||
description?: string;
|
||||
|
||||
Reference in new issue
Block a user