266 lines
7.5 KiB
JavaScript
266 lines
7.5 KiB
JavaScript
import {
|
|
isUndefined, isNaN, isNull,
|
|
reduce, constant, head, isEmpty,
|
|
tail, findIndex, startsWith, join,
|
|
dropRight, flow, takeRight, trim,
|
|
split, includes, replace, isArray,
|
|
isString, isInteger, isDate, toNumber,
|
|
} from 'lodash';
|
|
import { some } from 'lodash/fp';
|
|
import { events, eventsList } from './events';
|
|
import { apiWrapper } from './apiWrapper';
|
|
import {
|
|
getLock, NO_LOCK,
|
|
isNolock
|
|
} from './lock';
|
|
|
|
// this is the combinator function
|
|
export const $$ = (...funcs) => arg => flow(funcs)(arg);
|
|
|
|
// this is the pipe function
|
|
export const $ = (arg, funcs) => $$(...funcs)(arg);
|
|
|
|
export const keySep = '/';
|
|
const trimKeySep = str => trim(str, keySep);
|
|
const splitByKeySep = str => split(str, keySep);
|
|
export const safeKey = key => replace(`${keySep}${trimKeySep(key)}`, `${keySep}${keySep}`, keySep);
|
|
export const joinKey = (...strs) => {
|
|
const paramsOrArray = strs.length === 1 & isArray(strs[0])
|
|
? strs[0] : strs;
|
|
return safeKey(join(paramsOrArray, keySep));
|
|
};
|
|
export const splitKey = $$(trimKeySep, splitByKeySep);
|
|
export const getDirFomKey = $$(splitKey, dropRight, p => joinKey(...p));
|
|
export const getFileFromKey = $$(splitKey, takeRight, head);
|
|
|
|
export const configFolder = `${keySep}.config`;
|
|
export const fieldDefinitions = joinKey(configFolder, 'fields.json');
|
|
export const templateDefinitions = joinKey(configFolder, 'templates.json');
|
|
export const appDefinitionFile = joinKey(configFolder, 'appDefinition.json');
|
|
export const dirIndex = folderPath => joinKey(configFolder, 'dir', ...splitKey(folderPath), 'dir.idx');
|
|
export const getIndexKeyFromFileKey = $$(getDirFomKey, dirIndex);
|
|
|
|
export const ifExists = (val, exists, notExists) => (isUndefined(val)
|
|
? isUndefined(notExists) ? (() => { })() : notExists()
|
|
: exists());
|
|
|
|
export const getOrDefault = (val, defaultVal) => ifExists(val, () => val, () => defaultVal);
|
|
|
|
export const not = func => val => !func(val);
|
|
export const isDefined = not(isUndefined);
|
|
export const isNonNull = not(isNull);
|
|
export const isNotNaN = not(isNaN);
|
|
|
|
export const allTrue = (...funcArgs) => val => reduce(funcArgs,
|
|
(result, conditionFunc) => (isNull(result) || result == true) && conditionFunc(val),
|
|
null);
|
|
|
|
export const anyTrue = (...funcArgs) => val => reduce(funcArgs,
|
|
(result, conditionFunc) => result == true || conditionFunc(val),
|
|
null);
|
|
|
|
export const insensitiveEquals = (str1, str2) => str1.trim().toLowerCase() === str2.trim().toLowerCase();
|
|
|
|
export const isSomething = allTrue(isDefined, isNonNull, isNotNaN);
|
|
export const isNothing = not(isSomething);
|
|
export const isNothingOrEmpty = v => isNothing(v) || isEmpty(v);
|
|
export const somethingOrGetDefault = getDefaultFunc => val => (isSomething(val) ? val : getDefaultFunc());
|
|
export const somethingOrDefault = (val, defaultVal) => somethingOrGetDefault(constant(defaultVal))(val);
|
|
|
|
export const mapIfSomethingOrDefault = (mapFunc, defaultVal) => val => (isSomething(val) ? mapFunc(val) : defaultVal);
|
|
|
|
export const mapIfSomethingOrBlank = mapFunc => mapIfSomethingOrDefault(mapFunc, '');
|
|
|
|
export const none = predicate => collection => !some(predicate)(collection);
|
|
|
|
export const all = predicate => collection => none(v => !predicate(v))(collection);
|
|
|
|
export const isNotEmpty = ob => !isEmpty(ob);
|
|
export const isAsync = fn => fn.constructor.name === 'AsyncFunction';
|
|
export const isNonEmptyArray = allTrue(isArray, isNotEmpty);
|
|
export const isNonEmptyString = allTrue(isString, isNotEmpty);
|
|
export const tryOr = failFunc => (func, ...args) => {
|
|
try {
|
|
return func.apply(null, ...args);
|
|
} catch (_) {
|
|
return failFunc();
|
|
}
|
|
};
|
|
|
|
export const tryAwaitOr = failFunc => async (func, ...args) => {
|
|
try {
|
|
return await func.apply(null, ...args);
|
|
} catch (_) {
|
|
return await failFunc();
|
|
}
|
|
};
|
|
|
|
export const defineError = (func, errorPrefix) => {
|
|
try {
|
|
return func();
|
|
} catch (err) {
|
|
err.message = `${errorPrefix} : ${err.message}`;
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
export const tryOrIgnore = tryOr(() => { });
|
|
export const tryAwaitOrIgnore = tryAwaitOr(async () => { });
|
|
export const causesException = (func) => {
|
|
try {
|
|
func();
|
|
return false;
|
|
} catch (e) {
|
|
return true;
|
|
}
|
|
};
|
|
|
|
export const executesWithoutException = func => !causesException(func);
|
|
|
|
export const handleErrorWith = returnValInError => tryOr(constant(returnValInError));
|
|
|
|
export const handleErrorWithUndefined = handleErrorWith(undefined);
|
|
|
|
export const switchCase = (...cases) => (value) => {
|
|
const nextCase = () => head(cases)[0](value);
|
|
const nextResult = () => head(cases)[1](value);
|
|
|
|
if (isEmpty(cases)) return; // undefined
|
|
if (nextCase() === true) return nextResult();
|
|
return switchCase(...tail(cases))(value);
|
|
};
|
|
|
|
export const isValue = val1 => val2 => (val1 === val2);
|
|
export const isOneOf = (...vals) => val => includes(vals, val);
|
|
export const defaultCase = constant(true);
|
|
export const memberMatches = (member, match) => obj => match(obj[member]);
|
|
|
|
|
|
export const StartsWith = searchFor => searchIn => startsWith(searchIn, searchFor);
|
|
|
|
export const contains = val => array => (findIndex(array, v => v === val) > -1);
|
|
|
|
export const getHashCode = (s) => {
|
|
let hash = 0; let i; let char; let
|
|
l;
|
|
if (s.length == 0) return hash;
|
|
for (i = 0, l = s.length; i < l; i++) {
|
|
char = s.charCodeAt(i);
|
|
hash = ((hash << 5) - hash) + char;
|
|
hash |= 0; // Convert to 32bit integer
|
|
}
|
|
|
|
// converting to string, but dont want a "-" prefixed
|
|
if (hash < 0) { return `n${(hash * -1).toString()}`; }
|
|
return hash.toString();
|
|
};
|
|
|
|
// thanks to https://blog.grossman.io/how-to-write-async-await-without-try-catch-blocks-in-javascript/
|
|
export const awEx = async (promise) => {
|
|
try {
|
|
const result = await promise;
|
|
return [undefined, result];
|
|
} catch (error) {
|
|
return [error, undefined];
|
|
}
|
|
};
|
|
|
|
export const isSafeInteger = n => isInteger(n)
|
|
&& n <= Number.MAX_SAFE_INTEGER
|
|
&& n >= 0 - Number.MAX_SAFE_INTEGER;
|
|
|
|
export const toDateOrNull = s => (isNull(s) ? null
|
|
: isDate(s) ? s : new Date(s));
|
|
export const toBoolOrNull = s => (isNull(s) ? null
|
|
: s === 'true' || s === true);
|
|
export const toNumberOrNull = s => (isNull(s) ? null
|
|
: toNumber(s));
|
|
|
|
export const isArrayOfString = opts => isArray(opts) && all(isString)(opts);
|
|
|
|
export const pause = async duration => new Promise(res => setTimeout(res, duration));
|
|
|
|
export const retry = async (fn, retries, delay, ...args) => {
|
|
try {
|
|
return await fn(...args);
|
|
} catch (err) {
|
|
if (retries > 1) {
|
|
return await pause(delay).then(async () => await retry(fn, (retries - 1), delay, ...args));
|
|
}
|
|
throw err;
|
|
}
|
|
};
|
|
|
|
export { events } from './events';
|
|
export { apiWrapper, apiWrapperSync } from './apiWrapper';
|
|
export {
|
|
getLock, NO_LOCK, releaseLock,
|
|
extendLock, isNolock,
|
|
} from './lock';
|
|
|
|
export default {
|
|
ifExists,
|
|
getOrDefault,
|
|
isDefined,
|
|
isNonNull,
|
|
isNotNaN,
|
|
allTrue,
|
|
isSomething,
|
|
mapIfSomethingOrDefault,
|
|
mapIfSomethingOrBlank,
|
|
configFolder,
|
|
fieldDefinitions,
|
|
isNothing,
|
|
not,
|
|
switchCase,
|
|
defaultCase,
|
|
StartsWith,
|
|
contains,
|
|
templateDefinitions,
|
|
handleErrorWith,
|
|
handleErrorWithUndefined,
|
|
tryOr,
|
|
tryOrIgnore,
|
|
tryAwaitOr,
|
|
tryAwaitOrIgnore,
|
|
dirIndex,
|
|
keySep,
|
|
$,
|
|
$$,
|
|
getDirFomKey,
|
|
getFileFromKey,
|
|
splitKey,
|
|
somethingOrDefault,
|
|
getIndexKeyFromFileKey,
|
|
joinKey,
|
|
somethingOrGetDefault,
|
|
appDefinitionFile,
|
|
isValue,
|
|
all,
|
|
isOneOf,
|
|
memberMatches,
|
|
defineError,
|
|
anyTrue,
|
|
isNonEmptyArray,
|
|
causesException,
|
|
executesWithoutException,
|
|
none,
|
|
getHashCode,
|
|
awEx,
|
|
apiWrapper,
|
|
events,
|
|
eventsList,
|
|
isNothingOrEmpty,
|
|
isSafeInteger,
|
|
toNumber,
|
|
toDate: toDateOrNull,
|
|
toBool: toBoolOrNull,
|
|
isArrayOfString,
|
|
getLock,
|
|
NO_LOCK,
|
|
isNolock,
|
|
insensitiveEquals,
|
|
pause,
|
|
retry,
|
|
};
|