mirror of
https://github.com/sern-handler/handler
synced 2026-06-21 07:12:15 +00:00
refactor : change naming conventions to PascalCase
This commit is contained in:
@@ -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;
|
||||
|
||||
(<Observable<Interaction>> 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) {
|
||||
|
||||
@@ -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]);
|
||||
})
|
||||
|
||||
@@ -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<T extends keyof ModuleDefs>(
|
||||
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) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,8 +42,7 @@ const handler = ( name : string ) =>
|
||||
},
|
||||
[CommandType.MENU_SELECT] : mod => {
|
||||
Files.SelectMenus.set(name, mod);
|
||||
}
|
||||
|
||||
},
|
||||
} as ModuleHandlers);
|
||||
|
||||
const registerModules = <T extends ModuleType >(name : string, mod : ModuleStates[T]) =>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T>(...args : Option<T>[]) : Nullish<T> {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
//
|
||||
//Will need refactoring after applying context in practice
|
||||
//
|
||||
export default class Context {
|
||||
|
||||
private constructor(
|
||||
private oMsg: Option<Message> = None,
|
||||
private oInterac: Option<ChatInputCommandInteraction> = 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<GuildMember> {
|
||||
/*
|
||||
* interactions can return APIGuildMember if the guild it is emitted from is not cached
|
||||
*/
|
||||
public get member() : Nullish<GuildMember|APIGuildMember> {
|
||||
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<void>,
|
||||
): 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<void>
|
||||
): Context {
|
||||
this.oMsg.map( onMessage );
|
||||
if (this.oMsg.some) {
|
||||
onMessage(this.oMsg.val);
|
||||
return Context.wrap(this.oMsg.val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public takeInteractionValue<T>(
|
||||
@@ -108,14 +122,28 @@ export default class Context {
|
||||
if(this.oInterac.none) return null;
|
||||
return extract(this.oInterac.val);
|
||||
}
|
||||
|
||||
public takeMessageValue<T>(
|
||||
extract : (message: Message) => T
|
||||
): Nullish<T> {
|
||||
if(this.oMsg.none) return null;
|
||||
return extract(this.oMsg.val);
|
||||
}
|
||||
|
||||
|
||||
public reply(
|
||||
content : Omit<InteractionReplyOptions, 'fetchReply'> | ReplyMessageOptions
|
||||
): Promise<Context> {
|
||||
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);
|
||||
})
|
||||
)!;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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!`
|
||||
}
|
||||
|
||||
@@ -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<void>
|
||||
}
|
||||
//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<BaseModule, { execute : ( ctx: ContextMenuCommandInteraction ) => Awaitable<void> }>;
|
||||
export type ContextMenuMsg = {
|
||||
type : CommandType.MENU_MSG;
|
||||
type : CommandType.MenuMsg;
|
||||
} & Override<BaseModule, { execute : ( ctx: MessageContextMenuCommandInteraction ) => Awaitable<void> }>;
|
||||
export type ButtonCommand = {
|
||||
type : CommandType.BUTTON;
|
||||
type : CommandType.Button;
|
||||
} & Override<BaseModule, { execute : (ctx :ButtonInteraction ) => Awaitable<void> }>;
|
||||
export type SelectMenuCommand = {
|
||||
type : CommandType.MENU_SELECT;
|
||||
type : CommandType.MenuSelect;
|
||||
} & Override<BaseModule, { execute : (ctx : SelectMenuInteraction ) => Awaitable<void> }>;
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -44,7 +44,7 @@ export async function buildData(commandDir: string ): Promise<
|
||||
return Promise.all(
|
||||
getCommands(commandDir).map( async (absPath) => {
|
||||
const mod = <Module> (await import(absPath)).module;
|
||||
if (mod === undefined) throw Error(`${SernError.UNDEFINED_MODULE} ${absPath}`);
|
||||
if (mod === undefined) throw Error(`${SernError.UndefinedModule} ${absPath}`);
|
||||
return { mod, absPath };
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@ export type Args = ParseType<{ text: string[]; slash: SlashOptions }>;
|
||||
export type DiscordEvent =
|
||||
ParseType< { [K in keyof ClientEvents ] : (...args : ClientEvents[K]) => Awaitable<void> }>;
|
||||
|
||||
|
||||
export type SlashOptions = Omit<CommandInteractionOptionResolver, 'getMessage' | 'getFocused'>;
|
||||
|
||||
//https://dev.to/vborodulin/ts-how-to-override-properties-with-type-intersection-554l
|
||||
|
||||
Reference in New Issue
Block a user