-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: modularize commands and handlers (#48)
Co-authored-by: Peïo Thibault <[email protected]>
- Loading branch information
1 parent
46baabd
commit a8f1d96
Showing
29 changed files
with
462 additions
and
362 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import type { BotModule } from '../types/bot'; | ||
|
||
export const checkUniqueSlashCommandNames = (modulesToLoad: Record<string, BotModule>) => { | ||
const slashCommandNames = Object.values(modulesToLoad) | ||
.flatMap((module) => module.slashCommands ?? []) | ||
.map((command) => command.schema.name); | ||
const uniqueSlashCommandNames = new Set(slashCommandNames); | ||
if (uniqueSlashCommandNames.size !== slashCommandNames.length) { | ||
throw new Error('Found duplicate slash command names'); | ||
} | ||
}; |
2 changes: 1 addition & 1 deletion
2
src/delete-existing-commands.ts → src/core/deleteExistingCommands.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { type Client } from 'discord.js'; | ||
|
||
import type { BotModule } from '../types/bot'; | ||
import { checkUniqueSlashCommandNames } from './checkUniqueSlashCommandNames'; | ||
import { pushCommands, routeCommands } from './loaderCommands'; | ||
import { routeHandlers } from './routeHandlers'; | ||
|
||
export const loadModules = async ( | ||
client: Client<true>, | ||
modulesToLoad: Record<string, BotModule>, | ||
): Promise<void> => { | ||
const botCommands = Object.values(modulesToLoad).flatMap((module) => module.slashCommands ?? []); | ||
|
||
checkUniqueSlashCommandNames(modulesToLoad); | ||
routeCommands(client, botCommands); | ||
await pushCommands(botCommands.map((command) => command.schema)); | ||
|
||
routeHandlers(client, modulesToLoad); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { | ||
Client, | ||
REST, | ||
type RESTPostAPIChatInputApplicationCommandsJSONBody, | ||
Routes, | ||
} from 'discord.js'; | ||
|
||
import { config } from '../config'; | ||
import type { BotCommand } from '../types/bot'; | ||
import { deleteExistingCommands } from './deleteExistingCommands'; | ||
|
||
const { discord } = config; | ||
|
||
export const pushCommands = async (commands: RESTPostAPIChatInputApplicationCommandsJSONBody[]) => { | ||
const rest = new REST({ version: '10' }).setToken(discord.token); | ||
await deleteExistingCommands(rest, discord); | ||
await rest.put(Routes.applicationGuildCommands(discord.clientId, discord.guildId), { | ||
body: commands, | ||
}); | ||
}; | ||
|
||
export const routeCommands = (client: Client<true>, botCommands: BotCommand[]) => | ||
client.on('interactionCreate', async (interaction) => { | ||
if (!interaction.inGuild() || !interaction.isChatInputCommand()) { | ||
return; | ||
} | ||
|
||
const command = botCommands.find((command) => command.schema.name === interaction.commandName); | ||
|
||
if (!command) { | ||
await interaction.reply({ | ||
content: `Command not found ${interaction.commandName}`, | ||
ephemeral: true, | ||
}); | ||
return; | ||
} | ||
|
||
if (typeof command.handler === 'function') { | ||
await command.handler(interaction); | ||
return; | ||
} | ||
|
||
const subCommand = command.handler[interaction.options.getSubcommand()]; | ||
|
||
if (!subCommand) { | ||
await interaction.reply({ | ||
content: `Subcommand not found ${ | ||
interaction.commandName | ||
} ${interaction.options.getSubcommand()}`, | ||
ephemeral: true, | ||
}); | ||
return; | ||
} | ||
|
||
await subCommand(interaction); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import type { Client, ClientEvents } from 'discord.js'; | ||
|
||
import type { BotModule, EventHandler } from '../types/bot'; | ||
|
||
export const routeHandlers = (client: Client<true>, modulesToLoad: Record<string, BotModule>) => { | ||
const eventNames = Object.values(modulesToLoad).flatMap( | ||
(module) => Object.keys(module.eventHandlers ?? {}) as (keyof ClientEvents)[], | ||
); | ||
const uniqueEventNames = [...new Set(eventNames)]; | ||
|
||
uniqueEventNames.forEach((eventName) => { | ||
const eventHandlersToCall = Object.values(modulesToLoad) | ||
.map((module) => module.eventHandlers?.[eventName]) | ||
.filter((e): e is EventHandler => Boolean(e)); | ||
|
||
client.on(eventName, async (...args) => { | ||
const handlersPromises = eventHandlersToCall.map(async (handler) => handler(...args)); | ||
await Promise.allSettled(handlersPromises); | ||
}); | ||
}); | ||
}; |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.