dino-core
Version:
A dependency injection framework for NodeJS applications
225 lines • 9.04 kB
JavaScript
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
;