mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-02 21:16:09 +00:00
prefixed commands options
This commit is contained in:
parent
647f7d11d0
commit
8914b8c24c
@ -3,7 +3,7 @@ import { ApiHandler, Router } from '../api';
|
|||||||
import type { Adapter } from '../cache';
|
import type { Adapter } from '../cache';
|
||||||
import { Cache, MemoryAdapter } from '../cache';
|
import { Cache, MemoryAdapter } from '../cache';
|
||||||
import type { RegisteredMiddlewares } from '../commands';
|
import type { RegisteredMiddlewares } from '../commands';
|
||||||
import type { MiddlewareContext } from '../commands/applications/shared';
|
import type { InferWithPrefix, MiddlewareContext } from '../commands/applications/shared';
|
||||||
import { CommandHandler } from '../commands/handler';
|
import { CommandHandler } from '../commands/handler';
|
||||||
import {
|
import {
|
||||||
ChannelShorter,
|
ChannelShorter,
|
||||||
@ -24,10 +24,15 @@ import {
|
|||||||
type MakeRequired,
|
type MakeRequired,
|
||||||
} from '../common';
|
} from '../common';
|
||||||
|
|
||||||
import type { DeepPartial, IntentStrings, OmitInsert } from '../common/types/util';
|
import type { DeepPartial, IntentStrings, OmitInsert, When } from '../common/types/util';
|
||||||
import { ComponentHandler } from '../components/handler';
|
import { ComponentHandler } from '../components/handler';
|
||||||
import { LangsHandler } from '../langs/handler';
|
import { LangsHandler } from '../langs/handler';
|
||||||
import type { ChatInputCommandInteraction, Message, MessageCommandInteraction, UserCommandInteraction } from '../structures';
|
import type {
|
||||||
|
ChatInputCommandInteraction,
|
||||||
|
Message,
|
||||||
|
MessageCommandInteraction,
|
||||||
|
UserCommandInteraction,
|
||||||
|
} from '../structures';
|
||||||
|
|
||||||
export class BaseClient {
|
export class BaseClient {
|
||||||
rest!: ApiHandler;
|
rest!: ApiHandler;
|
||||||
@ -246,7 +251,7 @@ export interface BaseClientOptions {
|
|||||||
| ChatInputCommandInteraction<boolean>
|
| ChatInputCommandInteraction<boolean>
|
||||||
| UserCommandInteraction<boolean>
|
| UserCommandInteraction<boolean>
|
||||||
| MessageCommandInteraction<boolean>
|
| MessageCommandInteraction<boolean>
|
||||||
| Message
|
| When<InferWithPrefix, Message, never>,
|
||||||
) => {};
|
) => {};
|
||||||
globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[];
|
globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[];
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
import { ApplicationCommandType, InteractionType, type APIInteraction } from 'discord-api-types/v10';
|
import { ApplicationCommandType, InteractionType, type APIInteraction } from 'discord-api-types/v10';
|
||||||
import { CommandContext, MenuCommandContext, OptionResolver, type Command, type ContextMenuCommand } from '../commands';
|
import {
|
||||||
|
CommandContext,
|
||||||
|
type ContextOptionsResolved,
|
||||||
|
MenuCommandContext,
|
||||||
|
OptionResolver,
|
||||||
|
type Command,
|
||||||
|
type ContextMenuCommand,
|
||||||
|
} from '../commands';
|
||||||
import type {
|
import type {
|
||||||
ChatInputCommandInteraction,
|
ChatInputCommandInteraction,
|
||||||
ComponentInteraction,
|
ComponentInteraction,
|
||||||
@ -32,7 +39,7 @@ export async function onInteractionCreate(
|
|||||||
body.data.options ?? [],
|
body.data.options ?? [],
|
||||||
parentCommand as Command,
|
parentCommand as Command,
|
||||||
body.data.guild_id,
|
body.data.guild_id,
|
||||||
body.data.resolved,
|
body.data.resolved as ContextOptionsResolved,
|
||||||
);
|
);
|
||||||
const interaction = new AutocompleteInteraction(self, body, __reply);
|
const interaction = new AutocompleteInteraction(self, body, __reply);
|
||||||
const command = optionsResolver.getAutocomplete();
|
const command = optionsResolver.getAutocomplete();
|
||||||
@ -139,7 +146,7 @@ export async function onInteractionCreate(
|
|||||||
packetData.options ?? [],
|
packetData.options ?? [],
|
||||||
parentCommand as Command,
|
parentCommand as Command,
|
||||||
packetData.guild_id,
|
packetData.guild_id,
|
||||||
packetData.resolved,
|
packetData.resolved as ContextOptionsResolved,
|
||||||
);
|
);
|
||||||
const interaction = BaseInteraction.from(self, body, __reply) as ChatInputCommandInteraction;
|
const interaction = BaseInteraction.from(self, body, __reply) as ChatInputCommandInteraction;
|
||||||
const command = optionsResolver.getCommand();
|
const command = optionsResolver.getCommand();
|
||||||
|
@ -2,14 +2,15 @@ import {
|
|||||||
ApplicationCommandOptionType,
|
ApplicationCommandOptionType,
|
||||||
ChannelType,
|
ChannelType,
|
||||||
type APIApplicationCommandInteractionDataOption,
|
type APIApplicationCommandInteractionDataOption,
|
||||||
type APIInteractionDataResolved,
|
|
||||||
type GatewayMessageCreateDispatchData,
|
type GatewayMessageCreateDispatchData,
|
||||||
} from 'discord-api-types/v10';
|
} from 'discord-api-types/v10';
|
||||||
import {
|
import {
|
||||||
Command,
|
Command,
|
||||||
CommandContext,
|
CommandContext,
|
||||||
|
type ContextOptionsResolved,
|
||||||
OptionResolver,
|
OptionResolver,
|
||||||
SubCommand,
|
SubCommand,
|
||||||
|
User,
|
||||||
type Client,
|
type Client,
|
||||||
type CommandOption,
|
type CommandOption,
|
||||||
type SeyfertChannelOption,
|
type SeyfertChannelOption,
|
||||||
@ -88,7 +89,7 @@ export async function onMessageCreate(
|
|||||||
if (command.dm && !message.guildId) return;
|
if (command.dm && !message.guildId) return;
|
||||||
if (command.guild_id && !command.guild_id?.includes(message.guildId!)) return;
|
if (command.guild_id && !command.guild_id?.includes(message.guildId!)) return;
|
||||||
|
|
||||||
const resolved: MakeRequired<APIInteractionDataResolved> = {
|
const resolved: MakeRequired<ContextOptionsResolved> = {
|
||||||
channels: {},
|
channels: {},
|
||||||
roles: {},
|
roles: {},
|
||||||
users: {},
|
users: {},
|
||||||
@ -99,6 +100,7 @@ export async function onMessageCreate(
|
|||||||
const { options, errors } = await parseOptions(self, command, rawMessage, args, resolved);
|
const { options, errors } = await parseOptions(self, command, rawMessage, args, resolved);
|
||||||
const optionsResolver = new OptionResolver(self, options, parent as Command, message.guildId, resolved);
|
const optionsResolver = new OptionResolver(self, options, parent as Command, message.guildId, resolved);
|
||||||
const context = new CommandContext(self, message, optionsResolver, shardId, command);
|
const context = new CommandContext(self, message, optionsResolver, shardId, command);
|
||||||
|
//@ts-expect-error
|
||||||
const extendContext = self.options?.context?.(message) ?? {};
|
const extendContext = self.options?.context?.(message) ?? {};
|
||||||
Object.assign(context, extendContext);
|
Object.assign(context, extendContext);
|
||||||
try {
|
try {
|
||||||
@ -167,123 +169,201 @@ async function parseOptions(
|
|||||||
command: Command | SubCommand,
|
command: Command | SubCommand,
|
||||||
message: GatewayMessageCreateDispatchData,
|
message: GatewayMessageCreateDispatchData,
|
||||||
args: Partial<Record<string, string>>,
|
args: Partial<Record<string, string>>,
|
||||||
resolved: MakeRequired<APIInteractionDataResolved, keyof APIInteractionDataResolved>,
|
resolved: MakeRequired<ContextOptionsResolved>,
|
||||||
) {
|
) {
|
||||||
const options: APIApplicationCommandInteractionDataOption[] = [];
|
const options: APIApplicationCommandInteractionDataOption[] = [];
|
||||||
const errors: { name: string; error: string }[] = [];
|
const errors: { name: string; error: string }[] = [];
|
||||||
for (const i of (command.options ?? []) as (CommandOption & { type: ApplicationCommandOptionType })[]) {
|
for (const i of (command.options ?? []) as (CommandOption & { type: ApplicationCommandOptionType })[]) {
|
||||||
let value: string | boolean | number | undefined;
|
try {
|
||||||
let indexAttachment = -1;
|
let value: string | boolean | number | undefined;
|
||||||
switch (i.type) {
|
let indexAttachment = -1;
|
||||||
case ApplicationCommandOptionType.Attachment:
|
switch (i.type) {
|
||||||
if (message.attachments[++indexAttachment]) {
|
case ApplicationCommandOptionType.Attachment:
|
||||||
value = message.attachments[indexAttachment].id;
|
if (message.attachments[++indexAttachment]) {
|
||||||
resolved.attachments[value] = message.attachments[indexAttachment];
|
value = message.attachments[indexAttachment].id;
|
||||||
}
|
resolved.attachments[value] = message.attachments[indexAttachment];
|
||||||
break;
|
}
|
||||||
case ApplicationCommandOptionType.Boolean:
|
break;
|
||||||
if (args[i.name]) {
|
case ApplicationCommandOptionType.Boolean:
|
||||||
value = ['yes', 'y', 'true', 'treu'].includes(args[i.name]!.toLowerCase());
|
if (args[i.name]) {
|
||||||
}
|
value = ['yes', 'y', 'true', 'treu'].includes(args[i.name]!.toLowerCase());
|
||||||
break;
|
}
|
||||||
case ApplicationCommandOptionType.Channel:
|
break;
|
||||||
{
|
case ApplicationCommandOptionType.Channel:
|
||||||
const rawId = message.content.match(/(?<=<#)[0-9]{17,19}(?=>)/g)?.find(x => args[i.name]?.includes(x));
|
{
|
||||||
if (rawId) {
|
const rawId =
|
||||||
const channel = i.required ? await self.channels.fetch(rawId) : await self.cache.channels?.get(rawId);
|
message.content.match(/(?<=<#)[0-9]{17,19}(?=>)/g)?.find(x => args[i.name]?.includes(x)) ||
|
||||||
if (channel) {
|
args[i.name]?.match(/[0-9]{17,19}/g)?.[0];
|
||||||
if ('channel_types' in i) {
|
if (rawId) {
|
||||||
if (!(i as SeyfertChannelOption).channel_types!.includes(channel.type)) {
|
const channel =
|
||||||
|
(await self.cache.channels?.get(rawId)) ?? (i.required ? await self.channels.fetch(rawId) : undefined);
|
||||||
|
if (channel) {
|
||||||
|
if ('channel_types' in i) {
|
||||||
|
if (!(i as SeyfertChannelOption).channel_types!.includes(channel.type)) {
|
||||||
|
errors.push({
|
||||||
|
name: i.name,
|
||||||
|
error: `The entered channel type is not one of ${(i as SeyfertChannelOption)
|
||||||
|
.channel_types!.map(t => ChannelType[t])
|
||||||
|
.join(', ')}`,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = rawId;
|
||||||
|
resolved.channels[rawId] = channel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ApplicationCommandOptionType.Mentionable:
|
||||||
|
{
|
||||||
|
const matches = message.content.match(/<@[0-9]{17,19}(?=>)|<@&[0-9]{17,19}(?=>)/g) ?? [];
|
||||||
|
for (const match of matches) {
|
||||||
|
if (match.includes('&')) {
|
||||||
|
const rawId = match.slice(3);
|
||||||
|
if (rawId) {
|
||||||
|
const role =
|
||||||
|
(await self.cache.roles?.get(rawId)) ??
|
||||||
|
(i.required ? (await self.roles.list(message.guild_id!)).find(x => x.id === rawId) : undefined);
|
||||||
|
if (role) {
|
||||||
|
value = rawId;
|
||||||
|
resolved.roles[rawId] = role;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const rawId = match.slice(2);
|
||||||
|
const raw = message.mentions.find(x => rawId === x.id);
|
||||||
|
if (raw) {
|
||||||
|
const { member, ...user } = raw;
|
||||||
|
value = raw.id;
|
||||||
|
resolved.users[raw.id] = user;
|
||||||
|
if (member) resolved.members[raw.id] = member;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ApplicationCommandOptionType.Role:
|
||||||
|
{
|
||||||
|
const rawId =
|
||||||
|
message.mention_roles.find(x => args[i.name]?.includes(x)) || args[i.name]?.match(/[0-9]{17,19}/g)?.[0];
|
||||||
|
if (rawId) {
|
||||||
|
const role =
|
||||||
|
(await self.cache.roles?.get(rawId)) ??
|
||||||
|
(i.required ? (await self.roles.list(message.guild_id!)).find(x => x.id === rawId) : undefined);
|
||||||
|
|
||||||
|
if (role) {
|
||||||
|
value = rawId;
|
||||||
|
resolved.roles[rawId] = role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ApplicationCommandOptionType.User:
|
||||||
|
{
|
||||||
|
const rawId =
|
||||||
|
message.mentions.find(x => args[i.name]?.includes(x.id))?.id || args[i.name]?.match(/[0-9]{17,19}/g)?.[0];
|
||||||
|
if (rawId) {
|
||||||
|
const raw =
|
||||||
|
message.mentions.find(x => args[i.name]?.includes(x.id)) ??
|
||||||
|
(await self.cache.users?.get(rawId)) ??
|
||||||
|
(i.required ? await self.users.fetch(rawId) : undefined);
|
||||||
|
if (raw) {
|
||||||
|
value = raw.id;
|
||||||
|
if (raw instanceof User) {
|
||||||
|
resolved.users[raw.id] = raw;
|
||||||
|
if (message.guild_id) {
|
||||||
|
const member =
|
||||||
|
message.mentions.find(x => args[i.name]?.includes(x.id))?.member ??
|
||||||
|
(await self.cache.members?.get(rawId, message.guild_id)) ??
|
||||||
|
(i.required ? await self.members.fetch(rawId, message.guild_id) : undefined);
|
||||||
|
if (member) resolved.members[raw.id] = member;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const { member, ...user } = raw;
|
||||||
|
resolved.users[user.id] = user;
|
||||||
|
if (member) resolved.members[user.id] = member;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ApplicationCommandOptionType.String:
|
||||||
|
{
|
||||||
|
value = args[i.name];
|
||||||
|
const option = i as SeyfertStringOption;
|
||||||
|
if (value) {
|
||||||
|
if (option.min_length) {
|
||||||
|
if (value.length < option.min_length) {
|
||||||
|
value = undefined;
|
||||||
errors.push({
|
errors.push({
|
||||||
name: i.name,
|
name: i.name,
|
||||||
error: `The entered channel type is not one of ${(i as SeyfertChannelOption)
|
error: `The entered string has less than ${option.min_length} characters. The minimum required is ${option.min_length} characters.`,
|
||||||
.channel_types!.map(t => ChannelType[t])
|
|
||||||
.join(', ')}`,
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
value = rawId;
|
if (option.max_length) {
|
||||||
//@ts-expect-error
|
if (value.length > option.max_length) {
|
||||||
resolved.channels[rawId] = channel;
|
value = undefined;
|
||||||
}
|
errors.push({
|
||||||
}
|
name: i.name,
|
||||||
}
|
error: `The entered string has more than ${option.max_length} characters. The maximum required is ${option.max_length} characters.`,
|
||||||
break;
|
});
|
||||||
case ApplicationCommandOptionType.Mentionable:
|
|
||||||
{
|
|
||||||
const matches = message.content.match(/<@[0-9]{17,19}(?=>)|<@&[0-9]{17,19}(?=>)/g) ?? [];
|
|
||||||
for (const match of matches) {
|
|
||||||
if (match.includes('&')) {
|
|
||||||
const rawId = match.slice(3);
|
|
||||||
if (rawId) {
|
|
||||||
const role = i.required
|
|
||||||
? (await self.roles.list(message.guild_id!)).find(x => x.id === rawId)
|
|
||||||
: await self.cache.roles?.get(rawId);
|
|
||||||
if (role) {
|
|
||||||
value = rawId;
|
|
||||||
//@ts-expect-error
|
|
||||||
resolved.roles[rawId] = role;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
if (option.choices?.length) {
|
||||||
const rawId = match.slice(2);
|
if (!option.choices.some(x => x.name === value)) {
|
||||||
const raw = message.mentions.find(x => rawId === x.id);
|
value = undefined;
|
||||||
if (raw) {
|
errors.push({
|
||||||
value = raw.id;
|
name: i.name,
|
||||||
resolved.users[raw.id] = raw;
|
error: `The entered choice is invalid. Please choose one of the following options: ${option.choices
|
||||||
break;
|
.map(x => x.name)
|
||||||
|
.join(', ')}.`,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = option.choices.find(x => x.name === value)!.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
case ApplicationCommandOptionType.Number:
|
||||||
case ApplicationCommandOptionType.Role:
|
case ApplicationCommandOptionType.Integer:
|
||||||
{
|
{
|
||||||
const rawId = message.mention_roles.find(x => args[i.name]?.includes(x));
|
value = Number(args[i.name]);
|
||||||
if (rawId) {
|
if (args[i.name] === undefined) {
|
||||||
const role = i.required
|
value = undefined;
|
||||||
? (await self.roles.list(message.guild_id!)).find(x => x.id === rawId) //why, discord, why
|
break;
|
||||||
: await self.cache.roles?.get(rawId);
|
|
||||||
if (role) {
|
|
||||||
value = rawId;
|
|
||||||
//@ts-expect-error
|
|
||||||
resolved.roles[rawId] = role;
|
|
||||||
}
|
}
|
||||||
}
|
if (Number.isNaN(value)) {
|
||||||
}
|
value = undefined;
|
||||||
break;
|
errors.push({
|
||||||
case ApplicationCommandOptionType.User:
|
name: i.name,
|
||||||
{
|
error: 'The entered choice is an invalid number.',
|
||||||
const raw = message.mentions.find(x => args[i.name]?.includes(x.id));
|
});
|
||||||
if (raw) {
|
break;
|
||||||
value = raw.id;
|
}
|
||||||
resolved.users[raw.id] = raw;
|
const option = i as SeyfertNumberOption | SeyfertIntegerOption;
|
||||||
}
|
if (option.min_value) {
|
||||||
}
|
if (value < option.min_value) {
|
||||||
break;
|
|
||||||
case ApplicationCommandOptionType.String:
|
|
||||||
{
|
|
||||||
value = args[i.name];
|
|
||||||
const option = i as SeyfertStringOption;
|
|
||||||
if (value) {
|
|
||||||
if (option.min_length) {
|
|
||||||
if (value.length < option.min_length) {
|
|
||||||
value = undefined;
|
value = undefined;
|
||||||
errors.push({
|
errors.push({
|
||||||
name: i.name,
|
name: i.name,
|
||||||
error: `The entered string has less than ${option.min_length} characters. The minimum required is ${option.min_length} characters.`,
|
error: `The entered number is less than ${option.min_value}. The minimum allowed is ${option.min_value}`,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (option.max_length) {
|
if (option.max_value) {
|
||||||
if (value.length > option.max_length) {
|
if (value > option.max_value) {
|
||||||
value = undefined;
|
value = undefined;
|
||||||
errors.push({
|
errors.push({
|
||||||
name: i.name,
|
name: i.name,
|
||||||
error: `The entered string has more than ${option.max_length} characters. The maximum required is ${option.max_length} characters.`,
|
error: `The entered number is greater than ${option.max_value}. The maximum allowed is ${option.max_value}`,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -302,75 +382,27 @@ async function parseOptions(
|
|||||||
value = option.choices.find(x => x.name === value)!.value;
|
value = option.choices.find(x => x.name === value)!.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
break;
|
default:
|
||||||
case ApplicationCommandOptionType.Number:
|
break;
|
||||||
case ApplicationCommandOptionType.Integer:
|
}
|
||||||
{
|
if (value !== undefined) {
|
||||||
value = Number(args[i.name]);
|
options.push({
|
||||||
if (args[i.name] === undefined) {
|
name: i.name,
|
||||||
value = undefined;
|
type: i.type,
|
||||||
break;
|
value,
|
||||||
}
|
} as APIApplicationCommandInteractionDataOption);
|
||||||
if (Number.isNaN(value)) {
|
} else if (i.required)
|
||||||
value = undefined;
|
errors.push({
|
||||||
errors.push({
|
error: 'Option is required but returned undefined',
|
||||||
name: i.name,
|
name: i.name,
|
||||||
error: 'The entered choice is an invalid number.',
|
});
|
||||||
});
|
} catch (e) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
const option = i as SeyfertNumberOption | SeyfertIntegerOption;
|
|
||||||
if (option.min_value) {
|
|
||||||
if (value < option.min_value) {
|
|
||||||
value = undefined;
|
|
||||||
errors.push({
|
|
||||||
name: i.name,
|
|
||||||
error: `The entered number is less than ${option.min_value}. The minimum allowed is ${option.min_value}`,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (option.max_value) {
|
|
||||||
if (value > option.max_value) {
|
|
||||||
value = undefined;
|
|
||||||
errors.push({
|
|
||||||
name: i.name,
|
|
||||||
error: `The entered number is greater than ${option.max_value}. The maximum allowed is ${option.max_value}`,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (option.choices?.length) {
|
|
||||||
if (!option.choices.some(x => x.name === value)) {
|
|
||||||
value = undefined;
|
|
||||||
errors.push({
|
|
||||||
name: i.name,
|
|
||||||
error: `The entered choice is invalid. Please choose one of the following options: ${option.choices
|
|
||||||
.map(x => x.name)
|
|
||||||
.join(', ')}.`,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
value = option.choices.find(x => x.name === value)!.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (value !== undefined) {
|
|
||||||
options.push({
|
|
||||||
name: i.name,
|
|
||||||
type: i.type,
|
|
||||||
value,
|
|
||||||
} as APIApplicationCommandInteractionDataOption);
|
|
||||||
}
|
|
||||||
if (i.required && value === undefined)
|
|
||||||
errors.push({
|
errors.push({
|
||||||
error: 'Option is required but returned undefined',
|
error: e && typeof e === 'object' && 'message' in e ? (e.message as string) : `${e}`,
|
||||||
name: i.name,
|
name: i.name,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { errors, options };
|
return { errors, options };
|
||||||
|
@ -1,5 +1,14 @@
|
|||||||
import { Attachment, GuildMember } from '..';
|
import { Attachment, GuildMember } from '..';
|
||||||
import type { APIApplicationCommandInteractionDataOption, APIInteractionDataResolved, MakeRequired } from '../common';
|
import type {
|
||||||
|
APIApplicationCommandInteractionDataOption,
|
||||||
|
APIAttachment,
|
||||||
|
APIGuildMember,
|
||||||
|
APIInteractionDataResolvedChannel,
|
||||||
|
APIInteractionGuildMember,
|
||||||
|
APIRole,
|
||||||
|
APIUser,
|
||||||
|
MakeRequired,
|
||||||
|
} from '../common';
|
||||||
import { ApplicationCommandOptionType } from '../common';
|
import { ApplicationCommandOptionType } from '../common';
|
||||||
import type { AllChannels } from '../structures';
|
import type { AllChannels } from '../structures';
|
||||||
import { GuildRole, InteractionGuildMember, User } from '../structures';
|
import { GuildRole, InteractionGuildMember, User } from '../structures';
|
||||||
@ -7,6 +16,14 @@ import channelFrom from '../structures/channels';
|
|||||||
import type { Command, CommandAutocompleteOption, CommandOption, SubCommand } from './applications/chat';
|
import type { Command, CommandAutocompleteOption, CommandOption, SubCommand } from './applications/chat';
|
||||||
import type { UsingClient } from './applications/shared';
|
import type { UsingClient } from './applications/shared';
|
||||||
|
|
||||||
|
export type ContextOptionsResolved = {
|
||||||
|
members?: Record<string, APIGuildMember | APIInteractionGuildMember | GuildMember | InteractionGuildMember>;
|
||||||
|
users?: Record<string, APIUser | User>;
|
||||||
|
roles?: Record<string, APIRole | GuildRole>;
|
||||||
|
channels?: Record<string, APIInteractionDataResolvedChannel | AllChannels>;
|
||||||
|
attachments?: Record<string, APIAttachment | Attachment>;
|
||||||
|
};
|
||||||
|
|
||||||
export class OptionResolver {
|
export class OptionResolver {
|
||||||
readonly options: OptionResolved[];
|
readonly options: OptionResolved[];
|
||||||
public hoistedOptions: OptionResolved[];
|
public hoistedOptions: OptionResolved[];
|
||||||
@ -17,7 +34,7 @@ export class OptionResolver {
|
|||||||
options: APIApplicationCommandInteractionDataOption[],
|
options: APIApplicationCommandInteractionDataOption[],
|
||||||
public parent?: Command,
|
public parent?: Command,
|
||||||
public guildId?: string,
|
public guildId?: string,
|
||||||
public resolved?: APIInteractionDataResolved,
|
public resolved?: ContextOptionsResolved,
|
||||||
) {
|
) {
|
||||||
this.hoistedOptions = this.options = options.map(option => this.transformOption(option, resolved));
|
this.hoistedOptions = this.options = options.map(option => this.transformOption(option, resolved));
|
||||||
|
|
||||||
@ -129,7 +146,7 @@ export class OptionResolver {
|
|||||||
return option.value as string;
|
return option.value as string;
|
||||||
}
|
}
|
||||||
|
|
||||||
transformOption(option: APIApplicationCommandInteractionDataOption, resolved?: APIInteractionDataResolved) {
|
transformOption(option: APIApplicationCommandInteractionDataOption, resolved?: ContextOptionsResolved) {
|
||||||
const resolve: OptionResolved = {
|
const resolve: OptionResolved = {
|
||||||
...option,
|
...option,
|
||||||
};
|
};
|
||||||
@ -144,16 +161,18 @@ export class OptionResolver {
|
|||||||
const value = resolve.value as string;
|
const value = resolve.value as string;
|
||||||
const user = resolved.users?.[value];
|
const user = resolved.users?.[value];
|
||||||
if (user) {
|
if (user) {
|
||||||
resolve.user = new User(this.client, user);
|
resolve.user = user instanceof User ? user : new User(this.client, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
const member = resolved.members?.[value];
|
const member = resolved.members?.[value];
|
||||||
|
|
||||||
if (member) {
|
if (member) {
|
||||||
resolve.member =
|
resolve.member =
|
||||||
member instanceof GuildMember
|
member instanceof GuildMember || member instanceof InteractionGuildMember
|
||||||
? member
|
? member
|
||||||
: new InteractionGuildMember(this.client, member, user!, this.guildId!);
|
: 'permissions' in member
|
||||||
|
? new InteractionGuildMember(this.client, member, user!, this.guildId!)
|
||||||
|
: new GuildMember(this.client, member, user!, this.guildId!);
|
||||||
}
|
}
|
||||||
|
|
||||||
const channel = resolved.channels?.[value];
|
const channel = resolved.channels?.[value];
|
||||||
@ -168,7 +187,7 @@ export class OptionResolver {
|
|||||||
|
|
||||||
const attachment = resolved.attachments?.[value];
|
const attachment = resolved.attachments?.[value];
|
||||||
if (attachment) {
|
if (attachment) {
|
||||||
resolve.attachment = new Attachment(this.client, attachment);
|
resolve.attachment = attachment instanceof Attachment ? attachment : new Attachment(this.client, attachment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
18
src/index.ts
18
src/index.ts
@ -1,7 +1,13 @@
|
|||||||
import type { InternalRuntimeConfig, InternalRuntimeConfigHTTP, RuntimeConfig, RuntimeConfigHTTP } from './client/base';
|
import type { InternalRuntimeConfig, InternalRuntimeConfigHTTP, RuntimeConfig, RuntimeConfigHTTP } from './client/base';
|
||||||
import { GatewayIntentBits } from './common';
|
import type { InferWithPrefix } from './commands';
|
||||||
|
import { GatewayIntentBits, type When } from './common';
|
||||||
import type { ClientNameEvents, EventContext } from './events';
|
import type { ClientNameEvents, EventContext } from './events';
|
||||||
import type { ChatInputCommandInteraction, Message, MessageCommandInteraction, UserCommandInteraction } from './structures';
|
import type {
|
||||||
|
ChatInputCommandInteraction,
|
||||||
|
Message,
|
||||||
|
MessageCommandInteraction,
|
||||||
|
UserCommandInteraction,
|
||||||
|
} from './structures';
|
||||||
|
|
||||||
export { Logger, PermissionFlagsBits, PermissionStrings, Watcher } from './common';
|
export { Logger, PermissionFlagsBits, PermissionStrings, Watcher } from './common';
|
||||||
//
|
//
|
||||||
@ -95,7 +101,13 @@ export const config = {
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export function extendContext<T extends {}>(
|
export function extendContext<T extends {}>(
|
||||||
cb: (interaction: ChatInputCommandInteraction | UserCommandInteraction | MessageCommandInteraction | Message) => T,
|
cb: (
|
||||||
|
interaction:
|
||||||
|
| ChatInputCommandInteraction
|
||||||
|
| UserCommandInteraction
|
||||||
|
| MessageCommandInteraction
|
||||||
|
| When<InferWithPrefix, Message, never>,
|
||||||
|
) => T,
|
||||||
) {
|
) {
|
||||||
return cb;
|
return cb;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { mix } from 'ts-mixer';
|
|||||||
import type { RawFile } from '../api';
|
import type { RawFile } from '../api';
|
||||||
import { ActionRow, Embed, Modal, resolveAttachment, resolveFiles } from '../builders';
|
import { ActionRow, Embed, Modal, resolveAttachment, resolveFiles } from '../builders';
|
||||||
import type { BaseClient } from '../client/base';
|
import type { BaseClient } from '../client/base';
|
||||||
import { OptionResolver, type UsingClient } from '../commands';
|
import { type ContextOptionsResolved, OptionResolver, type UsingClient } from '../commands';
|
||||||
import type {
|
import type {
|
||||||
APIActionRowComponent,
|
APIActionRowComponent,
|
||||||
APIApplicationCommandAutocompleteInteraction,
|
APIApplicationCommandAutocompleteInteraction,
|
||||||
@ -303,7 +303,7 @@ export class AutocompleteInteraction<FromGuild extends boolean = boolean> extend
|
|||||||
interaction.data.options,
|
interaction.data.options,
|
||||||
undefined,
|
undefined,
|
||||||
interaction.guild_id,
|
interaction.guild_id,
|
||||||
interaction.data.resolved,
|
interaction.data.resolved as ContextOptionsResolved,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user