From 490d6403d73cbda5f66ba822be200a3988c3f023 Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Fri, 8 Apr 2022 13:10:46 -0500 Subject: [PATCH] refactor : change naming conventions to PascalCase --- src/handler/events/interactionCreate.ts | 14 +++--- src/handler/events/messageEvent.ts | 4 +- src/handler/events/observableHandling.ts | 9 ++-- src/handler/events/readyEvent.ts | 3 +- src/handler/sern.ts | 20 ++++---- src/handler/structures/context.ts | 46 +++++++++++++++---- src/handler/structures/errors.ts | 10 ++-- .../structures/modules/commands/module.ts | 20 ++++---- .../modules/commands/moduleHandler.ts | 24 ++++++---- src/handler/utilities/readFile.ts | 2 +- src/types/handler.ts | 1 + 11 files changed, 96 insertions(+), 57 deletions(-) diff --git a/src/handler/events/interactionCreate.ts b/src/handler/events/interactionCreate.ts index e44152c..4aee381 100644 --- a/src/handler/events/interactionCreate.ts +++ b/src/handler/events/interactionCreate.ts @@ -6,19 +6,17 @@ import Context from '../structures/context'; import type Wrapper from '../structures/wrapper'; import * as Files from '../utilities/readFile'; import { filterTap } from './observableHandling'; -import { filter } from 'rxjs'; export const onInteractionCreate = ( wrapper : Wrapper ) => { const { client } = wrapper; (> fromEvent(client, 'interactionCreate')) .pipe( - filter( i => i.inGuild() ), concatMap ( interaction => { if (interaction.isChatInputCommand()) { return of(Files.Commands.get(interaction.commandName)) .pipe( - filterTap(CommandType.SLASH, mod => { + filterTap(CommandType.Slash, mod => { const ctx = Context.wrap(interaction); mod.execute(ctx, ['slash', interaction.options]); }), @@ -27,7 +25,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { if (interaction.isContextMenuCommand()) { return of(Files.ContextMenuUser.get(interaction.commandName)) .pipe( - filterTap(CommandType.MENU_USER, mod => { + filterTap(CommandType.MenuUser, mod => { mod.execute(interaction); }), ); @@ -35,7 +33,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { if (interaction.isMessageContextMenuCommand()) { return of(Files.ContextMenuMsg.get(interaction.commandName)) .pipe( - filterTap(CommandType.MENU_MSG, mod => { + filterTap(CommandType.MenuMsg, mod => { mod.execute(interaction); }), ); @@ -43,7 +41,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { if (interaction.isButton()) { return of(Files.Buttons.get(interaction.customId)) .pipe( - filterTap(CommandType.BUTTON, mod => { + filterTap(CommandType.Button, mod => { mod.execute(interaction); }) ); @@ -51,12 +49,12 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { if (interaction.isSelectMenu()) { return of(Files.SelectMenus.get(interaction.customId)) .pipe( - filterTap(CommandType.MENU_SELECT, mod => { + filterTap(CommandType.MenuSelect, mod => { mod.execute(interaction); }) ); } - else { return of(); } + else return of(); }) ).subscribe({ error(e) { diff --git a/src/handler/events/messageEvent.ts b/src/handler/events/messageEvent.ts index d2ee6b6..473c074 100644 --- a/src/handler/events/messageEvent.ts +++ b/src/handler/events/messageEvent.ts @@ -1,4 +1,4 @@ -import type { ChatInputCommandInteraction, Message } from 'discord.js'; +import type { Message } from 'discord.js'; import { fromEvent, Observable, of, concatMap } from 'rxjs'; import { CommandType } from '../sern'; import Context from '../structures/context'; @@ -18,7 +18,7 @@ export const onMessageCreate = (wrapper : Wrapper) => { return of( posMod ) .pipe ( - filterTap(CommandType.TEXT, mod => { + filterTap(CommandType.Text, mod => { const ctx = Context.wrap(m); mod.execute(ctx, ['text', data]); }) diff --git a/src/handler/events/observableHandling.ts b/src/handler/events/observableHandling.ts index d5892b8..f93cf5d 100644 --- a/src/handler/events/observableHandling.ts +++ b/src/handler/events/observableHandling.ts @@ -4,7 +4,7 @@ import type { Module } from '../structures/structxports'; import { Observable, throwError } from 'rxjs'; import type { ModuleDefs } from '../structures/modules/commands/moduleHandler'; import { SernError } from '../structures/errors'; -import { isNotFromBot, isNotFromDM } from '../utilities/messageHelpers'; +import { isNotFromBot } from '../utilities/messageHelpers'; export function match(mod: Module | undefined, type : CommandType) : boolean { return mod !== undefined && (mod.type & type) != 0; @@ -23,9 +23,9 @@ export function filterTap( subscriber.next(asModT); } else { if (modul === undefined) { - return throwError(() => SernError.UNDEFINED_MODULE); + return throwError(() => SernError.UndefinedModule); } - return throwError(() => SernError.MISMATCH_MODULE_TYPE); + return throwError(() => SernError.MismatchModule); } }, error: (e) => subscriber.error(e), @@ -40,7 +40,6 @@ export function ignoreNonBot(prefix : string) { return src.subscribe({ next(m) { const passAll = [ - isNotFromDM, isNotFromBot, (m : Message) => m.content @@ -59,5 +58,3 @@ export function ignoreNonBot(prefix : string) { }); }); } - - diff --git a/src/handler/events/readyEvent.ts b/src/handler/events/readyEvent.ts index b389f94..7ef4c29 100644 --- a/src/handler/events/readyEvent.ts +++ b/src/handler/events/readyEvent.ts @@ -42,8 +42,7 @@ const handler = ( name : string ) => }, [CommandType.MENU_SELECT] : mod => { Files.SelectMenus.set(name, mod); - } - + }, } as ModuleHandlers); const registerModules = (name : string, mod : ModuleStates[T]) => diff --git a/src/handler/sern.ts b/src/handler/sern.ts index c9ed8ad..91b4b2b 100644 --- a/src/handler/sern.ts +++ b/src/handler/sern.ts @@ -12,6 +12,8 @@ import { SernError } from './structures/errors'; import { onReady } from './events/readyEvent'; import { onMessageCreate } from './events/messageEvent'; import { onInteractionCreate } from './events/interactionCreate'; +import type { Module } from '..'; +import { Modified, Modifiers } from './structures/modifiers'; export function init( wrapper : Wrapper ) { const { events, client } = wrapper; @@ -21,6 +23,7 @@ export function init( wrapper : Wrapper ) { onInteractionCreate ( wrapper ); } +//TODO : Add event listener for any other generic node js event emitter function eventObserver(client: Client, events: DiscordEvent[] ) { events.forEach( ( [event, cb] ) => { if (event === 'ready') throw Error(SernError.RESERVED_EVENT); @@ -29,17 +32,18 @@ function eventObserver(client: Client, events: DiscordEvent[] ) { } + /** * @enum { number }; */ export enum CommandType { - TEXT = 0b000001, - SLASH = 0b000010, - MENU_USER = 0b000100, - MENU_MSG = 0b001000, - BUTTON = 0b010000, - MENU_SELECT= 0b100000, - BOTH = 0b000011, - ANY = 0b111111 + Text = 0b0000001, + Slash = 0b0000010, + MenuUser = 0b0000100, + MenuMsg = 0b0001000, + Button = 0b0010000, + MenuSelect = 0b0100000, + Both = 0b0000011, + Auto = 0b1000000 } diff --git a/src/handler/structures/context.ts b/src/handler/structures/context.ts index b95ae3e..62b2b37 100644 --- a/src/handler/structures/context.ts +++ b/src/handler/structures/context.ts @@ -1,9 +1,12 @@ +import type { APIGuildMember } from 'discord-api-types/v9'; import type { Awaitable, ChatInputCommandInteraction, Guild, GuildMember, + InteractionReplyOptions, Message, + ReplyMessageOptions, Snowflake, TextBasedChannel, User @@ -17,8 +20,10 @@ function firstSome(...args : Option[]) : Nullish { } return null; } +// +//Will need refactoring after applying context in practice +// export default class Context { - private constructor( private oMsg: Option = None, private oInterac: Option = None @@ -71,7 +76,7 @@ export default class Context { public get guild() : Guild { return firstSome( - this.oMsg.map(m => m.guild!), + this.oMsg.map(m => m.guild), this.oInterac.map(i => i.guild) )!; } @@ -81,10 +86,13 @@ export default class Context { this.oInterac.map(i => i.guildId) )!; } - public get member() : Nullish { + /* + * interactions can return APIGuildMember if the guild it is emitted from is not cached + */ + public get member() : Nullish { return firstSome( - this.oMsg.andThen(m => Some(m.member!)), - this.oInterac.andThen(i => i.inCachedGuild() ? Some(i.member) : None) + this.oMsg.map(m => m.member), + this.oInterac.map(i => i.member) ); } /* @@ -93,13 +101,19 @@ export default class Context { public onInteraction( onInteraction : ( interaction : ChatInputCommandInteraction ) => Awaitable, ): Context { - this.oInterac.map(onInteraction); + if (this.oInterac.some) { + onInteraction(this.oInterac.val); + return Context.wrap(this.oInterac.val); + } return this; } public onMessage( onMessage : ( message : Message ) => Awaitable ): Context { - this.oMsg.map( onMessage ); + if (this.oMsg.some) { + onMessage(this.oMsg.val); + return Context.wrap(this.oMsg.val); + } return this; } public takeInteractionValue( @@ -108,14 +122,28 @@ export default class Context { if(this.oInterac.none) return null; return extract(this.oInterac.val); } + public takeMessageValue( extract : (message: Message) => T ): Nullish { if(this.oMsg.none) return null; return extract(this.oMsg.val); } - + + public reply( + content : Omit | ReplyMessageOptions + ): Promise { + return firstSome( + this.oInterac.map(async i => { + await i.reply( content as InteractionReplyOptions); + return new Context(Some(await i.fetchReply() as Message), Some(i)) + }), + this.oMsg.map(async m => { + const reply = await m.reply( content as ReplyMessageOptions ) + return new Context(Some(reply), this.oInterac); + }) + )!; + } } - diff --git a/src/handler/structures/errors.ts b/src/handler/structures/errors.ts index c29128e..869b2cd 100644 --- a/src/handler/structures/errors.ts +++ b/src/handler/structures/errors.ts @@ -1,7 +1,7 @@ export enum SernError { - RESERVED_EVENT = 'Cannot register the reserved ready event. Please use the init property.', - NO_ALIAS = 'You cannot provide an array with elements to a slash command.', - NOT_VALID_MOD_TYPE = 'Detected an unknown module type', - UNDEFINED_MODULE = `A module could not be detected at`, - MISMATCH_MODULE_TYPE = `A module type mismatched with event emitted!` + ReservedEvent = 'Cannot register the reserved ready event. Please use the init property.', + NoAlias = 'You cannot provide an array with elements to a slash command.', + NonValidModuleType = 'Detected an unknown module type', + UndefinedModule = `A module could not be detected at`, + MismatchModule = `A module type mismatched with event emitted!` } diff --git a/src/handler/structures/modules/commands/module.ts b/src/handler/structures/modules/commands/module.ts index 3314784..1443ec2 100644 --- a/src/handler/structures/modules/commands/module.ts +++ b/src/handler/structures/modules/commands/module.ts @@ -1,36 +1,40 @@ -import type { ApplicationCommandOptionData, Awaitable, ButtonInteraction, ContextMenuCommandInteraction, MessageContextMenuCommandInteraction, SelectMenuInteraction } from 'discord.js'; +import type { ApplicationCommandOptionData, AutocompleteInteraction, Awaitable, ButtonInteraction, ContextMenuCommandInteraction, MessageContextMenuCommandInteraction, SelectMenuInteraction } from 'discord.js'; import type { Override } from '../../../../types/handler'; import type { CommandType } from '../../../sern'; import type { BaseModule } from '../module'; + +type AutoComp = { + update : (ctx : AutocompleteInteraction) => Awaitable +} //possible refactoring to interfaces and not types export type TextCommand = { - type : CommandType.TEXT; + type : CommandType.Text; alias : string[] | [], } & BaseModule; export type SlashCommand = { - type : CommandType.SLASH; + type : CommandType.Slash; options : ApplicationCommandOptionData[] | [], } & BaseModule; export type BothCommand = { - type : CommandType.BOTH; + type : CommandType.Both; alias : string[] | []; options : ApplicationCommandOptionData[] | [], } & BaseModule; export type ContextMenuUser = { - type : CommandType.MENU_USER; + type : CommandType.MenuUser; } & Override Awaitable }>; export type ContextMenuMsg = { - type : CommandType.MENU_MSG; + type : CommandType.MenuMsg; } & Override Awaitable }>; export type ButtonCommand = { - type : CommandType.BUTTON; + type : CommandType.Button; } & Override Awaitable }>; export type SelectMenuCommand = { - type : CommandType.MENU_SELECT; + type : CommandType.MenuSelect; } & Override Awaitable }>; diff --git a/src/handler/structures/modules/commands/moduleHandler.ts b/src/handler/structures/modules/commands/moduleHandler.ts index caf1e01..07480e1 100644 --- a/src/handler/structures/modules/commands/moduleHandler.ts +++ b/src/handler/structures/modules/commands/moduleHandler.ts @@ -1,16 +1,24 @@ import { CommandType } from '../../../sern'; -import type { TextCommand, BothCommand, ButtonCommand, SlashCommand, ContextMenuMsg, ContextMenuUser, SelectMenuCommand } from './module'; +import type { + TextCommand, + BothCommand, + ButtonCommand, + SlashCommand, + ContextMenuMsg, + ContextMenuUser, + SelectMenuCommand +} from './module'; //https://stackoverflow.com/questions/64092736/alternative-to-switch-statement-for-typescript-discriminated-union // Explicit Module Definitions for mapping export type ModuleDefs = { - [CommandType.TEXT] : TextCommand, - [CommandType.SLASH] : SlashCommand, - [CommandType.BOTH] : BothCommand, - [CommandType.MENU_MSG] : ContextMenuMsg, - [CommandType.MENU_USER] : ContextMenuUser, - [CommandType.BUTTON] : ButtonCommand, - [CommandType.MENU_SELECT] : SelectMenuCommand + [CommandType.Text] : TextCommand, + [CommandType.Slash] : SlashCommand, + [CommandType.Both] : BothCommand, + [CommandType.MenuMsg] : ContextMenuMsg, + [CommandType.MenuUser] : ContextMenuUser, + [CommandType.Button] : ButtonCommand, + [CommandType.MenuSelect] : SelectMenuCommand, } //Keys of ModuleDefs diff --git a/src/handler/utilities/readFile.ts b/src/handler/utilities/readFile.ts index f933feb..9266f99 100644 --- a/src/handler/utilities/readFile.ts +++ b/src/handler/utilities/readFile.ts @@ -44,7 +44,7 @@ export async function buildData(commandDir: string ): Promise< return Promise.all( getCommands(commandDir).map( async (absPath) => { const mod = (await import(absPath)).module; - if (mod === undefined) throw Error(`${SernError.UNDEFINED_MODULE} ${absPath}`); + if (mod === undefined) throw Error(`${SernError.UndefinedModule} ${absPath}`); return { mod, absPath }; }), ); diff --git a/src/types/handler.ts b/src/types/handler.ts index 422f525..1fdfcc5 100644 --- a/src/types/handler.ts +++ b/src/types/handler.ts @@ -21,6 +21,7 @@ export type Args = ParseType<{ text: string[]; slash: SlashOptions }>; export type DiscordEvent = ParseType< { [K in keyof ClientEvents ] : (...args : ClientEvents[K]) => Awaitable }>; + export type SlashOptions = Omit; //https://dev.to/vborodulin/ts-how-to-override-properties-with-type-intersection-554l