@egodigital/egoose
Version:
Helper classes and functions for Node.js 10 or later.
560 lines • 15.4 kB
JavaScript
;
/**
* This file is part of the @egodigital/egoose distribution.
* Copyright (c) e.GO Digital GmbH, Aachen, Germany (https://www.e-go-digital.com/)
*
* @egodigital/egoose is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, version 3.
*
* @egodigital/egoose is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const _ = require("lodash");
const crypto = require("crypto");
const fsExtra = require("fs-extra");
const path = require("path");
const moment = require("moment-timezone");
const util = require("util");
const UUID = require("uuid");
const UUID_v5 = require("uuid/v5");
const yargs = require("yargs-parser");
/**
* Applies an object or value to a function.
*
* @param {TFunc} func The function to apply 'thisArg' to.
* @param {any} thisArg The object or value to apply to 'func'.
*
* @return {TFunc} The new function.
*/
function applyFuncFor(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
exports.applyFuncFor = applyFuncFor;
/**
* Returns an input value as array.
*
* @param {T|T[]} val The input value.
* @param {boolean} [noEmpty] Remove values, which are (null) or (undefined).
*
* @return {T[]} The input value as array.
*/
function asArray(val, noEmpty = true) {
if (!Array.isArray(val)) {
val = [val];
}
return val.filter(x => {
if (noEmpty) {
return !_.isNil(x);
}
return true;
});
}
exports.asArray = asArray;
/**
* Keeps sure that a value is a Moment instance (local timezone).
*
* @param {any} time The input value.
*
* @return {moment.Moment} The Moment instance.
*/
function asLocal(time) {
let result = asMoment(time);
if (!_.isNil(result)) {
if (result.isValid()) {
if (!result.isLocal()) {
result = result.local();
}
}
}
return result;
}
exports.asLocal = asLocal;
/**
* Keeps sure that a value is a Moment instance.
*
* @param {any} val The input value.
*
* @return {moment.Moment} The Moment instance.
*/
function asMoment(val) {
if (_.isNil(val)) {
return val;
}
let result;
if (moment.isMoment(val)) {
result = val;
}
else if (moment.isDate(val)) {
result = moment(val);
}
else {
const TIME_STR = toStringSafe(val).trim();
if (/^([0-9]{1,})$/i.test(TIME_STR)) {
// UNIX timestamp
result = moment(parseInt(TIME_STR));
}
else {
result = moment(TIME_STR);
}
}
return result;
}
exports.asMoment = asMoment;
/**
* Keeps sure that a value is a Moment instance (UTC timezone).
*
* @param {any} time The input value.
*
* @return {moment.Moment} The Moment instance.
*/
function asUTC(time) {
let result = asMoment(time);
if (!_.isNil(result)) {
if (result.isValid()) {
if (!result.isUTC()) {
result = result.utc();
}
}
}
return result;
}
exports.asUTC = asUTC;
/**
* Clones an object / value.
*
* @param {T} obj The value to clone.
*
* @return {T} The cloned value.
*/
function cloneObj(obj) {
if (!obj) {
return obj;
}
return JSON.parse(JSON.stringify(obj));
}
exports.cloneObj = cloneObj;
/**
* Compare to values for sorting.
*
* @param {any} x The "left" value.
* @param {any} y The "right" value.
*
* @return {number} The sort value.
*/
function compareValues(x, y) {
return compareValuesBy(x, y, i => i);
}
exports.compareValues = compareValues;
/**
* Compare to values for sorting by using a selector.
*
* @param {any} x The "left" value.
* @param {any} y The "right" value.
* @param {Function} selector The selector.
*
* @return {number} The sort value.
*/
function compareValuesBy(x, y, selector) {
const VAL_X = selector(x);
const VAL_Y = selector(y);
if (VAL_X !== VAL_Y) {
if (VAL_X < VAL_Y) {
return -1;
}
if (VAL_X > VAL_Y) {
return 1;
}
}
return 0;
}
exports.compareValuesBy = compareValuesBy;
/**
* Creates a simple 'completed' callback for a promise.
*
* @param {Function} resolve The 'succeeded' callback.
* @param {Function} reject The 'error' callback.
*
* @return {CompletedAction<TResult>} The created action.
*/
function createCompletedAction(resolve, reject) {
let completedInvoked = false;
return (err, result) => {
if (completedInvoked) {
return;
}
completedInvoked = true;
if (err) {
if (reject) {
reject(err);
}
}
else {
if (resolve) {
resolve(result);
}
}
};
}
exports.createCompletedAction = createCompletedAction;
/**
* Promise version of `child_process.exec()` function.
*
* @param {string} command The command to execute.
*
* @return {Promise<ExecResult>} The promise with the result.
*/
async function exec(command) {
command = toStringSafe(command);
return new Promise((resolve, reject) => {
try {
child_process_1.exec(command, (err, stdout, stderr) => {
if (err) {
reject(err);
}
else {
resolve({
stderr: stderr,
stdout: stdout,
});
}
});
}
catch (e) {
reject(e);
}
});
}
exports.exec = exec;
/**
* An async 'forEach'.
*
* @param {Enumerable.Sequence<T>} seq The sequence or array to iterate.
* @param {ForEachAsyncAction<T>} action The action to invoke.
*/
async function forEachAsync(seq, action) {
let i = -1;
for (const ITEM of seq) {
++i;
await Promise.resolve(action(ITEM, i));
}
}
exports.forEachAsync = forEachAsync;
/**
* Detects version information about the current app via Git (synchronous).
*
* @param {GetAppVersionOptions} [opts] Custom options.
*
* @return {AppVersion} Version information.
*/
function getAppVersionSync(opts) {
if (!opts) {
opts = {};
}
// working directory
let cwd = toStringSafe(opts.cwd);
if (isEmptyString(cwd)) {
cwd = process.cwd();
}
if (!path.isAbsolute(cwd)) {
cwd = path.join(process.cwd(), cwd);
}
cwd = path.resolve(cwd);
const VERSION = {};
// VERSION.date
try {
VERSION.date = asUTC(moment(child_process_1.execSync('git log -n1 --pretty=%cI HEAD', {
cwd: cwd,
}).toString('utf8')
.trim()));
}
catch {
VERSION.date = false;
}
// VERSION.hash
try {
VERSION.hash = normalizeString(child_process_1.execSync('git log --pretty="%H" -n1 HEAD', {
cwd: cwd,
}).toString('utf8'));
}
catch {
VERSION.hash = false;
}
// VERSION.code
try {
let buildNr = false;
// first check for 'BUILD_NR' file
const BUILD_NR_FILE = path.resolve(path.join(cwd, 'BUILD_NR'));
if (fsExtra.existsSync(BUILD_NR_FILE)) { // does exist?
if (fsExtra.statSync(BUILD_NR_FILE).isFile()) { // check if file
buildNr = parseInt(fsExtra.readFileSync(BUILD_NR_FILE, 'utf8')
.trim());
}
}
if (false === buildNr) {
// now try from 'BUILD_NR' env var
const BUILD_NR = toStringSafe(process.env.BUILD_NR)
.trim();
if ('' !== BUILD_NR) {
buildNr = parseInt(BUILD_NR);
}
}
if (false !== buildNr) {
VERSION.code = isNaN(buildNr) ?
false : buildNr;
}
}
catch (e) {
VERSION.code = false;
}
// VERSION.name
try {
const PACKAGE_JSON_FILE = path.resolve(path.join(cwd, 'package.json'));
if (fsExtra.existsSync(PACKAGE_JSON_FILE)) { // does exist?
if (fsExtra.statSync(PACKAGE_JSON_FILE).isFile()) { // check if file
const PACKAGE_JSON = JSON.parse(fsExtra.readFileSync(PACKAGE_JSON_FILE, 'utf8')
.trim());
if (PACKAGE_JSON && !isEmptyString(PACKAGE_JSON.version)) {
VERSION.name = toStringSafe(PACKAGE_JSON.version)
.trim();
}
}
}
}
catch (e) {
VERSION.name = false;
}
return VERSION;
}
exports.getAppVersionSync = getAppVersionSync;
/**
* Alias of 'uuid()' function.
*/
function guid(version) {
return uuid.apply(null, arguments);
}
exports.guid = guid;
/**
* Checks if the string representation of a value is an empty string or not.
*
* @param {any} val The value to check.
*
* @return {boolean} If empty string or not.
*/
function isEmptyString(val) {
return '' === toStringSafe(val)
.trim();
}
exports.isEmptyString = isEmptyString;
/**
* Normalizes a value to a string, which is comparable.
*
* @param {any} val The value to normalize.
*
* @return {string} The normalized string.
*/
function normalizeString(val) {
return toStringSafe(val).toLowerCase()
.trim();
}
exports.normalizeString = normalizeString;
/**
* Returns the current time.
*
* @param {string} [timezone] The custom timezone to use.
*
* @return {Moment.Moment} The current time.
*/
function now(timezone) {
timezone = toStringSafe(timezone).trim();
const NOW = moment();
return '' === timezone ? NOW
: NOW.tz(timezone);
}
exports.now = now;
/**
* Parses a value as string of a command line input.
*
* @param {any} cmd The command line input.
*
* @return {ParsedCommandLine} The parsed data.
*/
function parseCommandLine(cmd) {
cmd = toStringSafe(cmd).trim();
const ARGS = yargs(cmd);
cmd = normalizeString(ARGS._[0]);
ARGS._ = ARGS._.filter((a, i) => i > 0).map((a) => {
if (_.isString(a)) {
if (a.startsWith('"') && a.endsWith('"')) {
a = a.substr(1, a.length - 2);
a = a.split('\\"')
.join('"');
}
}
return a;
});
if ('' === cmd) {
cmd = undefined;
}
return {
arguments: ARGS,
command: cmd,
};
}
exports.parseCommandLine = parseCommandLine;
/**
* Generates a random string.
*
* @param {number} size The size of the result string.
* @param {string} [chars] The custom list of characters.
*
* @return {Promise<string>} The promise with the random string.
*/
async function randChars(size, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
return randCharsInner(await util.promisify(crypto.randomBytes)(size), chars);
}
exports.randChars = randChars;
function randCharsInner(randBlob, chars) {
chars = toStringSafe(chars);
let str = '';
for (let i = 0; i < randBlob.length; i++) {
str += chars.substr(randBlob.readInt8(i) % chars.length, 1);
}
return str;
}
/**
* Generates a random string.
*
* @param {number} size The size of the result string.
* @param {string} [chars] The custom list of characters.
*
* @return {string} The random string.
*/
function randCharsSync(size, chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') {
return randCharsInner(crypto.randomBytes(size), chars);
}
exports.randCharsSync = randCharsSync;
/**
* Returns a value as "real" boolean.
*
* @param {any} val The input value.
* @param {boolean} [defaultValue] The value to return if 'val' is (null) or (undefined).
*
* @return {boolean} The output value.
*/
function toBooleanSafe(val, defaultValue = false) {
if (_.isBoolean(val)) {
return val;
}
if (_.isNil(val)) {
return !!defaultValue;
}
return !!val;
}
exports.toBooleanSafe = toBooleanSafe;
/**
* Converts a value to a string (if needed), which is not (null) and not (undefined).
*
* @param {any} val The value to convert.
* @param {string} [defaultValue] The custom default value if 'val' is (null) or (undefined).
*
* @return {string} 'val' as string.
*/
function toStringSafe(val, defaultValue = '') {
if (_.isString(val)) {
return val;
}
if (_.isNil(val)) {
return '' + defaultValue;
}
if (val instanceof Error) {
return `[${val.name}] ${val.message}${_.isNil(val.stack) ? '' : ("\n\n" + val.stack)}`;
}
if (_.isFunction(val['toString'])) {
return '' + val.toString();
}
if (Array.isArray(val) || _.isObjectLike(val)) {
return JSON.stringify(val);
}
return '' + val;
}
exports.toStringSafe = toStringSafe;
/**
* Returns the current time in UTC.
*
* @return {moment.Moment} The current UTC time.
*/
function utc() {
return moment.utc();
}
exports.utc = utc;
/**
* Generates an unique ID.
*
* @param {string} [version] The custom version to use. Default: 4
* @param {any[]} []
*
* @return {string} The new GUID / unique ID.
*/
function uuid(version, ...args) {
version = normalizeString(version);
switch (version) {
case '':
case '4':
case 'v4':
return UUID.v4
.apply(null, args);
case '1':
case 'v1':
return UUID.v1
.apply(null, args);
case '5':
case 'v5':
return UUID_v5.apply(null, args);
}
throw new Error(`Version '${version}' is not supported`);
}
exports.uuid = uuid;
__export(require("./apis/host"));
__export(require("./apis/index"));
__export(require("./apis/statistics"));
__export(require("./apis/validation"));
__export(require("./azure/storage"));
__export(require("./cache"));
__export(require("./cache/redis"));
__export(require("./dev"));
__export(require("./diagnostics/logger"));
__export(require("./diagnostics/stopwatch"));
__export(require("./env"));
__export(require("./events"));
__export(require("./fs"));
__export(require("./geo"));
__export(require("./http"));
__export(require("./http/websockets"));
__export(require("./mail"));
__export(require("./mongo/index"));
__export(require("./mongo/statistics"));
__export(require("./oauth/microsoft"));
__export(require("./queues/index"));
__export(require("./schemas"));
__export(require("./services/feedback"));
__export(require("./statistics"));
__export(require("./streams"));
__export(require("./strings"));
__export(require("./system"));
__export(require("./zip/builder"));
var swagger_jsdoc_express_1 = require("swagger-jsdoc-express");
exports.setupSwaggerUIFromSourceFiles = swagger_jsdoc_express_1.setupSwaggerUIFromSourceFiles;
//# sourceMappingURL=index.js.map