feat: Add more plugin definitions

This commit is contained in:
Jacob Nguyen
2022-06-26 23:04:36 -05:00
parent c3b16b43ce
commit 1b447e3c4f
5 changed files with 145 additions and 86 deletions

View File

@@ -11,21 +11,18 @@
* Plugins are reminiscent of middleware in express.
*/
import type { Awaitable, Client } from 'discord.js';
import type { AutocompleteInteraction, Awaitable, Client, ClientEvents } from 'discord.js';
import type { Err, Ok, Result } from 'ts-results';
import type { DefinitelyDefined, Module, Override } from '../..';
import type { CommandType } from '../..';
import type {
BaseModule,
EventModule,
CommandModuleDefs,
CommandModule,
} from '../structures/module';
import { PluginType } from '../structures/enums';
import type { CommandType, DefinitelyDefined, Override, SernEventsMapping } from '../..';
import { EventType, PluginType } from '../..';
import type { BaseModule, CommandModuleDefs, EventModuleDefs } from '../structures/module';
import type { EventEmitter } from 'events';
import type { ExternalEventCommand, SernEventCommand } from '../structures/events';
import type {
DiscordEventCommand,
ExternalEventCommand,
SernEventCommand,
} from '../structures/events';
import type SernEmitter from '../sernEmitter';
import type { AutocompleteInteraction } from 'discord.js';
export interface Controller {
next: () => Ok<void>;
@@ -53,6 +50,17 @@ export type CommandPlugin<T extends keyof CommandModuleDefs = keyof CommandModul
>;
}[T];
export type DiscordEmitterPlugin = Override<
BasePlugin,
{
type: PluginType.Command;
execute: (
wrapper: Client,
module: DefinitelyDefined<DiscordEventCommand, 'name' | 'description'>,
controller: Controller,
) => Awaitable<Result<void, void>>;
}
>;
export type ExternalEmitterPlugin<T extends EventEmitter = EventEmitter> = Override<
BasePlugin,
{
@@ -84,7 +92,7 @@ export type AutocompletePlugin = Override<
execute: (
autocmp: AutocompleteInteraction,
controlller: Controller,
) => Awaitable<void | unknown>;
) => Awaitable<Result<void, void>>;
}
>;
@@ -101,77 +109,74 @@ export type EventPlugin<T extends keyof CommandModuleDefs = keyof CommandModuleD
>;
}[T];
// Syntactic sugar on hold
// export function plugins<T extends keyof ModuleDefs>(
// ...plug: (EventPlugin<T> | CommandPlugin<T>)[]
// ) {
// return plug;
// }
export type SernEventPlugin<T extends keyof SernEventsMapping = keyof SernEventsMapping> = Override<
BasePlugin,
{
name?: T;
type: PluginType.Event;
execute: (
args: SernEventsMapping[T],
controller: Controller,
) => Awaitable<Result<void, void>>;
}
>;
export type ModuleNoPlugins = {
[T in keyof CommandModuleDefs]: Omit<CommandModuleDefs[T], 'plugins' | 'onEvent'>;
export type ExternalEventPlugin = Override<
BasePlugin,
{
type: PluginType.Event;
execute: (args: unknown[], controller: Controller) => Awaitable<Result<void, void>>;
}
>;
export type DiscordEventPlugin<T extends keyof ClientEvents = keyof ClientEvents> = Override<
BasePlugin,
{
name?: T;
type: PluginType.Event;
execute: (args: ClientEvents[T], controller: Controller) => Awaitable<Result<void, void>>;
}
>;
export type CommandModuleNoPlugins = {
[T in CommandType]: Omit<CommandModuleDefs[T], 'plugins' | 'onEvent'>;
};
export type EventModulesNoPlugins = {
[T in EventType]: Omit<EventModuleDefs[T], 'plugins' | 'onEvent'>;
};
/**
* Event Module Event Plugins
*/
export type EventModuleEventPluginDefs = {
[EventType.Discord]: DiscordEventPlugin;
[EventType.Sern]: SernEventPlugin;
[EventType.External]: ExternalEventPlugin;
};
function isEventPlugin<T extends CommandType>(
e: CommandPlugin<T> | EventPlugin<T>,
): e is EventPlugin<T> {
return e.type === PluginType.Event;
}
function isCommandPlugin<T extends CommandType>(
e: CommandPlugin<T> | EventPlugin<T>,
): e is CommandPlugin<T> {
return !isEventPlugin(e);
}
/**
* Event Module Command Plugins
*/
export type EventModuleCommandPluginDefs = {
[EventType.Discord]: DiscordEmitterPlugin;
[EventType.Sern]: SernEmitterPlugin;
[EventType.External]: ExternalEmitterPlugin;
};
export type EventModulePlugin<T extends EventType> =
| EventModuleEventPluginDefs[T]
| EventModuleCommandPluginDefs[T];
export type CommandModulePlugin<T extends CommandType> = EventPlugin<T> | CommandPlugin<T>;
//TODO: I WANT BETTER TYPINGS AHHHHHHHHHHHHHHH
// Maybe add overlaods
export function sernModule<T extends CommandType.Slash = CommandType.Slash>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.Slash],
): Module;
export function sernModule<T extends CommandType.Text = CommandType.Text>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.Text],
): Module;
export function sernModule<T extends CommandType.Button = CommandType.Button>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.Button],
): Module;
export function sernModule<T extends CommandType.Both = CommandType.Both>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.Both],
): Module;
export function sernModule<T extends CommandType.MenuUser = CommandType.MenuUser>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.MenuMsg],
): Module;
export function sernModule<T extends CommandType.MenuSelect = CommandType.MenuSelect>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.MenuSelect],
): Module;
/**
* User inputs this type. Sern processes behind the scenes for better usage
*/
export type InputCommandModule = {
[T in CommandType]: CommandModuleNoPlugins[T] & { plugins?: CommandModulePlugin<T>[] };
}[CommandType];
export function sernModule<T extends CommandType.Modal = CommandType.Modal>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.Modal],
): Module;
export function sernModule<T extends CommandType.MenuUser = CommandType.MenuUser>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[CommandType.MenuUser],
): Module;
export function sernModule<T extends keyof CommandModuleDefs = keyof CommandModuleDefs>(
plugin: (CommandPlugin<T> | EventPlugin<T>)[],
mod: ModuleNoPlugins[T],
): CommandModule {
const onEvent = plugin.filter(isEventPlugin);
const plugins = plugin.filter(isCommandPlugin);
return {
onEvent,
plugins,
...mod,
} as CommandModule;
}
export function eventModule<T extends keyof EventModule>(): EventModule {
return {} as EventModule;
}
export type InputEventModule = {
[T in EventType]: EventModulesNoPlugins[T] & { plugins?: EventModulePlugin<T>[] };
}[EventType];

View File

@@ -6,6 +6,16 @@ import { Err, Ok } from 'ts-results';
import { ExternalEventEmitters } from './utilities/readFile';
import type { EventEmitter } from 'events';
import { processEvents } from './events/userDefinedEventsHandling';
import type { CommandModule, EventModule } from './structures/module';
import { EventType, PluginType } from './structures/enums';
import type {
CommandPlugin,
EventModuleCommandPluginDefs,
EventModuleEventPluginDefs,
EventPlugin,
InputCommandModule,
InputEventModule,
} from './plugins/plugin';
/**
*
@@ -27,7 +37,7 @@ export function init(wrapper: Wrapper) {
* @param emitter Any external event emitter.
* The object will be stored in a map, and then fetched by the name of the emitter provided.
* As there are infinite possibilities to adding external event emitters,
* Most types arent provided and are as narrow as possibly can.
* Most types aren't provided and are as narrow as possibly can.
*/
export function addExternal<T extends EventEmitter>(emitter: T) {
if (ExternalEventEmitters.has(emitter.constructor.name)) {
@@ -40,3 +50,38 @@ export const controller = {
next: () => Ok.EMPTY,
stop: () => Err.EMPTY,
};
export function commandModule(mod: InputCommandModule): CommandModule {
const onEvent: EventPlugin[] = [];
const plugins: CommandPlugin[] = [];
for (const pl of mod.plugins ?? []) {
if (pl.type === PluginType.Event) {
onEvent.push(pl);
} else {
plugins.push(pl as CommandPlugin);
}
}
return {
...mod,
onEvent,
plugins,
} as CommandModule;
}
export function eventModule(mod: InputEventModule): EventModule {
const onEvent: EventModuleEventPluginDefs[EventType][] = [];
const plugins: EventModuleCommandPluginDefs[EventType][] = [];
for (const pl of mod.plugins ?? []) {
if (pl.type === PluginType.Event) {
onEvent.push(pl);
} else {
plugins.push(pl);
}
}
return {
...mod,
onEvent,
plugins,
} as EventModule;
}

View File

@@ -1,7 +1,8 @@
import type { Override, SernEventsMapping } from '../../types/handler';
import type { BaseModule, EventModuleDefs } from './module';
import type { BaseModule } from './module';
import type {
DiscordEmitterPlugin,
DiscordEventPlugin,
ExternalEmitterPlugin,
ExternalEventPlugin,
SernEmitterPlugin,
@@ -26,7 +27,7 @@ export type DiscordEventCommand<T extends keyof ClientEvents = keyof ClientEvent
{
name?: T;
type: EventType.Discord;
onEvent: DiscordEventCommand[];
onEvent: DiscordEventPlugin[];
plugins: DiscordEmitterPlugin[];
execute(...args: ClientEvents[T]): Awaitable<void | unknown>;
}

View File

@@ -88,6 +88,13 @@ export function isExternalEvent(el: EventModule): el is ExternalEventCommand {
return !isDiscordEvent(el) && !isSernEvent(el);
}
export function isEventModule(module: Module): module is EventModule {
return [EventType.Sern, EventType.Discord, EventType.External].includes(module.type);
}
// export function isEventPlugin<T extends CommandType>(
// e: CommandModulePlugin<T>,
// ): e is EventPlugin<T> {
// return e.type === PluginType.Event;
// }
// export function isCommandPlugin<T extends CommandType>(
// e: CommandModulePlugin<T>,
// ): e is CommandPlugin<T> {
// return !isEventPlugin(e);
// }

View File

@@ -1,4 +1,5 @@
import SernEmitter from './handler/sernEmitter';
export { eventModule, commandModule } from './handler/sern';
export * as Sern from './handler/sern';
export * from './types/handler';
export * from './handler/structures/structxports';