Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 | 8x 8x 8x 8x 8x 11x 8x 8x 8x 8x | import 'reflect-metadata'; import * as fs from 'fs'; import * as path from 'path'; const DECORATOR_KEY = 'custom:decorator'; export type Token<T> = new (...args: any[]) => T; /** * @decorator Controller * @description A class decorator that marks a class as a controller. * @returns {ClassDecorator} */ export const Controller = (): ClassDecorator => (target: object) => Reflect.defineMetadata(DECORATOR_KEY, 'controller', target); /** * @decorator Service * @description A class decorator that marks a class as a service. * @returns {ClassDecorator} */ export const Service = (): ClassDecorator => (target: object) => Reflect.defineMetadata(DECORATOR_KEY, 'service', target); /** * @decorator Repository * @description A class decorator that marks a class as a repository. * @returns {ClassDecorator} */ export const Repository = (): ClassDecorator => (target: object) => Reflect.defineMetadata(DECORATOR_KEY, 'repository', target); /** * @class DependencyInjectionContainer * @description A container for managing dependencies. */ export class DependencyInjectionContainer { private dependencies: Map<Token<any>, any> = new Map(); /** * @method register * @description Registers a dependency with the container. * @param {Token<T>} token - The token to register the dependency with. * @param {T} instance - The instance of the dependency. */ public register<T>(token: Token<T>, instance: T): void { if (!this.dependencies.has(token)) { this.dependencies.set(token, instance); } } /** * @method resolve * @description Resolves a dependency from the container. * @param {Token<T>} token - The token of the dependency to resolve. * @returns {T} The resolved dependency. */ public resolve<T>(token: Token<T>): T { const instance = this.dependencies.get(token); if (!instance) { throw new Error(`Dependency not found for token: ${token.name || token}`); } return instance; } /** * @method load * @description Loads all dependencies from a directory. * @param {string} srcPath - The path to the directory to load dependencies from. */ public load(srcPath: string): void { const absolutePath = path.resolve(srcPath); this.loadFromDirectory(absolutePath); } /** * @method loadFromDirectory * @description Recursively loads all dependencies from a directory. * @param {string} directory - The directory to load dependencies from. */ private loadFromDirectory(directory: string): void { const files = fs.readdirSync(directory); for (const file of files) { const fullPath = path.join(directory, file); const stat = fs.statSync(fullPath); if (stat.isDirectory() && path.basename(fullPath) !== 'lib' && path.basename(fullPath) !== 'test') { this.loadFromDirectory(fullPath); } else if (stat.isFile() && (fullPath.endsWith('.ts') || fullPath.endsWith('.js'))) { this.loadDependenciesFromFile(fullPath); } } } /** * @method loadDependenciesFromFile * @description Loads all dependencies from a file. * @param {string} filePath - The path to the file to load dependencies from. */ private loadDependenciesFromFile(filePath: string): void { const module = require(filePath); for (const key in module) { const exported = module[key]; if (typeof exported === 'function' && Reflect.getMetadata(DECORATOR_KEY, exported)) { this.resolveAndRegister(exported); } } } /** * @method resolveAndRegister * @description Resolves and registers a dependency and its dependencies. * @param {T} target - The dependency to resolve and register. */ private resolveAndRegister<T extends { new(...args: any[]): {} }>(target: T): void { if (this.dependencies.has(target)) { return; } const paramTypes = Reflect.getMetadata('design:paramtypes', target) || []; const resolvedDependencies = paramTypes.map((param: Token<any>) => { this.resolveAndRegister(param); return this.resolve(param); }); const instance = new target(...resolvedDependencies); this.register(target, instance); console.log(`Loaded: ${target.name}`); } } export const container = new DependencyInjectionContainer(); |