From b0d4f96900871ac5c3e44d6100472f84c4764fcc Mon Sep 17 00:00:00 2001 From: Jacob Nguyen <76754747+jacoobes@users.noreply.github.com> Date: Sat, 26 Mar 2022 02:34:36 -0500 Subject: [PATCH] feat : add typings for ctx menus --- src/handler/events/interactionCreate.ts | 32 +++++++++++-------- src/handler/events/messageEvent.ts | 22 ++++++------- src/handler/events/readyEvent.ts | 21 ++++++++---- src/handler/sern.ts | 8 +++-- src/handler/structures/commands/module.ts | 19 ++++++++--- .../structures/commands/moduleHandler.ts | 6 ++-- src/handler/structures/context.ts | 4 +-- src/handler/utilities/readFile.ts | 2 +- src/types/handler.ts | 4 +-- 9 files changed, 72 insertions(+), 46 deletions(-) diff --git a/src/handler/events/interactionCreate.ts b/src/handler/events/interactionCreate.ts index ca70d3b..510aba1 100644 --- a/src/handler/events/interactionCreate.ts +++ b/src/handler/events/interactionCreate.ts @@ -1,9 +1,10 @@ -import type { Interaction } from "discord.js"; -import { map, filter, fromEvent, Observable, of, tap, concatMap} from "rxjs"; -import { None, Some } from "ts-results"; -import { CommandType } from "../sern"; -import Context from "../structures/context"; -import type Wrapper from "../structures/wrapper"; +import type { ChatInputCommandInteraction, CommandInteraction, Interaction } from 'discord.js'; +import { map, filter, fromEvent, Observable, of, tap, concatMap} from 'rxjs'; +import { None, Some } from 'ts-results'; +import type { SlashCommand } from '../..'; +import { CommandType } from '../sern'; +import Context from '../structures/context'; +import type Wrapper from '../structures/wrapper'; import * as Files from '../utilities/readFile'; @@ -17,17 +18,22 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { if (interaction.isChatInputCommand()) { return of(interaction.commandName).pipe( map ( name => Files.Commands.get(name) ), - filter( mod => mod !== undefined && (mod.type & CommandType.SLASH) != 0), + filter( mod => mod !== undefined + && (mod.type & CommandType.SLASH) != 0 + ), tap ( mod => { const ctx = new Context(None, Some(interaction)); - mod!.execute(ctx, ['slash', interaction.options]); + (mod as SlashCommand)!.execute(ctx, ['slash', interaction.options]); }), - ) + ); } if (interaction.isContextMenuCommand()) { - return of() + return of(); } - else { return of() } + if (interaction.isMessageContextMenuCommand()) { + return of(); + } + else { return of(); } }) ).subscribe({ error(e) { @@ -39,6 +45,6 @@ export const onInteractionCreate = ( wrapper : Wrapper ) => { }, - }) -} + }); +}; diff --git a/src/handler/events/messageEvent.ts b/src/handler/events/messageEvent.ts index 03669da..46c1e5c 100644 --- a/src/handler/events/messageEvent.ts +++ b/src/handler/events/messageEvent.ts @@ -1,11 +1,11 @@ -import type { Message } from "discord.js"; -import { map, filter, fromEvent, Observable, of, concatMap, tap } from "rxjs"; -import { None, Some } from "ts-results"; -import { CommandType } from "../sern"; -import type { TextCommand } from "../structures/commands/module"; -import Context from "../structures/context"; -import type Wrapper from "../structures/wrapper"; -import { isNotFromDM, isNotFromBot, hasPrefix, fmt } from "../utilities/messageHelpers"; +import type { Message } from 'discord.js'; +import { map, filter, fromEvent, Observable, of, concatMap, tap } from 'rxjs'; +import { None, Some } from 'ts-results'; +import { CommandType } from '../sern'; +import type { TextCommand } from '../structures/commands/module'; +import Context from '../structures/context'; +import type Wrapper from '../structures/wrapper'; +import { isNotFromDM, isNotFromBot, hasPrefix, fmt } from '../utilities/messageHelpers'; import * as Files from '../utilities/readFile'; export const onMessageCreate = (wrapper : Wrapper) => { @@ -26,7 +26,7 @@ export const onMessageCreate = (wrapper : Wrapper) => { ), filter( ([mod]) => mod !== undefined && (mod.type & CommandType.TEXT) != 0 ), tap ( ([ mod, ctx, args ]) => { - (mod as TextCommand)!.execute(ctx, ['text', args]) + (mod as TextCommand)!.execute(ctx, ['text', args]); }), ) ) @@ -40,7 +40,7 @@ export const onMessageCreate = (wrapper : Wrapper) => { //log on each command emitted console.log(command); }, - }) + }); -} +}; diff --git a/src/handler/events/readyEvent.ts b/src/handler/events/readyEvent.ts index 2369444..2fc4bda 100644 --- a/src/handler/events/readyEvent.ts +++ b/src/handler/events/readyEvent.ts @@ -1,10 +1,10 @@ -import { concatMap, first, from, fromEvent, map, pipe, tap } from "rxjs"; +import { concatMap, first, from, fromEvent, pipe, tap } from 'rxjs'; import { basename } from 'path'; import * as Files from '../utilities/readFile'; import type Wrapper from '../structures/wrapper'; -import type { Modules } from "../structures/structxports"; -import type { HandlerCallback, ModuleHandlers, ModuleStates, ModuleType } from "../structures/commands/moduleHandler"; -import { CommandType } from "../sern"; +import type { Module } from '../structures/structxports'; +import type { HandlerCallback, ModuleHandlers, ModuleStates, ModuleType } from '../structures/commands/moduleHandler'; +import { CommandType } from '../sern'; export const onReady = ( wrapper : Wrapper ) => { const { client, init, commands, } = wrapper; @@ -25,7 +25,7 @@ export const onReady = ( wrapper : Wrapper ) => { // log stuff? } }); -} +}; const handler = ( name : string ) => ({ @@ -39,19 +39,26 @@ const handler = ( name : string ) => [CommandType.BOTH] : mod => { Files.Commands.set ( name, mod); mod.alias.forEach (a => Files.Alias.set(a, mod)); + }, + [CommandType.MENU_USER] : mod => { + Files.Commands.set ( name, mod ); + }, + [CommandType.MENU_MSG] : mod => { + + Files.Commands.set (name, mod ); } } as ModuleHandlers); const registerModules = (name : string, mod : ModuleStates[T]) => (handler(name)[mod.type] as HandlerCallback)(mod); -function setCommands ( { mod, absPath } : { mod : Modules.Module, absPath : string } ) { +function setCommands ( { mod, absPath } : { mod : Module, absPath : string } ) { const name = mod.name ?? Files.fmtFileName(basename(absPath)); registerModules(name, mod); } async function createCommandCache( - arr: Promise<{mod: Modules.Module, absPath: string}[]> + arr: Promise<{mod: Module, absPath: string}[]> ) { from(await arr).subscribe ( setCommands ); } diff --git a/src/handler/sern.ts b/src/handler/sern.ts index 54d3b69..bafa7e2 100644 --- a/src/handler/sern.ts +++ b/src/handler/sern.ts @@ -112,7 +112,9 @@ export class Handler { * @enum { number }; */ export enum CommandType { - TEXT = 0b0001, - SLASH = 0b0010, - BOTH = 0b0011 + TEXT = 0b0001, + SLASH = 0b0010, + MENU_USER = 0b0100, + MENU_MSG = 0b1000, + BOTH = 0b0011, } diff --git a/src/handler/structures/commands/module.ts b/src/handler/structures/commands/module.ts index 63f16ff..28c17f0 100644 --- a/src/handler/structures/commands/module.ts +++ b/src/handler/structures/commands/module.ts @@ -1,7 +1,7 @@ -import type { ApplicationCommandOptionData, Awaitable, ChatInputCommandInteraction, Interaction } from "discord.js"; -import type { Args, Override } from "../../../types/handler"; -import type { CommandType } from "../../sern"; -import type Context from "../context"; +import type { ApplicationCommandOptionData, Awaitable, ChatInputCommandInteraction, ContextMenuCommandInteraction, Interaction, MessageContextMenuCommandInteraction } from 'discord.js'; +import type { Args, Override } from '../../../types/handler'; +import type { CommandType } from '../../sern'; +import type Context from '../context'; type executeSlash = { execute : (ctx : Context, args: Args) => Awaitable }; @@ -26,9 +26,18 @@ export type BothCommand = { options : ApplicationCommandOptionData[] | [], } & Override; +export type ContextMenuUser = { + type : CommandType.MENU_USER; +} & Override ) => Awaitable }>; + +export type ContextMenuMsg = { + type : CommandType.MENU_MSG; +} & Override ) => Awaitable }>; export type Module = TextCommand | SlashCommand - | BothCommand; + | BothCommand + | ContextMenuUser + | ContextMenuMsg; diff --git a/src/handler/structures/commands/moduleHandler.ts b/src/handler/structures/commands/moduleHandler.ts index 0efa1b8..405d673 100644 --- a/src/handler/structures/commands/moduleHandler.ts +++ b/src/handler/structures/commands/moduleHandler.ts @@ -1,5 +1,5 @@ -import { CommandType } from "../../sern"; -import type { TextCommand, BothCommand, SlashCommand, BaseModule } from "./module"; +import { CommandType } from '../../sern'; +import type { TextCommand, BothCommand, SlashCommand, BaseModule, ContextMenuMsg, ContextMenuUser } from './module'; //https://stackoverflow.com/questions/64092736/alternative-to-switch-statement-for-typescript-discriminated-union @@ -8,6 +8,8 @@ export type ModuleDefs = { [CommandType.TEXT] : TextCommand, [CommandType.SLASH] : SlashCommand, [CommandType.BOTH] : BothCommand, + [CommandType.MENU_MSG] : ContextMenuMsg, + [CommandType.MENU_USER] : ContextMenuUser } //Keys of ModuleDefs diff --git a/src/handler/structures/context.ts b/src/handler/structures/context.ts index d7b0a2a..deeae55 100644 --- a/src/handler/structures/context.ts +++ b/src/handler/structures/context.ts @@ -37,13 +37,13 @@ export default class Context { return firstSome( this.message.andThen(m => Some(m.channel)), this.interaction.andThen(i => Some(i.channel)) - ) + ); } public get user() { return firstSome( this.message.andThen(m => Some(m.author)), this.interaction.andThen(i => Some(i.user)) - ) + ); } } diff --git a/src/handler/utilities/readFile.ts b/src/handler/utilities/readFile.ts index 23a48b8..174c7c5 100644 --- a/src/handler/utilities/readFile.ts +++ b/src/handler/utilities/readFile.ts @@ -39,7 +39,7 @@ export async function buildData(commandDir: string ): Promise< return Promise.all( getCommands(commandDir).map( async (absPath) => { const mod = (await import(absPath)).module as Module; - if (mod === undefined) throw Error(`${SernError.UNDEFINED_MODULE} ${absPath}`) + if (mod === undefined) throw Error(`${SernError.UNDEFINED_MODULE} ${absPath}`); return { mod, absPath }; }), ); diff --git a/src/types/handler.ts b/src/types/handler.ts index 1644a64..6dc461a 100644 --- a/src/types/handler.ts +++ b/src/types/handler.ts @@ -7,11 +7,11 @@ import type { Awaitable, } from 'discord.js'; -import type { Modules } from '../handler/structures/structxports'; +import type { Module } from '../handler/structures/structxports'; // Anything that can be sent in a `#send` or `#reply` export type possibleOutput = T | (MessagePayload & MessageOptions); -export type execute = Modules.Module['execute']; +export type execute = Module['execute']; // Thanks @cursorsdottsx export type ParseType = {