UNPKG

@blynx/inject

Version:
99 lines (98 loc) 3.17 kB
import "reflect-metadata"; import { InjectProvider } from "./inject.provider"; import { getOptions } from "./getOptions"; import { ParamTypes } from "./constants"; import { getName } from "./getName"; function getNewConstructor(constructor, params) { return class extends constructor { constructor(...args) { var newParams = params.slice(0); for (let j = 0; j < args.length; j++) { let arg = args[j]; for (let i = 0; i < newParams.length; i++) { if (newParams[i] === void 0) { newParams[i] = arg; break; } } } super(...newParams); } }; } function getParams(excludes, metadata) { var params = []; for (let i = 0; i < metadata.length; i++) { let meta = metadata[i]; var key = getName(meta); if (excludes[key] !== true) { params.push(InjectProvider.Instance.get(meta)); } else { params.push(void 0); } } return params; } function setupNewConstructorPrototype(originalConstructor, newConstructor) { newConstructor.prototype = Object.create(originalConstructor.prototype); newConstructor.prototype.constructor = originalConstructor; Object.defineProperty(newConstructor, 'name', { value: getName(originalConstructor), enumerable: false, writable: false }); } /** * Inject dependencies into constructor * * @export * @param {IInjectOptions} [options={}] Options * @param {Function} constructor Constructor to inject into * @returns {Function} New constructor */ function Inject(options, constructor) { var metadata = Reflect.getMetadata(ParamTypes, constructor); if (metadata != null) { var params = getParams(options.exclude, metadata); var newConstructor = getNewConstructor(constructor, params); setupNewConstructorPrototype(constructor, newConstructor); var newMetadata = []; for (let i = 0; i < metadata.length; i++) { let meta = metadata[i]; if (options.exclude[getName(meta)] === true) { newMetadata.push(meta); } } Reflect.defineMetadata(ParamTypes, newMetadata, newConstructor); return newConstructor; } else { return constructor; } } /** * Decorate an object as Injectable into classes that are also decorated as Injectable * * @export * @param {IInjectableOptions} [options={}] Options * @returns Decorator */ export function Injectable(options = {}) { options = getOptions(options, defaultOptions); return function (constructor) { InjectProvider.Instance.setName(options.namespace, constructor); if (options.inject === true) { constructor = Inject(options, constructor); } InjectProvider.Instance.register(constructor); return constructor; }; } const defaultOptions = { namespace: '', exclude: { String: true, Number: true, Object: true, Array: true, Boolean: true }, inject: true };