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