UNPKG

low-code-service

Version:

to handle workflow execution, handlebars execution and condition execution for low code service

512 lines (425 loc) 15.2 kB
import * as HandleBars from 'handlebars'; const { parseBoolean } = require('../condition-executor/condition-handler'); const momentTimezone = require('moment-timezone'); const lodash = require('lodash'); function getEwayBillValues(ewayBill) { const invoiceDate = lodash.get(ewayBill, 'invoice_date') || lodash.get(ewayBill, 'invoiceDate') || ''; const invoiceNumber = lodash.get(ewayBill, 'invoice_number') || lodash.get(ewayBill, 'invoiceNumber') || ''; const invoiceValue = lodash.get(ewayBill, 'invoiceValue') || lodash.get(ewayBill, 'invoice_amount') || lodash.get(ewayBill, 'invoice_value') || ''; const ewbNumber = lodash.get(ewayBill, 'ewb_number') || lodash.get(ewayBill, 'ewbNumber') || ''; const expiryDate = lodash.get(ewayBill, 'expiry_date') || lodash.get(ewayBill, 'validTill') || ''; const ewbCreationDate = lodash.get(ewayBill, 'creationTime') || lodash.get(ewayBill, 'creation_time') || ''; return { invoiceDate, invoiceNumber, invoiceValue, ewbNumber, expiryDate, ewbCreationDate, }; } // registering all the helpers for Handlerbar (async function() { // ifEquals helper for comparing two strings HandleBars.registerHelper('ifEquals', (a, b) => { return (a ? a.toUpperCase() : '') === b.toUpperCase(); }); // exists helper for checking value is some truthy value and not falsy HandleBars.registerHelper('exists', (val) => { return !(val === undefined || val === null); }); // toUpperCase helper for converting string to uppper case HandleBars.registerHelper('toUpperCase', (val) => { return val.toUpperCase(); }); // toLowerCase helper for converting string to lower case HandleBars.registerHelper('toLowerCase', (val) => { return val.toLowerCase(); }); // "not" helper use with if HandleBars.registerHelper('not', function(val) { return !val; }); HandleBars.registerHelper('lookupByIndex', function(array, index) { return array[index]; }); HandleBars.registerHelper('multiply', function(value, multiplier) { if (!value || !multiplier) { return 0; } return (Number(value) * Number(multiplier)) || 0; }); HandleBars.registerHelper('dateConvertor', function(value, fromFormat, fromTimezone, toFormat, toTimezone) { let moment; if (value) { moment = momentTimezone(value, fromFormat, fromTimezone); } else { moment = momentTimezone(); } moment = moment.tz(toTimezone); if (toFormat === 'timestamp') { return moment.valueOf(); } return moment.format(toFormat); }); HandleBars.registerHelper('base64Decoder', function(value) { try { const decoded = Buffer.from(value, 'base64').toString('utf-8'); return decoded; } catch (err) { return ''; } }); HandleBars.registerHelper('base64Encoder', function(value) { try { const encoded = Buffer.from(value, 'utf-8').toString('base64'); return encoded; } catch (err) { return ''; } }); HandleBars.registerHelper('getBasicAuth', function(username, password) { try { const buff = new Buffer(username + ':' + password); const base64data = buff.toString('base64'); return base64data; } catch (err) { return null; } }); HandleBars.registerHelper('concat', function() { return Array.prototype.slice.call(arguments, 0, -1).join(''); }); HandleBars.registerHelper('toNumber', function(value) { return Number(value); }); HandleBars.registerHelper('toString', function(value) { return String(value); }); HandleBars.registerHelper('toBoolean', function(value) { return parseBoolean(value); }); HandleBars.registerHelper('getEwayBillValues', function(ewayBill) { return getEwayBillValues(ewayBill); }); HandleBars.registerHelper('arrayLength', function(array) { // Check if the array is not null or undefined if (Array.isArray(array)) { const length = array.length; // Return falsy if the length is 0, otherwise return the length return length === 0 ? '' : length; } // Return falsy if the input is not an array return ''; }); HandleBars.registerHelper('sumKey', function(array, key) { // Check if the array is valid and contains items if (Array.isArray(array) && array.length > 0) { // Sum the values of the specified key return array.reduce((total, item) => { // Ensure the key exists and is a number const value = parseFloat(item[key]) || 0; return total + value; }, 0); } // Return a falsy value if the array is empty or invalid return ''; }); HandleBars.registerHelper('getInvoiceValues', function(ewayBillList, consignmentExtraDetails) { let invoiceNumber = ''; let invoiceDate = ''; let ewbNumber = ''; let invoiceAmount: any = ''; let expiryDate = ''; let ewbCreationDate = ''; if (Array.isArray(ewayBillList) && ewayBillList.length) { const ewayBillValues = getEwayBillValues(ewayBillList[0]); invoiceNumber = ewayBillValues.invoiceNumber; invoiceDate = ewayBillValues.invoiceDate; ewbNumber = ewayBillValues.ewbNumber; invoiceAmount = ewayBillValues.invoiceValue; expiryDate = ewayBillValues.expiryDate; ewbCreationDate = ewayBillValues.ewbCreationDate; } if (consignmentExtraDetails.eway_bill) { const ewayBillValues = getEwayBillValues(consignmentExtraDetails.eway_bill); if (!invoiceNumber) invoiceNumber = ewayBillValues.invoiceNumber; if (!invoiceDate) invoiceDate = ewayBillValues.invoiceDate; if (!ewbNumber) ewbNumber = ewayBillValues.ewbNumber; if (!expiryDate) expiryDate = ewayBillValues.expiryDate; if (!ewbCreationDate) ewbCreationDate = ewayBillValues.ewbCreationDate; } if (!invoiceNumber) { invoiceNumber = lodash.get(consignmentExtraDetails, 'invoice_number', ''); } if (!invoiceDate) { invoiceDate = lodash.get(consignmentExtraDetails, 'invoice_date', ''); } if (!invoiceAmount) { invoiceAmount = lodash.get(consignmentExtraDetails, 'invoice_amount', ''); } return { invoiceNumber, invoiceDate, ewbNumber, invoiceAmount, expiryDate, ewbCreationDate, }; }); HandleBars.registerHelper('sumProperty', function(piecesDetail, property) { if (!piecesDetail || !Array.isArray(piecesDetail)) return 0; return piecesDetail.reduce((sum, item) => { if (!item) return sum; const value = item[property]; if (value === undefined || value === null) return sum; const numValue = parseFloat(value); return sum + (isNaN(numValue) ? 0 : numValue); }, 0); }); HandleBars.registerHelper('getRegexMatch', function (str, pattern, groupIndex = 0, flags = '') { if (typeof str !== 'string') { return ''; } if (str === '') { return ''; } let index: number; if (typeof groupIndex === 'string') { index = parseInt(groupIndex, 10); } else if (typeof groupIndex === 'number') { index = groupIndex; } else { return ''; } if (isNaN(index)) { return ''; } try { const patternStr = String(pattern); const validFlags = flags.replace(/[^gimsuyd]/g, ''); const regex = new RegExp(patternStr, validFlags); const match = str.match(regex); if (match && match[index] !== undefined) { return match[index]; } else { return ''; } } catch (error) { return ''; } }); HandleBars.registerHelper('arrayProperty', function (array, options) { const { operation, property, value, order = 'asc', dataType, checkType = 'any' } = options.hash; if (!Array.isArray(array)) { return operation === 'exists' ? false : []; } function getNestedValue(obj, path) { return path.split('.').reduce((acc, key) => acc?.[key], obj); } function isValidValue(val, type) { if (val == null) return false; switch ((type || '').toLowerCase()) { case 'string': return typeof val === 'string' && val.trim() !== ''; case 'number': return typeof val === 'number' && !isNaN(val); case 'boolean': return typeof val === 'boolean'; case 'array': return Array.isArray(val) && val.length > 0; case 'object': return typeof val === 'object' && !Array.isArray(val) && Object.keys(val).length > 0; case 'any': default: if (Array.isArray(val)) return val.length > 0; if (typeof val === 'object') return Object.keys(val).length > 0; return Boolean(val); } } switch (operation) { case 'exists': if (checkType === 'every') { return array.every(item => isValidValue(getNestedValue(item, property), dataType)); } else { return array.some(item => isValidValue(getNestedValue(item, property), dataType)); } case 'map': return array.map(item => getNestedValue(item, property)); case 'filter': return array.filter(item => getNestedValue(item, property) == value); case 'find': return array.find(item => getNestedValue(item, property) == value); case 'sort': return array.slice().sort((a, b) => { const aVal = getNestedValue(a, property); const bVal = getNestedValue(b, property); if (aVal == null && bVal == null) return 0; if (aVal == null) return 1; if (bVal == null) return -1; if (order === 'desc') { return aVal < bVal ? 1 : aVal > bVal ? -1 : 0; } return aVal > bVal ? 1 : aVal < bVal ? -1 : 0; }); case 'unique': const seen = new Set(); return array.filter(item => { const val = getNestedValue(item, property); if (seen.has(val)) return false; seen.add(val); return true; }); case 'sum': return array.reduce((acc, item) => { const val = getNestedValue(item, property); const num = parseFloat(val); return acc + (isNaN(num) ? 0 : num); }, 0); default: return array; } }); HandleBars.registerHelper('trimToLength', function (str, maxLength) { // Check if the string is shorter than or equal to the maxLength if (typeof str !== 'string') { return ''; // Return empty if input is not a string } if (str.length <= maxLength) { return str; // If string is shorter or equal to maxLength, return the original string } // If string is longer than maxLength, trim it return str.slice(0, maxLength); }); // abs - returns the absolute value of a number HandleBars.registerHelper('abs', function(value) { const num = parseFloat(value); return isNaN(num) ? 0 : Math.abs(num); }); // int - converts value to integer HandleBars.registerHelper('int', function(value) { const num = parseInt(value, 10); return isNaN(num) ? 0 : num; }); // round - rounds a number to specified decimal places (default: 0) HandleBars.registerHelper('round', function(value, decimalPlaces) { const num = parseFloat(value); if (isNaN(num)) return 0; const places = parseInt(decimalPlaces, 10); if (isNaN(places)) { return Math.round(num); // Default to 0 decimal places } const multiplier = Math.pow(10, places); return Math.round(num * multiplier) / multiplier; }); // max - returns the maximum value from arguments or array, preserving original type HandleBars.registerHelper('max', function() { const args = Array.prototype.slice.call(arguments, 0, -1); // Remove options object let values: any[] = []; // If first argument is an array, use that if (Array.isArray(args[0])) { values = args[0]; } else { // Otherwise, treat all arguments as values values = args; } // Filter out null/undefined values and convert to numbers for comparison const validValues = values.filter(val => val != null); if (validValues.length === 0) return 0; const numericValues = validValues.map(val => parseFloat(val)).filter(num => !isNaN(num)); if (numericValues.length === 0) return 0; const maxNumeric = Math.max(...numericValues); // Find the original value that corresponds to the maximum numeric value const maxOriginal = validValues.find(val => parseFloat(val) === maxNumeric); // Return the original value to preserve its type return maxOriginal; }); // min - returns the minimum value from arguments or array, preserving original type HandleBars.registerHelper('min', function() { const args = Array.prototype.slice.call(arguments, 0, -1); // Remove options object let values: any[] = []; // If first argument is an array, use that if (Array.isArray(args[0])) { values = args[0]; } else { // Otherwise, treat all arguments as values values = args; } // Filter out null/undefined values and convert to numbers for comparison const validValues = values.filter(val => val != null); if (validValues.length === 0) return 0; const numericValues = validValues.map(val => parseFloat(val)).filter(num => !isNaN(num)); if (numericValues.length === 0) return 0; const minNumeric = Math.min(...numericValues); // Find the original value that corresponds to the minimum numeric value const minOriginal = validValues.find(val => parseFloat(val) === minNumeric); // Return the original value to preserve its type return minOriginal; }); // float - converts value to floating point number HandleBars.registerHelper('float', function(value) { const num = parseFloat(value); return isNaN(num) ? 0.0 : num; }); // {{addMinutesToCurrentTime "timestamp" 15 "Europe/Rome"}} // addMinutesToCurrentTime - adds specified minutes to current time and returns in requested format with optional timezone HandleBars.registerHelper('addMinutesToCurrentTime', function(timeFormat, minutesToAdd, timezone) { const minutes = parseInt(minutesToAdd, 10) || 0; let currentTime = momentTimezone(); // If timezone is provided, convert to that timezone if (timezone) { currentTime = currentTime.tz(timezone); } const newTime = currentTime.add(minutes, 'minutes'); if (timeFormat === 'timestamp') { return newTime.valueOf(); } return newTime.format(timeFormat); }); // searchOne - searches for the first item in an array that matches the given criteria HandleBars.registerHelper('searchOne', function(array, value) { if (!Array.isArray(array)) { return null; } return array.find(item => item === value) || null; }); // all - checks if all items in an array have truthy values (for a property or the item itself) HandleBars.registerHelper('all', function(array, property, options) { if (!Array.isArray(array)) { return false; } if (array.length === 0) { return true; // vacuous truth - all items in empty array satisfy any condition } function getNestedValue(obj, path) { return path.split('.').reduce((acc, key) => acc?.[key], obj); } function isTruthy(value) { if(value){ return true; } return false; } return array.every(item => { if (!item) return false; const itemValue = property ? getNestedValue(item, property) : item; return isTruthy(itemValue); }); }); })(); export const getTemplateData = (template: string, data: any) => { const compiledTemplate = HandleBars.compile(template); return compiledTemplate(data); }; export const cleanHandleBarTemplate = (dataToClean, defaultBody) => { dataToClean = dataToClean.replace('\n', ''); dataToClean = dataToClean.replace('\t', ''); return dataToClean || defaultBody; };