mirror of https://github.com/Budibase/budibase.git
nocodelowcodelow-codedockerdocker-composeinternal-projectinternal-toolinternal-toolslow-code-developmentlow-code-development-platformopensourceselfhostedweb-devweb-developmentweb-development-toolswebdevwebdevelopmentworkflow-automationautomationdeveloper-tools
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
7.8 KiB
317 lines
7.8 KiB
import {
|
|
head,
|
|
tail,
|
|
findIndex,
|
|
startsWith,
|
|
dropRight,
|
|
flow,
|
|
takeRight,
|
|
trim,
|
|
replace,
|
|
} from "lodash"
|
|
import {
|
|
some,
|
|
reduce,
|
|
isEmpty,
|
|
isArray,
|
|
join,
|
|
isString,
|
|
isInteger,
|
|
isDate,
|
|
toNumber,
|
|
isUndefined,
|
|
isNaN,
|
|
isNull,
|
|
constant,
|
|
split,
|
|
includes,
|
|
filter,
|
|
} from "lodash/fp"
|
|
import { events, eventsList } from "./events"
|
|
import { apiWrapper } from "./apiWrapper"
|
|
import { getLock, NO_LOCK, isNolock } from "./lock"
|
|
import crypto from "./nodeCrypto"
|
|
|
|
// 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(keySep)(str)
|
|
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 $(paramsOrArray, [
|
|
filter(s => !isUndefined(s) && !isNull(s) && s.toString().length > 0),
|
|
join(keySep),
|
|
safeKey,
|
|
])
|
|
}
|
|
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(
|
|
(result, conditionFunc) =>
|
|
(isNull(result) || result == true) && conditionFunc(val),
|
|
null
|
|
)(funcArgs)
|
|
|
|
export const anyTrue = (...funcArgs) => val =>
|
|
reduce(
|
|
(result, conditionFunc) => result == true || conditionFunc(val),
|
|
null
|
|
)(funcArgs)
|
|
|
|
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(val)(vals)
|
|
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 pushAll = (target, items) => {
|
|
for (let i of items) target.push(i)
|
|
}
|
|
|
|
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 { crypto }
|
|
|
|
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,
|
|
pushAll,
|
|
}
|
|
|