UNPKG

@haystacks/async

Version:

A framework to build any number or any kind of native application or automation solution.

583 lines (563 loc) 31.4 kB
/** * @file dataArrayParsing.js * @module dataArrayParsing * @description Contains all system defined business rules for parsing arrays specific to data. * @requires module:dataBroker * @requires module:ruleParsing * @requires module:loggers * @requires module:data * @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/04/26 * @copyright Copyright © 2022-… by Seth Hollingsead. All rights reserved */ // Internal imports import dataBroker from '../../../brokers/dataBroker.js'; import ruleParsing from '../ruleParsing.js'; import loggers from '../../../executrix/loggers.js'; import D from '../../../structures/data.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.arrayParsing.dataArrayParsing. const namespacePrefix = wrd.cframework + bas.cDot + sys.cbusinessRules + bas.cDot + wrd.crules + bas.cDot + wrd.carray + wrd.cParsing + bas.cDot + baseFileName + bas.cDot; /** * @function arraysAreEqual * @description Determines if a set of arrays are equal or not. * @param {array<string|integer|boolean|float|object>} inputData The first array that should be checked for equality. * @param {array<string|integer|boolean|float|object>} inputMetaData The second array that should be checked for equality. * @return {boolean} True or False to indicate if the arrays are equal or not equal. * @author Seth Hollingsead * @date 2022/01/20 * @NOTE: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript */ async function arraysAreEqual(inputData, inputMetaData) { let functionName = arraysAreEqual.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; if (inputData && inputMetaData) { if (inputData === inputMetaData) { returnData = true; } if (inputData === null || inputMetaData === null) { returnData = false; } if (inputData.length != inputMetaData.length) { returnData = false; } } // End-if (inputData && inputMetaData) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function storeData * @description Stores some data using the DataStorage data hie on the D data store. * @param {string} inputData The context name that the data should be stored with. * @param {string|integer|boolean|object|array} inputMetaData The data that should be stored. * @return {void} * @author Seth Hollingsead * @date 2022/01/20 */ async function storeData(inputData, inputMetaData) { let functionName = arraysAreEqual.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; if (inputData && inputMetaData) { await dataBroker.storeData(inputData, inputMetaData); returnData = true; } // End-if (inputData && inputMetaData) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function getStoredData * @description Gets the named data stored in the D data structure in the DataStorage data hive. * @param {string} inputData The name of the sub-data hive that should contain the stored data we are looking for. * @param {string} inputMetaData Not used for this business rule. * @return {object} The data that was stored in the sub-data hive under the DataStorage data hive of the D data structure. * @author Seth Hollingsead * @date 2022/01/20 */ async function getStoredData(inputData, inputMetaData) { let functionName = getStoredData.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; if (inputData) { returnData = await dataBroker.getData(inputData); } await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function isObjectEmpty * @description Determines if a JSON object is empty or not. * @param {object} inputData The object that should be checked for emptiness. * @param {string} inputMetaData Not used for this business rule. * @return {boolean} True or False to indicate if the object is empty or not empty. * @author Seth Hollingsead * @date 2022/01/21 */ async function isObjectEmpty(inputData, inputMetaData) { let functionName = isObjectEmpty.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 + inputMetaData); let returnData = true; if (inputData) { for (let key in inputData) { if (Object.prototype.hasOwnProperty.call(inputData, key)) { returnData = false; // It may have a value, but is that value === null, if it is, reset back to true. if (inputData[key] === null) { returnData = true; } } // End-if (inputData.hasOwnProperty(key)) } // End-for (let key in inputData) } // End-if (inputData) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function isArrayEmpty * @description Determines if a JSON array is empty or not. * @param {array<string|integer|boolean|float|object>} inputData The array that should be checked for emptiness. * @param {string} inputMetaData Not used for this business rule. * @return {boolean} True or False to indicate if the array is empty or not empty. * @author Seth Hollingsead * @date 2022/01/21 */ async function isArrayEmpty(inputData, inputMetaData) { let functionName = isArrayEmpty.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 = true; if (inputData) { returnData = await !Object.keys(inputData).length; } await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function isObject * @description Determines if an object is a JSON object or not. * @param {object|array<string|integer|boolean|float|object>} inputData The object that should be tested to see if it is a JSON object or not. * @param {string} inputMetaData Not used for this business rule. * @return {boolean} True or False to indicate if the input object is an array or not. * @author Seth Hollingsead * @date 2022/01/21 */ async function isObject(inputData, inputMetaData) { let functionName = isObject.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 + inputMetaData); let returnData = false; if (inputData) { if (typeof inputData === wrd.cobject) { returnData = true; } } // End-if (inputData) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function isArray * @description Determines if an object is an array or not. * @param {object|array<string|integer|boolean|float|object>} inputData The object that * should be tested to see if it is an array or not. * @param {string} inputMetaData Not used for this business rule. * @return {boolean} True or False to indicate if the input object is an array or not. * @author Seth Hollingsead * @date 2022/01/21 */ async function isArray(inputData, inputMetaData) { let functionName = isArray.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 + inputMetaData); let returnData = false; if (inputData) { returnData = await Array.isArray(inputData); } await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function isArrayOrObject * @description Determines if an input object is either an array or a JSON object. * @param {object|array<string|integer|boolean|float|object>} inputData The object that * should be tested to see if it is either an array or a JSON object or not. * @param {string} inputMetaData Not used for this business rule. * @return {boolean} True or False to indicate if the input object is either an array or a JSON object. * @author Seth Hollingsead * @date 2022/01/21 */ async function isArrayOrObject(inputData, inputMetaData) { let functionName = isArrayOrObject.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 + inputMetaData); let returnData = false; if (inputData) { if (await isObject(inputData, '') === true || await isArray(inputData, '') === true) { returnData = true; } } // End-if (inputData) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function isNonZeroLengthArray * @description Determines if an object is an array of length greater than or equal to one or not. * @param {object|array<string|integer|boolean|float|object>} inputData The object/array that * should be tested to see if it is an array of length greater than or equal to 1 or not. * @param {string} inputMetaData Not used for this business rule. * @return {boolean} True or False to indicate if the input object is an array of length greater than equal to zero or not. * @author Seth Hollingsead * @date 2022/01/21 */ async function isNonZeroLengthArray(inputData, inputMetaData) { let functionName = isNonZeroLengthArray.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 + inputMetaData); let returnData = false; if (inputData) { if (await isArray(inputData, '') === true && inputData.length >= 1) { returnData = true; } } // End-if (inputData) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function arrayDeepClone * @description Clones an array by using JSON.stringify & JSON.parse. * Almost all other methods of cloning an array will actually clone by reference which essentially just clones the pointer to the array. * @NOTE: https://www.freecodecamp.org/news/how-to-clone-an-array-in-javascript-1d3183468f6a/ * @param {array<string|integer|boolean|float|object>} inputData The array that should be deeply cloned. * @param {string} inputMetaData Not used for this business rule. * @return {array<string|integer|boolean|float|object>} The new array object after being cloned deeply. * @author Seth Hollingsead * @date 2022/01/21 */ async function arrayDeepClone(inputData, inputMetaData) { let functionName = arrayDeepClone.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; if (inputData && await isArray(inputData, '') === true && await isArrayEmpty(inputData, '') === false) { returnData = await JSON.parse(await JSON.stringify(inputData)); } await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData)); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function objectDeepClone * @description Recursively walks through all levels of a JSON object and deeply clones all of its contents including function objects. * @param {object} inputData The JSON object that should be deeply cloned. * @param {string} inputMetaData Not used for this business rule. * @return {object} A clone of the original input JSON object. * @author Seth Hollingsead * @date 2023/02/15 * @NOTE This function was generated with the help of ChatGPT. */ async function objectDeepClone(inputData, inputMetaData) { let functionName = objectDeepClone.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 fastExit = false; if (typeof inputData !== wrd.cobject || inputData === null) { if (typeof inputData === wrd.cstring || typeof inputData === wrd.cnumber || typeof inputData === wrd.cboolean) { returnData = inputData; fastExit = true; // fast exit enabled await loggers.consoleLog(namespacePrefix + functionName, msg.cfastExitEnabled); } else { // Invalid input object. Expected a valid JSON object. Object type is: throw new Error(msg.cErrorObjectDeepCloneMessage01 + typeof inputData); } } if (fastExit === false) { if (Array.isArray(inputData)) { if (typeof inputData[1] === wrd.cobject) { // array cloning object await loggers.consoleLog(namespacePrefix + functionName, msg.carrayCloningObject); let cloneArray = []; for (let item in inputData) { cloneArray[item] = await objectDeepClone(inputData[item], ''); } returnData = cloneArray; } else { // array deep clone string await loggers.consoleLog(namespacePrefix + functionName, msg.carrayDeepCloneString); returnData = await arrayDeepClone(inputData, ''); } } else { // object deep cloning await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepCloning); returnData = {}; for (let key in inputData) { if (Object.prototype.hasOwnProperty.call(inputData, key)) { if (typeof inputData[key] === wrd.cobject && inputData[key] !== null) { returnData[key] = await objectDeepClone(inputData[key], ''); } else if (typeof inputData[key] === wrd.cfunction) { // Solution from: https://stackoverflow.com/questions/1833588/javascript-clone-a-function // const newFunction = inputData.bind(this); // Shallow copy any function properties if any. // returnData[key] = Object.assign(newFunction, inputData); returnData[key] = inputData[key]; } else { returnData[key] = inputData[key]; } } // End-if (inputData.hasOwnProperty(key)) } // End-for (let key in inpuData) } } await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData)); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function objectDeepMerge * @description Recursively deeply merges two objects that may or may not contains nested arrays. * @param {object} inputData The target data to be merged with. * @param {object} inputMetaData The data that should be merged. * @return {object} The merged data after the merge is complete. * @author Pery Mimon * @date 2020/04/23 * @reference: https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge */ async function objectDeepMerge(inputData, inputMetaData) { let functionName = objectDeepMerge.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; if (typeof inputData !== wrd.cobject || typeof inputMetaData !== wrd.cobject) { // inputData or inputMetaData or both ain't objets, merging doesn't make sense. returnData = false; } else { for (let property in inputMetaData) { if (!Object.prototype.hasOwnProperty.call(inputMetaData, property)) { continue; // Take into consideration only object's own properties. } // property is: await loggers.consoleLog(namespacePrefix + functionName, msg.cpropertyIs + JSON.stringify(property)); if (property in inputData) { // property is in inputData await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage01); // inputData[property] is: await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataPropertyIs + JSON.stringify(inputData[property])); // Handling merging of two properties with equal names. if (typeof inputData[property] !== wrd.cobject) { // inputData[property] is not an object! // Assign it directly. await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage02 + bas.cSpace + msg.cobjectDeepMergeMessage03); inputData[property] = inputMetaData[property]; } else { // inputData[property] is an object! await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage04); // inputMetaData[property] is: await loggers.consoleLog(namespacePrefix + functionName, msg.cinputMetaDataPropertyIs + JSON.stringify(inputMetaData[property])); if (typeof inputMetaData[property] !== wrd.cobject) { // inputMetaData[property] is not an object, // Assign it directly. await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage05 + msg.cobjectDeepMergeMessage03); inputData[property] = inputMetaData[property]; } else { // inputMetaData[property] is an object. await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage06); if (inputData[property].concat && inputMetaData[property].concat) { // Are the arrays length 1 or greater? if (inputData[property].length === 1 && inputMetaData[property].length === 1) { // Array lengths are the same at this level. await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage07); // We should deeply merge the contents of the arrays. inputData[property] = await objectDeepMerge(inputData[property], inputMetaData[property]); } else { // Two arrays get concatenated. await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage08); inputData[property] = inputData[property].concat(inputMetaData[property]); // AFTER concatenating two arrays: inputData[property] is: await loggers.consoleLog(namespacePrefix + functionName, msg.cAfterConcatenating2ArraysInputDataPropertyIs + JSON.stringify(inputData[property])); } } else { // Two objects get merged recursively. await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage09); inputData[property] = await objectDeepMerge(inputData[property], inputMetaData[property]); // AFTER recursive merge: inputData[property] is: await loggers.consoleLog(namespacePrefix + functionName, msg.cAfterRecursiveMergeInputDataPropertyIs + JSON.stringify(inputData[property])); } } } } else { // property is not in inputData, // so add it directly. await loggers.consoleLog(namespacePrefix + functionName, msg.cobjectDeepMergeMessage10 + msg.cobjectDeepMergeMessage11); inputData[property] = inputMetaData[property]; } } // End-for (let property in inputMetaData) returnData = inputData; } // NOTE: This implementation from Vincent on the reference: Dated: 2019/11/19 // https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge // Did not work: // inputData was: {"CommandWorkflows":{"businessRules":[{"arrayParsing":[{"characterArrayParsing":[{"Workflow":[{"$":{"Name":"doesArrayContainCharacter","Value":"cmdgen bizRul,doesArrayContainCharacter,$,[the|answer|to|life|the|universe|and|everything|is|$42] 4"}},{"$":{"Name":"removeCharacterFromArray","Value":"cmdgen bizRul,removeCharacterFromArray,$,[the|answer|to|life|the|universe|and|everything|is|$42] 4"}},{"$":{"Name":"replaceCharacterAtIndex","Value":"cmdgen bizRul,replaceCharacterAtIndex,aggregateNumericalDifferenceBetweenTwoStrings,[10|$] 4"}},{"$":{"Name":"characterArrayParsing","Value":"cmdSeq wrkflo,doesArrayContainCharacter wrkflo,removeCharacterFromArray wrkflo,replaceCharacterAtIndex"}}]}]}]}]}} // // inputMetaData was: {"CommandWorkflows":{"businessRules":[{"arrayParsing":[{"pathArrayParsing":[{"Workflow":[{"$":{"Name":"doesArrayContainFilename","Value":"cmdgen bizRul,doesArrayContainFilename,[20200603-142834-763_0.3.2_haystacks.zip|20200603-144529-749_0.3.3_haystacks.zip|20200604-133509-704_0.4.0_haystacks.zip|20200604-133546-749_0.4.1_haystacks.zip|20200604-160655-262_0.4.2_haystacks.zip|20200604-161819-191_0.4.3_haystacks.zip|20200604-173727-348_0.4.4_haystacks.zip|20200604-193551-258_0.5.0_haystacks.zip|20200604-193629-853_0.5.1_haystacks.zip|20200605-083055-193_0.5.2_haystacks.zip|20200610-170634-141_0.5.3_haystacks.zip|20200615-162658-576_0.5.4_haystacks.zip|20200617-150430-416_0.5.5_haystacks.zip|20200618-134424-575_0.5.6_haystacks.zip],20200604-193551-258_0.5.0_haystacks.zip 4"}},{"$":{"Name":"pathArrayParsing","Value":"cmdSeq wrkflo,doesArrayContainFilename"}}]}]}]}]}} // // returnData was: {"CommandWorkflows":{"businessRules":[{"arrayParsing":[{"characterArrayParsing":[{"Workflow":[{"$":{"Name":"doesArrayContainCharacter","Value":"cmdgen bizRul,doesArrayContainCharacter,$,[the|answer|to|life|the|universe|and|everything|is|$42] 4"}},{"$":{"Name":"removeCharacterFromArray","Value":"cmdgen bizRul,removeCharacterFromArray,$,[the|answer|to|life|the|universe|and|everything|is|$42] 4"}},{"$":{"Name":"replaceCharacterAtIndex","Value":"cmdgen bizRul,replaceCharacterAtIndex,aggregateNumericalDifferenceBetweenTwoStrings,[10|$] 4"}},{"$":{"Name":"characterArrayParsing","Value":"cmdSeq wrkflo,doesArrayContainCharacter wrkflo,removeCharacterFromArray wrkflo,replaceCharacterAtIndex"}}]}]}]}]}} // // Clearly it didn't do it's job!! // ************************************************** // if (inputData && inputMetaData) { // for (let key of Object.entries(inputMetaData)) { // if (!inputData.hasOwnProperty(key) || typeof inputMetaData[key] !== wrd.cobject) { inputData[key] = inputMetaData[key]; } // else if (inputData[key] instanceof Array && inputMetaData[key] instanceof Array) {inputData[key] = inputData[key].concat(inputMetaData[key]); } // else { objectDeepMerge(inputData[key], inputMetaData[key]); } // } // End-for (key of Object.keys(inputMetaData)) // returnData = inputData; // } // End-if (inputData && inputMetaData) // *************************************************** // NOTE: This implementation from Pery Mimon on the reference: Dated 2020/04/23 // https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge // Did not work: // Throws an error: inputMetaData is not iterable // ************************************************** // if (inputData && inputMetaData) { // for (source of inputMetaData) { // for (let k in source) { // let vs = source[k], vt = inputData[k]; // if (Object(vs) === vs && Object(vt) === vt) { // inputData[k] = objectDeepMerge(vt, vs); // continue; // } // inputData[k] = source[k]; // } // End-for (let k in source) // } // End-for (source of inputMetaData) // returnData = inputData; // } // End-if (inputData && inputMetaData) // ************************************************** await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData)); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function getNamespacedDataObject * @description Navigates the D data structure JSON data object tree to find the namespace of data settings. * @param {array<string>} inputData The path in the data JSON object where the * setting should be returned. * @param {boolean} inputMetaData True or False value to indicate if * the path elements should be created or not it they are not found. * @return {object|boolean} The object found at the specified namespace address in the data object, * or False if nothing was found. * @author Seth Hollingsead * @date 2022/05/10 * @NOTE This function contains duplicate code from the configurator.js, * however, we cannot call this business rule from the configurator because * the configurator gets called before the business rules are bootstrapped. * And there are protections in place, but rules cannot be called if they are not yet bootstrapped. * So therefore this code will need to remain duplicated. * And by the time this gets called everything should be effectively bootstrapped. * Therefore we can use the loggers here. */ async function getNamespacedDataObject(inputData, inputMetaData) { let functionName = getNamespacedDataObject.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 + inputMetaData); let returnData = false; let processingValidData = false; let namespaceDataObject = D; if (inputData && inputData.length > 0) { for (const element of inputData) { processingValidData = true; if (!namespaceDataObject[element] && inputMetaData === true) { // It doesn't exist yet, so lets make it. namespaceDataObject[element] = {}; } else if (!namespaceDataObject[element]) { console.log(msg.cnamespaceDataObjectPathNotFound + JSON.stringify(element)); processingValidData = false; break; } namespaceDataObject = namespaceDataObject[element]; } // End-for (const element of inputData) if (processingValidData === true) { returnData = namespaceDataObject; } } // End-if (inputData && inputData.length > 0) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } /** * @function setNamespacedDataObject * @description Persists a change to the data structure. * @param {array<string>} inputData The path in the data JSON object where the * setting should be persisted. * @param {object} inputMetaData The data to be persisted on the D-data structure. * @return {boolean} True or False to indicate if the data was persisted correctly or not. * @author Seth Hollingsead * @date 2022/05/11 */ async function setNamespacedDataObject(inputData, inputMetaData) { let functionName = setNamespacedDataObject.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 namespaceDataObject = D; if (inputData && inputData.length > 0) { for (let i = 0; i < inputData.length - 1; i++) { namespaceDataObject = namespaceDataObject[inputData[i]]; if (i === inputData.length - 2) { // namespaceDataObject is: await loggers.consoleLog(namespacePrefix + functionName, msg.cnamespaceDataObjectIs + JSON.stringify(namespaceDataObject)); let fullyQualifiedKey = await namespaceDataObject.join(bas.cDot); if (await ruleParsing.processRulesInternal([[namespaceDataObject, cfg.cdebugSetting], await ruleParsing.getRule(biz.cascertainMatchingElements)], [biz.cdoesArrayContainValue]) === true) { namespaceDataObject[fullyQualifiedKey] = inputMetaData; } else { namespaceDataObject[inputData[i + 1]] = inputMetaData; } returnData = true; } // End-if (i === inputData.length - 2) } // End-for (let i = 0; i < inputData.length - 1; i++) } // End-if (inputData && inputData.length > 0) await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + returnData); await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function); return returnData; } export default { arraysAreEqual, storeData, getStoredData, isObjectEmpty, isArrayEmpty, isObject, isArray, isArrayOrObject, isNonZeroLengthArray, arrayDeepClone, objectDeepClone, objectDeepMerge, getNamespacedDataObject, setNamespacedDataObject };