mirror of
https://github.com/sern-handler/handler
synced 2026-06-24 16:52:15 +00:00
feat: add externallyUsed.ts and support BothCommands again
This commit is contained in:
@@ -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<T>(...args: Option<T>[]): Nullish<T> {
|
||||
for (const op of args) {
|
||||
@@ -20,10 +21,12 @@ function firstSome<T>(...args: Option<T>[]): Nullish<T> {
|
||||
}
|
||||
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<Message> = 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<TextBasedChannel> {
|
||||
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<GuildMember | APIGuildMember> {
|
||||
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<void>): Context {
|
||||
if (this.oInterac.some) {
|
||||
onInteraction(this.oInterac.val);
|
||||
return Context.wrap(this.oInterac.val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public onMessage(onMessage: (message: Message) => Awaitable<void>): Context {
|
||||
if (this.oMsg.some) {
|
||||
onMessage(this.oMsg.val);
|
||||
return Context.wrap(this.oMsg.val);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public takeInteractionValue<T>(extract: (interaction: ChatInputCommandInteraction) => T): Nullish<T> {
|
||||
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> {
|
||||
//TODO: make this queueable
|
||||
@ExternallyUsed
|
||||
public reply(content: Omit<InteractionReplyOptions, 'fetchReply'> | 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()),
|
||||
)!;
|
||||
}
|
||||
}
|
||||
|
||||
18
src/handler/utilities/externallyUsed.ts
Normal file
18
src/handler/utilities/externallyUsed.ts
Normal file
@@ -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;
|
||||
}
|
||||
@@ -15,7 +15,9 @@ export function correctModuleType<T extends keyof ModuleDefs>(
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user