UNPKG

jasc

Version:

Jasc Another Service Container

85 lines (84 loc) 3.78 kB
"use strict"; 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;