@blynx/inject
Version:
Dependency injector for javascript
99 lines (98 loc) • 3.17 kB
JavaScript
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
};