diff --git a/src/lib/loaders/EventLoader.ts b/src/lib/loaders/EventLoader.ts new file mode 100644 index 0000000..9619d77 --- /dev/null +++ b/src/lib/loaders/EventLoader.ts @@ -0,0 +1,84 @@ +import { readdir } from "node:fs/promises"; +import { join } from "node:path"; +import type { Event } from "@lib/types"; +import type { LoadResult } from "./types"; +import type { Client } from "../BotClient"; + +/** + * Handles loading events from the file system + */ +export class EventLoader { + private client: Client; + + constructor(client: Client) { + this.client = client; + } + + /** + * Load events from a directory recursively + */ + async loadFromDirectory(dir: string, reload: boolean = false): Promise { + const result: LoadResult = { loaded: 0, skipped: 0, errors: [] }; + await this.scanDirectory(dir, reload, result); + return result; + } + + /** + * Recursively scan directory for event files + */ + private async scanDirectory(dir: string, reload: boolean, result: LoadResult): Promise { + try { + const files = await readdir(dir, { withFileTypes: true }); + + for (const file of files) { + const filePath = join(dir, file.name); + + if (file.isDirectory()) { + await this.scanDirectory(filePath, reload, result); + continue; + } + + if (!file.name.endsWith('.ts') && !file.name.endsWith('.js')) continue; + + await this.loadEventFile(filePath, reload, result); + } + } catch (error) { + console.error(`Error reading directory ${dir}:`, error); + result.errors.push({ file: dir, error }); + } + } + + /** + * Load a single event file + */ + private async loadEventFile(filePath: string, reload: boolean, result: LoadResult): Promise { + try { + const importPath = reload ? `${filePath}?t=${Date.now()}` : filePath; + const eventModule = await import(importPath); + const event = eventModule.default; + + if (this.isValidEvent(event)) { + if (event.once) { + this.client.once(event.name, (...args) => event.execute(...args)); + } else { + this.client.on(event.name, (...args) => event.execute(...args)); + } + console.log(`✅ Loaded event: ${event.name}`); + result.loaded++; + } else { + console.warn(`⚠️ Skipping invalid event in ${filePath}`); + result.skipped++; + } + } catch (error) { + console.error(`❌ Failed to load event from ${filePath}:`, error); + result.errors.push({ file: filePath, error }); + } + } + + /** + * Type guard to validate event structure + */ + private isValidEvent(event: any): event is Event { + return event && typeof event === 'object' && 'name' in event && 'execute' in event; + } +}