Skip to content

Instantly share code, notes, and snippets.

@servel333
Last active October 8, 2021 16:31
Show Gist options
  • Save servel333/a09539142fb4290f02add80a17a691d2 to your computer and use it in GitHub Desktop.
Save servel333/a09539142fb4290f02add80a17a691d2 to your computer and use it in GitHub Desktop.
JavaScript one-liners and simple blocks, and some bash
#!/usr/bin/env node
/* eslint-disable no-alert */
/* eslint-disable no-console */
const allParams = process.argv.slice(2).join(' ');
const relativeDir = require('path').resolve(__dirname, '../some/path');
const thisScript = require('path').basename(__filename);
/*!
* Wrap method in try-catch and return method return value or `def`.
* @example tri(() => { throw new Error('TEST'); }); // => Returns undefined
* @example tri(() => { throw new Error('TEST'); }, 'DEFAULT'); // => Returns 'DEFAULT'
*/
const tri = (fn, def) => { try { return fn(); } catch (e) { return def; } };
/*!
* Wrap method in try-catch and return method return value or the error.
* @example triErr(() => { throw new Error('TEST'); }); // => Returns Error
*/
const triErr = (fn) => { try { return fn(); } catch (err) { return err; } };
/*!
* Wrap method in await try-catch and return method return value or the error.
* @example
* const result = await triAsync(() => promiseFn());
* // => Returns promiseFn return or a thrown error.
* @example
* const result = await triAsync(() => require('util').promisify(callbackFn)());
* // => Returns callbackFn return or a thrown error.
*/
const triAsync = async (fn) => { try { return await fn(); } catch (err) { return err; } };
/*!
* Wrap method in await try-catch and return method return value or the error.
* @example
* const result = await triCallback(() => callbackFn());
* // => Returns promiseFn return or a thrown error.
*/
const triCallback = async (fn) => { try { return await require('util').promisify(fn)(); } catch (err) { return err; } };
// Simple read-keypath
const test = { a: {} };
const value = tri(() => test.a.b.c.d.e); // -> undefined (no error)
/*!
* Wrap method in try-catch and return method return value or the error thrown.
*/
const triOrErr = (fn) => { try { return fn(); } catch (e) { return e; } };
const canRequire = (moduleName) => { try { require(moduleName); return true; } catch (e) { return false; } }
const triRequire = (moduleName, mock = {}) => { try { return require(moduleName); } catch (e) { return mock; }}
const SECONDS_IN_MINUTE = 60;
const SECONDS_IN_HOUR = 3600;
const SECONDS_IN_DAY = 86400; // Excludes leap time.
const SECONDS_IN_WEEK = 604800; // Excludes leap time.
const addDays = (days = 1, dt = new Date()) => new Date(new Date(dt.getTime()).setDate(dt.getDate() + days));
const addHours = (hours = 1, dt = new Date()) => new Date(new Date(dt.getTime()).setHours(dt.getHours() + hours));
const addMinutes = (mins = 1, dt = new Date()) => new Date(new Date(dt.getTime()).setMinutes(dt.getMinutes() + mins));
const addMonths = (months = 1, dt = new Date()) => new Date(new Date(dt.getTime()).setMonth(dt.getMonth() + months));
const addMs = (ms = 1, dt = new Date()) => new Date(new Date(dt.getTime()).setMilliseconds(dt.getMilliseconds() + ms));
const addSecs = (secs = 1, dt = new Date()) => new Date(new Date(dt.getTime()).setSeconds(dt.getSeconds() + secs));
const addYears = (years = 1, dt = new Date()) => new Date(new Date(dt.getTime()).setFullYear(dt.getFullYear() + years));
const cloneDate = (dt = new Date()) => new Date(dt.getTime());
const zeroTime = (dt = new Date()) => new Date(new Date(dt.getTime()).setHours(0, 0, 0, 0));
const zeroUTCTime = (dt = new Date()) => new Date(new Date(dt.getTime()).setUTCHours(0, 0, 0, 0));
//! Returns now date and time in ISO format. {{yyyy}}-{{MM}}-{{dd}}T{{hh}}:{{MM}}:{{ss}}Z
const nowIso = () => new Date().toISOString();
//! Returns now date in ISO format. {{yyyy}}-{{MM}}-{{dd}}
const nowDate = () => new Date().toISOString().slice(0, 10);
// Simple output, shorter
const logJson = obj => console.log(JSON.stringify(Object.assign(obj, { time: new Date().toISOString() })));
// Closer to Bunyan's output with more info
const logJson = d => console.log(JSON.stringify(Object.assign({ name: require('path').basename(__filename), level: 30 }, d, { hostname: require('os').hostname(), pid: process.pid, time: new Date().toISOString(), v: 0 }))); // eslint-disable-line global-require, max-len, object-curly-newline
// Levels based on https://github.com/trentm/node-bunyan#levels
logJson.fatal = d => logJson(Object.assign(d, { level: 60 }));
logJson.error = d => logJson(Object.assign(d, { level: 50 }));
logJson.warn = d => logJson(Object.assign(d, { level: 40 }));
logJson.info = d => logJson(Object.assign(d, { level: 30 }));
logJson.debug = d => logJson(Object.assign(d, { level: 20 }));
logJson.trace = d => logJson(Object.assign(d, { level: 10 }));
logJson.trace = () => {}; // DISABLED
const inspect = obj => require('util').inspect(obj, { breakLength: Infinity, depth: Infinity, colors: true }); // DEBUG
const inspect = (obj) => { try { return JSON.stringify(obj); } catch (e) { return require('util').inspect(obj, { breakLength: Infinity, depth: Infinity, colors: true }); } }; // DEBUG
## Based on https://stackoverflow.com/a/14172822/761771
## Get the current stack, line number, and function name
const getStack = function getStack() {
const orig = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;
const err = new Error();
Error.captureStackTrace(err, arguments.callee);
const { stack } = err;
Error.prepareStackTrace = orig;
return stack;
};
const getLineNumber = function getLineNumber() { return getStack()[1].getLineNumber(); };
const getFunctionName = function getFunctionName() { return getStack()[1].getFunctionName(); };
Object.defineProperty(global, '__stack', { get: getStack });
Object.defineProperty(global, '__line', { get: getLineNumber });
Object.defineProperty(global, '__function', { get: getFunctionName });
// > FATAL : Any error that is forcing a shutdown of the service or application to prevent data loss (or further data loss). I reserve these only for the most heinous errors and situations where there is guaranteed to have been data corruption or loss.
// > ERROR : Any error which is fatal to the operation, but not the service or application (can't open a required file, missing data, etc.). These errors will force user (administrator, or direct user) intervention. These are usually reserved (in my apps) for incorrect connection strings, missing services, etc.
// > WARN : Anything that can potentially cause application oddities, but for which I am automatically recovering. (Such as switching from a primary to backup server, retrying an operation, missing secondary data, etc.)
// > INFO : Generally useful information to log (service start/stop, configuration assumptions, etc). Info I want to always have available but usually don't care about under normal circumstances. This is my out-of-the-box config level.
// > DEBUG : Information that is diagnostically helpful to people more than just developers (IT, sysadmins, etc.).
// > TRACE : Only when I would be "tracing" the code and trying to find one part of a function specifically.
// - REF https://stackoverflow.com/a/2031209/761771
// Or, put more succinctly
// > Would you want the message to get a system administrator out of bed in the middle of the night?
// > yes -> error
// > no -> warn
// - REF https://stackoverflow.com/a/2031195/761771
const DEFAULT_LOG_LEVEL = 30;
/* eslint-disable no-multi-spaces, no-unused-vars */
const LOG_LEVEL_FATAL = 60; // https://github.com/trentm/node-bunyan#levels
const LOG_LEVEL_CRITICAL = 55;
const LOG_LEVEL_ERR = 50;
const LOG_LEVEL_ERROR = 50; // https://github.com/trentm/node-bunyan#levels
const LOG_LEVEL_WARN = 40; // https://github.com/trentm/node-bunyan#levels
const LOG_LEVEL_WARNING = 40;
const LOG_LEVEL_ALERT = 40;
const LOG_LEVEL_INFO = 30; // https://github.com/trentm/node-bunyan#levels
const LOG_LEVEL_DEBUG = 20; // https://github.com/trentm/node-bunyan#levels
const LOG_LEVEL_VERBOSE = 15;
const LOG_LEVEL_TRACE = 10; // https://github.com/trentm/node-bunyan#levels
const LOG_LEVEL_SILLY = 5; // https://sailsjs.com/documentation/concepts/logging
const LOG_LEVEL_ALL = 0;
const LOG_LEVEL_NONE = 100;
const LOG_LEVEL_OFF = 100;
const LOG_LEVEL_SILENT = 100;
/* eslint-enable no-multi-spaces, no-unused-vars */
const logLevels = {
/* eslint-disable key-spacing */
fatal : 60, // https://github.com/trentm/node-bunyan#levels
critical : 55,
err : 50,
error : 50, // https://github.com/trentm/node-bunyan#levels
warn : 40, // https://github.com/trentm/node-bunyan#levels
warning : 40,
alert : 40,
info : 30, // https://github.com/trentm/node-bunyan#levels
debug : 20, // https://github.com/trentm/node-bunyan#levels
verbose : 15,
trace : 10, // https://github.com/trentm/node-bunyan#levels
silly : 5, // https://sailsjs.com/documentation/concepts/logging
all : 0,
none : 100,
off : 100,
silent : 100,
/* eslint-enable key-spacing */
};
//! Calls getter once then returns it's return value or def on error. #factory
const constantFactory = (getter, def) => {
const UNSET = {};
let cached = UNSET;
return () => {
if (cached === UNSET) {
try {
cached = getter();
} catch (err) {
cached = def;
}
}
return cached;
};
};
/*!
* @param mimeType [string] Mime or content type string, typically `${header}/${footer}` format.
*/
const isMime = (mimeType, header) => (mimeType || '').toLowerCase().split('/')[0] === header;
//! No-op function
//! @see https://lodash.com/docs/4.17.11#noop
const noop = () => {};
//! Get a random element in the array
const randInArray = arr => arr[Math.floor(Math.random() * arr.length)];
//! Timeout as a Promise
const timeoutAsync = ms => new Promise(resolve => setTimeout(resolve, ms));
/*!
* Sort a collection by an attribute
* @example
* const sorted = sortByAttr([{ id: 5 , name: 'f'}, { id: 9, name: 'a' }], 'name');
* console.log(JSON.stringify(sorted));
* // -> [{"id":9,"name":"a"},{"id":5,"name":"f"}]
*/
const sortByAttr = (array, attr) => array.sort((a, b) => ((a[attr] < b[attr]) ? -1 : (a[attr] > b[attr] ? 1 : 0)));
/// Used to filter a list by unique values.
/// @example const uniqList = myList.filter(arrayFilterUniqueCallback);
const arrayFilterUniqueCallback = (val, i, arr) => arr.indexOf(val) === i;
/// Returns a list of unique items
/// @example const uniqList = arrayFilterUnique(myList);
const arrayFilterUnique = (arr) => (arr.filter((val, i) => arr.indexOf(val) === i))
/// Returns a list of unique items
/// @example const uniqList = arrayUnique(myList);
const arrayUnique = (arr) => [...new Set(arr)];
/*
* Attempts to safely return the value at the keypath in the object.
* @example
* const val = { a: { b: [ { c: { d: 'value' } } ] } };
* getAtKeypath(val, 'a.b[0].c.d'); // => "Value"
* getAtKeypath(val, 'wwww', 'default'); // => "default"
*/
const getAtKeypath = (obj, path, defaultVal) => {
if (typeof path === 'string') {
path = path.split('.');
}
const newObj = obj[path[0]];
if (newObj == null) { return defaultVal; }
if (path[1]) {
path.splice(0, 1);
return get(newObj, path, defaultVal);
}
return newObj == null ? defaultVal : newObj;
};
//! @param cb [function] (val, key, obj) => newKey
const mapKeys = (obj, cb = d => d) => Object
.keys(obj)
.reduce((memo, key) => {
memo[cb(obj[key], key, obj)] = obj[key]; // eslint-disable-line no-param-reassign
return memo;
}, {});
//! @param cb [function] (val, key, obj) => newKey
const mapValues = (obj, cb = d => d) => Object
.keys(obj)
.reduce((memo, key) => {
memo[key] = cb(obj[key], key, obj); // eslint-disable-line no-param-reassign
return memo;
}, {});
//! @see https://lodash.com/docs/4.17.11#omit
const omitByKeys = (obj, keys) => Object
.keys(obj)
.filter(key => !keys.includes(key))
.reduce((memo, key) => {
memo[key] = obj[key]; // eslint-disable-line no-param-reassign
return memo;
}, {});
/*!
* One-line mimic of Bluebirds .tap
* @see http://bluebirdjs.com/docs/api/tap.html
* @example
* return Promise
* .resolve()
* .then(() => 'TEST')
* .then(tap(val => { val === 'TEST'; }))
* .then(val => { val === 'TEST'; })
* .then(val => { val === undefined; });
*/
const tap = cb => d => Promise.resolve().then(() => cb(d)).then(() => d);
/*!
* One-line mimic Bluebirds .tapCatch
* @see http://bluebirdjs.com/docs/api/tapcatch.html
* @example
* return Promise
* .resolve()
* .then(() => Promise.reject(new Error('TEST')))
* .catch(tapCatch(err => { err.message === 'TEST' ... }))
* .catch(tapCatch(err => { err.message === 'TEST' ... }));
*/
const tapCatch = cb => e => Promise.resolve().then(() => cb(e)).then(() => Promise.reject(e));
/*!
* Promisify a JS callback function. #factory
* @example
* const readFileAsync = promisify(fs.readFile);
* return Promise
* .resolve()
* .then(() => readFileAsync(argv.source, 'utf8'))
* .then(data => { ... })
* .catch(err => { ... });
*/
const promisify = fn => (...args) => new Promise((resolve, reject) => fn(...args, (err, data) => (err ? reject(err) : resolve(data))));
/*!
* Partly satire. If you want to take a Promise and convert it back to a callback-able function.
*/
const callbackify = (p) => (cb) => p.then((d) => cb(null, d)).catch((e) => cb(e));
const triRequest = (...args) => triAsync(() => require('util').promisify(require('request'))(...args));
const triRequestGet = (...args) => triAsync(() => require('util').promisify(require('request').get)(...args));
const triRequestPost = (...args) => triAsync(() => require('util').promisify(require('request').post)(...args));
const triRequestPut = (...args) => triAsync(() => require('util').promisify(require('request').put)(...args));
const triRequestPatch = (...args) => triAsync(() => require('util').promisify(require('request').patch)(...args));
const triRequestDelete = (...args) => triAsync(() => require('util').promisify(require('request').delete)(...args));
const triRequestHead = (...args) => triAsync(() => require('util').promisify(require('request').head)(...args));
const triRequestOptions = (...args) => triAsync(() => require('util').promisify(require('request').options)(...args));
//! Converts string to title case.
//! @example toTitleCase('multi word example'); // => "MultiWordExample"
const toTitleCase = str => str.replace(/\w\S*/g, word => `${word.charAt(0).toUpperCase()}${word.substr(1).toLowerCase()}`).replace(/\s/g, '');
//! Converts string to snake case.
//! @example toSnakeCase('multi word example'); // => "multi_word_example"
const toSnakeCase = str => str.replace(/\s+/g, '_');
//! Converts string to camel case.
//! @depends toTitleCase
//! @example toCamelCase('multi word example'); // => "multiWordExample"
const toCamelCase = str => str.charAt(0).toLowerCase() + toTitleCase(str).substr(1);
//! Upper case first character only. EX: "Multi word example"
//! @example toFirstUpperCase('multi word example'); // => "Multi word example"
const toFirstUpperCase = string => string.charAt(0).toUpperCase() + string.slice(1);
const assertKey = (obj,key) => require('assert')(null != obj[key], '"'+(name || key)+'" required.');
// ### Random / Faking
const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const randomChars = n => Array(n)
.join()
.split(',')
.map(() => charset.charAt(Math.floor(Math.random() * charset.length)))
.join('');
//! @depends randomChars
const random4x4 = () => `${randomChars(4)}-${randomChars(4)}-${randomChars(4)}-${randomChars(4)}`;
#!/bin/sh
# Default var
VAR=${FROM_ENV_VAR:-DEFAULT_VALUE}
# Loose JSON to strict JSON
ATTRIBUTES=$2
ATTRIBUTES="$( node -e "console.log(JSON.stringify(${ATTRIBUTES}))" )"
# Thanks to a nameless sys-op referenced in https://stackoverflow.com/a/25515370/761771
yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment