UNPKG

@runnerty/interpreter-core

Version:
953 lines (871 loc) 20.3 kB
import _uuid from 'uuid'; import crypto from 'crypto'; import lodash from 'lodash'; import moment from 'moment'; import path from 'path'; import interpreter from '../index'; export const functions = { gv: getvalue, getvalue: getvalue, gvq: getvaluequoted, getvaluequoted: getvaluequoted, getvalueescape: getvalueescape, gvescape: getvalueescape, getvalueunescape: getvalueunescape, gvunescape: getvalueunescape, genv: getenv, env: getenv, if: _if, eq: eq, ne: ne, gt: gt, gte: gte, lt: lt, lte: lte, sin: Math.sin, cos: Math.cos, tan: Math.tan, asin: Math.asin, acos: Math.acos, atan: Math.atan, abs: Math.abs, round: Math.round, ceil: Math.ceil, floor: Math.floor, log: Math.log, exp: Math.exp, pow: Math.pow, sqrt: Math.sqrt, max: Math.max, min: Math.min, random: random, add: add, trim: trim, ltrim: ltrim, rtrim: rtrim, substr: substr, length: length, replace: replace, escape: escape, unescape: unescape, htmlescape: htmlescape, htmlunescape: htmlunescape, hash: hash, encrypt: encrypt, decrypt: decrypt, uuid: uuid, uuidv4: uuid, uuidv1: uuidv1, uuidv3: uuidv3, uuidv5: uuidv5, uuidvalidate: uuid_validate, uuidversion: uuid_version, subtract: subtract, divide: divide, multiply: multiply, modulus: modulus, lpad: lpad, rpad: rpad, concat: concat, concatws: concatws, upper: upper, lower: lower, includes: includes, indexof: indexof, getdate: getDate, lastday: lastDay, dateformat: dateFormat, charcode: charcode, ifnull: ifnull, pathparse: pathParse, pathnormalize: path.normalize, pathjoin: path.join, urlparse: urlParse, quote: quote, stringify: stringify, jsonstringify: stringify, forof: for_of }; /** * Get Environment variable. * Used by GetValue / GetEnv * @param s string * @returns string */ function getENVs(s) { let res = ''; const envName = s.substr(4, s.length); if (s.startsWith('ENV_') && process.env[envName]) { res = process.env[envName]; } return res; } /** * GetValue/GV: Returns a value (idvalue) of values * Used to obtain values of the dynamic variables * @param idvalue * @param values * @returns {string} */ function getvalue(idvalue, quote, values) { let res = ''; if (values.hasOwnProperty(idvalue)) { const match = values[idvalue]; if (match || match === 0 || match === false) res = match; } else if (idvalue.startsWith('ENV_')) { res = getENVs(idvalue); } if (quote) { if (quote === "\\'") quote = "'"; res = quote + res + quote; } return res; } /** * GetValueQuoted/GVQ: Returns a value (idvalue) of values * Used to obtain values of the dynamic variables * @param idvalue * @quote quote (quote string) * @param values * @returns {string} */ function getvaluequoted(idvalue, quote = "'", values) { return getvalue(idvalue, quote, values); } /** * GetEnv/GENV: Returns a environment value * Used to obtain values of the environment * @param envName * @param values * @returns {string} */ function getenv(envName, quote) { let res = process.env[envName] || ''; if (quote) { if (quote === "\\'") quote = "'"; res = quote + res + quote; } return res; } /** * Escape * @param string * @returns {string} escaped string */ function escape(string) { return ('' + string).replace(/["'\\\n\r\u2028\u2029]/g, _char => { switch (_char) { case '"': return '\\' + _char; case "'": return '\\' + _char; case '\\': return '\\' + _char; case '\n': return '\\n'; case '\r': return '\\r'; case '\u2028': return '\\u2028'; case '\u2029': return '\\u2029'; default: return _char; } }); } /** * Unescape * @param string * @returns {string} unescaped string */ function unescape(string) { return ('' + string).replace(/\\'|\\"|\\n|\\r|\\u2028|\\u2029/g, _escapedChar => { switch (_escapedChar) { case '\\"': return '"'; case "\\'": return "'"; case '\\n': return '\n'; case '\\r': return '\r'; case '\\u2028': return '\u2028'; case '\\u2029': return '\u2029'; default: return _escapedChar; } }); } /** * Htmlescape * @param string * @returns {string} Escaped string for insertion into HTML, replacing "&", "<", ">", '"', and "'" by &amp;, &lt;, &gt;, &quot;, and &#39; */ function htmlescape(string) { return lodash.escape(string); } /** * Htmlunescape * @param string * @returns {string} Escaped string for insertion into HTML, replacing &amp;, &lt;, &gt;, &quot;, and &#39; by "'", "<", ">", '"', and "'" */ function htmlunescape(string) { return lodash.unescape(string); } /** * GetValueEscape/GVEscape: Returns a escaped value (idvalue) of values * Used to obtain values of the dynamic variables * @param idvalue * @param values * @returns {string} */ function getvalueescape(idvalue, values) { const match = values[idvalue]; let res = ''; if (match) { res = match; } else { if (idvalue.startsWith('ENV_')) { res = getENVs(idvalue); } } return escape(res); } /** * GetValueUnescape/GVUnescape: Returns a unescaped value (idvalue) of values * Used to obtain values of the dynamic variables * @param idvalue * @param values * @returns {string} */ function getvalueunescape(idvalue, values) { const match = values[idvalue]; let res = ''; if (match) { res = match; } else { if (idvalue.startsWith('ENV_')) { res = getENVs(idvalue); } } return unescape(res); } /** * Trim: Return trim input string * @param s {string} * @returns {string} */ function trim(s) { return s.replace(/'/g, '').trim(); } /** * LTrim: Return left trim input string * @param s {string} * @returns {string} */ function ltrim(s) { return s.replace(/'/g, '').ltrim(); } /** * RTrim: Return right trim input string * @param s {string} * @returns {string} */ function rtrim(s) { return s.replace(/'/g, '').rtrim(); } /** * LPad: Returns a string(s) that is left-padded with a specified string(p) to a certain length(l). * @param s {string} * @param l length {string} * @param p padded string {string} * @returns {string} */ function lpad(s, l, p) { return s.replace(/'/g, '').padStart(l, p.replace(/'/g, '')); } /** * RPad: Returns a string(s) that is right-padded with a specified string(p) to a certain length(l). * @param s {string} * @param l length {string} * @param p padded string {string} * @returns {string} */ function rpad(s, l, p) { return s.replace(/'/g, '').padEnd(l, p.replace(/'/g, '')); } /** * Concat: Concatenates two or more expressions together * @params N strings or functions * @returns {string} */ function concat() { let strOutput = ''; for (let i = 0; i < arguments.length; i++) { const arg = arguments[i]; strOutput += arg; } return strOutput; } /** * ConcatWS: Concatenates two or more expressions together and adds a separator between them * @params separator {string} * @params N strings or functions * @returns {string} */ function concatws() { let strOutput = ''; let separator = ''; for (let i = 1; i < arguments.length; i++) { if (strOutput !== '') separator = arguments[0]; const arg = arguments[i]; strOutput += separator + arg; } return strOutput; } /** * Upper: Converts a string to upper-case * @param s * @returns {string} */ function upper(s) { return s.toUpperCase(); } /** * Lower: Converts a string to lower-case * @param s * @returns {string} */ function lower(s) { return s.toLowerCase(); } /** * Includes: Returns true or false depending on whether it finds or not a string in another string * @param s - The string that will be searched {string} * @param is - The substring to search for in string {string} * @returns {boolean} */ function includes(s, is) { return s.includes(is); } /** * IndexOf: Returns the position of the first occurrence of a string in another string * @param s - The string that will be searched {string} * @param is - The substring to search for in string {string} * @returns {number} */ function indexof(s, is) { return s.indexof(is); } /** * SubStr: Returns a substring from a string (starting at any position). * @param s - The string to extract from * @param i - The start position * @param e - The number of characters to extract. If omitted, the whole string will be returned (from the start position) * @returns {string} */ function substr(s, i, e) { let res = ''; if (e) res = s.substr(i, e); else res = s.substr(i); return res; } /** * Length: Returns the length of the specified string (in bytes). * @param s {string} */ function length(s) { return s.length; } /** * Replace: Replaces all occurrences of a specified string. * @param s - The string * @param sub - The substring to find * @param n - The replacement substring * @param f - The flags (RegExp) */ function replace(s, sub, n, f) { let _regexp = sub; if (f) { _regexp = new RegExp(sub, f); } return s.replace(_regexp, n); } /** * CharCode: Returns the number code that represents the specific character. * @param s * @returns {number} */ function charcode(s) { return s.charCodeAt(0); } /** * Subtract * @params N {number} * @returns {number} */ function subtract() { let res = 0; for (let i = 0; i < arguments.length; i++) { if (i === 0) { res = arguments[0]; } else { res = res - arguments[i]; } } return res; } /** * Add * @params N {number} * @returns {number} */ function add() { let res = 0; for (let i = 0; i < arguments.length; i++) { const arg = arguments[i]; res += arg; } return res; } /** * Random: Returns a random number. * @param round - Decimals number * @param min - Min number random * @param max - Max number random * @returns {float} */ function random(round, min, max) { let res; if (round && typeof round === 'string') round = parseInt(round); if (min && typeof min === 'string') min = parseInt(min); if (max && typeof max === 'string') max = parseInt(max); if (round || round === 0) { res = parseFloat( (min || min === 0) && (max || max === 0) ? Math.random() * (max + 1 - min) + min : Math.random() ).toFixed(round); } else { res = (min || min === 0) && (max || max === 0) ? Math.random() * (max + 1 - min) + min : Math.random(); } return res; } /** * Multiply * @param x * @param y * @returns {number} */ function multiply(x, y) { return x * y; } /** * Divide * @param x * @param y * @returns {number} */ function divide(x, y) { return x / y; } /** * Modulus * @param x * @param y * @returns {number} */ function modulus(x, y) { return x % y; } /** * Ifnull: Returns an alternative (r) value if an expression is null and optionally other (e) if not. * @param v - The value to test whether is NULL * @param a - The value to return if expression is a NULL value * @param e - Optional: The value to return if expression is NOT NULL value * @returns {string} */ function ifnull(v, a, e) { let res = e || v; if (!v || v === '' || typeof v === 'undefined') { res = a; } return res; } /** * If * @param condition * @param ontrue * @param onfalse * @returns {*} * @private */ function _if(condition, ontrue, onfalse) { return condition === 'true' || condition === true ? ontrue : onfalse; } /** * Eq * @param oper_l * @param oper_r * @returns {boolean} */ function eq(oper_l, oper_r) { return oper_l == oper_r; } /** * ne * @param oper_l * @param oper_r * @returns {boolean} */ function ne(oper_l, oper_r) { return oper_l != oper_r; } /** * gt * @param oper_l * @param oper_r * @returns {boolean} */ function gt(oper_l, oper_r) { return oper_l > oper_r; } /** * gte * @param oper_l * @param oper_r * @returns {boolean} */ function gte(oper_l, oper_r) { return oper_l >= oper_r; } /** * lt * @param oper_l * @param oper_r * @returns {boolean} */ function lt(oper_l, oper_r) { return oper_l < oper_r; } /** * lte * @param oper_l * @param oper_r * @returns {boolean} */ function lte(oper_l, oper_r) { return oper_l <= oper_r; } /** * GetDate: Returns date as specified by a format mask, language and period. * @param format (http://momentjs.com/docs/#/parsing/string-format/) * @param lang * @param period * @param increment * @param uppercase * @returns {string} */ function getDate(format, lang, period, increment = 1, uppercase) { if (lang && lang !== '') { lang = lang.toLowerCase(); moment.locale(lang); } else { moment.locale('en'); } const mom = moment(); let strDate = ''; if (period) { period = period.toLowerCase(); strDate = mom.add(increment, period).format(format); } else { strDate = mom.format(format); } if (uppercase && uppercase !== 'false') { strDate = strDate.toUpperCase(); } return strDate; } /** * dateFormat: Returns a date as specified by a format mask, language and period. * @param format (http://momentjs.com/docs/#/parsing/string-format/) * @param lang * @param period * @param increment * @param uppercase * @returns {string} */ function dateFormat(date, format = 'YYYYMMDD', output_format, lang, period, increment = 1, uppercase) { if (lang && lang !== '') { lang = lang.toLowerCase(); moment.locale(lang); } else { moment.locale('en'); } if (!date) date = moment(); if (format && !output_format) output_format = format; let strDate = ''; if (period) { period = period.toLowerCase(); strDate = moment(date, format).add(increment, period).format(output_format); } else { strDate = moment(date, format).format(output_format); } if (uppercase && uppercase !== 'false') { strDate = strDate.toUpperCase(); } return strDate; } /** * LastDay: Returns last day of a date as specified by a format mask, language and period. * @param format (http://momentjs.com/docs/#/parsing/string-format/) * @param lang * @param period * @param increment * @param uppercase * @returns {string} */ function lastDay(date, format = 'YYYYMMDD', output_format, lang, uppercase) { if (lang && lang !== '') { lang = lang.toLowerCase(); moment.locale(lang); } else { moment.locale('en'); } if (!date) date = moment(); if (format && !output_format) output_format = format; let strDate = ''; strDate = moment(date, format).endOf('month').format(output_format); if (uppercase && uppercase !== 'false') { strDate = strDate.toUpperCase(); } return strDate; } /** * PathParser * @param _path * @param property * @returns {string} */ function pathParse(_path, property) { let res = ''; if (_path) { const pathProperties = path.parse(_path); property = property.replace(/['"]+/g, '').toLowerCase().trim(); if (pathProperties[property]) { res = pathProperties[property]; } else { throw new Error(`PathParse (${_path}) wrong property ${property}.`); } } return res; } /** * URLParser * @param _url * @param property * @returns {string} */ function urlParse(_url, property) { let res = ''; if (_url) { const urlProperties = new URL(_url); property = property.replace(/['"]+/g, '').toLowerCase().trim(); if (urlProperties[property]) { res = urlProperties[property]; } else { throw new Error(`UrlParser (${_url}) wrong property ${property}.`); } } return res; } /** * Hash: Return hashed string * @param s {string} * @param hash (openssl list-message-digest-algorithms) {string} * @param digets (hex, base64 or latin1) {string} * @returns {string} */ function hash(s, hash, digets) { digets = digets || 'hex'; return crypto.createHash(hash).update(s).digest(digets); } /** * Encrypt * @param s * @param algorithm (openssl list-cipher-algorithms) * @param password * @returns String crypted */ function encrypt(s, algorithm, password) { const IV_LENGTH = 16; // For AES, this is always 16 const iv = crypto.randomBytes(IV_LENGTH); const cipher = crypto.createCipheriv(algorithm, Buffer.from(password), iv); let crypted = cipher.update(s, 'utf8', 'hex'); crypted += cipher.final('hex'); return crypted; } /** * Decrypt * @param s * @param algorithm (openssl list-cipher-algorithms) * @param password * @returns String decrypted */ function decrypt(s, algorithm, password) { const textParts = s.split(':'); const iv = Buffer.from(textParts.shift(), 'hex'); const encryptedText = Buffer.from(textParts.join(':'), 'hex'); const decipher = crypto.createDecipheriv(algorithm, Buffer.from(password), iv); let decrypted = decipher.update(encryptedText); decrypted = Buffer.concat([decrypted, decipher.final()]); return decrypted.toString(); } /** * UUID * @returns A version 4 (random) UUID */ function uuid() { try { return _uuid.v4(); } catch (err) { throw new Error(`UUID error: ${err}`); } } /** * UUID * @returns A version 1 (timestamp) UUID */ function uuidv1() { try { return _uuid.v1(); } catch (err) { throw new Error(`UUID error: ${err}`); } } /** * UUID * @returns A version 5 (namespace w/ SHA-1) UUID */ function uuidv5(name, namespace_uuid) { if (_uuid.validate(namespace_uuid)) { try { return _uuid.v5(name, namespace_uuid); } catch (err) { throw new Error(`UUID error: ${err}`); } } else { throw new Error(`INVALID NAMESPACE UUID: ${namespace_uuid}`); } } /** * UUID * @returns A version 3 (namespace w/ MD5) UUID */ function uuidv3(name, namespace_uuid) { if (_uuid.validate(namespace_uuid)) { try { return _uuid.v3(name, namespace_uuid); } catch (err) { throw new Error(`UUID error: ${err}`); } } else { throw new Error(`INVALID NAMESPACE UUID: ${namespace_uuid}`); } } /** * UUID * @returns Test a string to see if it is a valid UUID */ function uuid_validate(uuid) { return _uuid.validate(uuid); } /** * UUID * @returns Detect RFC version of a UUID */ function uuid_version(uuid) { return _uuid.version(uuid); } /** * Quote * @param s (string) * @param quote (quote string) * @returns Quoted string */ function quote(s, quote = "'") { return quote + s + quote; } /** * JSON Stringify * @param obj * @returns {string} JSON stringified object */ function stringify(obj) { if (!obj) { throw new Error(`stringifying non value variable -> ${obj}`); } else { try { return JSON.stringify(obj); } catch (ex) { throw new Error(`Stringify exception: ${ex}`); } } } /** * Returns an array with one object for each element of the array of values * @param {Array<any>} values * @param {object} obj * @returns {Array<object>} Array of objects */ async function for_of(values, obj) { if (!Array.isArray(values)) { throw new Error(`For of exception: invalid array -> ${values}`); } if (typeof obj !== 'object') { try { obj = JSON.parse(obj); if (!obj) { throw new Error(`For of exception: null object -> ${obj}`); } } catch (ex) { if (typeof obj !== 'string') { throw new Error(`For of exception: invalid object -> ${obj}`); } } } const res = []; try { for (const value of values) { const newObjRaw = await interpreter.interpret(obj, value, { source: 'for_of' }); const newObjParsed = (obj => { if (typeof obj === 'object') { return obj; } else { try { return JSON.parse(obj, (k, v) => { if ( typeof v === 'string' && ((v.startsWith('{') && v.endsWith('}')) || (v.startsWith('[') && v.endsWith(']'))) ) { try { return JSON.parse(v); } catch (e) { return v; } } return v; }); } catch (e) { return obj; } } })(newObjRaw); res.push(newObjParsed); } return res; } catch (ex) { throw new Error(`For of exception: ${ex}`); } }