Files
handler/src/core/module-loading.ts
2023-05-03 13:01:14 -05:00

79 lines
2.5 KiB
TypeScript

import { readdirSync, statSync } from 'fs';
import { join, basename } from 'path';
import { type Observable, from, mergeMap } from 'rxjs';
import { SernError } from './structures/errors';
import { type Result, Err, Ok } from 'ts-results-es';
import { ImportPayload } from '../types/handler';
import { pathToFileURL } from 'node:url';
// Courtesy @Townsy45
function readPath(dir: string, arrayOfFiles: string[] = []): string[] {
try {
const files = readdirSync(dir);
for (const file of files) {
if (statSync(dir + '/' + file).isDirectory()) readPath(dir + '/' + file, arrayOfFiles);
else arrayOfFiles.push(join(dir, '/', file));
}
} catch (err) {
throw err;
}
return arrayOfFiles;
}
export const fmtFileName = (n: string) => n.substring(0, n.length - 3);
// export const isLazy = (n: string) => n.indexOf(".lazy.", n.length-9) !== -1;
export async function defaultModuleLoader<T>(
absPath: string,
): Promise<Result<ImportPayload<T>, SernError>> {
// prettier-ignore
let module: T | undefined
/// #if MODE === 'esm'
= (await import(pathToFileURL(absPath).toString())).default
/// #elif MODE === 'cjs'
= require(absPath).default; // eslint-disable-line
/// #endif
if (module === undefined) {
return Err(SernError.UndefinedModule);
}
try {
module = new (module as unknown as new () => T)();
} catch {}
return Ok({ module, absPath });
}
/**
* a directory string is converted into a stream of modules.
* starts the stream of modules that sern needs to process on init
* @returns {Observable<{ mod: Module; absPath: string; }[]>} data from command files
* @param commandDir
*/
export function buildModuleStream<T>(
commandDir: string,
): Observable<Result<ImportPayload<T>, SernError>> {
const commands = getCommands(commandDir);
return from(commands).pipe(mergeMap(defaultModuleLoader<T>));
}
export function getCommands(dir: string): string[] {
return readPath(join(process.cwd(), dir));
}
export function filename(path: string) {
return fmtFileName(basename(path))
}
//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;
}