collection.ts

1import { readdirSync, statSync } from 'node:fs'
2import { join } from 'node:path'
3import { Client, Collection } from 'discord.js'
4import { Bot, Command, Event } from '@/types/bot'
5import Logger from '@/classes/logger'
6
7const isProd = process.env.NODE_ENV === 'production'
8
9export const commands = new Collection<string, Command>()
10export const events = new Collection<string, Event>()
11
12export function loadCommands(path: string) {
13	Logger.log('debug', `Loading commands from ${path}`)
14
15	try {
16		const files = readdirSync(path)
17
18		for (const file of files) {
19			const filePath = join(path, file)
20			const stat = statSync(filePath)
21
22			if (stat.isDirectory()) {
23				loadCommands(filePath)
24				continue
25			}
26
27			const fileExtension = isProd ? '.js' : '.ts'
28			if (!file.endsWith(fileExtension)) {
29				continue
30			}
31
32			try {
33				const command = require(filePath)
34
35				if (!command.default?.data?.name) {
36					Logger.log(
37						'warn',
38						`Command ${file} is missing required properties`,
39						'Commands',
40					)
41					continue
42				}
43
44				commands.set(command.default.data.name, command.default)
45				Logger.log('info', `Loaded command: ${file}`, 'Commands')
46			} catch (error: any) {
47				Logger.log(
48					'error',
49					`Failed to load command: ${file}: ${error.message}`,
50					'Commands',
51				)
52			}
53		}
54	} catch (error: any) {
55		Logger.log(
56			'error',
57			`Failed to read directory ${path}: ${error.message}`,
58			'Commands',
59		)
60	}
61}
62
63export function loadEvents(path: string, client: Bot<Client>) {
64	Logger.log('debug', `Loading events from ${path}`)
65
66	try {
67		const files = readdirSync(path)
68
69		for (const file of files) {
70			const filePath = join(path, file)
71			const fileExtension = isProd ? '.js' : '.ts'
72
73			if (!file.endsWith(fileExtension)) {
74				continue
75			}
76
77			try {
78				const event = require(filePath)
79
80				if (!event.default?.name || !event.default?.execute) {
81					Logger.log(
82						'warn',
83						`Event ${file} is missing required properties`,
84						'Events',
85					)
86					continue
87				}
88
89				const execute = (...args: any[]) =>
90					event.default.execute(client, ...args)
91
92				if (event.default.once) {
93					client.once(event.default.name, execute)
94				} else {
95					client.on(event.default.name, execute)
96				}
97
98				events.set(event.default.name, event.default)
99				Logger.log(
100					'debug',
101					`Loaded event: ${file} (${event.default.name})`,
102					'Events',
103				)
104			} catch (error: any) {
105				Logger.log(
106					'error',
107					`Failed to load event: ${file}: ${error.message}`,
108					'Events',
109				)
110			}
111		}
112
113		Logger.log('debug', `Loaded ${events.size} events`, 'Events')
114	} catch (error: any) {
115		Logger.log(
116			'error',
117			`Failed to read directory ${path}: ${error.message}`,
118			'Events',
119		)
120	}
121}
122
123export function getCommands() {
124	return commands
125}
126
127export function getEvents() {
128	return events
129}
130