diff --git a/src/handlers/ready.ts b/src/handlers/ready.ts index 4ae4fc42..78181a27 100644 --- a/src/handlers/ready.ts +++ b/src/handlers/ready.ts @@ -3,10 +3,10 @@ import { once } from 'node:events'; import { resultPayload } from '../core/functions'; import { CommandType } from '../core/structures/enums'; import { Module } from '../types/core-modules'; -import type { UnpackedDependencies } from '../types/utility'; +import type { UnpackedDependencies, Wrapper } from '../types/utility'; import { callInitPlugins } from './event-utils'; -export default async function(dir: string, deps : UnpackedDependencies) { +export default async function(dirs: string | string[], deps : UnpackedDependencies) { const { '@sern/client': client, '@sern/logger': log, '@sern/emitter': sEmitter, @@ -17,16 +17,21 @@ export default async function(dir: string, deps : UnpackedDependencies) { // https://observablehq.com/@ehouais/multiple-promises-as-an-async-generator // possibly optimize to concurrently import modules - for await (const path of Files.readRecursive(dir)) { - let { module } = await Files.importModule(path); - const validType = module.type >= CommandType.Text && module.type <= CommandType.ChannelSelect; - if(!validType) { - throw Error(`Found ${module.name} at ${module.meta.absPath}, which has incorrect \`type\``); + + const directories = Array.isArray(dirs) ? dirs : [dirs]; + + for (const dir of directories) { + for await (const path of Files.readRecursive(dir)) { + let { module } = await Files.importModule(path); + const validType = module.type >= CommandType.Text && module.type <= CommandType.ChannelSelect; + if(!validType) { + throw Error(`Found ${module.name} at ${module.meta.absPath}, which has incorrect \`type\``); + } + const resultModule = await callInitPlugins(module, deps, true); + // FREEZE! no more writing!! + commands.set(resultModule.meta.id, Object.freeze(resultModule)); + sEmitter.emit('module.register', resultPayload('success', resultModule)); } - const resultModule = await callInitPlugins(module, deps, true); - // FREEZE! no more writing!! - commands.set(resultModule.meta.id, Object.freeze(resultModule)); - sEmitter.emit('module.register', resultPayload('success', resultModule)); } sEmitter.emit('modulesLoaded'); } diff --git a/src/handlers/tasks.ts b/src/handlers/tasks.ts index a204fc5c..e0720e3f 100644 --- a/src/handlers/tasks.ts +++ b/src/handlers/tasks.ts @@ -1,16 +1,21 @@ import * as Files from '../core/module-loading' -import { UnpackedDependencies } from "../types/utility"; +import { UnpackedDependencies, Wrapper } from "../types/utility"; import type { ScheduledTask } from "../types/core-modules"; import { relative } from "path"; import { fileURLToPath } from "url"; -export const registerTasks = async (tasksPath: string, deps: UnpackedDependencies) => { +export const registerTasks = async (tasksDirs: string | string[], deps: UnpackedDependencies) => { const taskManager = deps['@sern/scheduler'] - for await (const f of Files.readRecursive(tasksPath)) { - let { module } = await Files.importModule(f); - //module.name is assigned by Files.importModule<> - // the id created for the task is unique - const uuid = module.name+"/"+relative(tasksPath,fileURLToPath(f)) - taskManager.schedule(uuid, module, deps) + + const directories = Array.isArray(tasksDirs) ? tasksDirs : [tasksDirs]; + + for (const dir of directories) { + for await (const path of Files.readRecursive(dir)) { + let { module } = await Files.importModule(path); + //module.name is assigned by Files.importModule<> + // the id created for the task is unique + const uuid = module.name+"/"+relative(dir,fileURLToPath(path)) + taskManager.schedule(uuid, module, deps) + } } } diff --git a/src/handlers/user-defined-events.ts b/src/handlers/user-defined-events.ts index 00b72cc7..0cfc56b6 100644 --- a/src/handlers/user-defined-events.ts +++ b/src/handlers/user-defined-events.ts @@ -1,6 +1,6 @@ import { EventType, SernError } from '../core/structures/enums'; import { callInitPlugins } from './event-utils' -import { EventModule, Module } from '../types/core-modules'; +import { EventModule } from '../types/core-modules'; import * as Files from '../core/module-loading' import type { UnpackedDependencies } from '../types/utility'; import type { Emitter } from '../core/interfaces'; @@ -10,11 +10,16 @@ import type { Wrapper } from '../' export default async function(deps: UnpackedDependencies, wrapper: Wrapper) { const eventModules: EventModule[] = []; - for await (const path of Files.readRecursive(wrapper.events!)) { - let { module } = await Files.importModule(path); - await callInitPlugins(module, deps) - eventModules.push(module as EventModule); + const eventDirs = Array.isArray(wrapper.events!) ? wrapper.events! : [wrapper.events!]; + + for (const dir of eventDirs) { + for await (const path of Files.readRecursive(dir)) { + let { module } = await Files.importModule(path); + await callInitPlugins(module, deps) + eventModules.push(module); + } } + const logger = deps['@sern/logger'], report = deps['@sern/emitter']; for (const module of eventModules) { let source: Emitter; diff --git a/src/types/utility.ts b/src/types/utility.ts index 9be96cd4..5e315da5 100644 --- a/src/types/utility.ts +++ b/src/types/utility.ts @@ -34,16 +34,15 @@ export type ReplyOptions = string | Omit */ export interface Wrapper { /** - * @property {string} commands + * @property {string|string[]} commands * @description Specifies the directory path where command modules are located. * This is a required property that tells Sern where to find and load command files. * The path should be relative to the project root. * * @example - * commands: "./dist/commands" + * commands: ["./dist/commands"] */ - commands: string; - + commands: string | string[]; /** * @property {boolean} [autoHandleErrors] * @description Optional flag to enable automatic error handling for modules. @@ -53,7 +52,6 @@ export interface Wrapper { * @default false */ autoHandleErrors?: boolean; - /** * @property {string} [defaultPrefix] * @description Optional prefix for text commands. This prefix will be used @@ -64,26 +62,24 @@ export interface Wrapper { * defaultPrefix: "?" */ defaultPrefix?: string; - /** - * @property {string} [events] + * @property {string|string[]} [events] * @description Optional directory path where event modules are located. * If provided, Sern will automatically register and handle events from * modules in this directory. The path should be relative to the project root. * * @example - * events: "./dist/events" + * events: ["./dist/events"] */ - events?: string; - + events?: string | string[]; /** - * @property {string} [tasks] + * @property {string|string[]} [tasks] * @description Optional directory path where scheduled task modules are located. * If provided, Sern will automatically register and handle scheduled tasks * from modules in this directory. The path should be relative to the project root. * * @example - * tasks: "./dist/tasks" + * tasks: ["./dist/tasks"] */ - tasks?: string; + tasks?: string | string[]; }