diff --git a/package.json b/package.json index 8cf0759..bec15e0 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,7 @@ "version": "0.0.0", "description": "A wrapper that helps you create your own Discord bot easier.", "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, + "type": "module", "repository": { "type": "git", "url": "git+https://github.com/GRZ4NA/DiscordCommands.git" diff --git a/src/Bot.ts b/src/Bot.ts index 693703b..90da3fa 100644 --- a/src/Bot.ts +++ b/src/Bot.ts @@ -1,18 +1,23 @@ //IMPORTS -import { Client, ClientOptions } from 'discord.js'; +import { Client, ClientOptions, Message } from 'discord.js'; import { Command, CommandsManager } from './Commands'; +import { HelpMessage, HelpMessageParams } from './Help'; +import { CommandMessage } from './CommandMessage'; +import * as http from 'http'; //TYPE DEFINITIONS interface ConfigurationOptions { prefix: string, - accentColor: string + accentColor: string, + token?: string } interface ConstructorOptions { name: string, prefix: string, helpCommand?: boolean, clientOptions?: ClientOptions, - token?: string + token?: string, + accentColor?: string } //MAIN CLASS @@ -21,6 +26,13 @@ class Bot { client: Client; commands: CommandsManager; config: ConfigurationOptions; + messages: { + help: HelpMessageParams + } + on: { + message: (m: Message) => any, + command: (m: CommandMessage) => any + } constructor(options: ConstructorOptions) { this.name = options.name; @@ -28,7 +40,60 @@ class Bot { this.commands = new CommandsManager(); this.config = { prefix: options.prefix, - accentColor: "#000" + accentColor: "#000", + token: options.token + } + this.messages = { + help: { + title: 'Help', + description: 'List of all available commands', + color: '#000', + usage: '[command name (optional)]', + bottomText: 'List of all available commands' + } + } + this.on = { + message: (m: Message) => {}, + command: (m: CommandMessage) => { console.log(m.command); } + } + } + async start(port?: number, token?: string) : Promise { + try { + console.log(`Bot name: ${this.name}`); + const loginToken: string = token || this.config.token || ''; + if(loginToken === '') { + throw new ReferenceError('No token specified. Please pass your Discord application token as an argument to the "start" method or in the constructor'); + } + if(port) { + console.log(`Creating http server on port ${port}...`); + http.createServer().listen(port); + } + console.log('Starting modules...'); + const helpMsg: Command = new HelpMessage(this.commands, this.messages.help, this.config.prefix, this.name); + this.commands.add(helpMsg); + console.log('Connecting to Discord...'); + if(await this.client.login(token)) { + console.log('BOT IS READY!\n'); + this.client.on('message', (m) => { + this.on.message(m); + const cmdMsg: CommandMessage = new CommandMessage(m, this.config.prefix); + if(cmdMsg.command) { + this.on.command(cmdMsg); + const calledCommand = this.commands.get(cmdMsg.command.name); + if(calledCommand) { + calledCommand.start(cmdMsg); + } + } + }); + } + else { + return false; + } + return true; + } + catch (e) { + console.error(`ERROR! ${e.toString()}`); + return false; } } } diff --git a/src/CommandMessage.ts b/src/CommandMessage.ts new file mode 100644 index 0000000..3405363 --- /dev/null +++ b/src/CommandMessage.ts @@ -0,0 +1,32 @@ +import { Message } from 'discord.js'; + +interface CommandMessageStructure { + name: string, + arguments: string[] +} + +class CommandMessage extends Message { + command: CommandMessageStructure | null + + constructor(message: Message, prefix: string) { + super(message.client, message, message.channel); + if(!message.author.bot && message.content.startsWith(prefix)) { + let msgContent = message.content.replace(prefix, ''); + const cmdName = msgContent.split(' ')[0]; + msgContent = msgContent.replace(cmdName, ''); + let cmdArguments: string[] = msgContent.split(','); + cmdArguments = cmdArguments.map((a) => { + return a.replace(' ', ''); + }); + this.command = { + name: cmdName, + arguments: cmdArguments + } + } + else { + this.command = null; + } + } +} + +export { CommandMessage } \ No newline at end of file diff --git a/src/Commands.ts b/src/Commands.ts index ff929ab..ac0562b 100644 --- a/src/Commands.ts +++ b/src/Commands.ts @@ -1,5 +1,5 @@ //IMPORTS -import { Permissions, PermissionResolvable, Message, GuildMember } from 'discord.js'; +import { Permissions, PermissionResolvable, Message, GuildMember, MessageEmbed } from 'discord.js'; //TYPE DEFINITIONS interface CommandBuilder { @@ -9,7 +9,8 @@ interface CommandBuilder { description?: string, usage?: string, permissions?: PermissionResolvable, - function: (message?: Message) => void | string; + visible?: boolean + function: (message?: Message) => void | string | MessageEmbed; } //ERROR CLASSES @@ -33,21 +34,17 @@ class Command { description: string; usage: string; permissions: Permissions; - private function: (message?: Message) => void | string; + visible: boolean; + private function: (message?: Message) => void | string | MessageEmbed; constructor(options: CommandBuilder) { this.name = options.name.split(' ').join('_'); - this.aliases = []; - if(options.aliases) { - this.aliases = ProcessPhrase(options.aliases); - } - this.keywords = []; - if(options.keywords) { - this.keywords = ProcessPhrase(options.keywords); - } + this.aliases = ProcessPhrase(options.aliases); + this.keywords = ProcessPhrase(options.keywords); this.description = options.description || "No description"; - this.usage = options.usage || "-"; + this.usage = options.usage || ""; this.permissions = new Permissions(options.permissions || 0); + this.visible = options.visible || true; this.function = options.function; } async start(message?: Message) { @@ -107,18 +104,21 @@ class CommandsManager { } //FUNCTIONS -const ProcessPhrase = (phrase: string | string[]) : string[] => { +const ProcessPhrase = (phrase?: string | string[]) : string[] => { if(Array.isArray(phrase)) { const buff = phrase.map((p) => { return p.split(' ').join('_'); }); return buff; } - else { + else if(typeof phrase == 'string') { const buff = []; buff.push(phrase.split(' ').join('_')); return buff; } + else { + return []; + } } //EXPORTS diff --git a/src/Help.ts b/src/Help.ts new file mode 100644 index 0000000..2ebaa34 --- /dev/null +++ b/src/Help.ts @@ -0,0 +1,44 @@ +import { Message, MessageEmbed } from 'discord.js'; +import { Command, CommandsManager } from './Commands'; + +interface HelpMessageParams { + title: string, + bottomText: string + color: string, + description: string, + usage: string +} + +class HelpMessage extends Command { + constructor(cmdManager: CommandsManager, params: HelpMessageParams, prefix: string, botName?: string) { + super({ + name: 'help', + usage: params.usage, + permissions: 0, + description: params.description, + function: (m?: Message) => { + const helpMsg = new MessageEmbed() + if(helpMsg != null) { + helpMsg.setColor(params.color); + helpMsg.setDescription(params.bottomText); + helpMsg.setTimestamp(); + helpMsg.setTitle(params.title); + helpMsg.setFooter(botName || ''); + + cmdManager.list.map((c) => { + if(c.visible) { + helpMsg.addField( + `${prefix}${c.name} ${c.usage}`, + c.description, + false + ) + } + }); + } + return helpMsg; + } + }); + } +} + +export { HelpMessage, HelpMessageParams }; \ No newline at end of file