From 79835a3b470086fee75c6128aeb537dae9201bdc Mon Sep 17 00:00:00 2001 From: Luis Bauza Date: Wed, 19 Feb 2025 12:01:09 -0500 Subject: [PATCH] refactor: Migrate to ES modules and implement command loading utility for improved structure and logging --- bot.js | 34 +++++++++++++++------------------- deploy-commands.js | 20 +++++--------------- playbook.yml | 6 ++++++ utils/commandLoader.js | 31 +++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 34 deletions(-) create mode 100644 utils/commandLoader.js diff --git a/bot.js b/bot.js index c8d0ea0..677ca93 100644 --- a/bot.js +++ b/bot.js @@ -6,11 +6,17 @@ // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -require('dotenv').config(); -const fs = require('node:fs'); -const path = require('node:path'); -const { Client, Collection, Events, GatewayIntentBits } = require('discord.js'); -const Logger = require('./logger'); +import 'dotenv/config'; +import { fileURLToPath } from 'url'; +import { dirname } from 'path'; +import fs from 'node:fs'; +import path from 'node:path'; +import { Client, Collection, Events, GatewayIntentBits } from 'discord.js'; +import Logger from './logger.js'; +import { loadCommands } from './utils/commandLoader.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); const logger = new Logger('bot'); @@ -24,21 +30,11 @@ const client = new Client({ client.commands = new Collection(); const commandsPath = path.join(__dirname, 'commands'); -const commandFiles = fs.readdirSync(commandsPath).filter(file => file.endsWith('.js')); -await Promise.all( - commandFiles.map(async file => { - const filePath = path.join(commandsPath, file); - const command = await import(filePath); - if ('data' in command && 'execute' in command) { - client.commands.set(command.data.name, command); - } else { - logger.warn( - `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.`, - ); - } - }), -); +const commands = await loadCommands(commandsPath, logger); +commands.forEach(command => { + client.commands.set(command.data.name, command); +}); client.once(Events.ClientReady, () => { logger.log(`Ready! Logged in as ${client.user.tag}`); diff --git a/deploy-commands.js b/deploy-commands.js index 33078de..47a9bc2 100644 --- a/deploy-commands.js +++ b/deploy-commands.js @@ -8,39 +8,29 @@ import dotenv from 'dotenv'; import { REST, Routes } from 'discord.js'; -import { readdirSync } from 'node:fs'; import { join, dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; // eslint-disable-next-line import/extensions import Logger from './logger.js'; +import { loadCommands } from './utils/commandLoader.js'; dotenv.config(); const __dirname = dirname(fileURLToPath(import.meta.url)); const logger = new Logger('deploy-commands'); -const commands = []; const commandsPath = join(__dirname, 'commands'); -const commandFiles = readdirSync(commandsPath).filter(file => file.endsWith('.js')); - -await Promise.all( - commandFiles.map(async file => { - const filePath = join(commandsPath, file); - const command = await import(filePath); - if ('data' in command && 'execute' in command) { - commands.push(command.data.toJSON()); - } - }), -); +const commands = await loadCommands(commandsPath, logger); +const commandData = commands.map(command => command.data.toJSON()); const rest = new REST().setToken(process.env.DISCORD_TOKEN); (async () => { try { - logger.log(`Started refreshing ${commands.length} application (/) commands.`); + logger.log(`Started refreshing ${commandData.length} application (/) commands.`); const data = await rest.put(Routes.applicationCommands(process.env.CLIENT_ID), { - body: commands, + body: commandData, }); logger.log(`Successfully reloaded ${data.length} application (/) commands.`); diff --git a/playbook.yml b/playbook.yml index 1f95c06..3d3d900 100644 --- a/playbook.yml +++ b/playbook.yml @@ -46,6 +46,12 @@ dest: "{{ app_dir }}/commands/" mode: '0644' + - name: Copy utils directory + copy: + src: utils/ + dest: "{{ app_dir }}/utils/" + mode: '0644' + - name: Install npm dependencies npm: path: "{{ app_dir }}" diff --git a/utils/commandLoader.js b/utils/commandLoader.js new file mode 100644 index 0000000..9cd7006 --- /dev/null +++ b/utils/commandLoader.js @@ -0,0 +1,31 @@ +import { readdirSync } from 'node:fs'; +import { join } from 'node:path'; + +export async function loadCommands(commandsPath, logger) { + const commands = []; + const commandFiles = readdirSync(commandsPath).filter(file => file.endsWith('.js')); + + await Promise.all( + commandFiles.map(async file => { + try { + const filePath = join(commandsPath, file); + const commandModule = await import(filePath); + const command = commandModule.default; + + if (!command?.data || !command?.execute) { + logger.warn( + `[WARNING] The command at ${filePath} is missing a required "data" or "execute" property.` + ); + return; + } + + commands.push(command); + logger.log(`Loaded command: ${command.data.name}`); + } catch (error) { + logger.error(`Error loading command from ${file}:`, error); + } + }) + ); + + return commands; +}