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 { Cache, MemoryAdapter } from '../cache';
|
||||
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 {
|
||||
ChannelShorter,
|
||||
@ -24,10 +24,15 @@ import {
|
||||
type MakeRequired,
|
||||
} 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 { LangsHandler } from '../langs/handler';
|
||||
import type { ChatInputCommandInteraction, Message, MessageCommandInteraction, UserCommandInteraction } from '../structures';
|
||||
import type {
|
||||
ChatInputCommandInteraction,
|
||||
Message,
|
||||
MessageCommandInteraction,
|
||||
UserCommandInteraction,
|
||||
} from '../structures';
|
||||
|
||||
export class BaseClient {
|
||||
rest!: ApiHandler;
|
||||
@ -246,7 +251,7 @@ export interface BaseClientOptions {
|
||||
| ChatInputCommandInteraction<boolean>
|
||||
| UserCommandInteraction<boolean>
|
||||
| MessageCommandInteraction<boolean>
|
||||
| Message
|
||||
| When<InferWithPrefix, Message, never>,
|
||||
) => {};
|
||||
globalMiddlewares?: readonly (keyof RegisteredMiddlewares)[];
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
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 {
|
||||
ChatInputCommandInteraction,
|
||||
ComponentInteraction,
|
||||
@ -32,7 +39,7 @@ export async function onInteractionCreate(
|
||||
body.data.options ?? [],
|
||||
parentCommand as Command,
|
||||
body.data.guild_id,
|
||||
body.data.resolved,
|
||||
body.data.resolved as ContextOptionsResolved,
|
||||
);
|
||||
const interaction = new AutocompleteInteraction(self, body, __reply);
|
||||
const command = optionsResolver.getAutocomplete();
|
||||
@ -139,7 +146,7 @@ export async function onInteractionCreate(
|
||||
packetData.options ?? [],
|
||||
parentCommand as Command,
|
||||
packetData.guild_id,
|
||||
packetData.resolved,
|
||||
packetData.resolved as ContextOptionsResolved,
|
||||
);
|
||||
const interaction = BaseInteraction.from(self, body, __reply) as ChatInputCommandInteraction;
|
||||
const command = optionsResolver.getCommand();
|
||||
|
@ -2,14 +2,15 @@ import {
|
||||
ApplicationCommandOptionType,
|
||||
ChannelType,
|
||||
type APIApplicationCommandInteractionDataOption,
|
||||
type APIInteractionDataResolved,
|
||||
type GatewayMessageCreateDispatchData,
|
||||
} from 'discord-api-types/v10';
|
||||
import {
|
||||
Command,
|
||||
CommandContext,
|
||||
type ContextOptionsResolved,
|
||||
OptionResolver,
|
||||
SubCommand,
|
||||
User,
|
||||
type Client,
|
||||
type CommandOption,
|
||||
type SeyfertChannelOption,
|
||||
@ -88,7 +89,7 @@ export async function onMessageCreate(
|
||||
if (command.dm && !message.guildId) return;
|
||||
if (command.guild_id && !command.guild_id?.includes(message.guildId!)) return;
|
||||
|
||||
const resolved: MakeRequired<APIInteractionDataResolved> = {
|
||||
const resolved: MakeRequired<ContextOptionsResolved> = {
|
||||
channels: {},
|
||||
roles: {},
|
||||
users: {},
|
||||
@ -99,6 +100,7 @@ export async function onMessageCreate(
|
||||
const { options, errors } = await parseOptions(self, command, rawMessage, args, resolved);
|
||||
const optionsResolver = new OptionResolver(self, options, parent as Command, message.guildId, resolved);
|
||||
const context = new CommandContext(self, message, optionsResolver, shardId, command);
|
||||
//@ts-expect-error
|
||||
const extendContext = self.options?.context?.(message) ?? {};
|
||||
Object.assign(context, extendContext);
|
||||
try {
|
||||
@ -167,11 +169,12 @@ async function parseOptions(
|
||||
command: Command | SubCommand,
|
||||
message: GatewayMessageCreateDispatchData,
|
||||
args: Partial<Record<string, string>>,
|
||||
resolved: MakeRequired<APIInteractionDataResolved, keyof APIInteractionDataResolved>,
|
||||
resolved: MakeRequired<ContextOptionsResolved>,
|
||||
) {
|
||||
const options: APIApplicationCommandInteractionDataOption[] = [];
|
||||
const errors: { name: string; error: string }[] = [];
|
||||
for (const i of (command.options ?? []) as (CommandOption & { type: ApplicationCommandOptionType })[]) {
|
||||
try {
|
||||
let value: string | boolean | number | undefined;
|
||||
let indexAttachment = -1;
|
||||
switch (i.type) {
|
||||
@ -188,9 +191,12 @@ async function parseOptions(
|
||||
break;
|
||||
case ApplicationCommandOptionType.Channel:
|
||||
{
|
||||
const rawId = message.content.match(/(?<=<#)[0-9]{17,19}(?=>)/g)?.find(x => args[i.name]?.includes(x));
|
||||
const rawId =
|
||||
message.content.match(/(?<=<#)[0-9]{17,19}(?=>)/g)?.find(x => args[i.name]?.includes(x)) ||
|
||||
args[i.name]?.match(/[0-9]{17,19}/g)?.[0];
|
||||
if (rawId) {
|
||||
const channel = i.required ? await self.channels.fetch(rawId) : await self.cache.channels?.get(rawId);
|
||||
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)) {
|
||||
@ -204,7 +210,6 @@ async function parseOptions(
|
||||
}
|
||||
}
|
||||
value = rawId;
|
||||
//@ts-expect-error
|
||||
resolved.channels[rawId] = channel;
|
||||
}
|
||||
}
|
||||
@ -217,12 +222,11 @@ async function parseOptions(
|
||||
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);
|
||||
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;
|
||||
//@ts-expect-error
|
||||
resolved.roles[rawId] = role;
|
||||
break;
|
||||
}
|
||||
@ -231,8 +235,10 @@ async function parseOptions(
|
||||
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] = raw;
|
||||
resolved.users[raw.id] = user;
|
||||
if (member) resolved.members[raw.id] = member;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -241,14 +247,15 @@ async function parseOptions(
|
||||
break;
|
||||
case ApplicationCommandOptionType.Role:
|
||||
{
|
||||
const rawId = message.mention_roles.find(x => args[i.name]?.includes(x));
|
||||
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 = i.required
|
||||
? (await self.roles.list(message.guild_id!)).find(x => x.id === rawId) //why, discord, why
|
||||
: await self.cache.roles?.get(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;
|
||||
//@ts-expect-error
|
||||
resolved.roles[rawId] = role;
|
||||
}
|
||||
}
|
||||
@ -256,10 +263,30 @@ async function parseOptions(
|
||||
break;
|
||||
case ApplicationCommandOptionType.User:
|
||||
{
|
||||
const raw = message.mentions.find(x => args[i.name]?.includes(x.id));
|
||||
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;
|
||||
@ -365,12 +392,17 @@ async function parseOptions(
|
||||
type: i.type,
|
||||
value,
|
||||
} as APIApplicationCommandInteractionDataOption);
|
||||
}
|
||||
if (i.required && value === undefined)
|
||||
} else if (i.required)
|
||||
errors.push({
|
||||
error: 'Option is required but returned undefined',
|
||||
name: i.name,
|
||||
});
|
||||
} catch (e) {
|
||||
errors.push({
|
||||
error: e && typeof e === 'object' && 'message' in e ? (e.message as string) : `${e}`,
|
||||
name: i.name,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { errors, options };
|
||||
|
@ -1,5 +1,14 @@
|
||||
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 type { AllChannels } 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 { 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 {
|
||||
readonly options: OptionResolved[];
|
||||
public hoistedOptions: OptionResolved[];
|
||||
@ -17,7 +34,7 @@ export class OptionResolver {
|
||||
options: APIApplicationCommandInteractionDataOption[],
|
||||
public parent?: Command,
|
||||
public guildId?: string,
|
||||
public resolved?: APIInteractionDataResolved,
|
||||
public resolved?: ContextOptionsResolved,
|
||||
) {
|
||||
this.hoistedOptions = this.options = options.map(option => this.transformOption(option, resolved));
|
||||
|
||||
@ -129,7 +146,7 @@ export class OptionResolver {
|
||||
return option.value as string;
|
||||
}
|
||||
|
||||
transformOption(option: APIApplicationCommandInteractionDataOption, resolved?: APIInteractionDataResolved) {
|
||||
transformOption(option: APIApplicationCommandInteractionDataOption, resolved?: ContextOptionsResolved) {
|
||||
const resolve: OptionResolved = {
|
||||
...option,
|
||||
};
|
||||
@ -144,16 +161,18 @@ export class OptionResolver {
|
||||
const value = resolve.value as string;
|
||||
const user = resolved.users?.[value];
|
||||
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];
|
||||
|
||||
if (member) {
|
||||
resolve.member =
|
||||
member instanceof GuildMember
|
||||
member instanceof GuildMember || member instanceof InteractionGuildMember
|
||||
? 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];
|
||||
@ -168,7 +187,7 @@ export class OptionResolver {
|
||||
|
||||
const attachment = resolved.attachments?.[value];
|
||||
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 { GatewayIntentBits } from './common';
|
||||
import type { InferWithPrefix } from './commands';
|
||||
import { GatewayIntentBits, type When } from './common';
|
||||
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';
|
||||
//
|
||||
@ -95,7 +101,13 @@ export const config = {
|
||||
* });
|
||||
*/
|
||||
export function extendContext<T extends {}>(
|
||||
cb: (interaction: ChatInputCommandInteraction | UserCommandInteraction | MessageCommandInteraction | Message) => T,
|
||||
cb: (
|
||||
interaction:
|
||||
| ChatInputCommandInteraction
|
||||
| UserCommandInteraction
|
||||
| MessageCommandInteraction
|
||||
| When<InferWithPrefix, Message, never>,
|
||||
) => T,
|
||||
) {
|
||||
return cb;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { mix } from 'ts-mixer';
|
||||
import type { RawFile } from '../api';
|
||||
import { ActionRow, Embed, Modal, resolveAttachment, resolveFiles } from '../builders';
|
||||
import type { BaseClient } from '../client/base';
|
||||
import { OptionResolver, type UsingClient } from '../commands';
|
||||
import { type ContextOptionsResolved, OptionResolver, type UsingClient } from '../commands';
|
||||
import type {
|
||||
APIActionRowComponent,
|
||||
APIApplicationCommandAutocompleteInteraction,
|
||||
@ -303,7 +303,7 @@ export class AutocompleteInteraction<FromGuild extends boolean = boolean> extend
|
||||
interaction.data.options,
|
||||
undefined,
|
||||
interaction.guild_id,
|
||||
interaction.data.resolved,
|
||||
interaction.data.resolved as ContextOptionsResolved,
|
||||
);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user