From 6e7a5bf89feb869e656cb1a07bb29a664b1ebd41 Mon Sep 17 00:00:00 2001 From: Jeroen Claassens Date: Wed, 7 Aug 2024 19:58:07 +0200 Subject: [PATCH] refactor: changed no match errors to emit on a subcommand listener instead of the root MessageCommandError / ChatInputCommandError (#601) BREAKING CHANGE: If no subcommand matched the error was emitted to `MessageCommandError` or `ChatInputCommandError`. This was inconsistent with errors during runtime emitted to `MessageSubcommandError` and `ChatInputSubcommandError` respectively. Therefore these events are now emitted to the new events `PluginMessageSubcommandNoMatch` and `PluginChatInputSubcommandNoMatch` respectively. New built-in listeners for these events will log the infractions to the console at the error level. You can override these listeners to provide your functionality. --- packages/subcommands/src/lib/Subcommand.ts | 33 +++++++++++-------- packages/subcommands/src/lib/types/Events.ts | 15 ++++++++- .../PluginChatInputSubcommandNoMatch.ts | 12 +++++++ .../PluginMessageSubcommandNoMatch.ts | 13 ++++++++ packages/subcommands/src/listeners/_load.ts | 12 +++++++ 5 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 packages/subcommands/src/listeners/PluginChatInputSubcommandNoMatch.ts create mode 100644 packages/subcommands/src/listeners/PluginMessageSubcommandNoMatch.ts diff --git a/packages/subcommands/src/lib/Subcommand.ts b/packages/subcommands/src/lib/Subcommand.ts index de4128c8..f54047e9 100644 --- a/packages/subcommands/src/lib/Subcommand.ts +++ b/packages/subcommands/src/lib/Subcommand.ts @@ -233,7 +233,7 @@ export class Subcommand>> { args.save(); const parameters = await args.restResult('string'); diff --git a/packages/subcommands/src/lib/types/Events.ts b/packages/subcommands/src/lib/types/Events.ts index ad72822c..73a0e334 100644 --- a/packages/subcommands/src/lib/types/Events.ts +++ b/packages/subcommands/src/lib/types/Events.ts @@ -1,4 +1,4 @@ -import type { ChatInputCommand, MessageCommand, MessageCommandDeniedPayload, UserError } from '@sapphire/framework'; +import type { Args, ChatInputCommand, ChatInputCommandContext, MessageCommand, MessageCommandDeniedPayload, UserError } from '@sapphire/framework'; import type { Message } from 'discord.js'; import type { Subcommand } from '../Subcommand'; import type { ChatInputCommandSubcommandMappingMethod, MessageSubcommandMappingMethod, SubcommandMappingMethod } from './SubcommandMappings'; @@ -8,11 +8,13 @@ export const SubcommandPluginEvents = { ChatInputSubcommandRun: 'chatInputSubcommandRun' as const, ChatInputSubcommandSuccess: 'chatInputSubcommandSuccess' as const, ChatInputSubcommandError: 'chatInputSubcommandError' as const, + ChatInputSubcommandNoMatch: 'chatInputSubcommandNoMatch' as const, MessageSubcommandDenied: 'messageSubcommandDenied' as const, MessageSubcommandRun: 'messageSubcommandRun' as const, MessageSubcommandSuccess: 'messageSubcommandSuccess' as const, MessageSubcommandError: 'messageSubcommandError' as const, + MessageSubcommandNoMatch: 'messageSubcommandNoMatch' as const, SubcommandMappingIsMissingMessageCommandHandler: 'subcommandMappingIsMissingMessageCommandHandler' as const, SubcommandMappingIsMissingChatInputCommandHandler: 'subcommandMappingIsMissingChatInputCommandHandler' as const @@ -25,10 +27,19 @@ export enum SubcommandPluginIdentifiers { } export interface MessageSubcommandNoMatchContext extends MessageCommand.RunContext { + command: Subcommand; + identifier: SubcommandPluginIdentifiers.MessageSubcommandNoMatch; + message: string; possibleSubcommandName: string | null; possibleSubcommandGroupOrName: string | null; } +export interface ChatInputSubcommandNoMatchContext extends ChatInputCommandContext { + command: Subcommand; + identifier: SubcommandPluginIdentifiers.ChatInputSubcommandNoMatch; + message: string; +} + export interface IMessageSubcommandPayload { message: Message; command: Subcommand; @@ -87,6 +98,7 @@ declare module 'discord.js' { payload: ChatInputSubcommandSuccessPayload ]; [SubcommandPluginEvents.ChatInputSubcommandError]: [error: unknown, payload: ChatInputSubcommandErrorPayload]; + [SubcommandPluginEvents.ChatInputSubcommandNoMatch]: [interaction: ChatInputCommand.Interaction, context: ChatInputSubcommandNoMatchContext]; [SubcommandPluginEvents.MessageSubcommandDenied]: [error: UserError, payload: MessageSubcommandDeniedPayload]; [SubcommandPluginEvents.MessageSubcommandRun]: [ @@ -100,6 +112,7 @@ declare module 'discord.js' { payload: MessageSubcommandSuccessPayload ]; [SubcommandPluginEvents.MessageSubcommandError]: [error: unknown, payload: MessageSubcommandErrorPayload]; + [SubcommandPluginEvents.MessageSubcommandNoMatch]: [message: Message, args: Args, context: MessageSubcommandNoMatchContext]; [SubcommandPluginEvents.SubcommandMappingIsMissingMessageCommandHandler]: [ message: Message, diff --git a/packages/subcommands/src/listeners/PluginChatInputSubcommandNoMatch.ts b/packages/subcommands/src/listeners/PluginChatInputSubcommandNoMatch.ts new file mode 100644 index 00000000..c88d7367 --- /dev/null +++ b/packages/subcommands/src/listeners/PluginChatInputSubcommandNoMatch.ts @@ -0,0 +1,12 @@ +import { Listener, type ChatInputCommand } from '@sapphire/framework'; +import { SubcommandPluginEvents, type ChatInputSubcommandNoMatchContext } from '../lib/types/Events'; + +export class PluginListener extends Listener { + public constructor(context: Listener.LoaderContext) { + super(context, { event: SubcommandPluginEvents.ChatInputSubcommandNoMatch }); + } + + public override run(_interaction: ChatInputCommand.Interaction, context: ChatInputSubcommandNoMatchContext) { + this.container.logger.error(context.message); + } +} diff --git a/packages/subcommands/src/listeners/PluginMessageSubcommandNoMatch.ts b/packages/subcommands/src/listeners/PluginMessageSubcommandNoMatch.ts new file mode 100644 index 00000000..09561b3d --- /dev/null +++ b/packages/subcommands/src/listeners/PluginMessageSubcommandNoMatch.ts @@ -0,0 +1,13 @@ +import { Args, Listener } from '@sapphire/framework'; +import type { Message } from 'discord.js'; +import { SubcommandPluginEvents, type MessageSubcommandNoMatchContext } from '../lib/types/Events'; + +export class PluginListener extends Listener { + public constructor(context: Listener.LoaderContext) { + super(context, { event: SubcommandPluginEvents.MessageSubcommandNoMatch }); + } + + public override run(_message: Message, _args: Args, context: MessageSubcommandNoMatchContext) { + this.container.logger.error(context.message); + } +} diff --git a/packages/subcommands/src/listeners/_load.ts b/packages/subcommands/src/listeners/_load.ts index 8d25cff1..da8277af 100644 --- a/packages/subcommands/src/listeners/_load.ts +++ b/packages/subcommands/src/listeners/_load.ts @@ -1,6 +1,8 @@ import { container } from '@sapphire/pieces'; import { PluginListener as PluginChatInputSubcommandError } from './PluginChatInputSubcommandError'; +import { PluginListener as PluginChatInputSubcommandNoMatch } from './PluginChatInputSubcommandNoMatch'; import { PluginListener as PluginMessageSubcommandError } from './PluginMessageSubcommandError'; +import { PluginListener as PluginMessageSubcommandNoMatch } from './PluginMessageSubcommandNoMatch'; import { PluginListener as PluginSubcommandMappingIsMissingChatInputCommandHandler } from './PluginSubcommandMappingIsMissingChatInputCommandHandler'; import { PluginListener as PluginSubcommandMappingIsMissingMessageCommandHandler } from './PluginSubcommandMappingIsMissingMessageCommandHandler'; @@ -18,4 +20,14 @@ export function loadListeners() { piece: PluginSubcommandMappingIsMissingMessageCommandHandler, store }); + void container.stores.loadPiece({ + name: 'PluginMessageSubcommandNoMatch', + piece: PluginMessageSubcommandNoMatch, + store + }); + void container.stores.loadPiece({ + name: 'PluginChatInputSubcommandNoMatch', + piece: PluginChatInputSubcommandNoMatch, + store + }); }