UNPKG

dino-core

Version:

A dependency injection framework for NodeJS applications

180 lines 8.53 kB
"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