dynamicl
Version:
A library for auto-detecting and loading classes
55 lines (46 loc) • 1.9 kB
text/typescript
import 'reflect-metadata';
import * as fs from 'fs';
import * as path from 'path';
export abstract class Detectable {
constructor(public name: string) {}
}
export function autodetect<T extends Detectable>(options: { baseClass: new (...args: any[]) => T, location: string }) {
return function (target: any, propertyKey: string) {
const location = path.resolve(options.location);
Reflect.defineMetadata('autodetect:options', options, target, propertyKey);
Object.defineProperty(target, propertyKey, {
get: function() {
if (!this._loadedItems) {
this._loadedItems = loadItems(location, options.baseClass);
}
return this._loadedItems;
},
configurable: true,
enumerable: true
});
};
}
function loadItems<T extends Detectable>(directoryPath: string, BaseClass: new (...args: any[]) => T): T[] {
const items: T[] = [];
const files = fs.readdirSync(directoryPath);
for (const file of files) {
if (file.endsWith('.ts') || file.endsWith('.js')) {
const filePath = path.join(directoryPath, file);
let module;
try {
module = require(filePath);
} catch (error) {
console.error(`Error loading module ${filePath}:`, error);
continue;
}
for (const exportedItem of Object.values(module)) {
if (typeof exportedItem === 'function' &&
exportedItem.prototype instanceof BaseClass) {
const ItemClass = exportedItem as new (name: string) => T;
items.push(new ItemClass(path.basename(file, path.extname(file))));
}
}
}
}
return items;
}