inversify
Version:
A powerful and lightweight inversion of control container for JavaScript and Node.js apps powered by TypeScript.
249 lines (248 loc) • 10.4 kB
JavaScript
import BindingCount from "../bindings/binding_count";
import Binding from "../bindings/binding";
import Lookup from "./lookup";
import Planner from "../planning/planner";
import Resolver from "../resolution/resolver";
import * as ERROR_MSGS from "../constants/error_msgs";
import * as METADATA_KEY from "../constants/metadata_keys";
import BindingToSyntax from "../syntax/binding_to_syntax";
import Metadata from "../planning/metadata";
import Target from "../planning/target";
import TargetType from "../planning/target_type";
import Request from "../planning/request";
import KernelSnapshot from "./kernel_snapshot";
import guid from "../utils/guid";
import { getFunctionName } from "../utils/utils";
var Kernel = (function () {
function Kernel() {
this.guid = guid();
this._planner = new Planner();
this._resolver = new Resolver();
this._bindingDictionary = new Lookup();
this._middleware = null;
this._snapshots = [];
}
Kernel.prototype.load = function () {
var _this = this;
var modules = [];
for (var _i = 0; _i < arguments.length; _i++) {
modules[_i - 0] = arguments[_i];
}
var getBindFunction = function (moduleId) {
return function (serviceIdentifier) {
var _bind = _this.bind.bind(_this);
var bindingToSyntax = _bind(serviceIdentifier);
bindingToSyntax._binding.moduleId = moduleId;
return bindingToSyntax;
};
};
modules.forEach(function (module) {
var bindFunction = getBindFunction(module.guid);
module.registry(bindFunction);
});
};
Kernel.prototype.unload = function () {
var _this = this;
var modules = [];
for (var _i = 0; _i < arguments.length; _i++) {
modules[_i - 0] = arguments[_i];
}
modules.forEach(function (module) {
_this._bindingDictionary.removeByModuleId(module.guid);
});
};
Kernel.prototype.bind = function (serviceIdentifier) {
var binding = new Binding(serviceIdentifier);
this._bindingDictionary.add(serviceIdentifier, binding);
return new BindingToSyntax(binding);
};
Kernel.prototype.unbind = function (serviceIdentifier) {
try {
this._bindingDictionary.remove(serviceIdentifier);
}
catch (e) {
throw new Error(ERROR_MSGS.CANNOT_UNBIND + " " + this.getServiceIdentifierAsString(serviceIdentifier));
}
};
Kernel.prototype.unbindAll = function () {
this._bindingDictionary = new Lookup();
};
Kernel.prototype.isBound = function (serviceIdentifier) {
var bindings = this._planner.getBindings(this, serviceIdentifier);
return bindings.length > 0;
};
Kernel.prototype.get = function (serviceIdentifier) {
return this._get({
contextInterceptor: function (context) { return context; },
multiInject: false,
serviceIdentifier: serviceIdentifier,
target: null
})[0];
};
Kernel.prototype.getNamed = function (serviceIdentifier, named) {
return this.getTagged(serviceIdentifier, METADATA_KEY.NAMED_TAG, named);
};
Kernel.prototype.getTagged = function (serviceIdentifier, key, value) {
var metadata = new Metadata(key, value);
var target = new Target(TargetType.ConstructorArgument, null, serviceIdentifier, metadata);
return this._get({
contextInterceptor: function (context) { return context; },
multiInject: false,
serviceIdentifier: serviceIdentifier,
target: target
})[0];
};
Kernel.prototype.snapshot = function () {
this._snapshots.push(KernelSnapshot.of(this._bindingDictionary.clone(), this._middleware));
};
Kernel.prototype.restore = function () {
if (this._snapshots.length === 0) {
throw new Error(ERROR_MSGS.NO_MORE_SNAPSHOTS_AVAILABLE);
}
var snapshot = this._snapshots.pop();
this._bindingDictionary = snapshot.bindings;
this._middleware = snapshot.middleware;
};
Kernel.prototype.getServiceIdentifierAsString = function (serviceIdentifier) {
var type = typeof serviceIdentifier;
if (type === "function") {
var _serviceIdentifier = serviceIdentifier;
return _serviceIdentifier.name;
}
else if (type === "symbol") {
return serviceIdentifier.toString();
}
else {
var _serviceIdentifier = serviceIdentifier;
return _serviceIdentifier;
}
};
Kernel.prototype.applyMiddleware = function () {
var middlewares = [];
for (var _i = 0; _i < arguments.length; _i++) {
middlewares[_i - 0] = arguments[_i];
}
var previous = (this._middleware) ? this._middleware : this._planAndResolve.bind(this);
this._middleware = middlewares.reduce(function (prev, curr) {
return curr(prev);
}, previous);
};
Kernel.prototype.getAll = function (serviceIdentifier) {
return this._get({
contextInterceptor: function (context) { return context; },
multiInject: true,
serviceIdentifier: serviceIdentifier,
target: null
});
};
Kernel.prototype.getAllNamed = function (serviceIdentifier, named) {
return this.getAllTagged(serviceIdentifier, METADATA_KEY.NAMED_TAG, named);
};
Kernel.prototype.getAllTagged = function (serviceIdentifier, key, value) {
var metadata = new Metadata(key, value);
var target = new Target(null, null, serviceIdentifier, metadata);
return this._get({
contextInterceptor: function (context) { return context; },
multiInject: true,
serviceIdentifier: serviceIdentifier,
target: target
});
};
Object.defineProperty(Kernel.prototype, "parent", {
set: function (kernel) {
this._parentKernel = kernel;
},
enumerable: true,
configurable: true
});
Kernel.prototype._get = function (args) {
var result = null;
if (this._middleware) {
result = this._middleware(args);
}
else {
result = this._planAndResolve(args);
}
if (Array.isArray(result) === false) {
throw new Error(ERROR_MSGS.INVALID_MIDDLEWARE_RETURN);
}
return result;
};
Kernel.prototype._planAndResolve = function (args) {
var contexts = this._plan(args.multiInject, args.serviceIdentifier, args.target);
var results = this._resolve(contexts, args.contextInterceptor);
return results;
};
Kernel.prototype._getActiveBindings = function (multiInject, serviceIdentifier, target) {
var bindings = this._planner.getBindings(this, serviceIdentifier);
if (target !== null) {
var request = new Request(serviceIdentifier, this._planner.createContext(this), null, bindings, target);
bindings = this._planner.getActiveBindings(request, target);
}
switch (bindings.length) {
case BindingCount.NoBindingsAvailable:
var serviceIdentifierString = this.getServiceIdentifierAsString(serviceIdentifier), msg = ERROR_MSGS.NOT_REGISTERED;
if (target !== null) {
msg = msg + " " + serviceIdentifierString + "\n " + serviceIdentifierString + " - " + target.metadata[0].toString();
msg += this._listRegisteredBindingsForServiceIdentifier(serviceIdentifierString);
}
else {
msg = msg + " " + serviceIdentifierString;
}
throw new Error(msg);
case BindingCount.OnlyOneBindingAvailable:
if (multiInject === false) {
return bindings;
}
case BindingCount.MultipleBindingsAvailable:
default:
if (multiInject === false) {
var serviceIdentifierString_1 = this.getServiceIdentifierAsString(serviceIdentifier), msg_1 = ERROR_MSGS.AMBIGUOUS_MATCH + " " + serviceIdentifierString_1;
msg_1 += this._listRegisteredBindingsForServiceIdentifier(serviceIdentifierString_1);
throw new Error(msg_1);
}
else {
return bindings;
}
}
};
Kernel.prototype._plan = function (multiInject, serviceIdentifier, target) {
var _this = this;
var bindings = this._getActiveBindings(multiInject, serviceIdentifier, target);
var contexts = bindings.map(function (binding) {
return _this._createContext(binding, target);
});
return contexts;
};
Kernel.prototype._createContext = function (binding, target) {
var context = this._planner.createContext(this);
this._planner.createPlan(context, binding, target);
return context;
};
Kernel.prototype._resolve = function (contexts, contextInterceptor) {
var _this = this;
var results = contexts.map(function (context) {
return _this._resolver.resolve(contextInterceptor(context));
});
return results;
};
Kernel.prototype._listRegisteredBindingsForServiceIdentifier = function (serviceIdentifier) {
var registeredBindingsList = "", registeredBindings = this._planner.getBindings(this, serviceIdentifier);
if (registeredBindings.length !== 0) {
registeredBindingsList = "\nRegistered bindings:";
registeredBindings.forEach(function (binding) {
var name = "Object";
if (binding.implementationType !== null) {
name = getFunctionName(binding.implementationType);
}
registeredBindingsList = registeredBindingsList + "\n " + name;
if (binding.constraint.metaData) {
registeredBindingsList = registeredBindingsList + " - " + binding.constraint.metaData;
}
});
}
return registeredBindingsList;
};
return Kernel;
}());
export default Kernel;