fix: interaction option resolver

This commit is contained in:
Yuzu 2022-08-02 19:39:48 -05:00
parent a765fddf32
commit fecd90a6f4
2 changed files with 54 additions and 123 deletions

View File

@ -348,8 +348,8 @@ export interface CommandInteractionDataResolved {
users: Map<Snowflake, User>; users: Map<Snowflake, User>;
members: Map<Snowflake, Member>; members: Map<Snowflake, Member>;
roles: Map<Snowflake, Role>; roles: Map<Snowflake, Role>;
attachments: Map<Snowflake, Attachment>;
messages: Map<Snowflake, Message>; messages: Map<Snowflake, Message>;
attachments: Map<Snowflake, Attachment>;
} }
export class CommandInteraction extends BaseInteraction implements Model { export class CommandInteraction extends BaseInteraction implements Model {

View File

@ -1,64 +1,10 @@
import type { import type {
DiscordInteractionDataOption, DiscordInteractionDataOption,
DiscordInteractionDataResolved, DiscordInteractionDataResolved,
Snowflake,
} from '@biscuitland/api-types'; } from '@biscuitland/api-types';
import { ApplicationCommandOptionTypes } from '@biscuitland/api-types'; import { ApplicationCommandOptionTypes } from '@biscuitland/api-types';
export function transformOasisInteractionDataOption(
o: DiscordInteractionDataOption
): CommandInteractionOption {
const output: CommandInteractionOption = {
...o,
Otherwise: o.value as string | boolean | number | undefined,
};
switch (o.type) {
case ApplicationCommandOptionTypes.String:
output.String = o.value as string;
break;
case ApplicationCommandOptionTypes.Number:
output.Number = o.value as number;
break;
case ApplicationCommandOptionTypes.Integer:
output.Integer = o.value as number;
break;
case ApplicationCommandOptionTypes.Boolean:
output.Boolean = o.value as boolean;
break;
case ApplicationCommandOptionTypes.Role:
output.Role = BigInt(o.value as string);
break;
case ApplicationCommandOptionTypes.User:
output.User = BigInt(o.value as string);
break;
case ApplicationCommandOptionTypes.Channel:
output.Channel = BigInt(o.value as string);
break;
case ApplicationCommandOptionTypes.Mentionable:
case ApplicationCommandOptionTypes.SubCommand:
case ApplicationCommandOptionTypes.SubCommandGroup:
default:
output.Otherwise = o.value as string | boolean | number | undefined;
}
return output;
}
export interface CommandInteractionOption
extends Omit<DiscordInteractionDataOption, 'value'> {
Attachment?: string;
Boolean?: boolean;
User?: bigint;
Role?: bigint;
Number?: number;
Integer?: number;
Channel?: bigint;
String?: string;
Mentionable?: string;
Otherwise: string | number | boolean | bigint | undefined;
}
/** /**
* Utility class to get the resolved options for a command * Utility class to get the resolved options for a command
* It is really typesafe * It is really typesafe
@ -68,15 +14,14 @@ export class CommandInteractionOptionResolver {
#subcommand?: string; #subcommand?: string;
#group?: string; #group?: string;
hoistedOptions: CommandInteractionOption[]; hoistedOptions: DiscordInteractionDataOption[];
resolved?: DiscordInteractionDataResolved; resolved?: DiscordInteractionDataResolved;
constructor( constructor(
options?: DiscordInteractionDataOption[], options?: DiscordInteractionDataOption[],
resolved?: DiscordInteractionDataResolved resolved?: DiscordInteractionDataResolved
) { ) {
this.hoistedOptions = this.hoistedOptions = options ?? [];
options?.map(transformOasisInteractionDataOption) ?? [];
// warning: black magic do not edit and thank djs authors // warning: black magic do not edit and thank djs authors
@ -85,9 +30,7 @@ export class CommandInteractionOptionResolver {
ApplicationCommandOptionTypes.SubCommandGroup ApplicationCommandOptionTypes.SubCommandGroup
) { ) {
this.#group = this.hoistedOptions[0].name; this.#group = this.hoistedOptions[0].name;
this.hoistedOptions = (this.hoistedOptions[0].options ?? []).map( this.hoistedOptions = this.hoistedOptions[0].options ?? [];
transformOasisInteractionDataOption
);
} }
if ( if (
@ -95,9 +38,7 @@ export class CommandInteractionOptionResolver {
ApplicationCommandOptionTypes.SubCommand ApplicationCommandOptionTypes.SubCommand
) { ) {
this.#subcommand = this.hoistedOptions[0].name; this.#subcommand = this.hoistedOptions[0].name;
this.hoistedOptions = (this.hoistedOptions[0].options ?? []).map( this.hoistedOptions = this.hoistedOptions[0].options ?? [];
transformOasisInteractionDataOption
);
} }
this.resolved = resolved; this.resolved = resolved;
@ -106,10 +47,10 @@ export class CommandInteractionOptionResolver {
private getTypedOption( private getTypedOption(
name: string | number, name: string | number,
type: ApplicationCommandOptionTypes, type: ApplicationCommandOptionTypes,
properties: (keyof CommandInteractionOption)[], properties: (keyof DiscordInteractionDataOption)[],
required: boolean required: boolean
): CommandInteractionOption | void { ): DiscordInteractionDataOption | void {
const option: CommandInteractionOption | undefined = this.get( const option: DiscordInteractionDataOption | undefined = this.get(
name, name,
required required
); );
@ -136,14 +77,14 @@ export class CommandInteractionOptionResolver {
return option; return option;
} }
get(name: string | number, required: true): CommandInteractionOption; get(name: string | number, required: true): DiscordInteractionDataOption;
get( get(
name: string | number, name: string | number,
required: boolean required: boolean
): CommandInteractionOption | undefined; ): DiscordInteractionDataOption | undefined;
get(name: string | number, required?: boolean) { get(name: string | number, required?: boolean) {
const option: CommandInteractionOption | undefined = const option: DiscordInteractionDataOption | undefined =
this.hoistedOptions.find(o => this.hoistedOptions.find(o =>
typeof name === 'number' typeof name === 'number'
? o.name === name.toString() ? o.name === name.toString()
@ -165,84 +106,84 @@ export class CommandInteractionOptionResolver {
getString(name: string | number, required: true): string; getString(name: string | number, required: true): string;
getString(name: string | number, required?: boolean): string | undefined; getString(name: string | number, required?: boolean): string | undefined;
getString(name: string | number, required = false) { getString(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.String, ApplicationCommandOptionTypes.String,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for a number option */ /** searches for a number option */
getNumber(name: string | number, required: true): number; getNumber(name: string | number, required: true): number;
getNumber(name: string | number, required?: boolean): number | undefined; getNumber(name: string | number, required?: boolean): number | undefined;
getNumber(name: string | number, required = false) { getNumber(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.Number, ApplicationCommandOptionTypes.Number,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searhces for an integer option */ /** searhces for an integer option */
getInteger(name: string | number, required: true): number; getInteger(name: string | number, required: true): number;
getInteger(name: string | number, required?: boolean): number | undefined; getInteger(name: string | number, required?: boolean): number | undefined;
getInteger(name: string | number, required = false) { getInteger(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.Integer, ApplicationCommandOptionTypes.Integer,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for a boolean option */ /** searches for a boolean option */
getBoolean(name: string | number, required: true): boolean; getBoolean(name: string | number, required: true): boolean;
getBoolean(name: string | number, required?: boolean): boolean | undefined; getBoolean(name: string | number, required?: boolean): boolean | undefined;
getBoolean(name: string | number, required = false) { getBoolean(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.Boolean, ApplicationCommandOptionTypes.Boolean,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for a user option */ /** searches for a user option */
getUser(name: string | number, required: true): bigint; getUser(name: string | number, required: true): Snowflake;
getUser(name: string | number, required?: boolean): bigint | undefined; getUser(name: string | number, required?: boolean): Snowflake | undefined;
getUser(name: string | number, required = false) { getUser(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.User, ApplicationCommandOptionTypes.User,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for a channel option */ /** searches for a channel option */
getChannel(name: string | number, required: true): bigint; getChannel(name: string | number, required: true): Snowflake;
getChannel(name: string | number, required?: boolean): bigint | undefined; getChannel(name: string | number, required?: boolean): Snowflake | undefined;
getChannel(name: string | number, required = false) { getChannel(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.Channel, ApplicationCommandOptionTypes.Channel,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for a mentionable-based option */ /** searches for a mentionable-based option */
@ -253,71 +194,61 @@ export class CommandInteractionOptionResolver {
): string | undefined; ): string | undefined;
getMentionable(name: string | number, required = false) { getMentionable(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.Mentionable, ApplicationCommandOptionTypes.Mentionable,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for a mentionable-based option */ /** searches for a mentionable-based option */
getRole(name: string | number, required: true): bigint; getRole(name: string | number, required: true): Snowflake;
getRole(name: string | number, required?: boolean): bigint | undefined; getRole(name: string | number, required?: boolean): Snowflake | undefined;
getRole(name: string | number, required = false) { getRole(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.Role, ApplicationCommandOptionTypes.Role,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for an attachment option */ /** searches for an attachment option */
getAttachment(name: string | number, required: true): string; getAttachment(name: string | number, required: true): Snowflake;
getAttachment( getAttachment(name: string | number, required?: boolean): Snowflake | undefined;
name: string | number,
required?: boolean
): string | undefined;
getAttachment(name: string | number, required = false) { getAttachment(name: string | number, required = false) {
const option: CommandInteractionOption | void = this.getTypedOption( const option: DiscordInteractionDataOption | void = this.getTypedOption(
name, name,
ApplicationCommandOptionTypes.Attachment, ApplicationCommandOptionTypes.Attachment,
['Otherwise'], ['value'],
required required
); );
return option?.Otherwise ?? undefined; return option?.value ?? undefined;
} }
/** searches for the focused option */ /** searches for the focused option */
getFocused( getFocused(full: true): DiscordInteractionDataOption;
full = false getFocused(full: false): DiscordInteractionDataOption["value"];
): getFocused(full: boolean = false) {
| string const focusedOption: DiscordInteractionDataOption | void =
| number
| bigint
| boolean
| undefined
| CommandInteractionOption {
const focusedOption: CommandInteractionOption | void =
this.hoistedOptions.find(option => option.focused); this.hoistedOptions.find(option => option.focused);
if (!focusedOption) { if (!focusedOption) {
throw new TypeError('No option found'); throw new TypeError('No option found');
} }
return full ? focusedOption : focusedOption.Otherwise; return full ? focusedOption : focusedOption.value;
} }
getSubCommand( getSubCommand(
required = true required = true
): (string | CommandInteractionOption[] | undefined)[] { ): [string | undefined, DiscordInteractionDataOption[]] {
if (required && !this.#subcommand) { if (required && !this.#subcommand) {
throw new TypeError('Option marked as required was undefined'); throw new TypeError('Option marked as required was undefined');
} }
@ -327,7 +258,7 @@ export class CommandInteractionOptionResolver {
getSubCommandGroup( getSubCommandGroup(
required = false required = false
): (string | CommandInteractionOption[] | undefined)[] { ): [string | undefined, DiscordInteractionDataOption[]] {
if (required && !this.#group) { if (required && !this.#group) {
throw new TypeError('Option marked as required was undefined'); throw new TypeError('Option marked as required was undefined');
} }