jasc
Version:
Jasc Another Service Container
85 lines (84 loc) • 3.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var tree_1 = require("./tree");
/**
*
* @template P The services the container should hold
* @template Dependencies **DO NOT SET!* This template is only used internally for `ContainerProvider<Services, Dependencies>`'s
*/
var Container = /** @class */ (function () {
function Container() {
this._tree = tree_1.createTree();
this._current = null;
}
/**
* Use a provider function that provides some of services defined in the template `<P>`
* @param provider see `ContainerProvider`
*/
Container.prototype.use = function (provider) {
return provider(this);
};
/**
* Define a service for the container to serve.
* The service will be defined as a property on the service, and will be lazily constructed.
* The construction of the service takes place the first time it is resolved (read).
* If a circular dependency is detected, an Error is thrown.
* @param name Name of the service
* @param factory The service factory
* @returns The container
* @throws {TypeError} if name is null, undefined or not a string, or if factory is null, undefined or not a function
*/
Container.prototype.serve = function (name, factory) {
var _this = this;
if (!name || typeof name !== 'string')
throw new TypeError("'name' must be defined");
if (!factory)
throw new TypeError("'factory' must be defined");
Object.defineProperty(this, name, {
get: function () {
var tree = _this._tree;
if (tree.has(name)) {
var node_1 = tree.get(name);
// the _current property is the parent to the service currently being resolved
// if _current is not null then we're loading a dependency that has not yet been loaded
if (_this._current) {
node_1.parents.add(_this._current);
_this._current.children.add(node_1);
}
// factory has not yet returned, so we're in a resolve stack where we have looped back on ourselves (since tree.has(name) is true)
if (node_1.value === undefined) {
var parents_1 = [name];
node_1.traverseParents(function (p) {
if (p.key === node_1.key)
return true;
parents_1.push(p.key);
});
console.warn("Detected circular dependency: " + name + " -> " + parents_1.reverse().join(' -> '));
throw new Error("Circular dependency detected while resolving " + name);
}
// the service we're resolving has been initialized previously.
return node_1.value;
}
var parent = _this._current;
var node = _this._current = tree.add(name, parent);
var instance = factory(_this);
if (instance === undefined)
throw new Error('factory returned undefined');
_this._current = parent;
return node.value = instance;
},
configurable: false,
enumerable: true
});
return this;
};
/**
* Dumps the loaded services to the console.
*/
Container.prototype.dump = function () {
this._tree.dump();
return this;
};
return Container;
}());
exports.default = Container;