feat: dev and prod mode

This commit is contained in:
Jacob Nguyen
2023-05-13 00:52:46 -05:00
parent 3ed6d84727
commit 6fd9f8f032
6 changed files with 94 additions and 66 deletions

View File

@@ -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;
}

View File

@@ -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>();

View File

@@ -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>;
}

View File

@@ -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(

View File

@@ -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[];
};

View File

@@ -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 {