# Source: commandsBlob/commands/integrationTests.js

    /**
     * @file integrationTests.js
     * @module integrationTests
     * @description Contains all of the commands to test various components of the system.
     * @requires module:commandBroker
     * @requires module:ruleBroker
     * @requires module:workflowBroker
     * @requires module:colorizer
     * @requires module:configurator
     * @requires module:loggers
     * @requires module:data
     * @requires module:queue
     * @requires module:stack
     * @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/03/25
     * @copyright Copyright © 2022-… by Seth Hollingsead. All rights reserved
     */

    // Internal imports
    import commandBroker from '../../brokers/commandBroker.js';
    import ruleBroker from '../../brokers/ruleBroker.js';
    import workflowBroker from '../../brokers/workflowBroker.js';
    import colorizer from '../../executrix/colorizer.js';
    import configurator from '../../executrix/configurator.js';
    import loggers from '../../executrix/loggers.js';
    import D from '../../structures/data.js';
    import queue from '../../structures/queue.js';
    import stack from '../../structures/stack.js';
    // External imports
    import hayConst from '@haystacks/constants';
    import path from 'path';

    const {bas, biz, clr, cmd, cfg, msg, num, sys, wrd} = hayConst;
    const baseFileName = path.basename(import.meta.url, path.extname(import.meta.url));
    // framework.commandsBlob.commands.integrationTests.
    const namespacePrefix = wrd.cframework + bas.cDot + sys.ccommandsBlob + bas.cDot + wrd.ccommands + bas.cDot + baseFileName + bas.cDot;

    /**
     * @function validateConstants
     * @description Validates all constants with a 2-phase verification process.
     * @param {array<string>} inputData An array that could possibly include the name of this command,
     * and a list of top-level constants validation data structures to be validated.
     * That way we can parameterize and optimize the validation of the constants specific to the testing needs.
     * Rather than always running the full set of constants validation, as that could take a very long time,
     * and only needs to be done exhaustively when releasing a new instance of the entire Haystacks platform.
     * inputData[1] = validateConstants - This command name
     * inputData[2] = Could be a coma-separated string list of constants validation data to validate.
     * inputData[n] = Could be additional list of constants validation data to validate if the user entered a space-separated list.
     * Options are: Framework,Platform,Application,App,Plugins,Plugin
     * @param {string} inputMetaData Not used for this command.
     * @return {array<boolean,string|integer|boolean|object|array>} An array with a boolean True or False value to
     * indicate if the application should exit or not exit, followed by the command output.
     * @author Seth Hollingsead
     * @date 2022/03/25
     */
    async function validateConstants(inputData, inputMetaData) {
      let functionName = validateConstants.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, false];
      if (await configurator.getConfigurationSetting(wrd.csystem, cfg.cenableConstantsValidation) === true) {
        let pluginNamespace = '';
        let processingPluginResults = false;
        let validationTypesInputArray = []; // Use this to process any inputs the user may have entered.
        let validationTypesConfirmedArray = []; // Use this once we've confirmed valid user entry for inputs given the types of validation that are available.
        let validationTypesConfirmedList = '';
        let validUserEntry = false;
        // Get the array of keys and values for all the constants that need to be validated.
        let validationArray = []; // D[sys.cConstantsValidationData][sys.cConstantsFilePaths]; // This will return an object with all of the key-value pair attributes we need.
        let validationFrameworkArray = D[sys.cConstantsValidationData][wrd.cFramework][sys.cConstantsFilePaths]; // Framework constants paths
        let validationApplicationArray = D[sys.cConstantsValidationData][wrd.cApplication][sys.cConstantsFilePaths]; // Application constants paths
        let validationPluginsMetaArray = D[sys.cConstantsValidationData][wrd.cPlugins]; // Will need to iterate through each of the plugins and capture the plugin constants path for each plugin!
        let phase1FinalResult = true;
        let phase2FinalResult = true;
        let phase1Results = {};
        let phase2Results = {};
        let validConstantsValidationTypes = [wrd.cFramework, wrd.cApplication, wrd.cPlugins];
        let validConstantsValidationUserTypes = [wrd.cFramework, wrd.cPlatform, wrd.cApplication, wrd.cApp, wrd.cPlugins, wrd.cPlugin]

        // validationFrameworkArray is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationFrameworkArrayIs + JSON.stringify(validationFrameworkArray));
        // validationApplicationArray is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationApplicationArrayIs + JSON.stringify(validationApplicationArray));
        // validationPluginsMetaArray is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationPluginsMetaArrayIs + JSON.stringify(validationPluginsMetaArray));

        // Check first to see what, if any options, the user may have entered into this command,
        // that will determine to what extent we do validation.
        if (Array.isArray(inputData) && inputData.length === 2) {
          // User either entered a single data structure to validate, or a coma-separated list.
          // inputData.length is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataLengthIs + inputData.length);
          if (inputData[1].includes(bas.cComa)) {
            validationTypesInputArray = inputData[1].split(bas.cComa);
          } else if (inputData[1].includes(bas.cSemiColon)) {
            validationTypesInputArray = inputData[1].split(bas.cSemiColon);
          } else if (inputData[1].includes(bas.cForwardSlash)) {
            validationTypesInputArray = inputData[1].split(bas.cForwardSlash);
          } else if (inputData[1].includes(bas.cBackSlash)) {
            validationTypesInputArray = inputData[1].split(bas.cBackSlash);
          } else {
            // shift the data1!
            await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData1);
            inputData.shift();
            validationTypesInputArray = inputData;
          }
        } else if (Array.isArray(inputData) && inputData.length > 2) {
          // shift the data2!
          await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData2);
          inputData.shift();
          validationTypesInputArray = inputData;
        }

        // validationTypesInputArray is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesInputArrayIs + JSON.stringify(validationTypesInputArray));

        // This is where we need to process the array of inputs to normalize them to the validation types available by the system.
        // Available types are: Framework,Platform,Application,App,Plugins,Plugin
        if (validationTypesInputArray.length > 0) {
          for (let validationTypesKey in validationTypesInputArray) {
            let userEnteredValidationType = validationTypesInputArray[validationTypesKey];
            if (userEnteredValidationType.toUpperCase().trim() === wrd.cFRAMEWORK || userEnteredValidationType.toUpperCase().trim() === wrd.cPLATFORM) {
              validationTypesConfirmedArray.push(wrd.cFramework);
            } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cAPPLICATION || userEnteredValidationType.toUpperCase().trim() === wrd.cAPP) {
              validationTypesConfirmedArray.push(wrd.cApplication);
            } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGINS || userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGIN) {
              validationTypesConfirmedArray.push(wrd.cPlugins);
            } else if (userEnteredValidationType === '') {
              // Just ignore it!
            } else {
              // WARNING: The specified validation type is not available, please enter a valid type and try again. Type not recognized:
              // Constants validation types are:
              console.log(msg.cWarningUserEnteredConstantsValidationDataTypeMessage01 + userEnteredValidationType);
              console.log(msg.cWarningUserEnteredConstantsValidationDataTypeMessage02 + validConstantsValidationUserTypes.join(bas.cComa + bas.cSpace));
            }
          } // End-for (let validationTypesKey in validationTypesInputArray)

          // validationTypesConfirmedArray is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedArrayIs + JSON.stringify(validationTypesConfirmedArray));

          if (validationTypesConfirmedArray.length > 0) {
            validationTypesConfirmedList = validationTypesConfirmedArray.join(bas.cComa);
            validUserEntry = true;
          } else {
            // WARNING: No valid constants validation types were entered.
            console.log(msg.cWarningUserEnteredConstantsValidationDataTypeMessage03);
            // Constants validation types are:
            console.log(msg.cWarningUserEnteredConstantsValidationDataTypeMessage02 + validConstantsValidationUserTypes.join(bas.cComa + bas.cSpace));
          }
        } else {
          // User didn't enter any parameters at all....just run it all!
          validationTypesConfirmedList = validConstantsValidationTypes.join(bas.cComa);
          validUserEntry = true;
        }

        // validationTypesConfirmedList is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedListIs + validationTypesConfirmedList);

        if (validUserEntry) {
          if (validationTypesConfirmedList.includes(wrd.cFramework)) {
            validationArray = validationFrameworkArray;
          }
          if (validationTypesConfirmedList.includes(wrd.cApplication)) {
            validationArray = Object.assign(validationArray, validationApplicationArray);
          }
          // validationArray before plugin constants validation data merge is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationArrayBeforePluginConstantsValidationDataMergeIs + JSON.stringify(validationArray));
          if (await configurator.getConfigurationSetting(wrd.csystem, cfg.cenablePluginLoader)) {
            if (validationTypesConfirmedList.includes(wrd.cPlugins)) {
              for (let plugin in validationPluginsMetaArray) {
                // plugin is:
                await loggers.consoleLog(namespacePrefix + functionName, msg.cpluginIs + plugin);
                let pluginValidationPathData = validationPluginsMetaArray[plugin][sys.cConstantsFilePaths];
                for (let constantsFilePathName in pluginValidationPathData) {
                  // constantsFilePathName is:
                  await loggers.consoleLog(namespacePrefix + functionName, msg.cconstantsFilePathNamesIs + constantsFilePathName);
                  let constantsFilePathValue = pluginValidationPathData[constantsFilePathName];
                  // constantsFilePathValue is:
                  await loggers.consoleLog(namespacePrefix + functionName, msg.cconstantsFilePathValueIs + constantsFilePathValue);
                  let newPluginConstantValidationName = plugin + bas.cColon + constantsFilePathName;
                  // newPluginConstantValidationName is:
                  await loggers.consoleLog(namespacePrefix + functionName, msg.cnewPluginConstantValidationNameIs + newPluginConstantValidationName);
                  let newPluginConstantValidationPathObject = {[newPluginConstantValidationName]: constantsFilePathValue};
                  validationArray = Object.assign(validationArray, newPluginConstantValidationPathObject);
                  // validationArray after plugin constants validation data merge is:
                  await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationArrayAfterPluginConstantsValidationDataMergeIs + JSON.stringify(validationArray));
                } // End-for (let constantsFilePathNames in pluginValidationPathData)
              } // End-for (let plugin in validationPluginsMetaArray)
            } // End-if (validationTypesConfirmedList.includes(wrd.cPlugins))
          } // End-if (await configurator.getConfigurationSetting(wrd.csystem, cfg.cenablePluginLoader))

          // validationArray is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationArrayIs + JSON.stringify(validationArray));

          // Phase1 Constants Validation
          // BEGIN Phase 1 Constants Validation
          await loggers.consoleLog(namespacePrefix + functionName, msg.cBeginPhase1ConstantsValidation);
          console.log(msg.cBeginPhase1ConstantsValidation);
          // First scan through each file and validate that the constants defined in the constants code file are also contained in the validation file.
          for (let key1 in validationArray) {
            let constantsPath = validationArray[key1];
            phase1Results[key1] = await ruleBroker.processRules([constantsPath, key1], [biz.cvalidateConstantsDataValidation]);
          } // End-for (let key1 in validationArray)
          // END Phase 1 Constants Validation
          await loggers.consoleLog(namespacePrefix + functionName, msg.cEndPhase1ConstantsValidation);
          // phase1Results is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cphase1ResultsIs + JSON.stringify(phase1Results));

          // Phase 2 Constants Validation
          // BEGIN Phase 2 Constants Validation
          await loggers.consoleLog(namespacePrefix + functionName, msg.cBeginPhase2ConstantsValidation);
          console.log(msg.cBeginPhase2ConstantsValidation);
          // Now verify that the values of the constants are what they are expected to be by using the constants validation data to validate.
          for (let key2 in validationArray) {
            phase2Results[key2] = await ruleBroker.processRules([key2, ''], [biz.cvalidateConstantsDataValues]);
          } // End-for (let key2 in validationArray)
          // END Phase 2 Constants Validation
          await loggers.consoleLog(namespacePrefix + functionName, msg.cEndPhase2ConstantsValidation);
          // phase2Results is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cphase2ResultsIs + JSON.stringify(phase2Results));

          for (let key3 in phase1Results) {
            let constantsPhase1ValidationNamespaceParentObject = await ruleBroker.processRules([key3, ''], [biz.cgetConstantsValidationNamespaceParentObject]);
            if (key3.includes(bas.cColon) && key3.toUpperCase().includes(wrd.cPLUGIN)) {
              let pluginPhase1NamespaceArray = key3.split(bas.cColon);
              pluginNamespace = pluginPhase1NamespaceArray[1];
              processingPluginResults = true;
            }
            if (processingPluginResults === false) {
              await loggers.constantsValidationSummaryLog(constantsPhase1ValidationNamespaceParentObject[sys.cConstantsPhase1ValidationMessages][key3], phase1Results[key3]);
            } else if (processingPluginResults === true) {
              await loggers.constantsValidationSummaryLog(constantsPhase1ValidationNamespaceParentObject[sys.cConstantsPhase1ValidationMessages][pluginNamespace], phase1Results[key3]);
            }
            processingPluginResults = false;
            pluginNamespace = '';

            if (phase1Results[key3] === false) {
              phase1FinalResult = false;
            }
          } // End-for (let key3 in phase1ResultsArray)

          for (let key4 in phase2Results) {
            let constantsPhase2ValidationNamespaceParentObject = await ruleBroker.processRules([key4, ''], [biz.cgetConstantsValidationNamespaceParentObject]);
            if (key4.includes(bas.cColon) && key4.toUpperCase().includes(wrd.cPLUGIN)) {
              let pluginPhase2NamespaceArray = key4.split(bas.cColon);
              pluginNamespace = pluginPhase2NamespaceArray[1];
              processingPluginResults = true;
            }
            if (processingPluginResults === false) {
              await loggers.constantsValidationSummaryLog(constantsPhase2ValidationNamespaceParentObject[sys.cConstantsPhase2ValidationMessages][key4], phase2Results[key4]);
            } else if (processingPluginResults === true) {
              await loggers.constantsValidationSummaryLog(constantsPhase2ValidationNamespaceParentObject[sys.cConstantsPhase2ValidationMessages][pluginNamespace], phase2Results[key4]);
            }
            processingPluginResults = false
            pluginNamespace = '';

            if (phase2Results[key4] === false) {
              phase2FinalResult = false;
            }
          } // End-for (let key4 in phase2Results)

          if (phase1FinalResult === true && phase2FinalResult === true) {
            await configurator.setConfigurationSetting(wrd.csystem, cfg.cpassAllConstantsValidation, true);
            returnData[1] = true;
          } else {
            await configurator.setConfigurationSetting(wrd.csystem, cfg.cpassAllConstantsValidation, false);
            returnData[1] = false;
          }
        } else {
          await configurator.setConfigurationSetting(wrd.csystem, cfg.cpassAllConstantsValidation, false);
          returnData[1] = false;
        } // End-if (validUserEntry)
      } else {
        // The enableConstantsValidation flag is disabled. Enable this flag in the configuration settings to activate this command.
        console.log(msg.ccconstantsGeneratorMessage3 + msg.cconstantsGeneratorMessage4);
        await configurator.setConfigurationSetting(wrd.csystem, cfg.cpassAllConstantsValidation, false);
        returnData[1] = false;
      }
      await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
      await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
      return returnData;
    }

    /**
     * @function validateCommandAliases
     * @description Validates all command aliases have no duplicates within a command, but also between commands.
     * @param {array<string>} inputData An array that could possibly include the name of this command,
     * and a list of top-level command aliases data structures to be validated.
     * That way we can parameterize and optimize the validation of the command aliases specific to the testing needs.
     * Rather than always running the full set of command aliases, as that could take a very long time,
     * and only needs to be done exhaustively when releasing a new instance of the entire Haystacks platform.
     * inputData[1] = validateCommandAliases
     * inputData[2] = Could be a coma-separated string list of command alias data types to validate.
     * inputData[n] = Could be additional list of command alias list data to validate if the user entered a space-separated list.
     * Options are: Framework,Platform,Application,App,Plugins,Plugin
     * @param {string} inputMetaData Not used for this command.
     * @return {array<boolean,string|integer|boolean|object|array>} An array with a boolean True or False value to
     * indicate if the application should exit or not exit, followed by the command output.
     * @author Seth Hollingsead
     * @date 2022/03/30
     */
    async function validateCommandAliases(inputData, inputMetaData) {
      let functionName = validateCommandAliases.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, false];
      let validationTypesInputArray = []; // Use this to process any inputs the user may have entered.
      let validationTypesConfirmedArray = []; // Use this once we've confirmed valid user entry for inputs given the types of validation that are available.
      let validationTypesConfirmedList = '';
      let validUserEntry = false;
      let allCommandAliasesToValidate = []
      let passedAllCommandAliasesDuplicateCheck = true;
      let duplicateAliasCount = 0
      let blackColorArray = await colorizer.getNamedColorData(clr.cBlack, [0,0,0]);
      let redColorArray = await colorizer.getNamedColorData(clr.cRed, [255,0,0]);
      let validCommandAliasesValidationTypes = [wrd.cFramework, wrd.cApplication, wrd.cPlugins];
      let validCommandAliasesValidationUserTypes = [wrd.cFramework, wrd.cPlatform, wrd.cApplication, wrd.cApp, wrd.cPlugins, wrd.cPlugin];

      // Process user input(s).
      // Check first to see what, if any options, the user may have entered into this command,
      // that will determine to what extent we do validation.
      if (Array.isArray(inputData) && inputData.length === 2) {
        // User either entered a single data structure to validate, or a coma-separated list.
        // inputData.length is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataLengthIs + inputData.length);
        if (inputData[1].includes(bas.cComa)) {
          validationTypesInputArray = inputData[1].split(bas.cComa);
        } else if (inputData[1].includes(bas.cSemiColon)) {
          validationTypesInputArray = inputData[1].split(bas.cSemiColon);
        } else if (inputData[1].includes(bas.cForwardSlash)) {
          validationTypesInputArray = inputData[1].split(bas.cForwardSlash);
        } else if (inputData[1].includes(bas.cBackSlash)) {
          validationTypesInputArray = inputData[1].split(bas.cBackSlash);
        } else {
          // shift the data1!
          await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData1);
          inputData.shift();
          validationTypesInputArray = inputData;
        }
      } else if (Array.isArray(inputData) && inputData.length > 2) {
        // shift the data2!
        await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData2);
        inputData.shift();
        validationTypesInputArray = inputData;
      }

      // validationTypesInputArray is:
      await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesInputArrayIs + JSON.stringify(validationTypesInputArray));

      // This is where we need to process the array of inputs to normalize them to the validation types available by the system.
      // Available types are: Framework,Platform,Application,App,Plugins,Plugin
      if (validationTypesInputArray.length > 0) {
        for (let validationTypesKey in validationTypesInputArray) {
          let userEnteredValidationType = validationTypesInputArray[validationTypesKey];
          if (userEnteredValidationType.toUpperCase().trim() === wrd.cFRAMEWORK || userEnteredValidationType.toUpperCase().trim() === wrd.cPLATFORM) {
            validationTypesConfirmedArray.push(wrd.cFramework);
          } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cAPPLICATION || userEnteredValidationType.toUpperCase().trim() === wrd.cAPP) {
            validationTypesConfirmedArray.push(wrd.cApplication);
          } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGINS || userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGIN) {
            validationTypesConfirmedArray.push(wrd.cPlugins);
          } else if (userEnteredValidationType === '') {
            // Just ignore it!
          } else {
            // WARNING: The specified validation type is not available, please enter a valid type and try again. Type not recognized:
            console.log(msg.cWarningUserEnteredConstantsValidationDataTypeMessage01 + userEnteredValidationType);
            // Command Aliases validation types are:
            console.log(msg.cWarningUserEnteredCommandAliasesValidationDataTypeMessage02 + validCommandAliasesValidationUserTypes.join(bas.cComa + bas.cSpace));
          }
        } // End-for (let validationTypesKey in validationTypesInputArray)

        // validationTypesConfirmedArray is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedArrayIs + JSON.stringify(validationTypesConfirmedArray));

        if (validationTypesConfirmedArray.length > 0) {
          validationTypesConfirmedList = validationTypesConfirmedArray.join(bas.cComa);
          validUserEntry = true;
        } else {
          // WARNING: No valid command aliases validation types were entered.
          console.log(msg.cWarningUserEnteredCommandAliasesValidationDataTypeMessage03);
          // Command Aliases validation types are:
          console.log(msg.cWarningUserEnteredCommandAliasesValidationDataTypeMessage02 + validCommandAliasesValidationUserTypes.join(bas.cComa + bas.cSpace));
        }
      } else {
        // User didn't enter any parameters at all....just run it all!
        validationTypesConfirmedList = validCommandAliasesValidationTypes.join(bas.cComa);
        validUserEntry = true;
      }

      // validationTypesConfirmedList is:
      await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedListIs + validationTypesConfirmedList);

      if (validUserEntry === true) {
        if (validationTypesConfirmedList.includes(wrd.cFramework)) {
          let frameworkCommandAliases = await commandBroker.getAllCommandAliasData(D[sys.cCommandsAliases][wrd.cFramework]);
          // frameworkCommandAliases is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cframeworkCommandAliasesIs + JSON.stringify(frameworkCommandAliases));
          if (frameworkCommandAliases) {
            allCommandAliasesToValidate = await ruleBroker.processRules([allCommandAliasesToValidate, frameworkCommandAliases], [biz.cobjectDeepMerge]);
          }
        }
        if (validationTypesConfirmedList.includes(wrd.cApplication)) {
          let applicationCommandAliases = await commandBroker.getAllCommandAliasData(D[sys.cCommandsAliases][wrd.cApplication]);
          // applicationCommandAliases is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.capplicationCommandAliasesIs + JSON.stringify(applicationCommandAliases));
          if (applicationCommandAliases) {
            if (Object.keys(allCommandAliasesToValidate).length != 0) {
              allCommandAliasesToValidate = await ruleBroker.processRules([allCommandAliasesToValidate, applicationCommandAliases], [biz.cobjectDeepMerge]);
            } else {
              allCommandAliasesToValidate = applicationCommandAliases;
            }
          }
        }
        // If the system is either loading plugins or plugin data has been loaded by the build-release-deployment system for
        // the purpose of releasing a plugin and running plugin validations as part of the plugin release process.
        if (await configurator.getConfigurationSetting(wrd.csystem, cfg.cenablePluginLoader) ||
        await configurator.getConfigurationSetting(wrd.csystem, sys.cPluginName)) {
          if (validationTypesConfirmedList.includes(wrd.cPlugins)) {
            let pluginCommandAliases = await commandBroker.getAllCommandAliasData(D[sys.cCommandsAliases][wrd.cPlugins]);
            // pluginCommandAliases is:
            await loggers.consoleLog(namespacePrefix + functionName, msg.cpluginCommandAliasesIs + JSON.stringify(pluginCommandAliases));
            if (pluginCommandAliases) {
              if (Object.keys(allCommandAliasesToValidate).length != 0) {
                allCommandAliasesToValidate = await ruleBroker.processRules([allCommandAliasesToValidate, pluginCommandAliases], [biz.cobjectDeepMerge]);
              } else {
                allCommandAliasesToValidate = pluginCommandAliases;
              }
            }
          }
        }
        // Old method of getting all the command aliases data:
        // allCommandAliasesToValidate = await commandBroker.getAllCommandAliasData(D[sys.cCommandsAliases]);

        // allCommandAliasesToValidate is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.callCommandAliasesToValidateIs + JSON.stringify(allCommandAliasesToValidate));

        // Now do the validation from the flattened array of command aliases data.
        // Begin command aliases validation
        console.log(msg.cBeginCommandAliasesValidationMessage);
        for (let key1 in allCommandAliasesToValidate[0]) {
          // key1 is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.ckey1Is + key1);
          let currentCommand = allCommandAliasesToValidate[0][key1];
          // currentCommand is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.ccurrentCommandIs + JSON.stringify(currentCommand));
          console.log(msg.ccurrentCommandIs + currentCommand[wrd.cName]);
          let aliasList = currentCommand[wrd.cAliases];
          // aliasList is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.caliasListIs + aliasList);
          let arrayOfAliases = aliasList.split(bas.cComa);
          for (let j = 0; j < arrayOfAliases.length; j++) {
            // BEGIN j-th loop:
            await loggers.consoleLog(namespacePrefix + functionName, msg.cBEGIN_jthLoop + j);
            let currentAlias = arrayOfAliases[j];
            // currentAlias is:
            await loggers.consoleLog(namespacePrefix + functionName, msg.ccurrentAliasIs + currentAlias);
            duplicateAliasCount = await commandBroker.countMatchingCommandAlias(D[sys.cCommandsAliases], currentAlias);
            if (duplicateAliasCount > 1) {

              // duplicateAliasCount is:
              let duplicateAliasCountMessage = msg.cduplicateAliasCountIs + duplicateAliasCount;
              duplicateAliasCountMessage = await colorizer.colorizeMessageSimple(duplicateAliasCountMessage, blackColorArray, true);
              duplicateAliasCountMessage = await colorizer.colorizeMessageSimple(duplicateAliasCountMessage, redColorArray, false);
              console.log(duplicateAliasCountMessage);
              // duplicate command alias is:
              let duplicateAliasCommandMessage = msg.cduplicateCommandAliasIs + currentAlias;
              duplicateAliasCommandMessage = await colorizer.colorizeMessageSimple(duplicateAliasCommandMessage, blackColorArray, true);
              duplicateAliasCommandMessage = await colorizer.colorizeMessageSimple(duplicateAliasCommandMessage, redColorArray, false);
              console.log(duplicateAliasCommandMessage);

              passedAllCommandAliasesDuplicateCheck = false;
              returnData[1] = false;
              // DO NOT break out of any loops here, the command should scan all command aliases!
            }
            // END j-th loop:
            await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_jthLoop + j);
          } // End-for (let j = 0; j < arrayOfAliases.length; j++)
        } // End-for (let key1 in allCommandAliasesToValidate[0])
        if (passedAllCommandAliasesDuplicateCheck === true) {
          // PASSED: All duplicate command aliases validation tests!
          console.log(msg.cvalidateCommandAliasesMessage1);
          returnData[1] = true;
        } // End-if (passedAllCommandAliasesDuplicateCheck === true)
      } else {
        // No validation was run, YOU SHALL NOT PASS!!!!
        passedAllCommandAliasesDuplicateCheck = false;
        returnData[1] = false;
      } // End-if (validUserEntry === true)
      await configurator.setConfigurationSetting(wrd.csystem, cfg.cpassedAllCommandAliasesDuplicateChecks, passedAllCommandAliasesDuplicateCheck);
      await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
      await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
      return returnData;
    }

    /**
     * @function validateWorkflows
     * @description Validates all the workflows have no duplicates.
     * @param {array<string>} inputData An array that could possibly include the name of this command,
     * and a list of top-level workflows data structures to be validated.
     * That way we can parameterize and optimize the validation of the workflows specific to the testing needs.
     * Rather than always running the full set of workflows, as that could take longer,
     * and only needs to be done exhaustively when releasing a new instance of the entire Haystacks platform.
     * inputData[1] = validateWorkflows
     * inputData[2] = Could be a coma-separated string list of workflow data types to validate.
     * inputData[n] = Could be additional list of workflow data types list to validate if the user entered a space-separated list.
     * Options are: Framework,Platform,Application,App,Plugins,Plugin
     * @param {string} inputMetaData Not used for this command.
     * @return {array<boolean,string|integer|boolean|object|array>} An array with a boolean True or False value to
     * indicate if the application should exit or not exit, followed by the command output.
     * @author Seth Hollingsead
     * @date 2022/06/08
     */
    async function validateWorkflows(inputData, inputMetaData) {
      let functionName = validateWorkflows.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, false];
      let validationTypesInputArray = []; // Use this to process any inputs the user may have entered.
      let validationTypesConfirmedArray = []; // Use this once we've confirmed valid user entry for inputs given the types of validation that are available.
      let validationTypesConfirmedList = '';
      let validUserEntry = false;
      let allWorkflowsToValidate = [];
      let numberOfDuplicatesFound = 0;
      let passedAllWorkflowDuplicateCheck = true;
      let blackColorArray = await colorizer.getNamedColorData(clr.cBlack, [0,0,0]);
      let redColorArray = await colorizer.getNamedColorData(clr.cRed, [255,0,0]);
      let validWorkflowsValidationTypes = [wrd.cFramework, wrd.cApplication, wrd.cPlugins];
      let validWorkflowsValidationUserTypes = [wrd.cFramework, wrd.cPlatform, wrd.cApplication, wrd.cApp, wrd.cPlugins, wrd.cPlugin];

      // Process user input(s).
      // Check first to see what, if any options, the user may have entered into this command,
      // that will determine to what extent we do validation.
      if (Array.isArray(inputData) && inputData.length === 2) {
        // User either entered a single data structure to validate, or a coma-separated list.
        // inputData.length is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataLengthIs + inputData.length);
        if (inputData[1].includes(bas.cComa)) {
          validationTypesInputArray = inputData[1].split(bas.cComa);
        } else if (inputData[1].includes(bas.cSemiColon)) {
          validationTypesInputArray = inputData[1].split(bas.cSemiColon);
        } else if (inputData[1].includes(bas.cForwardSlash)) {
          validationTypesInputArray = inputData[1].split(bas.cForwardSlash);
        } else if (inputData[1].includes(bas.cBackSlash)) {
          validationTypesInputArray = inputData[1].split(bas.cBackSlash);
        } else {
          // shift the data1!
          await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData1);
          inputData.shift();
          validationTypesInputArray = inputData;
        }
      } else if (Array.isArray(inputData) && inputData.length > 2) {
        // shift the data2!
        await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData2);
        inputData.shift();
        validationTypesInputArray = inputData;
      }

      // validationTypesInputArray is:
      await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesInputArrayIs + JSON.stringify(validationTypesInputArray));

      // This is where we need to process the array of inputs to normalize them to the validation types available by the system.
      // Available types are: Framework,Platform,Application,App,Plugins,Plugin
      if (validationTypesInputArray.length > 0) {
        for (let validationTypesKey in validationTypesInputArray) {
          let userEnteredValidationType = validationTypesInputArray[validationTypesKey];
          if (userEnteredValidationType.toUpperCase().trim() === wrd.cFRAMEWORK || userEnteredValidationType.toUpperCase().trim() === wrd.cPLATFORM) {
            validationTypesConfirmedArray.push(wrd.cFramework);
          } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cAPPLICATION || userEnteredValidationType.toUpperCase().trim() === wrd.cAPP) {
            validationTypesConfirmedArray.push(wrd.cApplication);
          } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGINS || userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGIN) {
            validationTypesConfirmedArray.push(wrd.cPlugins);
          } else if (userEnteredValidationType === '') {
            // Just ignore it!
          } else {
            // WARNING: The specified validation type is not available, please enter a valid type and try again. Type not recognized:
            console.log(msg.cWarningUserEnteredConstantsValidationDataTypeMessage01 + userEnteredValidationType);
            // Workflows validation types are:
            console.log(msg.cWarningUserEnteredWorkflowsValidationDataTypeMessage02 + validWorkflowsValidationUserTypes.join(bas.cComa + bas.cSpace));
          }
        } // End-for (let validationTypesKey in validationTypesInputArray)

        // validationTypesConfirmedArray is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedArrayIs + JSON.stringify(validationTypesConfirmedArray));

        if (validationTypesConfirmedArray.length > 0) {
          validationTypesConfirmedList = validationTypesConfirmedArray.join(bas.cComa);
          validUserEntry = true;
        } else {
          // WARNING: No valid workflow validation types were entered.
          console.log(msg.cWarningUserEnteredWorkflowsValidationDataTypeMessage03);
          // Workflows validation types are:
          console.log(msg.cWarningUserEnteredWorkflowsValidationDataTypeMessage02 + validWorkflowsValidationUserTypes.join(bas.cComa + bas.cSpace));
        }
      } else {
        // User didn't enter any parameters at all....just run it all!
        validationTypesConfirmedList = validWorkflowsValidationTypes.join(bas.cComa);
        validUserEntry = true;
      }

      // validationTypesConfirmedList is:
      await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedListIs + validationTypesConfirmedList);

      if (validUserEntry === true) {
        if (validationTypesConfirmedList.includes(wrd.cFramework)) {
          allWorkflowsToValidate = await workflowBroker.getAllWorkflows(D[sys.cCommandWorkflows][wrd.cFramework]);
        }
        // allWorkflowsToValidate is: 1
        await loggers.consoleLog(namespacePrefix + functionName, msg.callWorkflowsToValidate + num.c1 + bas.cSpace + JSON.stringify(allWorkflowsToValidate));
        if (validationTypesConfirmedList.includes(wrd.cApplication)) {
          allWorkflowsToValidate.push(...await workflowBroker.getAllWorkflows(D[sys.cCommandWorkflows][wrd.cApplication]));
        }
        // If the system is either loading plugins or plugin data has been loaded by the build-release-deployment system for
        // the purpose of releasing a plugin and running plugin validations as part of the plugin release process.
        if (await configurator.getConfigurationSetting(wrd.csystem, cfg.cenablePluginLoader) ||
        await configurator.getConfigurationSetting(wrd.csystem, sys.cPluginName)) {
          // NOTE: If the plugin system is enabled, but no plugins are loaded, then the following will be undefined if we don't check to see if it is also undefined.
          // The result would be the call to getAllWorkflows will return the contents of all workflows and they would get duplicate added to the allWorkflowsToValidate array.
          // This will generate many duplicate entries that are not actual duplicates, causing false positive failures.
          if (validationTypesConfirmedList.includes(wrd.cPlugins) && D[sys.cCommandWorkflows][wrd.cPlugins] !== undefined) {
            allWorkflowsToValidate.push(...await workflowBroker.getAllWorkflows(D[sys.cCommandWorkflows][wrd.cPlugins]));
          }
        }
        // Old method of getting all the command aliases data:
        // allWorkflowsToValidate = await workflowBroker.getAllWorkflows(D[sys.cCommandWorkflows]);
        // allWorkflowsToValidate is: 2
        await loggers.consoleLog(namespacePrefix + functionName, msg.callWorkflowsToValidate + num.c2 + bas.cSpace + JSON.stringify(allWorkflowsToValidate));
        // Begin workflows validation
        console.log(msg.cBeginWorkflowsValidationMessage);
        for (let workflowKey in allWorkflowsToValidate) {
          numberOfDuplicatesFound = 0;
          let workflowName = allWorkflowsToValidate[workflowKey];
          // workflowName is:
          await loggers.consoleLog(namespacePrefix + functionName, msg.cworkflowNameIs + workflowName);
          console.log(msg.cworkflowNameIs + workflowName);
          for (const element of allWorkflowsToValidate) {
            let secondTierWorkflowName = element;
            // secondTierWorkflowName is:
            await loggers.consoleLog(namespacePrefix + functionName, msg.csecondTierWorkflowNameIs + secondTierWorkflowName);
            if (workflowName === secondTierWorkflowName) {
              numberOfDuplicatesFound = numberOfDuplicatesFound + 1;
            }
          } // End-for (const element of allWorkflowsToValidate)
          if (numberOfDuplicatesFound > 1) {
            // Duplicate workflow count is:
            let duplicateWorkflowCountMessage = msg.cDuplicateWorkflowCountIs + numberOfDuplicatesFound;
            duplicateWorkflowCountMessage = await colorizer.colorizeMessageSimple(duplicateWorkflowCountMessage, blackColorArray, true);
            duplicateWorkflowCountMessage = await colorizer.colorizeMessageSimple(duplicateWorkflowCountMessage, redColorArray, false);
            console.log(duplicateWorkflowCountMessage);

            // Duplicate workflow name is:
            let duplicateWorkflowMessage = msg.cDuplicateWorkflowNameIs + workflowName;
            duplicateWorkflowMessage = await colorizer.colorizeMessageSimple(duplicateWorkflowMessage, blackColorArray, true);
            duplicateWorkflowMessage = await colorizer.colorizeMessageSimple(duplicateWorkflowMessage, redColorArray, false);
            console.log(duplicateWorkflowMessage);

            passedAllWorkflowDuplicateCheck = false;
            returnData[1] = false;
          } // End-if (numberOfDuplicatesFound > 1)
        } // End-for (let workflowName in allWorkflowsToValidate)
      } else {
        // No validation was run, YOU SHALL NOT PASS!!!!
        passedAllWorkflowDuplicateCheck = false;
        returnData[1] = false;
      } // End-if (validUserEntry === true)

      if (passedAllWorkflowDuplicateCheck === true) {
        // PASSED: All duplicate workflow validation tests!
        console.log(msg.cvalidateWorkflowsMessage01);
        returnData[1] = true;
      } // End-if (passedAllWorkflowDuplicateCheck === true)
      await configurator.setConfigurationSetting(wrd.csystem, cfg.cpassedAllWorkflowDuplicateChecks, passedAllWorkflowDuplicateCheck);
      await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
      await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
      return returnData;
    }

    /**
     * @function runAllValidations
     * @description Runs all validations together, constants validation, command alias validation and workflow validation.
     * @param {string} inputData An array that could possibly include the name of this command,
     * and a list of top-level data structures that all validations should be run against.
     * Rather than always running the full set of validations against everything, as that could take longer,
     * and only needs to be done exhaustively when releasing a new instance of the entire Haystacks platform.
     * inputData[1] = runAllValidations
     * inputData[2] = Could be a coma-separated string list of data types to run all validation with.
     * inputData[n] = Could be additional list of workflow data types list to validate if the user entered a space-separated list.
     * Options are: Framework,Platform,Application,App,Plugins,Plugin
     * @param {string} inputMetaData Not used for this command.
     * @return {array<boolean,string|integer|boolean|object|array>} An array with a boolean True or False value to
     * indicate if the application should exit or not exit, followed by the command output.
     * @author Seth Hollingsead
     * @date 2023/02/20
     */
    async function runAllValidations(inputData, inputMetaData) {
      let functionName = runAllValidations.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, false];
      let validationTypesInputArray = []; // Use this to process any inputs the user may have entered.
      let validationTypesConfirmedArray = []; // Use this once we've confirmed valid user entry for inputs given the types of validation that are available.
      let validationTypesConfirmedList = '';
      let validUserEntry = false;
      let validValidationTypes = [wrd.cFramework, wrd.cApplication, wrd.cPlugins];
      let validValidationUserTypes = [wrd.cFramework, wrd.cPlatform, wrd.cApplication, wrd.cApp, wrd.cPlugins, wrd.cPlugin];

      // Process user input(s).
      // Check first to see what, if any options, the user may have entered nto this command,
      // that will determine to what extent we do validation.
      if (Array.isArray(inputData) && inputData.length === 2) {
        // User either entered a single data structure to validate, or a coma-separated list.
        // inputData.length is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cinputDataLengthIs + inputData.length);
        if (inputData[1].includes(bas.cComa)) {
          validationTypesInputArray = inputData[1].split(bas.cComa);
        } else if (inputData[1].includes(bas.cSemiColon)) {
          validationTypesInputArray = inputData[1].split(bas.cSemiColon);
        } else if (inputData[1].includes(bas.cForwardSlash)) {
          validationTypesInputArray = inputData[1].split(bas.cForwardSlash);
        } else if (inputData[1].includes(bas.cBackSlash)) {
          validationTypesInputArray = inputData[1].split(bas.cForwardSlash);
        } else {
          // shift the data1!
          await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData1);
          inputData.shift();
          validationTypesInputArray = inputData;
        }
      } else if (Array.isArray(inputData) && inputData.length > 2) {
        // shift the data2!
        await loggers.consoleLog(namespacePrefix + functionName, msg.cshiftData2);
        inputData.shift();
        validationTypesInputArray = inputData;
      }

      // validationTypesInputArray is:
      await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesInputArrayIs + JSON.stringify(validationTypesInputArray));

      // This is where we need to process the array of inputs to normalize them to the validation types available by the system.
      // Available types are: Framework,Platform,Application,App,Plugins,Plugin
      if (validationTypesInputArray.length > 0) {
        for (let validationTypesKey in validationTypesInputArray) {
          let userEnteredValidationType = validationTypesInputArray[validationTypesKey];
          if (userEnteredValidationType.toUpperCase().trim() === wrd.cFRAMEWORK || userEnteredValidationType.toUpperCase().trim() === wrd.cPLATFORM) {
            validationTypesConfirmedArray.push(wrd.cFramework);
          } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cAPPLICATION || userEnteredValidationType.toUpperCase().trim() === wrd.cAPP) {
            validationTypesConfirmedArray.push(wrd.cApplication);
          } else if (userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGINS || userEnteredValidationType.toUpperCase().trim() === wrd.cPLUGIN) {
            validationTypesConfirmedArray.push(wrd.cPlugins);
          } else if (userEnteredValidationType === '') {
            // Just ignore it
          } else {
            // WARNING: The specified validation type is not available, please enter a valid type and try again. Type not recognized:
            console.log(msg.cWarningUserEnteredConstantsValidationDataTypeMessage01 + userEnteredValidationType);
            // Validation types are:
            console.log(msg.cWarningUserEnteredValidationDateTypeMessage02 + validValidationUserTypes.join(bas.cComa + bas.cSpace));
          }
        } // End-for (let validationTypesKey in validationTypesInputArray)

        // validationTypesConfirmedArray is:
        await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedArrayIs + JSON.stringify(validationTypesConfirmedArray));

        if (validationTypesConfirmedArray.length > 0) {
          validationTypesConfirmedList = validationTypesConfirmedArray.join(bas.cComa);
          validUserEntry = true;
        } else {
          // WARNING: No valid validation types were entered.
          console.log(msg.cWarningUserEnteredValidationDataTypeMessage03);
          // All validation types are:
          console.log(msg.cWarningUserEnteredValidationDataTypeMessage02 + validValidationUserTypes.join(bas.cComa + bas.cSpace));
        }
      } else {
        // User didn't enter any parameters at all....just run it all!
        validationTypesConfirmedList = validValidationTypes.join(bas.cComa);
        validationTypesConfirmedArray = validValidationTypes
        validUserEntry = true;
      }

      // vaidationTypesConfirmedList is:
      await loggers.consoleLog(namespacePrefix + functionName, msg.cvalidationTypesConfirmedListIs + validationTypesConfirmedList);

      if (validUserEntry === true) {
        let constantsValidationCommandToQueue = cmd.cvalidateConstants + bas.cSpace + validationTypesConfirmedList;
        let commandAliasesValidationCommandToQueue = cmd.cvalidateCommandAliases + bas.cSpace + validationTypesConfirmedList;
        let workflowsValidationCommandToQueue = cmd.cvalidateWorkflows + bas.cSpace + validationTypesConfirmedList;
        if (await configurator.getConfigurationSetting(wrd.csystem, cfg.clogAllCommands) === true) {
          await stack.push(sys.cSystemCommandLog, constantsValidationCommandToQueue);
          await stack.push(sys.cSystemCommandLog, commandAliasesValidationCommandToQueue);
          await stack.push(sys.cSystemCommandLog, workflowsValidationCommandToQueue);
        }
        // Now add them to the front of the command queue in reverse order, so they will get executed next.
        // Running all validations
        console.log(msg.cRunningAllValidationsMessage);
        await queue.enqueueFront(sys.cCommandQueue, workflowsValidationCommandToQueue);
        await queue.enqueueFront(sys.cCommandQueue, commandAliasesValidationCommandToQueue);
        await queue.enqueueFront(sys.cCommandQueue, constantsValidationCommandToQueue);
      }
      await loggers.consoleLog(namespacePrefix + functionName, msg.creturnDataIs + JSON.stringify(returnData));
      await loggers.consoleLog(namespacePrefix + functionName, msg.cEND_Function);
      return returnData;
    }

    export default {
      validateConstants,
      validateCommandAliases,
      validateWorkflows,
      runAllValidations
    }