mirror of
https://github.com/sern-handler/handler
synced 2026-06-25 17:22:15 +00:00
feat: dev and prod mode
This commit is contained in:
@@ -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<T> = Promise<Result<ImportPayload<T>, SernError>>;
|
||||
|
||||
export async function importModule<T>(absPath: string) {
|
||||
@@ -43,28 +44,44 @@ export function buildModuleStream<T extends Module>(
|
||||
return from(input).pipe(mergeMap(defaultModuleLoader<T>));
|
||||
}
|
||||
|
||||
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<string> {
|
||||
//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<string> {
|
||||
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<string> {
|
||||
}
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
@@ -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<string, string>();
|
||||
|
||||
@@ -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<T extends keyof ClientEvents>(mod: {
|
||||
});
|
||||
}
|
||||
|
||||
///**
|
||||
// * @Experimental
|
||||
// * Will be refactored / changed in future
|
||||
// */
|
||||
//export abstract class CommandExecutable<Type extends CommandType> {
|
||||
// abstract type: Type;
|
||||
// private static _fullPath = filePath();
|
||||
// name = filename(CommandExecutable._fullPath);
|
||||
// [sernMeta] = {
|
||||
// id: ``,
|
||||
// fullPath: CommandExecutable._fullPath
|
||||
// }
|
||||
// plugins: InitPlugin[] = [];
|
||||
// onEvent: ControlPlugin[] = [];
|
||||
// abstract execute() : Awaitable<unknown>
|
||||
//
|
||||
//}
|
||||
///**
|
||||
// * @Experimental
|
||||
// * Will be refactored in future
|
||||
// */
|
||||
//export abstract class EventExecutable<Type extends EventType> {
|
||||
// abstract type: Type;
|
||||
// [sernMeta] = {
|
||||
// id: '',
|
||||
// fullPath: ''
|
||||
// }
|
||||
// plugins: InitPlugin[] = [];
|
||||
// onEvent: ControlPlugin[] = [];
|
||||
// abstract execute(): Awaitable<unknown>;
|
||||
//}
|
||||
/**
|
||||
* @Experimental
|
||||
* Will be refactored / changed in future
|
||||
*/
|
||||
export abstract class CommandExecutable<Type extends CommandType> {
|
||||
abstract type: Type;
|
||||
[sernMeta] = {
|
||||
id: UNREGISTERED,
|
||||
fullPath: EMPTY_PATH
|
||||
};
|
||||
plugins: InitPlugin[] = [];
|
||||
onEvent: ControlPlugin[] = [];
|
||||
abstract execute() : Awaitable<unknown>
|
||||
|
||||
}
|
||||
/**
|
||||
* @Experimental
|
||||
* Will be refactored in future
|
||||
*/
|
||||
export abstract class EventExecutable<Type extends EventType> {
|
||||
abstract type: Type;
|
||||
[sernMeta] = {
|
||||
id: UNREGISTERED,
|
||||
fullPath: EMPTY_PATH
|
||||
};
|
||||
plugins: InitPlugin[] = [];
|
||||
onEvent: ControlPlugin[] = [];
|
||||
abstract execute(): Awaitable<unknown>;
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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[];
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user