···12121313Each loader additionally implements an asynchronous `collect` method for initial data collection.
14141515+Additionally, each loader implements their own asynchronous `validate` method, which is invoked within `collect`, to validate the contents of a file, before adding it to the Loader store.
1616+1517Finally, loaders provide various means of exporting data in supported formats, through methods like `getJSON`, `getCSV` and more...
16181719### Event loader
+48-6
src/core/Loader.ts
···11-export interface ILoader {
22- store: object[];
11+import { Glob } from "bun";
22+33+export interface ILoader<T> {
44+ dataSource: string,
55+ store: T[];
3647 collect: () => Promise<ThisType<this>>,
55- getJSON: () => object,
88+ validate: (data: Partial<T>) => Promise<T | null>,
99+ getJSON: () => T[],
610}
71188-export class Loader implements ILoader {
99- public store = [];
1212+export class Loader<T extends object> implements ILoader<T> {
1313+ public dataSource;
1414+ public store: T[] = [];
1515+1616+ public constructor(dataSource: string) {
1717+ if (!dataSource) throw new Error("Class of type Loader was initialized without the *required* dataSource parameter.");
1818+1919+ this.dataSource = dataSource;
2020+ }
10212222+ /**
2323+ * Recursively collects data from a directory based on the directory specificed in dataSource property.
2424+ */
1125 public async collect() {
2626+ const glob = new Glob(`**.ts`);
2727+ const iterator = glob.scan(this.dataSource);
2828+2929+ for await (const path of iterator) {
3030+ let moduleDefault: T | null;
3131+3232+ try {
3333+ const module = (await import(`${this.dataSource}/${path}`));
3434+ moduleDefault = module.default;
3535+3636+ if (!moduleDefault) continue;
3737+ } catch {
3838+ continue;
3939+ }
4040+4141+ const final = await this.validate(moduleDefault);
4242+ if (!final) continue;
4343+4444+ this.store.push(final);
4545+ }
4646+1247 return this;
1348 }
14495050+ /**
5151+ * Validates a singular element during data collection, and returns whatever should be written to the store.
5252+ */
5353+ public async validate(data: Partial<T>): Promise<T | null> {
5454+ return null;
5555+ }
5656+1557 public getJSON() {
1616- return {};
5858+ return this.store;
1759 }
1860};
+10
src/events/ready.ts
···11+import { Events } from "discord.js";
22+import type { IEvent } from "../loaders/EventLoader";
33+44+export default {
55+ name: Events.ClientReady,
66+ once: false,
77+ execute: () => {
88+99+ }
1010+} as IEvent;
+5-2
src/index.ts
···11import { GatewayIntentBits } from "discord.js"
22import { VoidyClient } from "./core/VoidyClient"
33+import { EventLoader } from "./loaders/EventLoader";
44+import { join } from "node:path";
3546// Client initialization with intents and stuff...
57const client = new VoidyClient({
···1012if (!Bun.env.BOT_TOKEN) throw new Error("[Voidy] Missing bot token");
1113client.start(Bun.env.BOT_TOKEN);
12141313-// @Todo: Remove after core registry implementation is complete
1414-console.log(client.registries[0]);
1515+// @Todo: Remove after event and command loader implementation is complete
1616+const eventLoader = await new EventLoader(join(__dirname, "events")).collect();
1717+console.log(eventLoader);
+15
src/loaders/EventLoader.ts
···11+import { Events } from "discord.js";
22+import { Loader } from "../core/Loader";
33+44+export interface IEvent {
55+ name: Events,
66+ once?: boolean,
77+ execute: () => void,
88+}
99+1010+export class EventLoader extends Loader<IEvent> {
1111+ public override async validate(data: Partial<IEvent>) {
1212+ if (!data.name || !data.execute) return null;
1313+ return data as IEvent;
1414+ }
1515+}