diff --git a/src/handler/structures/context.ts b/src/handler/structures/context.ts index c9c2512..487eef1 100644 --- a/src/handler/structures/context.ts +++ b/src/handler/structures/context.ts @@ -1,6 +1,5 @@ import type { APIGuildMember } from 'discord-api-types/v9'; import type { - Awaitable, ChatInputCommandInteraction, Guild, GuildMember, @@ -13,6 +12,8 @@ import type { } from 'discord.js'; import { None, Option, Some } from 'ts-results'; import type { Nullish } from '../../types/handler'; +import type { Client } from 'discord.js'; +import { ExternallyUsed } from '../utilities/externallyUsed'; function firstSome(...args: Option[]): Nullish { for (const op of args) { @@ -20,10 +21,12 @@ function firstSome(...args: Option[]): Nullish { } return null; } - -// -//Will need refactoring after applying context in practice -// +//Could I refactor with Either monad? +/** + * The Context class will provide values that are shared between + * Message and ChatInputCommandInteraction + * + */ export default class Context { private constructor( private oMsg: Option = None, @@ -32,50 +35,50 @@ export default class Context { this.oMsg = oMsg; this.oInterac = oInterac; } - + @ExternallyUsed public get message() { return this.oMsg.unwrap(); } - + @ExternallyUsed public get interaction() { return this.oInterac.unwrap(); } - + @ExternallyUsed public get id(): Snowflake { return firstSome( this.oInterac.map(i => i.id), this.oMsg.map(m => m.id), )!; } - + @ExternallyUsed public get channel(): Nullish { return firstSome( this.oMsg.map(m => m.channel), this.oInterac.map(i => i.channel), ); } - + @ExternallyUsed public get user(): User { return firstSome( this.oMsg.map(m => m.author), this.oInterac.map(i => i.user), )!; } - + @ExternallyUsed public get createdTimestamp(): number { return firstSome( this.oMsg.map(m => m.createdTimestamp), this.oInterac.map(i => i.createdTimestamp), )!; } - + @ExternallyUsed public get guild(): Guild { return firstSome( this.oMsg.map(m => m.guild), this.oInterac.map(i => i.guild), )!; } - + @ExternallyUsed public get guildId(): Snowflake { return firstSome( this.oMsg.map(m => m.guildId), @@ -86,6 +89,7 @@ export default class Context { /* * interactions can return APIGuildMember if the guild it is emitted from is not cached */ + @ExternallyUsed public get member(): Nullish { return firstSome( this.oMsg.map(m => m.member), @@ -99,50 +103,35 @@ export default class Context { } return new Context(Some(wrappable), None); } - + @ExternallyUsed public isEmpty() { return this.oMsg.none && this.oInterac.none; } - /* - * Returns the underlying Context but allows for doing other operations - */ - public onInteraction(onInteraction: (interaction: ChatInputCommandInteraction) => Awaitable): Context { - if (this.oInterac.some) { - onInteraction(this.oInterac.val); - return Context.wrap(this.oInterac.val); - } - return this; - } - - public onMessage(onMessage: (message: Message) => Awaitable): Context { - if (this.oMsg.some) { - onMessage(this.oMsg.val); - return Context.wrap(this.oMsg.val); - } - return this; - } - - public takeInteractionValue(extract: (interaction: ChatInputCommandInteraction) => T): Nullish { - if (this.oInterac.none) return null; - return extract(this.oInterac.val); - } - - public takeMessageValue(extract: (message: Message) => T): Nullish { - if (this.oMsg.none) return null; - return extract(this.oMsg.val); - } - - public reply(content: Omit | ReplyMessageOptions): Promise { + //TODO: make this queueable + @ExternallyUsed + public reply(content: Omit | ReplyMessageOptions) { 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.oInterac.map(i => { + return i.reply(content as InteractionReplyOptions).then(() => i.fetchReply()); }), - this.oMsg.map(async m => { - const reply = await m.reply(content as ReplyMessageOptions); - return new Context(Some(reply), this.oInterac); + this.oMsg.map(m => { + return m.reply(content as ReplyMessageOptions); }), )!; } + @ExternallyUsed + public get client(): Client { + return firstSome( + this.oMsg.map(m => m.client), + this.oInterac.map(i => i.client), + )!; + } + @ExternallyUsed + public get inGuild(): boolean { + return firstSome( + this.oMsg.map(m => m.inGuild()), + this.oInterac.map(i => i.inGuild()), + )!; + } } diff --git a/src/handler/utilities/externallyUsed.ts b/src/handler/utilities/externallyUsed.ts new file mode 100644 index 0000000..0f0fe81 --- /dev/null +++ b/src/handler/utilities/externallyUsed.ts @@ -0,0 +1,18 @@ +/** + * This function denotes usage of decorated method is external + * Also, makes method appear 'used' in IDEs + * @param _target + * @param _propertyKey + * @param _descriptor + * @constructor + */ +export function ExternallyUsed( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _target: unknown, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _propertyKey: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _descriptor: PropertyDescriptor, +) { + return void 0; +} diff --git a/src/handler/utilities/predicates.ts b/src/handler/utilities/predicates.ts index ce400b8..1c2cdfb 100644 --- a/src/handler/utilities/predicates.ts +++ b/src/handler/utilities/predicates.ts @@ -15,7 +15,9 @@ export function correctModuleType( plug: Module | undefined, type: T, ): plug is ModuleDefs[T] { - return plug !== undefined && plug.type === type; + // Another way to check if type is equivalent, + // It will check based on flag system instead + return plug !== undefined && (plug.type & type) !== 0; } export function isChatInputCommand(i: CommandInteraction): i is ChatInputCommandInteraction {