dino-core
Version:
A dependency injection framework for NodeJS applications
180 lines • 8.53 kB
JavaScript
"use strict";
// Copyright 2021 Quirino Brizi [quirino.brizi@gmail.com]
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.ComponentDescriptor = void 0;
const LazyLoadingResolver_1 = require("../context/LazyLoadingResolver");
const DependencyExtractor_1 = require("../DependencyExtractor");
const object_helper_1 = require("../helper/object.helper");
const Inject_1 = require("./decorators/Inject");
const resolver_1 = require("./resolver");
/**
* The definition of the object that need to be created for the application context
* @public
*/
class ComponentDescriptor {
/**
* Create a new component descriptor
* @param {String} name the component registration name
* @param {String|Injectable} component the source for the component
* @param {Scope} scope the scope for the component resolution
* @param {Resolver} resolver the resolver for the component
* @param {Injectable} value deprecated use source instead
* @param {Boolean} lazy a flag indicating if the component should be lazy loaded
* @param {Array<String>} dependencies the dependencies defined for this component
* @param {Boolean} isConfiguration a flag indicating if this component descriptor is loading a configuration class
*/
constructor(name, component, scope, resolver, lazy = false, dependencies = [], isConfiguration = false) {
this.name = name;
this.component = component;
this.scope = scope;
this.resolver = resolver;
this.lazy = lazy;
this.dependencies = dependencies;
this.isConfiguration = isConfiguration;
this.dependencyExtractor = new DependencyExtractor_1.DependencyExtractor();
}
getName() {
return this.name;
}
getScope() {
return this.scope;
}
isForConfiguration() {
return this.isConfiguration;
}
/**
* Resolve a component in to its primitive form to be managed by awilix
* @param {ApplicationContext} applicationContext the application context that will be injected for later
* resolution of if the component is defined as lazy
*
* @returns {any} the awilix resolver
* @public
*/
resolve(applicationContext) {
let answer;
if (!this.lazy) {
answer = this.resolver.wrap(this.requireIfNeeded());
if (this.resolver.isClassOrFunction()) {
answer = answer.setLifetime(this.scope.asPrimitive());
}
}
else {
const concreteClone = new ComponentDescriptor(this.name, this.component, this.scope, this.resolver, false);
const proxy = new Proxy({}, new LazyLoadingResolver_1.LazyLoadingResolver(applicationContext, concreteClone));
answer = resolver_1.Resolver.VALUE.wrap(proxy);
}
return answer;
}
/**
* Validate if the component wrapped on this component descriptor has no dependencies or depends only on base dependencies;
* @returns {Boolean} true if has not dependencies or depends only on base ones, false otherwise
*
* @public
*/
hasNotDependenciesOrDependsOnlyOnBase() {
return this.getDependencies().length === 0 || this.dependencies.every((element) => ['applicationContext', 'environment'].includes(element));
}
/**
* Allows to access the dependencies for the wrapped component
* @returns {Array<String>} the array that describe the dependencies for this component
*
* @public
*/
getDependencies() {
if (this.dependencies.length === 0) {
const requiredComponentType = this.requireIfNeeded();
const injectableDependencies = (0, Inject_1.getInjectableDependencies)(requiredComponentType);
const dependencies = this.dependencyExtractor.extractDependenciesFor(requiredComponentType);
this.dependencies.push(...dependencies, ...injectableDependencies);
}
return this.dependencies;
}
requireIfNeeded() {
let answer;
if (typeof this.component === 'string') {
// assume the provided source is a path that need to be required
answer = require(this.component);
this.component = answer;
}
// assume source is already an object...
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
answer = this.component;
return answer;
}
/**
* Create an new generic component descriptor.
*
* @param {String} name the name of the component, it will be used as a reference to the component
* in the application context and for injection.
* @param {String|Component} component the path of the source file relative to the root of the project or the component itself
* @param scope the scope of the component, can be one of:
* - **transient**: a new instance of the component will be created ond injected when required
* - **singleton**: a single component instance will be create and reused every time is required
* - **scoped**: The registration is scoped to the container - that means that the resolved value
* @param {Resolver} resolver the resolver that will be used to create the resolution scope (or a child scope)
* @param {Boolean} lazy a flag indicating if this component descriptor should be lazily instantiated
* @param {Array<String>} dependencies the dependencies for the component described using this component descriptor
*
* @returns {ComponentDescriptor} the ComponentDescriptor
*
* @public
* @static
*
* @deprecated use any of {ComponentDescriptor#createFromValue} or {ComponentDescriptor#createFromImport} or {ComponentDescriptor#createFromType} methods
*/
static create(name,
// eslint-disable-next-line @typescript-eslint/ban-types
source, scope, resolver, lazy = false, dependencies, isConfiguration = false) {
if (object_helper_1.ObjectHelper.isNotDefined(source)) {
throw Error('component source must be provided');
}
return new ComponentDescriptor(name, source, scope, resolver, lazy, dependencies, isConfiguration);
}
/**
* Create a component descriptor for value base context registration
* @param name the name of the value, used to reference this value on the application context
* @param value the value to set on the application context
* @param scope the resolution scope for the value
*
* @returns the ComponentDescriptor
*/
static createFromValue(name, value, scope) {
return new ComponentDescriptor(name, value, scope, resolver_1.Resolver.VALUE, false, [], false);
}
/**
* Create a component descriptor for value base context registration
* @param name the name of the value, used to reference this value on the application context
* @param path the path to the script to import and that will define the object to register on the application context
* @param scope the resolution scope for the value
*
* @returns the ComponentDescriptor
*/
static createFromImport(name, path, scope) {
return new ComponentDescriptor(name, path, scope, resolver_1.Resolver.VALUE, false, [], false);
}
/**
* Create a component descriptor for class base context registration
* @param name the name of the value, used to reference this value on the application context
* @param type the type definition to register as class in the application context
* @param scope the scope of the value
*
* @returns {ComponentDescriptor} the ComponentDescriptor
*/
static createFromType(name, type, scope) {
return new ComponentDescriptor(name, type, scope, resolver_1.Resolver.CLASS, false, [], false);
}
}
exports.ComponentDescriptor = ComponentDescriptor;
//# sourceMappingURL=ComponentDescriptor.js.map