mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-03 05:26:07 +00:00
268 lines
7.1 KiB
TypeScript
268 lines
7.1 KiB
TypeScript
import type {
|
|
DiscordInteractionDataOption,
|
|
DiscordInteractionDataResolved,
|
|
Snowflake,
|
|
} from '@biscuitland/api-types';
|
|
import { ApplicationCommandOptionTypes } from '@biscuitland/api-types';
|
|
|
|
/**
|
|
* Utility class to get the resolved options for a command
|
|
* @example const option = ctx.options.getStringOption("name");
|
|
*/
|
|
export class InteractionOptions {
|
|
private _subcommand?: string;
|
|
private _group?: string;
|
|
|
|
hoistedOptions: DiscordInteractionDataOption[];
|
|
resolved?: DiscordInteractionDataResolved;
|
|
|
|
constructor(
|
|
options?: DiscordInteractionDataOption[],
|
|
resolved?: DiscordInteractionDataResolved
|
|
) {
|
|
this.hoistedOptions = options ?? [];
|
|
|
|
// warning: black magic do not edit and thank djs authors
|
|
|
|
if (
|
|
this.hoistedOptions[0]?.type ===
|
|
ApplicationCommandOptionTypes.SubCommandGroup
|
|
) {
|
|
this._group = this.hoistedOptions[0].name;
|
|
this.hoistedOptions = this.hoistedOptions[0].options ?? [];
|
|
}
|
|
|
|
if (
|
|
this.hoistedOptions[0]?.type ===
|
|
ApplicationCommandOptionTypes.SubCommand
|
|
) {
|
|
this._subcommand = this.hoistedOptions[0].name;
|
|
this.hoistedOptions = this.hoistedOptions[0].options ?? [];
|
|
}
|
|
|
|
this.resolved = resolved;
|
|
}
|
|
|
|
private getTypedOption(
|
|
name: string | number,
|
|
type: ApplicationCommandOptionTypes,
|
|
properties: (keyof DiscordInteractionDataOption)[],
|
|
required: boolean
|
|
): DiscordInteractionDataOption | void {
|
|
const option: DiscordInteractionDataOption | undefined = this.get(
|
|
name,
|
|
required
|
|
);
|
|
|
|
if (!option) {
|
|
return;
|
|
}
|
|
|
|
if (option.type !== type) {
|
|
// pass
|
|
}
|
|
|
|
if (
|
|
required === true &&
|
|
properties.every(prop => typeof option[prop] === 'undefined')
|
|
) {
|
|
throw new TypeError(
|
|
`Properties ${properties.join(
|
|
', '
|
|
)} are missing in option ${name}`
|
|
);
|
|
}
|
|
|
|
return option;
|
|
}
|
|
|
|
get(name: string | number, required: true): DiscordInteractionDataOption;
|
|
get(
|
|
name: string | number,
|
|
required: boolean
|
|
): DiscordInteractionDataOption | undefined;
|
|
|
|
get(name: string | number, required?: boolean) {
|
|
const option: DiscordInteractionDataOption | undefined =
|
|
this.hoistedOptions.find(o =>
|
|
typeof name === 'number'
|
|
? o.name === name.toString()
|
|
: o.name === name
|
|
);
|
|
|
|
if (!option) {
|
|
if (required && name in this.hoistedOptions.map(o => o.name)) {
|
|
throw new TypeError('Option marked as required was undefined');
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
return option;
|
|
}
|
|
|
|
/** searches for a string option */
|
|
getString(name: string | number, required: true): string;
|
|
getString(name: string | number, required?: boolean): string | undefined;
|
|
getString(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.String,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for a number option */
|
|
getNumber(name: string | number, required: true): number;
|
|
getNumber(name: string | number, required?: boolean): number | undefined;
|
|
getNumber(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.Number,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searhces for an integer option */
|
|
getInteger(name: string | number, required: true): number;
|
|
getInteger(name: string | number, required?: boolean): number | undefined;
|
|
getInteger(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.Integer,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for a boolean option */
|
|
getBoolean(name: string | number, required: true): boolean;
|
|
getBoolean(name: string | number, required?: boolean): boolean | undefined;
|
|
getBoolean(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.Boolean,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for a user option */
|
|
getUser(name: string | number, required: true): Snowflake;
|
|
getUser(name: string | number, required?: boolean): Snowflake | undefined;
|
|
getUser(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.User,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for a channel option */
|
|
getChannel(name: string | number, required: true): Snowflake;
|
|
getChannel(name: string | number, required?: boolean): Snowflake | undefined;
|
|
getChannel(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.Channel,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for a mentionable-based option */
|
|
getMentionable(name: string | number, required: true): string;
|
|
getMentionable(
|
|
name: string | number,
|
|
required?: boolean
|
|
): string | undefined;
|
|
|
|
getMentionable(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.Mentionable,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for a mentionable-based option */
|
|
getRole(name: string | number, required: true): Snowflake;
|
|
getRole(name: string | number, required?: boolean): Snowflake | undefined;
|
|
getRole(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.Role,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for an attachment option */
|
|
getAttachment(name: string | number, required: true): Snowflake;
|
|
getAttachment(name: string | number, required?: boolean): Snowflake | undefined;
|
|
getAttachment(name: string | number, required = false) {
|
|
const option: DiscordInteractionDataOption | void = this.getTypedOption(
|
|
name,
|
|
ApplicationCommandOptionTypes.Attachment,
|
|
['value'],
|
|
required
|
|
);
|
|
|
|
return option?.value ?? undefined;
|
|
}
|
|
|
|
/** searches for the focused option */
|
|
getFocused(full: true): DiscordInteractionDataOption;
|
|
getFocused(full: false): DiscordInteractionDataOption["value"];
|
|
getFocused(full: boolean = false) {
|
|
const focusedOption: DiscordInteractionDataOption | void =
|
|
this.hoistedOptions.find(option => option.focused);
|
|
|
|
if (!focusedOption) {
|
|
throw new TypeError('No option found');
|
|
}
|
|
|
|
return full ? focusedOption : focusedOption.value;
|
|
}
|
|
|
|
getSubCommand(
|
|
required = true
|
|
): [string | undefined, DiscordInteractionDataOption[]] {
|
|
if (required && !this._subcommand) {
|
|
throw new TypeError('Option marked as required was undefined');
|
|
}
|
|
|
|
return [this._subcommand, this.hoistedOptions];
|
|
}
|
|
|
|
getSubCommandGroup(
|
|
required = false
|
|
): [string | undefined, DiscordInteractionDataOption[]] {
|
|
if (required && !this._group) {
|
|
throw new TypeError('Option marked as required was undefined');
|
|
}
|
|
|
|
return [this._group, this.hoistedOptions];
|
|
}
|
|
}
|