From 88dcdee818e42405234ef502087226a8c042c92f Mon Sep 17 00:00:00 2001 From: jacoobes Date: Fri, 13 May 2022 14:33:17 -0500 Subject: [PATCH] feat: broadening EventPlugin default generic type, reformat with prettier --- .prettierrc | 3 +- src/handler/events/interactionCreate.ts | 109 ++++++----- src/handler/events/messageEvent.ts | 70 ++++---- src/handler/events/observableHandling.ts | 101 +++++------ src/handler/events/readyEvent.ts | 170 +++++++++--------- src/handler/plugins/plugin.ts | 82 ++++----- src/handler/sern.ts | 69 ++++--- .../modules/commands/moduleHandler.ts | 41 ++--- src/handler/structures/modules/module.ts | 14 +- 9 files changed, 329 insertions(+), 330 deletions(-) diff --git a/.prettierrc b/.prettierrc index 2f31668..f0c38cf 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,5 +3,6 @@ "trailingComma": "all", "singleQuote": true, "printWidth": 120, - "tabWidth": 4 + "tabWidth": 4, + "arrowParens": "avoid" } diff --git a/src/handler/events/interactionCreate.ts b/src/handler/events/interactionCreate.ts index 3a50670..4b898d7 100644 --- a/src/handler/events/interactionCreate.ts +++ b/src/handler/events/interactionCreate.ts @@ -1,50 +1,78 @@ - -import type { ApplicationCommandType, ChatInputCommandInteraction, CommandInteraction, Interaction } from 'discord.js'; -import { fromEvent, Observable, of, concatMap, map, throwError } from 'rxjs'; +import type { + ChatInputCommandInteraction, + CommandInteraction, + Interaction, + MessageContextMenuCommandInteraction as MessageCtxInt, + UserContextMenuCommandInteraction as UserCtxInt, +} from 'discord.js'; +import { concatMap, fromEvent, Observable, of, throwError } from 'rxjs'; import type Wrapper from '../structures/wrapper'; import * as Files from '../utilities/readFile'; import { isEventPlugin } from './readyEvent'; -import { P, match } from 'ts-pattern'; +import { match, P } from 'ts-pattern'; import { SernError } from '../structures/errors'; -import { correctModuleType } from './observableHandling'; +import Context from '../structures/context'; +import type { Result } from 'ts-results'; +import type { PluggedModule } from '../structures/modules/module'; +import { CommandType, controller } from '../sern'; +import type { EventPlugin } from '../plugins/plugin'; +function applicationCommandHandler< + T extends CommandType.Both | CommandType.MenuUser | CommandType.MenuMsg | CommandType.Slash, +>(mod: PluggedModule | undefined, interaction: CommandInteraction) { + if (mod === undefined) { + return throwError(() => SernError.UndefinedModule); + } + const eventPlugins = mod.plugins.filter(isEventPlugin); + return match(interaction) + .when( + i => i.isChatInputCommand(), + (i: ChatInputCommandInteraction) => { + const ctx = Context.wrap(i); + const res = eventPlugins.map((e: EventPlugin) => { + if (![CommandType.Slash, CommandType.Both].includes(e.modType)) { + return throwError(() => SernError.NonValidModuleType); + } + return e.execute([ctx, ['slash', i.options]], controller); + }) as Awaited>[]; + //Possible unsafe cast + // could result in the promises not being resolved + return of({ res, mod, ctx }); + }, + ) + .when( + () => P._, + (i: MessageCtxInt | UserCtxInt) => { + // const res = eventPlugins.map(e => { + // + // + // }); + return of({}); + }, + ) + .run(); +} +export const onInteractionCreate = (wrapper: Wrapper) => { + const { client } = wrapper; -export const onInteractionCreate = ( wrapper : Wrapper ) => { - const { client } = wrapper; + const interactionEvent$ = >fromEvent(client, 'interactionCreate'); - const interactionEvent$ = (> fromEvent(client, 'interactionCreate')); + interactionEvent$ + .pipe( + concatMap(interaction => { + if (interaction.isCommand()) { + const modul = + Files.ApplicationCommandStore[interaction.commandType].get(interaction.commandName) ?? + Files.BothCommand.get(interaction.commandName); + return applicationCommandHandler(modul, interaction); + } + return of({}); + }), + ) + .subscribe(console.log); - interactionEvent$.pipe( - concatMap( interaction => { - if(interaction.isCommand()) { - const modul = - Files.ApplicationCommandStore[interaction.commandType].get(interaction.commandName) - ?? Files.BothCommand.get(interaction.commandName); - return of(modul).pipe( - map ( plug => { - console.log('a'); - if(plug === undefined) { - return throwError(() => SernError.UndefinedModule); - } - const eventPlugins = plug.plugins.filter(isEventPlugin); - match(interaction) - .when(i => i.isChatInputCommand(), (i : ChatInputCommandInteraction) => { - console.log('chatI', eventPlugins); - }) - .when(() => P._, i => { - console.log('other I', eventPlugins); - }); - }) - ); - } - return of(null); - }) - ).subscribe(console.log); - - - -/** concatMap (async interaction => { + /** concatMap (async interaction => { if (interaction.isChatInputCommand()) { return of(Files.Commands.get(interaction.commandName)) .pipe( @@ -89,7 +117,7 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { else return of(); }) - ).subscribe({ + ).subscribe({ error(e){ throw e; }, @@ -98,6 +126,5 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { //console.log(command); }, }); - **/ + **/ }; - diff --git a/src/handler/events/messageEvent.ts b/src/handler/events/messageEvent.ts index 9916b89..96ba638 100644 --- a/src/handler/events/messageEvent.ts +++ b/src/handler/events/messageEvent.ts @@ -1,64 +1,64 @@ import type { Message } from 'discord.js'; -import { fromEvent, Observable, of, concatMap, map, from, filter, concatAll, tap } from 'rxjs'; -import { Err, Ok } from 'ts-results'; +import { concatMap, from, fromEvent, map, Observable, of } from 'rxjs'; +import { Err } from 'ts-results'; import type { Args } from '../..'; -import { CommandType } from '../sern'; +import { CommandType, controller } from '../sern'; import Context from '../structures/context'; import type Wrapper from '../structures/wrapper'; import { fmt } from '../utilities/messageHelpers'; import * as Files from '../utilities/readFile'; -import { filterCorrectModule, ignoreNonBot, correctModuleType } from './observableHandling'; +import { filterCorrectModule, ignoreNonBot } from './observableHandling'; import { isEventPlugin } from './readyEvent'; -export const onMessageCreate = (wrapper : Wrapper) => { +export const onMessageCreate = (wrapper: Wrapper) => { const { client, defaultPrefix } = wrapper; if (defaultPrefix === undefined) return; - const messageEvent$ = (> fromEvent( client, 'messageCreate')); + const messageEvent$ = >fromEvent(client, 'messageCreate'); const processMessage$ = messageEvent$.pipe( ignoreNonBot(defaultPrefix), map(message => { const [prefix, ...rest] = fmt(message, defaultPrefix); return { - ctx : Context.wrap(message), //TODO : check for BothCommand - args : ['text', rest], - mod : Files.ApplicationCommandStore[1].get(prefix) - ?? Files.BothCommand.get(prefix) - ?? Files.TextCommandStore.aliases.get(prefix) + ctx: Context.wrap(message), //TODO : check for BothCommand + args: ['text', rest], + mod: + Files.ApplicationCommandStore[1].get(prefix) ?? + Files.BothCommand.get(prefix) ?? + Files.TextCommandStore.aliases.get(prefix), }; - })); + }), + ); const ensureModuleType$ = processMessage$.pipe( - concatMap(payload => of(payload.mod) - .pipe( + concatMap(payload => + of(payload.mod).pipe( filterCorrectModule(CommandType.Text), // fix for BothCommand - map( textCommand => ({ ...payload, mod : textCommand })) - ))); + map(textCommand => ({ ...payload, mod: textCommand })), + ), + ), + ); const processEventPlugins$ = ensureModuleType$.pipe( - concatMap( ({ctx, args, mod:plugged}) => { - const eventPlugins = plugged.plugins.filter(isEventPlugin); - const res = Promise.all(eventPlugins.map(ePlug => { - if((ePlug.modTy & plugged.mod.type) === 0) { + concatMap(({ ctx, args, mod: plugged }) => { + const eventPlugins = plugged.plugins.filter(isEventPlugin); + const res = Promise.all( + eventPlugins.map(ePlug => { + if ((ePlug.modType & plugged.mod.type) === 0) { return Err.EMPTY; } - return ePlug.execute([ctx, args], { - next : () => Ok.EMPTY, - stop : () => Err.EMPTY - }); - })); - return from(res).pipe(map(res => ({ plugged, ctx, args, res }))); - })); - - processEventPlugins$.subscribe( ( { plugged, ctx, args, res } ) => { - if(res.every( pl => pl.ok)) { - Promise.resolve(plugged.mod.execute(ctx, args)).then(() => - console.log(plugged) + return ePlug.execute([ctx, args], controller); + }), ); - } - else { + return from(res).pipe(map(res => ({ plugged, ctx, args, res }))); + }), + ); + + processEventPlugins$.subscribe(({ plugged, ctx, args, res }) => { + if (res.every(pl => pl.ok)) { + Promise.resolve(plugged.mod.execute(ctx, args)).then(() => console.log(plugged)); + } else { console.log(plugged, 'failed'); } - }); }; diff --git a/src/handler/events/observableHandling.ts b/src/handler/events/observableHandling.ts index 2a1c812..875e082 100644 --- a/src/handler/events/observableHandling.ts +++ b/src/handler/events/observableHandling.ts @@ -1,43 +1,42 @@ -import type { Awaitable, InteractionType, Message } from 'discord.js'; +import type { Message } from 'discord.js'; import { Observable, throwError } from 'rxjs'; import type { ModuleDefs } from '../structures/modules/commands/moduleHandler'; import { SernError } from '../structures/errors'; import { isNotFromBot } from '../utilities/messageHelpers'; import type { PluggedModule } from '../structures/modules/module'; -import type { EventPlugin, SernPlugin } from '../plugins/plugin'; - +import type { SernPlugin } from '../plugins/plugin'; export function correctModuleType( - plug: PluggedModule | undefined, type : T -) : plug is { mod: ModuleDefs[T], plugins : SernPlugin[] } { + plug: PluggedModule | undefined, + type: T, +): plug is { mod: ModuleDefs[T]; plugins: SernPlugin[] } { return plug !== undefined && plug.mod.type === type; } -export function filterCorrectModule(cmdType : T) { - return (src : Observable) => - new Observable<{ mod : ModuleDefs[T], plugins : SernPlugin[] }>( subscriber => { - return src.subscribe({ +export function filterCorrectModule(cmdType: T) { + return (src: Observable) => + new Observable<{ mod: ModuleDefs[T]; plugins: SernPlugin[] }>(subscriber => { + return src.subscribe({ next(plug) { - if(correctModuleType(plug, cmdType)) { - subscriber.next({ mod : plug.mod, plugins : plug.plugins }); + if (correctModuleType(plug, cmdType)) { + subscriber.next({ mod: plug.mod, plugins: plug.plugins }); } else { - if (plug === undefined) { - return throwError(() => SernError.UndefinedModule); - } - return throwError(() => SernError.MismatchModule); + if (plug === undefined) { + return throwError(() => SernError.UndefinedModule); + } + return throwError(() => SernError.MismatchModule); } }, - error: (e) => subscriber.error(e), - complete: () => subscriber.complete() + error: e => subscriber.error(e), + complete: () => subscriber.complete(), }); - }); + }); } - /** export function filterTap( - cmdType : T, - tap: (mod : ModuleDefs[T], plugins : EventPlugin[]) => Awaitable -) { + cmdType : T, + tap: (mod : ModuleDefs[T], plugins : EventPlugin[]) => Awaitable + ) { return (src : Observable) => new Observable( subscriber => { return src.subscribe({ @@ -58,45 +57,35 @@ export function filterCorrectModule(cmdType : T) { }); }); } -**/ -export function ignoreNonBot(prefix : string) { - return (src : Observable) => + **/ +export function ignoreNonBot(prefix: string) { + return (src: Observable) => new Observable(subscriber => { - return src.subscribe({ - next(m) { - const passAll = [ - isNotFromBot, - (m : Message) => - m.content - .slice(0,prefix.length) - .localeCompare(prefix, - undefined, { sensitivity : 'accent' } - ) === 0 - ].every( fn => fn(m)); + return src.subscribe({ + next(m) { + const passAll = [ + isNotFromBot, + (m: Message) => + m.content + .slice(0, prefix.length) + .localeCompare(prefix, undefined, { sensitivity: 'accent' }) === 0, + ].every(fn => fn(m)); - if (passAll) { - subscriber.next(m); - } - }, - error: (e) => subscriber.error(e), - complete: () => subscriber.complete() + if (passAll) { + subscriber.next(m); + } + }, + error: e => subscriber.error(e), + complete: () => subscriber.complete(), }); - }); + }); } -export function partition( - condition : (el : T) => el is U, - array : T[] -) : [ U[], T[] ] { - const uArr : U[] = []; - const vArr : T[] = []; - for (const el of array ) { +export function partition(condition: (el: T) => el is U, array: T[]): [U[], T[]] { + const uArr: U[] = []; + const vArr: T[] = []; + for (const el of array) { (condition(el) ? uArr : vArr).push(el); } - return [ uArr, vArr ]; + return [uArr, vArr]; } - - - - - diff --git a/src/handler/events/readyEvent.ts b/src/handler/events/readyEvent.ts index ba4ab0e..140f352 100644 --- a/src/handler/events/readyEvent.ts +++ b/src/handler/events/readyEvent.ts @@ -1,115 +1,115 @@ -import {concatMap, from, fromEvent, map, take,concat, skip, Observable, of, } from 'rxjs'; +import { concat, concatMap, from, fromEvent, map, Observable, of, skip, take } from 'rxjs'; import { basename } from 'path'; import * as Files from '../utilities/readFile'; import type Wrapper from '../structures/wrapper'; -import type { HandlerCallback, ModuleHandlers, ModuleStates, ModuleType} from '../structures/modules/commands/moduleHandler'; +import type { + HandlerCallback, + ModuleHandlers, + ModuleStates, + ModuleType, +} from '../structures/modules/commands/moduleHandler'; import { CommandType } from '../sern'; import { CommandPlugin, EventPlugin, PluginType, SernPlugin } from '../plugins/plugin'; -import { correctModuleType, partition } from './observableHandling'; +import { partition } from './observableHandling'; import { Err, Ok, Result } from 'ts-results'; import type { PluggedModule } from '../structures/modules/module'; import type { Awaitable } from 'discord.js'; -export const onReady = ( wrapper : Wrapper ) => { - +export const onReady = (wrapper: Wrapper) => { const { client, commands } = wrapper; - const ready$ = fromEvent(client, 'ready').pipe(take(1),skip(1)); - const processCommandFiles$ = Files.buildData(commands).pipe( - map(({plugged, absPath}) => { - const name = plugged.mod?.name ?? Files.fmtFileName(basename(absPath)); - if (plugged.mod?.name === undefined ) { - return { mod: { name, ...plugged.mod }, plugins : plugged.plugins }; - } - return plugged; - })); - const processPlugins$ = processCommandFiles$.pipe( - concatMap( ({mod, plugins:allPlugins}) => { - const [ cmdPlugins, eventPlugins ] = partition(isCmdPlugin, allPlugins); - const cmdPluginsRes = cmdPlugins.map(plug => { - return { - ...plug, - name: plug?.name ?? 'Unnamed Plugin', - execute : plug.execute(client, mod, { - next : () => Ok.EMPTY, - stop : () => Err.EMPTY - }) - }; - }); - return of({ plugged : { mod , plugins : eventPlugins }, cmdPluginsRes }); - }), - ); + const ready$ = fromEvent(client, 'ready').pipe(take(1), skip(1)); + const processCommandFiles$ = Files.buildData(commands).pipe( + map(({ plugged, absPath }) => { + const name = plugged.mod?.name ?? Files.fmtFileName(basename(absPath)); + if (plugged.mod?.name === undefined) { + return { mod: { name, ...plugged.mod }, plugins: plugged.plugins }; + } + return plugged; + }), + ); + const processPlugins$ = processCommandFiles$.pipe( + concatMap(({ mod, plugins: allPlugins }) => { + const [cmdPlugins, eventPlugins] = partition(isCmdPlugin, allPlugins); + const cmdPluginsRes = cmdPlugins.map(plug => { + return { + ...plug, + name: plug?.name ?? 'Unnamed Plugin', + execute: plug.execute(client, mod, { + next: () => Ok.EMPTY, + stop: () => Err.EMPTY, + }), + }; + }); + return of({ plugged: { mod, plugins: eventPlugins }, cmdPluginsRes }); + }), + ); - - (concat(ready$,processPlugins$) as Observable<{ - plugged: PluggedModule; - cmdPluginsRes: { - execute: Awaitable>; - type: PluginType.Command; - name: string; - description: string; - }[]; - }>).pipe ( - concatMap( pl => - from(Promise.all(pl.cmdPluginsRes.map(async e=> ({...e, execute : await e.execute })))) - .pipe( - map(res => ({...pl, cmdPluginsRes : res })), - ) - ), -) - .subscribe(({ plugged, cmdPluginsRes }) => { - const loadedPluginsCorrectly = cmdPluginsRes.every(res => res.execute.ok); - const { mod, plugins } = plugged; - if(loadedPluginsCorrectly) { - registerModule(mod.name!, mod, plugins); - } - else { - console.log(`Failed to load command ${mod.name!}`); - console.log(mod); - } - }); - + ( + concat(ready$, processPlugins$) as Observable<{ + plugged: PluggedModule; + cmdPluginsRes: { + execute: Awaitable>; + type: PluginType.Command; + name: string; + description: string; + }[]; + }> + ) + .pipe( + concatMap(pl => + from(Promise.all(pl.cmdPluginsRes.map(async e => ({ ...e, execute: await e.execute })))).pipe( + map(res => ({ ...pl, cmdPluginsRes: res })), + ), + ), + ) + .subscribe(({ plugged, cmdPluginsRes }) => { + const loadedPluginsCorrectly = cmdPluginsRes.every(res => res.execute.ok); + const { mod, plugins } = plugged; + if (loadedPluginsCorrectly) { + registerModule(mod.name!, mod, plugins); + } else { + console.log(`Failed to load command ${mod.name!}`); + console.log(mod); + } + }); }; -function handler( name : string ) : ModuleHandlers { - return { - [CommandType.Text] : (mod, plugins) => { - mod.alias.forEach ( a => Files.TextCommandStore.aliases.set(a,{ mod, plugins})); - Files.TextCommandStore.text.set( name, { mod, plugins } ); +function handler(name: string): ModuleHandlers { + return { + [CommandType.Text]: (mod, plugins) => { + mod.alias.forEach(a => Files.TextCommandStore.aliases.set(a, { mod, plugins })); + Files.TextCommandStore.text.set(name, { mod, plugins }); }, [CommandType.Slash]: (mod, plugins) => { - Files.ApplicationCommandStore[1].set( name , { mod, plugins }); + Files.ApplicationCommandStore[1].set(name, { mod, plugins }); }, - [CommandType.Both] :( mod, plugins )=> { - Files.BothCommand.set ( name,{ mod, plugins}); - mod.alias.forEach (a => Files.TextCommandStore.aliases.set(a, {mod,plugins})); + [CommandType.Both]: (mod, plugins) => { + Files.BothCommand.set(name, { mod, plugins }); + mod.alias.forEach(a => Files.TextCommandStore.aliases.set(a, { mod, plugins })); }, - [CommandType.MenuUser] : (mod, plugins) => { - Files.ApplicationCommandStore[2].set ( name, {mod, plugins} ); + [CommandType.MenuUser]: (mod, plugins) => { + Files.ApplicationCommandStore[2].set(name, { mod, plugins }); }, - [CommandType.MenuMsg] : (mod,plugins) => { - Files.ApplicationCommandStore[3].set (name, {mod, plugins} ); + [CommandType.MenuMsg]: (mod, plugins) => { + Files.ApplicationCommandStore[3].set(name, { mod, plugins }); }, - [CommandType.Button] : (mod,plugins) => { - Files.MessageCompCommandStore[2].set(name, {mod, plugins}); + [CommandType.Button]: (mod, plugins) => { + Files.MessageCompCommandStore[2].set(name, { mod, plugins }); }, - [CommandType.MenuSelect] : ( mod, plugins ) => { + [CommandType.MenuSelect]: (mod, plugins) => { Files.MessageCompCommandStore[2].set(name, { mod, plugins }); }, }; - } - -function isCmdPlugin (p : SernPlugin) : p is CommandPlugin { +function isCmdPlugin(p: SernPlugin): p is CommandPlugin { return (p.type & PluginType.Command) !== 0; } -export function isEventPlugin( p : SernPlugin) : p is EventPlugin { + +export function isEventPlugin(p: SernPlugin): p is EventPlugin { return (p.type & PluginType.Event) !== 0; } -function registerModule ( - name : string, - mod : ModuleStates[T], - plugins : SernPlugin[] -) { - return (> handler(name)[mod.type])(mod, plugins); + +function registerModule(name: string, mod: ModuleStates[T], plugins: SernPlugin[]) { + return (>handler(name)[mod.type])(mod, plugins); } diff --git a/src/handler/plugins/plugin.ts b/src/handler/plugins/plugin.ts index 7b97c92..768ce53 100644 --- a/src/handler/plugins/plugin.ts +++ b/src/handler/plugins/plugin.ts @@ -1,11 +1,11 @@ // // Plugins can be inserted on all commands and are emitted // -// 1.) on ready event, where all commands are loaded. +// 1.) on ready event, where all commands are loaded. // 2.) on corresponding observable (command triggers) -// -// The goal of plugins is to organize commands and -// provide extensions to repetitive patterns +// +// The goal of plugins is to organize commands and +// provide extensions to repetitive patterns // examples include refreshing modules, // categorizing commands, cooldowns, permissions, etc // Plugins are reminisce of middleware in express. @@ -20,62 +20,50 @@ import type { BaseModule, PluggedModule } from '../structures/modules/module'; export enum PluginType { Command = 0b01, - Event = 0b10 + Event = 0b10, } export interface Controller { - next : () => Ok, - stop : () => Err - + next: () => Ok; + stop: () => Err; } -type executeCmdPlugin = { execute : ( wrapper : Wrapper, controller : Controller ) => Result } +type executeCmdPlugin = { execute: (wrapper: Wrapper, controller: Controller) => Result }; -interface BasePlugin extends Override{ - type : PluginType +interface BasePlugin extends Override { + type: PluginType; } export type CommandPlugin = { - type : PluginType.Command -} & Override Awaitable> -}>; + type: PluginType.Command; +} & Override< + BasePlugin, + { + execute: (wrapper: Client, module: Module, controller: Controller) => Awaitable>; + } +>; -export type EventPlugin = { - type : PluginType.Event, - modTy : T -} & Override, controller: Controller ) => Awaitable> -}>; +//TODO: rn adding the modType check a little hackish. Find better way to determine the +// module type of the event plugin +export type EventPlugin = { + type: PluginType.Event; + modType: T; +} & Override< + BasePlugin, + { + execute: (event: Parameters, controller: Controller) => Awaitable>; + } +>; -export type SernPlugin = - CommandPlugin - | EventPlugin; +export type SernPlugin = CommandPlugin | EventPlugin; -export function commmand(plug : CommandPlugin) { +export function plugins | CommandPlugin>(...plug: V[]) { return plug; } -export function event(plug : EventPlugin) { - return plug; +export function sernModule(plugins: { command: CommandPlugin[]; onEvent: EventPlugin[] }, mod: Module): PluggedModule { + return { + mod, + plugins: [...plugins.command, ...plugins.onEvent], + }; } - -export function apply(...plugins: SernPlugin[]) { - return plugins; -} - -export function sernModule - (plugins : SernPlugin[], mod : Module ) : PluggedModule { - return { - mod, - plugins - }; -} - - - - - - diff --git a/src/handler/sern.ts b/src/handler/sern.ts index 622c72f..c143fe8 100644 --- a/src/handler/sern.ts +++ b/src/handler/sern.ts @@ -1,11 +1,6 @@ -import type { - DiscordEvent, -} from '../types/handler'; +import type { DiscordEvent } from '../types/handler'; -import { - ApplicationCommandType, - Client, -} from 'discord.js'; +import { ApplicationCommandType, Client } from 'discord.js'; import type Wrapper from './structures/wrapper'; import { fromEvent } from 'rxjs'; @@ -13,47 +8,51 @@ import { SernError } from './structures/errors'; import { onReady } from './events/readyEvent'; import { onMessageCreate } from './events/messageEvent'; import { onInteractionCreate } from './events/interactionCreate'; -import { match } from 'ts-pattern'; -import { P } from 'ts-pattern'; -import { Sern } from '..'; +import { match, P } from 'ts-pattern'; +import { Err, Ok } from 'ts-results'; -export function init( wrapper : Wrapper ) { - const { events, client } = wrapper; - if (events !== undefined) eventObserver(client, events); - onReady( wrapper ); - onMessageCreate( wrapper ); - onInteractionCreate ( wrapper ); +export function init(wrapper: Wrapper) { + const { events, client } = wrapper; + if (events !== undefined) eventObserver(client, events); + onReady(wrapper); + onMessageCreate(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.ReservedEvent); - fromEvent(client, event, cb).subscribe(); - }); +function eventObserver(client: Client, events: DiscordEvent[]) { + events.forEach(([event, cb]) => { + if (event === 'ready') throw Error(SernError.ReservedEvent); + fromEvent(client, event, cb).subscribe(); + }); } /** * @enum { number }; */ export enum CommandType { - Text = 0b0000001, - Slash = 0b0000010, - MenuUser = 0b0000100, - MenuMsg = 0b0001000, - Button = 0b0010000, + Text = 0b0000001, + Slash = 0b0000010, + MenuUser = 0b0000100, + MenuMsg = 0b0001000, + Button = 0b0010000, MenuSelect = 0b0100000, - Both = 0b0000011, + Both = 0b0000011, } export function cmdTypeToDjs(ty: CommandType) { - return match(ty) - .with(CommandType.Slash, () => ApplicationCommandType.ChatInput) - .with(CommandType.MenuUser, () => ApplicationCommandType.User) - .with(CommandType.MenuMsg, ()=> ApplicationCommandType.Message) - .with(CommandType.Both, () => ApplicationCommandType.ChatInput ) - .with(P._, () => { throw new Error(SernError.NonValidModuleType); }) - .exhaustive(); + return match(ty) + .with(CommandType.Slash, () => ApplicationCommandType.ChatInput) + .with(CommandType.MenuUser, () => ApplicationCommandType.User) + .with(CommandType.MenuMsg, () => ApplicationCommandType.Message) + .with(CommandType.Both, () => ApplicationCommandType.ChatInput) + .with(P._, () => { + throw new Error(SernError.NonValidModuleType); + }) + .exhaustive(); } - +export const controller = { + next: () => Ok.EMPTY, + stop: () => Err.EMPTY, +}; diff --git a/src/handler/structures/modules/commands/moduleHandler.ts b/src/handler/structures/modules/commands/moduleHandler.ts index 9a85a2c..52a5afb 100644 --- a/src/handler/structures/modules/commands/moduleHandler.ts +++ b/src/handler/structures/modules/commands/moduleHandler.ts @@ -1,36 +1,33 @@ import type { SernPlugin } from '../../../plugins/plugin'; import { CommandType } from '../../../sern'; -import type { - TextCommand, +import type { BothCommand, ButtonCommand, - SlashCommand, - ContextMenuMsg, + ContextMenuMsg, ContextMenuUser, - SelectMenuCommand -} from './module'; + SelectMenuCommand, + SlashCommand, + TextCommand, +} 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.MenuMsg] : ContextMenuMsg; - [CommandType.MenuUser] : ContextMenuUser; - [CommandType.Button] : ButtonCommand; - [CommandType.MenuSelect] : 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 export type ModuleType = keyof ModuleDefs; // The keys mapped to a constructed union with its type -export type ModuleStates = { - [ K in ModuleType ] : { type : K } & ModuleDefs[K] +export type ModuleStates = { + [K in ModuleType]: { type: K } & ModuleDefs[K]; }; -// A handler callback that is called on each ModuleDef -export type HandlerCallback = - ( mod: ModuleStates[K], plugins : SernPlugin[] ) => unknown; +// A handler callback that is called on each ModuleDef +export type HandlerCallback = (mod: ModuleStates[K], plugins: SernPlugin[]) => unknown; //An object that acts as the mapped object to handler -export type ModuleHandlers = { [K in ModuleType] : HandlerCallback }; - +export type ModuleHandlers = { [K in ModuleType]: HandlerCallback }; diff --git a/src/handler/structures/modules/module.ts b/src/handler/structures/modules/module.ts index 5a93758..80e04d7 100644 --- a/src/handler/structures/modules/module.ts +++ b/src/handler/structures/modules/module.ts @@ -1,17 +1,15 @@ -import type { Awaitable, ChatInputCommandInteraction } from 'discord.js'; +import type { Awaitable } from 'discord.js'; import type { Args, Module } from '../../..'; -import type { CommandPlugin, EventPlugin, SernPlugin } from '../../plugins/plugin'; +import type { SernPlugin } from '../../plugins/plugin'; import type Context from '../context'; export interface BaseModule { - name? : string; - description : string; + name?: string; + description: string; execute: (ctx: Context, args: Args) => Awaitable; } export interface PluggedModule { - mod : Module; - plugins : SernPlugin[]; + mod: Module; + plugins: SernPlugin[]; } - -