From ff14817f324b96aecf4cb344c49ab42231a36312 Mon Sep 17 00:00:00 2001 From: GRZ4NA Date: Sat, 7 Aug 2021 01:19:12 +0200 Subject: [PATCH] code splitting --- index.ts | 2 +- src/Bot.ts | 27 ++--- src/Command.ts | 206 ++---------------------------------- src/CommandManager.ts | 171 ++++++++++++++++++++++++++++++ src/Help.ts | 15 +-- src/Parameter.ts | 6 +- src/SystemMessage.ts | 2 +- src/{Error.ts => errors.ts} | 3 +- src/types.ts | 47 ++++++++ 9 files changed, 245 insertions(+), 234 deletions(-) create mode 100644 src/CommandManager.ts rename src/{Error.ts => errors.ts} (92%) create mode 100644 src/types.ts diff --git a/index.ts b/index.ts index a697b1e..843045c 100644 --- a/index.ts +++ b/index.ts @@ -1,6 +1,6 @@ import { Bot } from "./src/Bot.js"; import { Command } from "./src/Command.js"; -import { ParameterResolvable, ParameterType } from "./src/Parameter.js"; +import { ParameterResolvable, ParameterType } from "./src/types.js"; import { MessageEmbed } from "discord.js"; export default Bot; diff --git a/src/Bot.ts b/src/Bot.ts index d2da38c..8358b1d 100644 --- a/src/Bot.ts +++ b/src/Bot.ts @@ -1,13 +1,17 @@ -//IMPORTS -import { Client, ClientOptions, Message } from "discord.js"; -import { Command, CommandManager, CommandMessageStructure } from "./Command.js"; -import { PermissionsError } from "./Error.js"; -import { HelpMessage, HelpMessageParams } from "./Help.js"; +import { Client, Message } from "discord.js"; +import { Command } from "./Command.js"; +import { CommandManager } from "./CommandManager.js"; +import { + CommandMessageStructure, + InitOptions, + HelpMessageParams, +} from "./types.js"; +import { PermissionsError } from "./errors.js"; +import { HelpMessage } from "./Help.js"; import * as http from "http"; import { SystemMessageManager } from "./SystemMessage.js"; import { EventEmitter } from "events"; -//TYPE DEFINITIONS export declare interface Bot { on(event: "READY", listener: Function): this; on(event: "MESSAGE", listener: (m: Message) => void): this; @@ -17,15 +21,7 @@ export declare interface Bot { ): this; on(event: "ERROR", listener: (e: any) => void): this; } -interface ConstructorOptions { - name: string; - prefix: string; - argumentSeparator?: string; - clientOptions?: ClientOptions; - token?: string; -} -//MAIN CLASS export class Bot extends EventEmitter { name: string; client: Client; @@ -46,7 +42,7 @@ export class Bot extends EventEmitter { * @param {ClientOptions} [options.clientOptions] - client options from Discord.js * @param {string} [options.token] - bot token from Discord Developer Portal */ - constructor(options: ConstructorOptions) { + constructor(options: InitOptions) { super(); this.name = options.name; this.client = new Client(options.clientOptions); @@ -156,5 +152,4 @@ export class Bot extends EventEmitter { } } -//EXPORTS export default Bot; diff --git a/src/Command.ts b/src/Command.ts index 3af3394..44989d2 100644 --- a/src/Command.ts +++ b/src/Command.ts @@ -1,43 +1,12 @@ //IMPORTS +import { Permissions, Message, MessageEmbed } from "discord.js"; import { - Permissions, - PermissionResolvable, - Message, - MessageEmbed, -} from "discord.js"; -import { MissingParameterError, PermissionsError } from "./Error.js"; -import { - Parameter, + CommandBuilder, + PermissionCheckTypes, ParameterResolvable, - ProcessArgument, -} from "./Parameter.js"; - -//TYPE DEFINITIONS -type GetMode = "ALL" | "PREFIX" | "NO_PREFIX"; -type PermissionCheckTypes = "ALL" | "ANY"; -export interface CommandMessageStructure { - command: Command; - parameters: string[]; -} -interface CommandBuilder { - name: string; - parameters?: Parameter[]; - aliases?: string[] | string; - keywords?: string[] | string; - description?: string; - usage?: string; - permissionCheck?: PermissionCheckTypes; - permissions?: PermissionResolvable; - visible?: boolean; - function: ( - message?: Message, - cmdParams?: ParameterResolvable[] - ) => void | string | MessageEmbed | Promise; -} -interface PhraseOccurrenceData { - command: Command; - type: "NAME" | "ALIAS"; -} +} from "./types.js"; +import { MissingParameterError, PermissionsError } from "./errors.js"; +import { Parameter, ProcessArgument } from "./Parameter.js"; //CLASSES export class Command { @@ -153,166 +122,3 @@ export class Command { return usageTemplate; } } -export class CommandManager { - list: Command[]; - prefix: string; - argumentSeparator: string; - - constructor(prefix: string, argumentSeparator?: string) { - this.list = []; - this.prefix = prefix; - this.argumentSeparator = argumentSeparator || ","; - } - - /** - * Retrieves the command by name, alias or keyword - * @param {string} phrase - command name, alias or keyword - * @param {GetMode} [mode='ALL'] - specifies which types of command triggers will be used to find the command [*NO_PREFIX* - only keywords; *PREFIX* - names and aliases] - * @returns *Command* | *null* - */ - get(phrase: string, mode?: GetMode): Command | null { - if (!mode) mode = "ALL"; - let command: Command | null = null; - this.list.map((c) => { - switch (mode) { - case "PREFIX": - if (c.name == phrase) { - command = c; - } - c.aliases.map((a) => { - if (a == phrase) { - command = c; - } - }); - break; - case "NO_PREFIX": - c.keywords.map((k) => { - if (k == phrase) { - command = c; - } - }); - break; - case "ALL": - if (c.name == phrase) { - command = c; - } - c.aliases.map((a) => { - if (a == phrase) { - command = c; - } - }); - c.keywords.map((k) => { - if (k == phrase) { - command = c; - } - }); - break; - } - }); - return command; - } - - /** - * Adds the given command to the instance manager - * @param {Command} command - *Command* or *HelpMessage* object - * @returns *boolean* - */ - add(command: Command): boolean { - try { - if (!(command instanceof Command)) { - throw new TypeError("Inavlid argument type"); - } - const nameOccurrence: PhraseOccurrenceData | null = - this.findPhraseOccurrence(command.name); - if (nameOccurrence) { - throw new Error( - `The name "${command.name}" has already been registered as ${nameOccurrence.type} in the "${nameOccurrence.command.name}" command.` - ); - } - command.aliases.map((a, i, ar) => { - const aliasOccurrence: PhraseOccurrenceData | null = - this.findPhraseOccurrence(a); - if (aliasOccurrence) { - console.warn( - `[⚠ WARN] The name "${a}" is already registered as ${aliasOccurrence.type} in the "${aliasOccurrence.command.name}" command. It will be removed from the "${command.name}" command.` - ); - ar.splice(i, 1); - } - }); - this.list.map((c) => { - command.keywords.map((k, i, a) => { - if (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` - ); - a.splice(i, 1); - } - }); - }); - this.list.push(command); - return true; - } catch (e) { - console.error(`[❌ ERROR] ${e.toString()}`); - return false; - } - } - - /** - * Fetches command and parameters from the given *Message* object - * @param {Message} message - *Message* object - * @returns *CommandMessagesStructure* | *null* - */ - fetch(message: Message): CommandMessageStructure | null { - if (!message.author.bot) { - let prefix = false; - if (message.content.startsWith(this.prefix)) { - prefix = true; - } - const content = prefix - ? message.content.replace(this.prefix, "") - : message.content; - const name = content.split(" ")[0]; - const command = this.get(name, prefix ? "PREFIX" : "NO_PREFIX"); - if (command) { - const argumentsText = content.replace(name, ""); - const paramsList = argumentsText - .split(this.argumentSeparator) - .map((a) => { - return a.replace(" ", ""); - }); - if ( - (paramsList[0] == "" || paramsList[0] == " ") && - paramsList.length == 1 - ) { - paramsList.splice(0, 1); - } - return { - command: command, - parameters: paramsList, - }; - } else { - return null; - } - } else { - return null; - } - } - - private findPhraseOccurrence(phrase?: string): PhraseOccurrenceData | null { - let returnValue: PhraseOccurrenceData | null = null; - this.list.map((c) => { - if (phrase == c.name) { - returnValue = { - command: c, - type: "NAME", - }; - } else if (c.aliases.indexOf(phrase || "") != -1) { - returnValue = { - command: c, - type: "ALIAS", - }; - } - }); - return returnValue; - } -} diff --git a/src/CommandManager.ts b/src/CommandManager.ts new file mode 100644 index 0000000..b2cb91f --- /dev/null +++ b/src/CommandManager.ts @@ -0,0 +1,171 @@ +import { Message } from "discord.js"; +import { Command } from "./Command.js"; +import { + CommandMessageStructure, + GetMode, + PhraseOccurrenceData, +} from "./types.js"; + +export class CommandManager { + list: Command[]; + prefix: string; + argumentSeparator: string; + + constructor(prefix: string, argumentSeparator?: string) { + this.list = []; + this.prefix = prefix; + this.argumentSeparator = argumentSeparator || ","; + } + + /** + * Retrieves the command by name, alias or keyword + * @param {string} phrase - command name, alias or keyword + * @param {GetMode} [mode='ALL'] - specifies which types of command triggers will be used to find the command [*NO_PREFIX* - only keywords; *PREFIX* - names and aliases] + * @returns *Command* | *null* + */ + get(phrase: string, mode?: GetMode): Command | null { + if (!mode) mode = "ALL"; + let command: Command | null = null; + this.list.map((c) => { + switch (mode) { + case "PREFIX": + if (c.name == phrase) { + command = c; + } + c.aliases.map((a) => { + if (a == phrase) { + command = c; + } + }); + break; + case "NO_PREFIX": + c.keywords.map((k) => { + if (k == phrase) { + command = c; + } + }); + break; + case "ALL": + if (c.name == phrase) { + command = c; + } + c.aliases.map((a) => { + if (a == phrase) { + command = c; + } + }); + c.keywords.map((k) => { + if (k == phrase) { + command = c; + } + }); + break; + } + }); + return command; + } + + /** + * Adds the given command to the instance manager + * @param {Command} command - *Command* or *HelpMessage* object + * @returns *boolean* + */ + add(command: Command): boolean { + try { + if (!(command instanceof Command)) { + throw new TypeError("Inavlid argument type"); + } + const nameOccurrence: PhraseOccurrenceData | null = + this.findPhraseOccurrence(command.name); + if (nameOccurrence) { + throw new Error( + `The name "${command.name}" has already been registered as ${nameOccurrence.type} in the "${nameOccurrence.command.name}" command.` + ); + } + command.aliases.map((a, i, ar) => { + const aliasOccurrence: PhraseOccurrenceData | null = + this.findPhraseOccurrence(a); + if (aliasOccurrence) { + console.warn( + `[⚠ WARN] The name "${a}" is already registered as ${aliasOccurrence.type} in the "${aliasOccurrence.command.name}" command. It will be removed from the "${command.name}" command.` + ); + ar.splice(i, 1); + } + }); + this.list.map((c) => { + command.keywords.map((k, i, a) => { + if (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` + ); + a.splice(i, 1); + } + }); + }); + this.list.push(command); + return true; + } catch (e) { + console.error(`[❌ ERROR] ${e.toString()}`); + return false; + } + } + + /** + * Fetches command and parameters from the given *Message* object + * @param {Message} message - *Message* object + * @returns *CommandMessagesStructure* | *null* + */ + fetch(message: Message): CommandMessageStructure | null { + if (!message.author.bot) { + let prefix = false; + if (message.content.startsWith(this.prefix)) { + prefix = true; + } + const content = prefix + ? message.content.replace(this.prefix, "") + : message.content; + const name = content.split(" ")[0]; + const command = this.get(name, prefix ? "PREFIX" : "NO_PREFIX"); + if (command) { + const argumentsText = content.replace(name, ""); + const paramsList = argumentsText + .split(this.argumentSeparator) + .map((a) => { + return a.replace(" ", ""); + }); + if ( + (paramsList[0] == "" || paramsList[0] == " ") && + paramsList.length == 1 + ) { + paramsList.splice(0, 1); + } + return { + command: command, + parameters: paramsList, + }; + } else { + return null; + } + } else { + return null; + } + } + + private findPhraseOccurrence(phrase?: string): PhraseOccurrenceData | null { + let returnValue: PhraseOccurrenceData | null = null; + this.list.map((c) => { + if (phrase == c.name) { + returnValue = { + command: c, + type: "NAME", + }; + } else if (c.aliases.indexOf(phrase || "") != -1) { + returnValue = { + command: c, + type: "ALIAS", + }; + } + }); + return returnValue; + } +} diff --git a/src/Help.ts b/src/Help.ts index 6688c49..4974631 100644 --- a/src/Help.ts +++ b/src/Help.ts @@ -1,14 +1,7 @@ -import { ColorResolvable, MessageEmbed } from "discord.js"; -import { Command, CommandManager } from "./Command.js"; - -export interface HelpMessageParams { - enabled: boolean; - title: string; - bottomText: string; - color: ColorResolvable; - description: string; - usage: string; -} +import { MessageEmbed } from "discord.js"; +import { Command } from "./Command.js"; +import { CommandManager } from "./CommandManager.js"; +import { HelpMessageParams } from "./types.js"; export class HelpMessage extends Command { constructor( diff --git a/src/Parameter.ts b/src/Parameter.ts index 2221f1d..cdeba1a 100644 --- a/src/Parameter.ts +++ b/src/Parameter.ts @@ -1,7 +1,5 @@ -import { ParameterTypeError } from "./Error.js"; - -export type ParameterType = "TEXT" | "TRUE/FALSE" | "NUMBER"; -export type ParameterResolvable = string | boolean | number; +import { ParameterTypeError } from "./errors.js"; +import { ParameterType, ParameterResolvable } from "./types.js"; export interface Parameter { name: string; optional: boolean; diff --git a/src/SystemMessage.ts b/src/SystemMessage.ts index ccd6408..4cbe45f 100644 --- a/src/SystemMessage.ts +++ b/src/SystemMessage.ts @@ -9,7 +9,7 @@ import { User, } from "discord.js"; import { Command } from "./Command.js"; -import { PermissionsError } from "./Error.js"; +import { PermissionsError } from "./errors.js"; export type MessageType = "PERMISSION" | "ERROR" | "NOT_FOUND"; export interface SystemMessageAppearance { diff --git a/src/Error.ts b/src/errors.ts similarity index 92% rename from src/Error.ts rename to src/errors.ts index 0a20613..6d73aae 100644 --- a/src/Error.ts +++ b/src/errors.ts @@ -1,6 +1,7 @@ import { Command } from "./Command.js"; import { GuildMember } from "discord.js"; -import { Parameter, ParameterType } from "./Parameter.js"; +import { Parameter } from "./Parameter.js"; +import { ParameterType } from "./types.js"; export class PermissionsError extends Error { private command: Command; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..a02bd99 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,47 @@ +import { ClientOptions, ColorResolvable } from "discord.js"; +import { Parameter } from "./Parameter.js"; +import { PermissionResolvable, Message, MessageEmbed } from "discord.js"; +import type { Command } from "./Command.js"; + +export interface InitOptions { + name: string; + prefix: string; + argumentSeparator?: string; + clientOptions?: ClientOptions; + token?: string; +} +export type GetMode = "ALL" | "PREFIX" | "NO_PREFIX"; +export type PermissionCheckTypes = "ALL" | "ANY"; +export interface CommandBuilder { + name: string; + parameters?: Parameter[]; + aliases?: string[] | string; + keywords?: string[] | string; + description?: string; + usage?: string; + permissionCheck?: PermissionCheckTypes; + permissions?: PermissionResolvable; + visible?: boolean; + function: ( + message?: Message, + cmdParams?: ParameterResolvable[] + ) => void | string | MessageEmbed | Promise; +} +export interface PhraseOccurrenceData { + command: Command; + type: "NAME" | "ALIAS"; +} +export interface CommandMessageStructure { + command: Command; + parameters: string[]; +} +export interface HelpMessageParams { + enabled: boolean; + title: string; + bottomText: string; + color: ColorResolvable; + description: string; + usage: string; +} +export type ParameterType = "TEXT" | "TRUE/FALSE" | "NUMBER"; +export type ParameterResolvable = string | boolean | number;