Last active
October 8, 2021 16:31
-
-
Save servel333/a09539142fb4290f02add80a17a691d2 to your computer and use it in GitHub Desktop.
JavaScript one-liners and simple blocks, and some bash
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* 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; }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 */ | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! 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)]; | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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; | |
}, {}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* 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)); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! 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); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)}`; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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