diff --git a/src/core/module-loading.ts b/src/core/module-loading.ts index a1a66f9..f50b055 100644 --- a/src/core/module-loading.ts +++ b/src/core/module-loading.ts @@ -7,6 +7,7 @@ import { basename, join, resolve } from 'path'; import { ImportPayload } from '../handler/types'; import * as assert from 'node:assert'; import { sernMeta } from '../handler/commands'; + export type ModuleResult = Promise, SernError>>; export async function importModule(absPath: string) { @@ -43,28 +44,44 @@ export function buildModuleStream( return from(input).pipe(mergeMap(defaultModuleLoader)); } -export function getFullPathTree(dir: string) { - return readPath(resolve(dir)); +export function getFullPathTree(dir: string, mode: boolean) { + return readPaths(resolve(dir), mode); } export function filename(path: string) { return fmtFileName(basename(path)); } - -async function* readPath(dir: string): AsyncGenerator { +//https://stackoverflow.com/questions/190852/how-can-i-get-file-extensions-with-javascript +function extension(fname: string) { + return fname.slice((fname.lastIndexOf(".") - 1 >>> 0) + 2); +} +async function* readPaths(dir: string, shouldDebug: boolean): AsyncGenerator { try { const files = await readdir(dir); for (const file of files) { const fullPath = join(dir, file); const fileStats = await stat(fullPath); + const base = basename(file); + const isSkippable = fmtFileName(base).endsWith('-ignore!') + || !['js', 'cjs', 'mts', 'mjs'].includes(extension(base)); if (fileStats.isDirectory()) { - yield* readPath(fullPath); + if(isSkippable) { + if(shouldDebug) + console.info(`ignored directory: ${fullPath}`); + } else { + yield* readPaths(fullPath, shouldDebug); + } } else { - /// #if MODE === 'esm' - yield 'file:///' + fullPath; - /// #elif MODE === 'cjs' - yield fullPath; - /// #endif + if(isSkippable) { + if(shouldDebug) + console.info(`ignored: ${fullPath}`); + } else { + /// #if MODE === 'esm' + yield 'file:///' + fullPath; + /// #elif MODE === 'cjs' + yield fullPath; + /// #endif + } } } } catch (err) { @@ -72,18 +89,3 @@ async function* readPath(dir: string): AsyncGenerator { } } -//https://stackoverflow.com/questions/16697791/nodejs-get-filename-of-caller-function -export function filePath() { - const err = new Error(); - - Error.prepareStackTrace = (_, stack) => stack; - - const stack = err.stack as unknown as NodeJS.CallSite[]; - - Error.prepareStackTrace = undefined; - const path = stack[2].getFileName(); - if (path === null) { - throw Error('Could not get the name of commandModule.'); - } - return path; -} diff --git a/src/core/structures/module-store.ts b/src/core/structures/module-store.ts index 18c56a4..f2a60fc 100644 --- a/src/core/structures/module-store.ts +++ b/src/core/structures/module-store.ts @@ -3,6 +3,7 @@ import { CoreModuleStore } from '../contracts'; /* * @internal * Version 4.0.0 will internalize this api. Please refrain from using ModuleStore! + * For interacting with ModuleStore, use CoreModuleStore contract. */ export class ModuleStore implements CoreModuleStore { commands = new Map(); diff --git a/src/handler/commands.ts b/src/handler/commands.ts index 689a3a7..140433f 100644 --- a/src/handler/commands.ts +++ b/src/handler/commands.ts @@ -1,6 +1,6 @@ import { ClientEvents } from 'discord.js'; -import { EventType, PluginType } from '../core/structures'; -import { AnyEventPlugin, Plugin } from '../core/types/plugins'; +import { CommandType, EventType, PluginType } from '../core/structures'; +import { AnyEventPlugin, ControlPlugin, InitPlugin, Plugin } from '../core/types/plugins'; import { CommandModule, EventModule, InputCommand, InputEvent } from '../core/types/modules'; import { partition } from '../core/functions'; import { Awaitable } from '../shared'; @@ -64,34 +64,32 @@ export function discordEvent(mod: { }); } -///** -// * @Experimental -// * Will be refactored / changed in future -// */ -//export abstract class CommandExecutable { -// abstract type: Type; -// private static _fullPath = filePath(); -// name = filename(CommandExecutable._fullPath); -// [sernMeta] = { -// id: ``, -// fullPath: CommandExecutable._fullPath -// } -// plugins: InitPlugin[] = []; -// onEvent: ControlPlugin[] = []; -// abstract execute() : Awaitable -// -//} -///** -// * @Experimental -// * Will be refactored in future -// */ -//export abstract class EventExecutable { -// abstract type: Type; -// [sernMeta] = { -// id: '', -// fullPath: '' -// } -// plugins: InitPlugin[] = []; -// onEvent: ControlPlugin[] = []; -// abstract execute(): Awaitable; -//} +/** + * @Experimental + * Will be refactored / changed in future + */ +export abstract class CommandExecutable { + abstract type: Type; + [sernMeta] = { + id: UNREGISTERED, + fullPath: EMPTY_PATH + }; + plugins: InitPlugin[] = []; + onEvent: ControlPlugin[] = []; + abstract execute() : Awaitable + +} +/** + * @Experimental + * Will be refactored in future + */ +export abstract class EventExecutable { + abstract type: Type; + [sernMeta] = { + id: UNREGISTERED, + fullPath: EMPTY_PATH + }; + plugins: InitPlugin[] = []; + onEvent: ControlPlugin[] = []; + abstract execute(): Awaitable; +} diff --git a/src/handler/sern.ts b/src/handler/sern.ts index 7c850c9..ab3752d 100644 --- a/src/handler/sern.ts +++ b/src/handler/sern.ts @@ -26,22 +26,30 @@ import { Wrapper } from '../shared'; */ export function init(wrapper: Wrapper) { + const startTime = performance.now(); const dependencies = useDependencies(); + const logger = dependencies[2]; + const errorHandler = dependencies[1]; + const mode = debugModuleLoading(process.env.MODE); if (wrapper.events !== undefined) { makeEventsHandler( dependencies, - getFullPathTree(wrapper.events), + getFullPathTree(wrapper.events, mode), ); } - startReadyEvent(dependencies, getFullPathTree(wrapper.commands)).add(() => console.log('ready')); - - const logger = dependencies[2]; - const errorHandler = dependencies[1]; + startReadyEvent( + dependencies, + getFullPathTree(wrapper.commands, mode) + ).add(() => { + const endTime = performance.now(); + logger?.info({ message: `sern: registered all modules in ${((endTime - startTime) / 1000).toFixed(2)} s` }); + }); + const messages$ = makeMessageHandler(dependencies, wrapper.defaultPrefix); const interactions$ = makeInteractionHandler(dependencies); @@ -58,10 +66,23 @@ export function init(wrapper: Wrapper) { }) ).subscribe(); - const endTime = performance.now(); - logger?.info({ message: `sern : ${(endTime - startTime).toFixed(2)} ms` }); } +function debugModuleLoading(mode: string|undefined) { + console.info(`Detected mode: "${mode}"`) + if(mode === undefined) { + console.info("No mode found in process.env, assuming DEV"); + } + switch(mode) { + case 'PROD': return false; + case 'DEV': + case undefined: return true; + default: { + console.warn(mode + " is not a valid. Should be PROD or DEV"); + return false; + } + } +} function useDependencies() { return Services( diff --git a/src/shared.ts b/src/shared.ts index 2b259ca..977535d 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -35,6 +35,13 @@ export interface Wrapper { commands: string; defaultPrefix?: string; events?: string; + /** + * Overload to enable mode in case developer does not use a .env file. + */ + mode?: 'DEV' | 'PROD' + /* + * @deprecated + */ containerConfig?: { get: (...keys: (keyof Dependencies)[]) => unknown[]; }; diff --git a/tsup.config.js b/tsup.config.js index e1d7160..b8e9c14 100644 --- a/tsup.config.js +++ b/tsup.config.js @@ -21,7 +21,6 @@ export default defineConfig([ tsconfig: './tsconfig-esm.json', outDir: './dist/esm', splitting: true, - bundle: true, esbuildPlugins: [ifdefPlugin({ variables: { MODE: 'esm' }, verbose: true })], outExtension() { return {