const moment = require('moment'); const path = require('path'); const _ = require('lodash'); const settings = require('../data/settings.json'); const LOWERS = settings.titlecase.lowers; const UPPERS = settings.titlecase.uppers; const CWD = process.cwd(); // get the current working directory const LOG_LEVEL = 'low'; // should we print more information when log printing ['debug','high','medium','low'] /** * get a stack error and get the details we need for logging * * @param {Object} stack Error stack. * * @return {Object} just the stuff we need for logging details; */ const getStackInfo = stack => { let whodidit = stack .split('\n')[2] .trim() .substring(3) .replace(/\s\(/, ' at ') .replace(/\)/, ''); // strip out the stuff we dont care about let [caller, fileinfo] = whodidit.split(' at '); // grab the caller and fileinfo let [filename, linenumber, columnnumber] = fileinfo ? fileinfo.split(':', 3) : ['', '', '']; // get the filename line number and column number let relative = path.relative(CWD, filename); // get the relative path let name = `dc:${relative}`.replace(/.js$/, ''); // get a clean relative path name return { // return what we care about filename: filename, linenumber: linenumber, columnnumber: columnnumber, caller: caller, name: name, }; }; /** * get the name from the module * * @param {Object} mod module that is requireing us. * * @return {Object} just the stuff we need for logging details; */ const getNameFromModule = mod => { let filename = mod && mod.parent && mod.parent.filename ? mod.parent.filename : ''; // who included me? let relative = path.relative(CWD, filename); // get the relative path let name = `dc:${relative}`.replace(/.js$/, ''); // get a clean relative path name return { // return what we care about name: name, }; }; /** * is a value blank? * * @param {Object} value value to check. * * @return {Boolean} result of the test. */ const isBlank = value => { return (_.isEmpty(value) && !_.isNumber(value)) || _.isNaN(value); }; /** * log * * @param {String} str string to print. * @param {Boolean} clearLine clear the line?. */ const log = (...args) => { let { name, linenumber, columnnumber, caller } = getStackInfo(new Error().stack); let debug = require('debug')(name); // require debug let logArgs = args.slice(0); // clone args if (LOG_LEVEL && LOG_LEVEL === 'debug') { // only add stuff if we want it ... IE debug logArgs.unshift(`${linenumber}:${columnnumber}`); // add the linenumber and columnnumber logArgs.unshift(`${caller}`); // add the name } if (LOG_LEVEL && ['debug', 'high', 'medium'].indexOf(LOG_LEVEL) > -1) { logArgs.unshift(`${name} :`); // add the name logArgs.unshift(`${now()} -`); // add the timestamp } debug.apply(this, args); return console.log.apply(this, logArgs); // apply the new console.log }; /** * print line * * @param {String} str string to print. * @param {Boolean} clearLine clear the line?. */ const println = (str = '', clearLine = true) => { if (clearLine) { process.stdout.clearLine(); process.stdout.cursorTo(0); } process.stdout.write(str); }; /** * use moment to get a string version of now * * @param {Date|String|Number} seed seed the moment. * * @return {String} now formatted with DATE_TIME_FORMAT; */ const now = seed => { // private now ... so we can use it locally let n = seed ? moment(seed) : moment(); return n.toISOString(); }; /** * string to title case * * @param {String} str string to print. */ const toTitleCase = (str = '') => { str = str.replace(/([^\W_]+[^\s-]*) */g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()); for (let i = 0, j = LOWERS.length; i < j; i++) str = str.replace(new RegExp('\\s' + LOWERS[i] + '\\s', 'g'), txt => txt.toLowerCase()); for (let i = 0, j = UPPERS.length; i < j; i++) str = str.replace(new RegExp('\\b' + UPPERS[i] + '\\b', 'g'), UPPERS[i].toUpperCase()); return str; }; module.exports = { _, after: (...args) => { return moment() .add(...args) .format(DATE_TIME_FORMAT); }, before: (...args) => { return moment() .subtract(...args) .format(DATE_TIME_FORMAT); }, debug: (...args) => { let { name } = getStackInfo(new Error().stack); let debug = require('debug')(name); // require debug if (LOG_LEVEL && LOG_LEVEL === 'debug') { let logArgs = args.slice(0); // clone args logArgs.unshift(`${name} :`); // add the name logArgs.unshift(`${now()} -`); // add the timestamp console.log.apply(this, logArgs); // apply the new console.log } return debug.apply(this, args); // send the orig args to debug }, errorpromise: (...args) => { return Promise.reject(new Error(args)); }, isArray: v => { return _.isArray(v); // use lodash is array check }, isBlank, isEmpty: v => { return _.isEmpty(v); // use lodash is empty check }, isJson: v => { // safe check if this is json v = typeof v !== 'string' ? JSON.stringify(v) : v; try { v = JSON.parse(v); } catch (e) { return false; } return v && typeof v === 'object' && v !== null ? true : false; }, later: (...args) => { return moment() .add(...args) .format(DATE_TIME_FORMAT); }, log, moment: seed => { return seed ? moment(seed) : moment(); // return a new moment object ... }, now, // alias the private method println, sleep: async ms => { return new Promise(resolve => setTimeout(resolve, ms)); }, toJson: v => { try { v = v && typeof v === 'string' ? JSON.parse(v) : v; } catch (e) { console.error('toJson error', e.message || e); return false; } return v; }, toTitleCase };