UNPKG

dino-core

Version:

A dependency injection framework for NodeJS applications

225 lines 9.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Helper = void 0; const tslib_1 = require("tslib"); const path_1 = tslib_1.__importStar(require("path")); // Copyright 2018 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. const app_root_path_1 = tslib_1.__importDefault(require("app-root-path")); const fs_1 = require("fs"); const yamljs_1 = tslib_1.__importDefault(require("yamljs")); const Logger_1 = require("../Logger"); const injectable_1 = require("../model/injectable"); const resolver_1 = require("../model/resolver"); const scope_1 = require("../model/scope"); const object_helper_1 = require("./object.helper"); const excludes = ['node_modules', 'coverage', 'eslint', 'test', 'specs', 'nyc_output']; /** * Collection of utility functions * @typedef Helper * @public */ // eslint-disable-next-line @typescript-eslint/no-extraneous-class class Helper { /** * Load the context configuration or defaults to. * `{ injectionMode: 'proxy', contextScan: true, components: [], configurations: [] }` * @param config the configuration path or object * @returns the context configuration */ static loadConfig(config) { let conf = { injectionMode: 'proxy', contextScan: true, components: [], configurations: [] }; if (config !== undefined) { if (typeof config === 'string') { try { Logger_1.Logger.debug(`loading config from path [${config}]`); conf = yamljs_1.default.load(`${app_root_path_1.default}/${config}`); } catch (e) { Logger_1.Logger.error('unable to load config default to contextScan', e); } } else { conf = config; } } return conf; } /** * Load all the source files found starting form the provided root directory. * @param {String} dir the directly to scan for source files * @returns {Generator<String>} * * @public * @static */ static loadSources(dir) { Logger_1.Logger.debug(`scanning directory ${dir} for candidate files`); if (!(0, fs_1.existsSync)(dir)) { Logger_1.Logger.warn(`Directory ${dir} does not exists`); return []; } if (excludes.some((name) => dir.endsWith(name))) { return []; } return (0, fs_1.readdirSync)(dir).reduce((files, file) => { Logger_1.Logger.debug(`**** found new candidate file - ${file} - for processing`); const name = (0, path_1.join)(dir, file); if (!(0, fs_1.existsSync)(name)) { return files; } const isDirectory = (0, fs_1.statSync)(name).isDirectory(); if (isDirectory) { Logger_1.Logger.debug(`found directory ${file}, scanning it recoursivelly`); return [...files, ...Helper.loadSources(name)]; } else { const ext = (0, path_1.extname)(name); Logger_1.Logger.debug(`found file ${file} with extension ${ext}`); if (ext === '.js') { Logger_1.Logger.debug(`found valid source file ${file} with extension ${ext}`); return [...files, name]; } } return files; }, []); } /** * Find a source file starting from the requested directory. * @param {String} dir the start directory for the search * @param {String} name the name of the file source to find */ static findSource(dir, name) { const _name = name.endsWith('.js') ? name : `${name}.js`; const matches = Helper.loadSources(dir).filter((source) => source.includes(_name)); if (matches.length === 0) { // no source found assume the name is a module return name; } if (matches.length === 1) { return matches[0]; } throw new Error(`found multiple ${matches.join(',')} matches for ${name}`); } /** * Allows to retrieve a variable from the configuration or as environment variable, supports * both `:` and `_` notation. * @param {Environment} environment the configuration container * @param {string} key the key for the variable to retrieve * @param {any} _default the default value if the variable is nt defined. */ static getVariable(environment, key, _default) { const envVarKey = key.replace(/[.:]/g, '_'); const value = [environment.get(envVarKey), environment.get(envVarKey.toUpperCase()), environment.get(key)].find((v) => v !== undefined); return value !== undefined ? value : _default; } static getContextRoot(config) { return config.contextRoot ?? process.env.DINO_CONTEXT_ROOT ?? 'src/main/node'; } static isPath(_string) { return _string !== undefined && /[<>:"/\\|?*]/.test(_string); } static fileNameFromPath(_path) { return path_1.default.basename(_path).replace('.js', ''); } /** * Convert the required scope to Scope * @param {String|Scope} scope the scope required for the component * @returns {Scope} * * @static * @public */ static asLifetime(scope) { if (scope === undefined) { return scope_1.Scope.SINGLETON; } if (typeof scope === 'string') { // TODO: QB backward compatibility, remove as soon as possible return scope_1.Scope.fromName(scope); } return scope; } /** * Convert the required resolver to Resolver * @param {String|Resolver} resolver the resolver required for the component * @returns {Resolver} * * @static * @public */ static asResolver(resolver) { if (resolver === undefined) { return resolver_1.Resolver.CLASS; } if (typeof resolver === 'string') { // TODO: QB backward compatibility, remove as soon as possible return resolver_1.Resolver.fromName(resolver); } return resolver; } static isInjectable(obj) { // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions if (object_helper_1.ObjectHelper.instanceOf(obj, injectable_1.Injectable)) { return true; } if (!object_helper_1.ObjectHelper.isObject(obj) && object_helper_1.ObjectHelper.isDefined(obj.prototype?.getTypeName)) { return Helper.supportedInjectableTypeNames.includes(obj.prototype.getTypeName()); } if (object_helper_1.ObjectHelper.isNotDefined(obj.getTypeName)) { return false; } return Helper.supportedInjectableTypeNames.includes(obj.getTypeName()); } static isConfiguration(obj) { if (obj.getTypeName === undefined) { return false; } return obj.getTypeName() === 'Configuration'; } /** * Imports all modules declared as part of the specified path * @param {string} path the module path * @returns Array<Injectable> * * @public * @static */ static async dynamicallyImport(path) { try { const module = await Promise.resolve(`${path}`).then(s => tslib_1.__importStar(require(s))); if (module.__esModule === undefined || !object_helper_1.ObjectHelper.isDefined(module.default)) { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument return Object.keys(module).reduce((answer, key) => { const _class = module[key]; if (Helper.isInjectable(_class)) { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument answer.push(_class); } return answer; }, []); } else { return Helper.isInjectable(module) ? [module] : []; } } catch (e) { Logger_1.Logger.error(`unable to import dependency ${path} because ${e.type} - ${e.message}`); throw e; } } } exports.Helper = Helper; Helper.supportedInjectableTypeNames = ['Injectable', 'Component', 'Service', 'Repository', 'Configuration', 'ErrorHandler']; //# sourceMappingURL=helper.js.map