@micro.ts/core
Version:
Microservice framework with Typescript
164 lines (163 loc) • 5.41 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContainerModule = void 0;
const DiRegistry_1 = require("./DiRegistry");
const DiOptionsTypes_1 = require("./types/DiOptionsTypes");
/**
* Container Module is a scoped dependency resolver and container,
* The module is used to manage the main container dependencies,
* also the request scoped dependencies
* A new module is created when calling Container.newModule
* using the current container module as the parent of the new module
* therefore treating the newly created module as request scoped
*/
class ContainerModule {
/**
* If a parent is provided, this module is a scoped module,
* meaning for singleton scoped dependencies it will fall back to the parent module
* @param registyr
* @param parent
*/
constructor(registry = DiRegistry_1.ContainerRegistry, parent) {
this.registry = registry;
this.parent = parent;
/**
* Key value to store the resolved dependencies if they match the module scope
*/
this.instances = new Map();
this.set(ContainerModule, this);
}
/**
* Return true only if it has a parent
*/
get isScoped() {
return !!this.parent;
}
/**
* Construct an object with its constructor,
* using the information it has from the constructor metadata
* If not in transient scope store the created value
* @param ctor
* @param keyMetadata
*/
buildValue(ctor, keyMetadata) {
// Fetch the constructor metadata
const ctorParams = keyMetadata.ctorParams || [];
/**
* Build or fetch each constructor argument using the modules's get method
*/
const args = ctorParams.map((x) => {
if (x.injectOptions) {
return this.get(x.injectOptions.key);
}
return this.get(x.type);
});
/**
* Create the object
*/
const value = new ctor(...args);
/**
* Check if the value should be stored
*/
if (keyMetadata.scope !== DiOptionsTypes_1.ServiceScope.Transient) {
this.instances.set(ctor, value);
}
return value;
}
/**
* Resolve with the resolver and store the value if not transient scoped
* @param key
* @param resolveItem
*/
resolve(key, resolveItem) {
const value = resolveItem.resolver(this);
if (resolveItem.scope !== DiOptionsTypes_1.ServiceScope.Transient) {
this.instances.set(key, value);
}
return value;
}
/**
* Return true if this module is scoped and the required scope is singleton scope
* Throws error if this module is not scoped and the required scope is request scoped
* @param scope
*/
useParentScope(scope) {
if (this.isScoped && scope === DiOptionsTypes_1.ServiceScope.Singleton) {
return true;
}
else if (scope === DiOptionsTypes_1.ServiceScope.Request && !this.isScoped) {
throw new Error('Can not inject a scoped dependency in a singleton dependency');
}
return false;
}
/**
* Set an arbitrary value for the given key
* @param key
* @param value
*/
set(key, value) {
this.instances.set(key, value);
}
/**
* Try and resolve the value
* Might return undefined if it doesn't find
* the stored key and/or cannot construct the value
* @param key
*/
get(key) {
var _a, _b;
/**
* Check if module contains an instance
*/
const existing = this.instances.get(key);
/**
* Exists in own instances
*/
if (existing) {
return existing;
}
/**
* Check for resolvers
*/
if (this.registry.hasResolver(key)) {
/**
* Get resolver info and function from the registry
*/
const resolveItem = this.registry.getResolver(key);
/**
* Check if the parent should create the resolver
*/
if (this.useParentScope(resolveItem.scope)) {
return (_a = this.parent) === null || _a === void 0 ? void 0 : _a.get(key);
}
/**
* If not resolve dhe dependency
*/
return this.resolve(key, resolveItem);
}
if (typeof key === 'function') {
/**
* Doesn't exist in own instances
*/
let keyMetadata = this.registry.getMetadata(key);
if (!keyMetadata) {
/**
* Initialize metadata and call this method again
*/
keyMetadata = this.registry.initializeMetadata(key);
}
/**
* Check if parent should provide this dependency
*/
if (this.useParentScope(keyMetadata.scope || DiOptionsTypes_1.ServiceScope.Singleton)) {
return (_b = this.parent) === null || _b === void 0 ? void 0 : _b.get(key);
}
/**
* Construct the value
*/
return this.buildValue(key, keyMetadata);
}
return undefined;
}
}
exports.ContainerModule = ContainerModule;