refactor: shorten code, add UnionToTuple type

This commit is contained in:
Jacob Nguyen
2022-05-14 19:28:30 -05:00
parent 2697e35b2e
commit 58b7a6c21b
4 changed files with 40 additions and 62 deletions

View File

@@ -5,7 +5,7 @@ import type {
MessageContextMenuCommandInteraction as MessageCtxInt,
UserContextMenuCommandInteraction as UserCtxInt,
} from 'discord.js';
import { concatMap, fromEvent, Observable, of, throwError } from 'rxjs';
import { concatMap, fromEvent, Observable, of, throwError, map } from 'rxjs';
import type Wrapper from '../structures/wrapper';
import * as Files from '../utilities/readFile';
import { isEventPlugin } from './readyEvent';
@@ -15,80 +15,65 @@ import Context from '../structures/context';
import type { Result } from 'ts-results';
import type { PluggedModule } from '../structures/modules/module';
import { CommandType, controller } from '../sern';
import { resolveParameters } from '../utilities/resolveParameters';
import type { Args } from '../../types/handler';
import type { MessageComponentInteraction } from 'discord.js';
import { ButtonInteraction, ComponentType, SelectMenuInteraction } from 'discord.js';
import { ComponentType } from 'discord.js';
import type { UnionToTuple } from '../utilities/resolveParameters';
function applicationCommandHandler<
T extends CommandType.Both | CommandType.MenuUser | CommandType.MenuMsg | CommandType.Slash,
>(mod: PluggedModule | undefined, interaction: CommandInteraction) {
if (mod === undefined) {
function isChatInputCommand(i : CommandInteraction) : i is ChatInputCommandInteraction {
return i.isChatInputCommand();
}
function applicationCommandHandler(plugged: PluggedModule | undefined, interaction: CommandInteraction) {
if (plugged === undefined) {
return throwError(() => SernError.UndefinedModule);
}
const eventPlugins = mod.plugins.filter(isEventPlugin);
const eventPlugins = plugged.plugins.filter(isEventPlugin);
return match(interaction)
.when(
i => i.isChatInputCommand(),
(i: ChatInputCommandInteraction) => {
.when(isChatInputCommand, i => {
const ctx = Context.wrap(i);
const res = eventPlugins.map(e => {
return e.execute(
resolveParameters<CommandType.Both>([ctx, <Args>['slash', i.options]]
), controller);
[ctx, <Args>['slash', i.options]]
, controller);
}) as Awaited<Result<void, void>>[];
//Possible unsafe cast
// could result in the promises not being resolved
return of({ res, mod, ctx });
return of({ type : plugged.mod.type, res, plugged, ctx });
},
)
.when(
() => P._,
(ctx : UserCtxInt | MessageCtxInt) => {
//Kinda hackish
const args : [UserCtxInt] | [MessageCtxInt] = ctx.isUserContextMenuCommand()
? [ ctx as UserCtxInt ] : [ ctx as MessageCtxInt ];
const res = eventPlugins.map(e => {
return e.execute(
resolveParameters<CommandType.MenuMsg | CommandType.MenuUser>(args
), controller);
[ctx] as UnionToTuple<CommandType.MenuMsg | CommandType.MenuUser>
, controller);
}) as Awaited<Result<void, void>>[];
return of({ res, mod, ctx });
return of({ type : plugged.mod.type, res, plugged, ctx });
},
)
.run();
}
function messageComponentInteractionHandler(
mod: PluggedModule | undefined,
plugged: PluggedModule | undefined,
interaction: MessageComponentInteraction,
) {
if (mod === undefined) {
if (plugged === undefined) {
return throwError(() => SernError.UndefinedModule);
}
const eventPlugins = mod.plugins.filter(isEventPlugin);
const eventPlugins = plugged.plugins.filter(isEventPlugin);
return match(interaction)
.with({ componentType : ComponentType.Button }, (i : ButtonInteraction) => {
.with({
componentType : P.union(ComponentType.Button, ComponentType.SelectMenu)
},(ctx ) => {
const res = eventPlugins.map(e => {
return e.execute(resolveParameters<CommandType.Button>([i]), controller);
return e.execute([ctx] as UnionToTuple<CommandType.Button | CommandType.MenuSelect>, controller);
}) as Awaited<Result<void, void>>[];
return of({ res, mod, i});
return of({ type : plugged.mod.type, res, plugged, ctx });
})
.with( { componentType : ComponentType.SelectMenu }, (i : SelectMenuInteraction) => {
const res = eventPlugins.map(e => {
return e.execute(resolveParameters<CommandType.MenuSelect>([i]), controller);
}) as Awaited<Result<void, void>>[];
return of({ res, mod, i});
})
.with( { componentType : ComponentType.TextInput }, _ => {
return throwError(() => SernError.NotImplemented);
} )
.with( { componentType : P._ }, i => {
return throwError(() => SernError.NotSupportedInteraction);
})
.exhaustive();
.otherwise(_ => throwError( () => SernError.NotSupportedInteraction) );
}
export const onInteractionCreate = (wrapper: Wrapper) => {
@@ -98,6 +83,7 @@ export const onInteractionCreate = (wrapper: Wrapper) => {
interactionEvent$
.pipe(
/*processing plugins*/
concatMap(interaction => {
if (interaction.isCommand()) {
const modul =
@@ -111,10 +97,12 @@ export const onInteractionCreate = (wrapper: Wrapper) => {
.get(interaction.customId);
return messageComponentInteractionHandler(modul, interaction);
}
return of({});
else return throwError(() => SernError.NotSupportedInteraction);
}),
)
.subscribe(console.log);
.subscribe(modul => {
});
};

View File

@@ -9,7 +9,6 @@ import { fmt } from '../utilities/messageHelpers';
import * as Files from '../utilities/readFile';
import { filterCorrectModule, ignoreNonBot } from './observableHandling';
import { isEventPlugin } from './readyEvent';
import { resolveParameters } from '../utilities/resolveParameters';
export const onMessageCreate = (wrapper: Wrapper) => {
const { client, defaultPrefix } = wrapper;
@@ -48,7 +47,7 @@ export const onMessageCreate = (wrapper: Wrapper) => {
if ((ePlug.modType & plugged.mod.type) === 0) {
return Err.EMPTY;
}
return ePlug.execute(resolveParameters<CommandType.Both>([ctx, args]), controller);
return ePlug.execute([ctx, args], controller);
}),
);
return from(res).pipe(map(res => ({ plugged, ctx, args, res })));

View File

@@ -31,9 +31,11 @@ export type BothCommand = {
export type ContextMenuUser = {
type: CommandType.MenuUser;
} & Override<BaseModule, { execute: (ctx: UserContextMenuCommandInteraction) => Awaitable<void> }>;
export type ContextMenuMsg = {
type: CommandType.MenuMsg;
} & Override<BaseModule, { execute: (ctx: MessageContextMenuCommandInteraction) => Awaitable<void> }>;
export type ButtonCommand = {
type: CommandType.Button;
} & Override<BaseModule, { execute: (ctx: ButtonInteraction) => Awaitable<void> }>;

View File

@@ -1,18 +1,7 @@
import type { CommandType } from '../sern';
import type { ModuleDefs } from '../structures/modules/commands/moduleHandler';
import type { ParseType } from '../../types/handler';
type ParamMap<T extends CommandType> = {
[K in T] : Parameters<ModuleDefs[K]['execute']>
}[T]
/**
* Identity function x => x to narrow type of parameters
* @param params
*/
export function resolveParameters<T extends CommandType>
( params: ParamMap<T> )
{
return params;
}
export type UnionToTuple<T> = T extends readonly [ infer V, infer S ]
? V extends V
? S extends S
? [ V, S ]
: [ V ]
: never
: never;