@haystacks/async
Version:
A framework to build any number or any kind of native application or automation solution.
388 lines (375 loc) • 23.2 kB
JavaScript
/**
* @file lexicalAnalyzer.js
* @module lexicalAnalyzer
* @description Contains all functions used for parsing command arguments and/or business rule argumetns.
* @requires module:ruleParsing
* @requires module:configurator
* @requires module:loggers
* @requires {@link https://www.npmjs.com/package/@haystacks/constants|@haystacks/constants}
* @requires {@link https://www.npmjs.com/package/path|path}
* @author Seth Hollingsead
* @date 2022/02/03
* @copyright Copyright © 2022-… by Seth Hollingsead. All rights reserved
*/
// Internal imports
import ruleParsing from './ruleParsing.js';
import configurator from '../../executrix/configurator.js';
import loggers from '../../executrix/loggers.js';
// External imports
import hayConst from '@haystacks/constants';
import path from 'path';
const {bas, biz, cfg, msg, sys, wrd} = hayConst;
const baseFileName = path.basename(import.meta.url, path.extname(import.meta.url));
// framework.businessRules.rules.lexicalAnalyzer.
const namespacePrefix = wrd.cframework + bas.cDot + sys.cbusinessRules + bas.cDot + wrd.crules + bas.cDot + baseFileName + bas.cDot;
/**
* @function parseBusinessRuleArgument
* @description Parses a single business rule argument and returns it after cleaning it up or
* doing required operations on it to convert it to valid input for a command as necessary.
* @param {string|array<string|integer|boolean|object>} inputData The value of the argument, could be an array or a string.
* @param {integer} inputMetaData The index of the argument (1, 2, 3, 4).
* @return {string|array<string|integer|boolean|object>} The value of the argument as it should be passed into the business rule call.
* @author Seth Hollingsead
* @date 2022/05/03
*/
async function parseBusinessRuleArgument(inputData, inputMetaData) {
let functionName = parseBusinessRuleArgument.name;
await loggers.consoleLog(namespacePrefix + functionName, msg.cBEGIN_Function);
// console.log(`BEGIN ${namespacePrefix}${functionName} function`);
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataIs + JSON.stringify(inputData));
// console.log(msg.cinputDataIs + JSON.stringify(inputData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
// console.log(msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
let returnData;
if (inputMetaData === 1) {
// Pushing the inputData to the returnData as an array element
await loggers.consoleLog(namespacePrefix + functionName, msg.cPushingArgumentValueToReturnDataAsArrayElement);
// console.log(msg.cPushingArgumentValueToReturnDataAsArrayElement);
returnData = [];
returnData.push(inputData);
} else {
// Calling analyzeArgument for index = 2, consolidatedArgumentMode = false
await loggers.consoleLog(namespacePrefix + functionName, msg.cCallingAnalyzeArgumentIndexIs + inputMetaData);
// console.log(msg.cCallingAnalyzeArgumentIndexIs + inputMetaData);
returnData = await analyzeArgument(inputData, '');
// } else if (inputMetaData === 2 && consolidatedArgumentMode === true) {
// // Calling analyzeArgument for inputMetaData = 2, consolidatedArgumentMode = true
// loggers.consoleLog(namespacePrefix + functionName, msg.cCallingAnalyzeArgumentIndex2ConsolidatedArgumentModeTrue);
// if (inputData.length > 0) {
// returnData = [];
// // inputData.length > 0
// loggers.consoleLog(namespacePrefix + functionName, msg.cargumentValueLengthGreaterThanZero);
// for (let i = 1; i < inputData.length; i++) {
// // Combine all arguments into a single array on the returnData
// returnData.push(inputData[i]);
// } // End-for (let i = 1; i < inputData.length; i++)
// } else {
// // Return the inputData the same as it was passed in.
// loggers.consoleLog(namespacePrefix + functionName, msg.cReturnArgumentValueSameAsItWasPassedIn);
// returnData = inputData;
// }
// } else if (inputMetaData === 3 && consolidatedArgumentMode === false) {
// // Calling analyzeArgument for inputMetaData = 3, consolidatedArgumentMode = false
// loggers.consoleLog(namespacePrefix + functionName, msg.cCallingAnalyzeArgumentIndex3ConsolidatedArgumentModeFalse);
// returnData = analyzeArgument(inputData);
// } else {
// // WARNING: lexical.parseBusinessRuleArgument: invalid combination of inputs to the lexical.parseBusinessRuleArgument function! Pleae adjust inputs and try again.
// console.log(msg.cparseBusinessRuleArgumentMessage1 + msg.cparseBusinessRuleArgumentMessage2);
}
await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
// console.log(msg.creturnDataIs + JSON.stringify(returnData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
// console.log(`END ${namespacePrefix}${functionName} function`);
return returnData;
}
/**
* @function analyzeArgument
* @description Does additional parsing of an individual argument.
* Identifies the case that the argument needs to be treated as an array,
* then the function will clean the array string tags and split the string into an array and return it.
* This function can also identify the case that an argument contains a regular expression that must be formally created,
* using the RegExp constructor, then the RegExp object will be returned as part of the return object.
* @param {string} inputData The argument string that needs additional parsing.
* @param {string} inputMetaData Not used for this business rule.
* @return {string|array<string|integer|boolean|object>} The argument that should be returned and used by the system after all necessary parsing.
* @author Seth Hollingsead
* @date 2022/05/03
*/
async function analyzeArgument(inputData, inputMetaData) {
let functionName = analyzeArgument.name;
await loggers.consoleLog(namespacePrefix + functionName, msg.cBEGIN_Function);
// console.log(`BEGIN ${namespacePrefix}${functionName} function`);
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataIs + JSON.stringify(inputData));
// console.log(msg.cinputDataIs + JSON.stringify(inputData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
// console.log(msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
let returnData;
let argsArrayContainsCharacterRule = [];
argsArrayContainsCharacterRule[0] = biz.cdoesArrayContainCharacter;
let secondaryCommandArgsDelimiter = await configurator.getConfigurationSetting(wrd.csystem, cfg.csecondaryCommandDelimiter);
let tertiaryCommandArgsDelimiter = await configurator.getConfigurationSetting(wrd.csystem, cfg.ctertiaryCommandDelimiter);
let argsArrayContainsOpenBracket = await ruleParsing.processRulesInternal([bas.cOpenBracket, inputData], argsArrayContainsCharacterRule);
let argsArrayContainsCloseBracket = await ruleParsing.processRulesInternal([bas.cCloseBracket, inputData], argsArrayContainsCharacterRule);
if (inputData.includes(secondaryCommandArgsDelimiter) === true ||
inputData.includes(tertiaryCommandArgsDelimiter) === true) {
// Check if there are brackets or no brackets.
await loggers.consoleLog(namespacePrefix + functionName, msg.cCheckIfThereAreBracketsOrNoBrackets);
// console.log(msg.cCheckIfThereAreBracketsOrNoBrackets);
if (argsArrayContainsOpenBracket === false || argsArrayContainsCloseBracket === false) {
// Brackets were not found
await loggers.consoleLog(namespacePrefix + functionName, msg.cBracketsWereNotFound);
// console.log(msg.cBracketsWereNotFound);
// Check if there is a regular expression or not.
await loggers.consoleLog(namespacePrefix + functionName, msg.cCheckIfThereIsRegularExpressionOrNot);
// console.log(msg.cCheckIfThereIsRegularExpressionOrNot);
if (analyzeForRegularExpression(inputData, '') === true) {
// A regular expression was found!
await loggers.consoleLog(namespacePrefix + functionName, msg.cRegularExpressionWasFound);
// console.log(msg.cRegularExpressionWasFound);
returnData = await parseArgumentAsRegularExpression(inputData, '');
} else { // No regular expression, just return the argument as it was passed in, no additional processing required.
// No RegExp found!
await loggers.consoleLog(namespacePrefix + functionName, msg.cNoRegExpFound);
// console.log(msg.cNoRegExpFound);
returnData = inputData;
}
} else {
// There are Brackets, so treat the argument as an array.
// Brackets ARE found!
await loggers.consoleLog(namespacePrefix + functionName, msg.cBracketsAreFound);
// console.log(msg.cBracketsAreFound);
returnData = await parseArgumentAsArray(inputData, '');
}
} else { // The inputData does not contain a secondaryCommandArgsDelimiter
// NO secondary command argument delimiters.
await loggers.consoleLog(namespacePrefix + functionName, msg.cNoSecondaryCommandArgumentDelimiters);
// console.log(msg.cNoSecondaryCommandArgumentDelimiters);
if (argsArrayContainsOpenBracket === false || argsArrayContainsCloseBracket === false) {
// Brackets were not found
await loggers.consoleLog(namespacePrefix + functionName, msg.cBracketsWereNotFound);
// console.log(msg.cBracketsWereNotFound);
// Check if there is a Regular Expression or not.
await loggers.consoleLog(namespacePrefix + functionName, msg.cCheckIfThereIsRegularExpressionOrNot);
// console.log(msg.cCheckIfThereIsRegularExpressionOrNot);
if (analyzeForRegularExpression(inputData, '') === true) {
// A regular expression was found!
await loggers.consoleLog(namespacePrefix + functionName, msg.cRegularExpressionWasFound);
// console.log(msg.cRegularExpressionWasFound);
returnData = await parseArgumentAsRegularExpression(inputData, '');
} else { // No regular expression, just return the argument as it was passed in, no additional processing required.
// NO RegExp found!
await loggers.consoleLog(namespacePrefix + functionName, msg.cNoRegExpFound);
// console.log(msg.cNoRegExpFound);
returnData = inputData;
}
} else {
// There are Brackets, so treat the argument as an array.
// Brackets ARE found!
await loggers.consoleLog(namespacePrefix + functionName, msg.cBracketsAreFound);
// console.log(msg.cBracketsAreFound);
returnData = await parseArgumentAsArray(inputData, '');
}
}
await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
// console.log(msg.creturnDataIs + JSON.stringify(returnData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
// console.log(`BEGIN ${namespacePrefix}{functionName} function`);
return returnData;
}
/**
* @function analyzeForRegularExpression
* @description Analyzes the argument value to determine if it incudes a regular expression or no regular expression.
* @param {string} inputData The business rule argument that should be analyzed to determine if it includes a regular expression or not regular expression.
* @param {string} inputMetaData Not used for this business rule.
* @return {boolean} True or False to indicate if the argument contains a regular expression or no regular expression.
* @author Seth Hollingsead
* @date 2022/05/03
*/
async function analyzeForRegularExpression(inputData, inputMetaData) {
let functionName = analyzeForRegularExpression.name;
await loggers.consoleLog(namespacePrefix + functionName, msg.cBEGIN_Function);
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataIs + JSON.stringify(inputData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
let returnData = false;
let argsArrayContainsCharacterRule = [];
argsArrayContainsCharacterRule[0] = biz.cdoesArrayContainCharacter;
let argsArrayContainsRegEx1 = await ruleParsing.processRulesInternal([wrd.cregEx, [inputData]], argsArrayContainsCharacterRule);
await loggers.consoleLog(namespacePrefix + functionName, msg.cargsArrayContainsRegEx1Is + argsArrayContainsRegEx1);
let argsArrayContainsRegEx2 = await ruleParsing.processRulesInternal([wrd.cRegEx, [inputData]], argsArrayContainsCharacterRule);
await loggers.consoleLog(namespacePrefix + functionName, msg.cargsArrayContainsRegEx2Is + argsArrayContainsRegEx2);
let argsArrayContainsColon = await ruleParsing.processRulesInternal([bas.cColon, [inputData]], argsArrayContainsCharacterRule);
await loggers.consoleLog(namespacePrefix + functionName, msg.cargsArrayContainsColonIs + argsArrayContainsColon);
if ((argsArrayContainsRegEx1 === true || argsArrayContainsRegEx2 === true) && argsArrayContainsColon === true) {
returnData = true;
}
await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
return returnData;
}
/**
* @function parseArgumentAsRegularExpression
* @description Parses the argument as a regular expression and returns a new RegExp object.
* @param {string} inputData The argument string that should be parsed as a RegExp.
* @param {string} inputMetaData Not used for this business rule.
* @return {object} A RegExp object.
* @author Seth Hollingsead
* @date 2022/05/03
*/
async function parseArgumentAsRegularExpression(inputData, inputMetaData) {
let functionName = parseArgumentAsRegularExpression.name;
await loggers.consoleLog(namespacePrefix + functionName, msg.cBEGIN_Function);
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataIs + JSON.stringify(inputData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
let returnData = [];
let regExValue, regExFlags;
let regExArray = inputData.split(bas.cColon);
for (let k = 0; k < regExArray.length; k++) {
if (regExArray[k] === wrd.cregEx || regExArray[k] === wrd.cRegEx) {
k++;
// regular expression is:
await loggers.consoleLog(namespacePrefix + functionName, msg.cregularExpressionIs + regExArray[k]);
regExValue = regExArray[k];
// regExValue is:
await loggers.consoleLog(namespacePrefix + functionName, msg.cregExValueIs + regExValue);
} else if (regExArray[k] === wrd.cflags || regExArray[k] === wrd.cFlags) {
k++;
// regular expression flags are:
await loggers.consoleLog(namespacePrefix + functionName, msg.cregularExpressionFlagsAre + regExArray[k]);
regExFlags = regExArray[k];
// regExFlags is:
await loggers.consoleLog(namespacePrefix + functionName, msg.cregExFlagsIs + regExFlags);
}
} // End-for (let k = 0; k < regExArray.length; k++)
let regularExpression;
if (regExValue !== undefined && regExFlags === undefined) {
regularExpression = new RegExp(regExValue);
} else if (regExValue !== undefined && regExFlags !== undefined) {
regularExpression = new RegExp(regExValue, regExFlags);
} else {
regularExpression = new RegExp(regExValue);
}
returnData = regularExpression;
await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
return returnData;
}
/**
* @function parseArgumentAsArray
* @description Parses teh argument as an array and return the array.
* @param {string} inputData A string that contains an array, we will use the
* secondary command delimiter to split the string into an array.
* @param {string} inputMetaData Not used for this business rule.
* @return {array<string>} An array of strings.
* @author Seth Hollingsead
* @date 2022/05/03
*/
async function parseArgumentAsArray(inputData, inputMetaData) {
let functionName = parseArgumentAsArray.name;
await loggers.consoleLog(namespacePrefix + functionName, msg.cBEGIN_Function);
// console.log(`BEGIN ${namespacePrefix}${functionName} function`);
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataIs + JSON.stringify(inputData));
// console.log(msg.cinputDataIs + JSON.stringify(inputData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
// console.log(msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
let returnData;
let argumentValue = inputData;
let isArray = false;
let secondaryCommandArgsDelimiter = await configurator.getConfigurationSetting(wrd.csystem, cfg.csecondaryCommandDelimiter);
let argsArrayContainsCharacterRule = [];
let removeBracketsFromArgsArrayRule = [];
let utilitiesReplaceCharacterWithCharacterRule = [];
argsArrayContainsCharacterRule[0] = biz.cdoesArrayContainCharacter;
removeBracketsFromArgsArrayRule[0] = biz.cremoveCharacterFromArray;
utilitiesReplaceCharacterWithCharacterRule[0] = biz.cutilitiesReplaceCharacterWithCharacter;
let argsArrayContainsOpenBracket = false;
let argsArrayContainsCloseBracket = false;
if (Array.isArray(argumentValue) === true) {
argsArrayContainsOpenBracket = await ruleParsing.processRulesInternal([bas.cOpenBracket, argumentValue], argsArrayContainsCharacterRule);
argsArrayContainsCloseBracket = await ruleParsing.processRulesInternal([bas.cCloseBracket, argumentValue], argsArrayContainsCharacterRule);
isArray = true;
} else {
argsArrayContainsOpenBracket = argumentValue.includes(bas.cOpenBracket);
argsArrayContainsCloseBracket = argumentValue.includes(bas.cCloseBracket);
isArray = false;
}
if (isArray === false) {
if (argumentValue.includes(secondaryCommandArgsDelimiter) === true) {
// argumentValue contains the delimiter, lets split it!
await loggers.consoleLog(namespacePrefix + functionName, msg.cargumentValueContainsTheDelimiterLetsSplitIt);
// console.log(msg.cargumentValueContainsTheDelimiterLetsSplitIt);
argumentValue = argumentValue.split(secondaryCommandArgsDelimiter);
// Re-evaluate to determine if additional actions are necessary or not.
argsArrayContainsOpenBracket = await ruleParsing.processRulesInternal([bas.cOpenBracket, argumentValue], argsArrayContainsCharacterRule);
argsArrayContainsCloseBracket = await ruleParsing.processRulesInternal([bas.cCloseBracket, argumentValue], argsArrayContainsCharacterRule);
isArray = true;
} // End-if (argumentValue.includes(secondaryCommandArgsDelimiter) === true)
} // End-if (isArray === false)
if (argsArrayContainsOpenBracket === true) {
if (isArray === true) {
argumentValue = await ruleParsing.processRulesInternal([bas.cOpenBracket, argumentValue], removeBracketsFromArgsArrayRule);
} else {
argumentValue = await ruleParsing.processRulesInternal([argumentValue, [bas.cOpenBracket, '']], utilitiesReplaceCharacterWithCharacterRule);
}
// argumentValue after attempting to remove a open bracket from all array elements is:
await loggers.consoleLog(namespacePrefix + functionName, msg.cargumentValueAfterAttemptingToRemoveOpenBracketFromAllArrayElementsIs + JSON.stringify(argumentValue));
// console.log(msg.cargumentValueAfterAttemptingToRemoveOpenBracketFromAllArrayElementsIs + JSON.stringify(argumentValue));
} // End-if (argsArrayContainsOpenBracket === true)
if (argsArrayContainsCloseBracket === true) {
if (isArray === true) {
argumentValue = await ruleParsing.processRulesInternal([bas.cCloseBracket, argumentValue], removeBracketsFromArgsArrayRule);
} else {
argumentValue = await ruleParsing.processRulesInternal([argumentValue, [bas.cCloseBracket, '']], utilitiesReplaceCharacterWithCharacterRule);
}
// argumentValue after attempting to remove a close bracket from all array elements is:
await loggers.consoleLog(namespacePrefix + functionName, msg.cargumentValueAfterAttemptingToRemoveCloseBracketFromAllArrayElementsIs + JSON.stringify(argumentValue));
// console.log(msg.cargumentValueAfterAttemptingToRemoveCloseBracketFromAllArrayElementsIs + JSON.stringify(argumentValue));
} // End-if (argsArrayContainsCloseBracket === true)
// secondaryCommandArgsDelimiter is:
await loggers.consoleLog(namespacePrefix + functionName, msg.csecondaryCommandArgsDelimiterIs + secondaryCommandArgsDelimiter);
// console.log(msg.csecondaryCommandArgsDelimiterIs + secondaryCommandArgsDelimiter);
if (isArray === true) {
if (argumentValue.includes(secondaryCommandArgsDelimiter) === true) {
// argumentValue contains the delimiter, lets split it!
await loggers.consoleLog(namespacePrefix + functionName, msg.cargumentValueContainsTheDelimiterLetsSplitIt);
// console.log(msg.cargumentValueContainsTheDelimiterLetsSplitIt);
argumentValue = argumentValue.split(secondaryCommandArgsDelimiter);
} // End-if (argumentValue.includes(secondaryCommandArgsDelimiter) === true)
returnData = argumentValue;
} else {
returnData = [argumentValue];
}
await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
// console.log(msg.creturnDataIs + JSON.stringify(returnData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
// console.log(`END ${namespacePrefix}${functionName} function`);
return returnData;
}
/**
* @function removeStringLiteralTagsFromArray
* @description Removes all string literal tags from all the argument array elements passed as input to the function.
* @param {array<string>} inputData The argument array that should have the string literal tags removed.
* The string literal tag is the tilde character: "~"
* @param {string} inputMetaData Not used for this business rule.
* @return {array<string>} The same as the input, but just with the string literal tags removed from all array elements.
* @author Seth Hollingsead
* @date 2022/05/03
*/
async function removeStringLiteralTagsFromArray(inputData, inputMetaData) {
let functionName = removeStringLiteralTagsFromArray.name;
await loggers.consoleLog(namespacePrefix + functionName, msg.cBEGIN_Function);
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataIs + JSON.stringify(inputData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cinputMetaDataIs + JSON.stringify(inputMetaData));
let returnData;
returnData = await ruleParsing.processRulesInternal([bas.cTilde, inputData], [biz.cremoveCharacterFromArray]);
await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
return returnData;
}
export default {
parseBusinessRuleArgument,
analyzeArgument,
analyzeForRegularExpression,
parseArgumentAsRegularExpression,
parseArgumentAsArray,
removeStringLiteralTagsFromArray
};