fix: Non-exhaustiveness led to commands not registering readyEvent.ts

This commit is contained in:
Jacob Nguyen
2022-05-17 11:31:35 -05:00
parent 97907b746f
commit b26650818e
5 changed files with 38 additions and 21 deletions

View File

@@ -21,9 +21,6 @@ import { filterCorrectModule } from './observableHandling';
//TODO : atm, i have to cast for every interaction. is there a way to not cast?
// maybe pass it through an observable
function applicationCommandHandler(mod: Module | undefined, interaction: CommandInteraction) {
if (mod === undefined) {
return throwError(() => SernError.UndefinedModule);
}
const mod$ = <T extends CommandType>(cmdTy : T) => of(mod).pipe(
filterCorrectModule(cmdTy)
);
@@ -33,10 +30,11 @@ function applicationCommandHandler(mod: Module | undefined, interaction: Command
const ctx = Context.wrap(i);
return mod$(CommandType.Slash).pipe(
concatMap(m => {
console.log(m);
return of(m.onEvent.map(e => e.execute(
[ctx, ['slash', i.options]],
controller
))).pipe(map(res => ({ m, res, execute() { m.execute(ctx, ['slash', i.options]); } }) ));
))).pipe(map(res => ({ m, res, execute() { return m.execute(ctx, ['slash', i.options]); } }) ));
}),
);
},
@@ -49,7 +47,7 @@ function applicationCommandHandler(mod: Module | undefined, interaction: Command
return of(m.onEvent.map(e => e.execute(
[ctx],
controller
))).pipe(map(res => ({ m, res, execute() { m.execute(ctx); } }) ));
))).pipe(map(res => ({ m, res, execute() { return m.execute(ctx); } }) ));
}),
);
},
@@ -60,7 +58,7 @@ function applicationCommandHandler(mod: Module | undefined, interaction: Command
return of(m.onEvent.map(e => e.execute(
[ctx],
controller
))).pipe(map(res => ({ m, res, execute() { m.execute(ctx); } }) ));
))).pipe(map(res => ({ m, res, execute() { return m.execute(ctx); } }) ));
}),
);
})
@@ -71,9 +69,7 @@ function messageComponentInteractionHandler(
mod: Module | undefined,
interaction: MessageComponentInteraction,
) {
if (mod === undefined) {
return throwError(() => SernError.UndefinedModule);
}
const mod$ = <T extends CommandType>(ty : T) => of(mod).pipe( filterCorrectModule(ty));
//Todo: refactor so that we dont have to have two separate branches. They're near identical!!
//Only thing that differs is type of interaction
@@ -84,7 +80,7 @@ function messageComponentInteractionHandler(
return of(m.onEvent.map(e => e.execute(
[ctx],
controller
))).pipe(map(res => ({ m, res, execute() { m.execute(ctx); } }) ));
))).pipe(map(res => ({ m, res, execute() { return m.execute(ctx); } }) ));
}),
);
})
@@ -94,7 +90,7 @@ function messageComponentInteractionHandler(
return of(m.onEvent.map(e => e.execute(
[ctx],
controller
))).pipe(map(res => ({ m, res, execute() { m.execute(ctx); } }) ));
))).pipe(map(res => ({ m, res, execute() { return m.execute(ctx); } }) ));
}),
);
})
@@ -125,10 +121,10 @@ export function onInteractionCreate (wrapper: Wrapper) {
}),
).subscribe({
next({m, res, execute}) {
// execute();
console.log(res);
},
error(err) {
return;
console.log(err);
}
});

View File

@@ -1,5 +1,5 @@
import type { Message } from 'discord.js';
import { concatMap, from, fromEvent, map, Observable, of } from 'rxjs';
import { concatMap, filter, from, fromEvent, map, Observable, of } from 'rxjs';
import { Err } from 'ts-results';
import type { Args } from '../..';
import { CommandType, controller } from '../sern';
@@ -32,7 +32,7 @@ export const onMessageCreate = (wrapper: Wrapper) => {
concatMap(payload =>
of(payload.mod).pipe(
filterCorrectModule(CommandType.Text), // fix for BothCommand
map(textCommand => ({ ...payload, mod: textCommand })),
map(mod => ({ ...payload, mod })),
),
),
);

View File

@@ -6,10 +6,13 @@ import type { Module, ModuleDefs } from '../structures/module';
import { correctModuleType } from '../utilities/predicates';
export function filterCorrectModule<T extends keyof ModuleDefs>(cmdType: T) {
return (src: Observable<Module>) =>
return (src: Observable<Module|undefined>) =>
new Observable<ModuleDefs[T]>(subscriber => {
return src.subscribe({
next(mod) {
if (mod === undefined) {
return throwError(() => SernError.UndefinedModule);
}
if (correctModuleType(mod, cmdType)) {
subscriber.next(mod);
} else {

View File

@@ -9,6 +9,8 @@ import type { Awaitable } from 'discord.js';
import type { Module } from '../structures/module';
import { match } from 'ts-pattern';
import { ApplicationCommandType, ComponentType } from 'discord.js';
import { Err, Ok } from 'ts-results';
import { SernError } from '../structures/errors';
export const onReady = (wrapper: Wrapper) => {
const { client, commands } = wrapper;
@@ -56,7 +58,10 @@ export const onReady = (wrapper: Wrapper) => {
.subscribe(({ mod, cmdPluginsRes }) => {
const loadedPluginsCorrectly = cmdPluginsRes.every(res => res.execute.ok);
if (loadedPluginsCorrectly) {
registerModule(mod);
const res = registerModule(mod);
if(res.err) {
throw Error(SernError.NonValidModuleType);
}
} else {
console.log(`Failed to load command ${mod.name!}`);
console.log(mod);
@@ -64,30 +69,38 @@ export const onReady = (wrapper: Wrapper) => {
});
};
function registerModule(mod: Module) {
function registerModule(mod: Module) : Result<void, void> {
const name = mod.name!;
match<Module>(mod)
return match<Module>(mod)
.with({ type: CommandType.Text }, mod => {
mod.alias.forEach(a => Files.TextCommands.aliases.set(a, mod));
Files.TextCommands.text.set(name, mod);
return Ok.EMPTY;
})
.with({ type: CommandType.Slash }, mod => {
Files.ApplicationCommands[ApplicationCommandType.ChatInput].set(name, mod);
return Ok.EMPTY;
})
.with({ type: CommandType.Both }, mod => {
Files.BothCommands.set(name, mod);
mod.alias.forEach(a => Files.TextCommands.aliases.set(a, mod));
return Ok.EMPTY;
})
.with({ type: CommandType.MenuUser }, mod => {
Files.ApplicationCommands[ApplicationCommandType.User].set(name, mod);
return Ok.EMPTY;
})
.with({ type: CommandType.MenuMsg }, mod => {
Files.ApplicationCommands[ApplicationCommandType.Message].set(name, mod);
return Ok.EMPTY;
})
.with({ type: CommandType.Button }, mod => {
Files.ApplicationCommands[ComponentType.Button].set(name, mod);
return Ok.EMPTY;
})
.with({ type: CommandType.MenuSelect }, mod => {
Files.MessageCompCommands[ComponentType.SelectMenu].set(name, mod);
});
return Ok.EMPTY;
})
.otherwise(() => Err.EMPTY);
}

View File

@@ -1,5 +1,5 @@
import type { Module, ModuleDefs } from '../structures/module';
import type { ChatInputCommandInteraction, CommandInteraction } from 'discord.js';
import type { Awaitable, ChatInputCommandInteraction, CommandInteraction } from 'discord.js';
import type { ButtonInteraction, MessageComponentInteraction, SelectMenuInteraction } from 'discord.js';
import type { MessageContextMenuCommandInteraction, UserContextMenuCommandInteraction } from 'discord.js';
@@ -27,4 +27,9 @@ export function isMessageCtxMenuCmd(i : CommandInteraction) : i is MessageContex
export function isUserContextMenuCmd(i : CommandInteraction) : i is UserContextMenuCommandInteraction {
return i.isUserContextMenuCommand();
}
function isPromise<T>(promiseLike : Awaitable<T>) : promiseLike is Promise<T> {
const keys = new Set(Object.keys(promiseLike));
return keys.has('then') && keys.has('catch');
}