haystacks-tt
Version:
A simple Haystacks-async based command line typing tutor program for Windows, Mac & Linux.
218 lines (209 loc) • 10.8 kB
JavaScript
/* eslint-disable no-undef */
/**
* @file haystacks-tt.js
* @module haystacks-tt
* @description This is the main init for the haystacks-tt application.
* It contains just enough of the main program loop and basic argument parsing to function as an interactive typing tutor application.
* @requires module:accountBroker
* @requires module:tutoringRules
* @requires module:tutoringCommands
* @requires module:application.command.constants
* @requires module:application.configuration.constants
* @requires module:application.constants
* @requires module:application.function.constants
* @requires module:application.message.constants
* @requires module:allApplicationConstantsValidationMetadata
* @requires {@link https://www.npmjs.com/package/@haystacks/async|@haystacks/async}
* @requires {@link https://www.npmjs.com/package/@haystacks/constants|@haystacks/constants}
* @requires {@link https://www.npmjs.com/package/url|url}
* @requires {@link https://www.npmjs.com/package/dotenv|dotenv}
* @requires {@link https://www.npmjs.com/package/path|path}
* @author Seth Hollingsead
* @date 2023/02/23
* @copyright Copyright © 2023-… by Seth Hollingsead. All rights reserved
*/
// Internal imports
import accountBroker from './brokers/accountBroker.js';
import tutoringRules from './businessRules/tutoringRulesLibrary.js';
import tutoringCommands from './commands/tutoringCommandsLibrary.js';
import * as app_cmd from './constants/application.command.constants.js';
import * as app_cfg from './constants/application.configuration.constants.js';
import * as apc from './constants/application.constants.js';
import * as app_msg from './constants/application.message.constants.js';
import * as app_sys from './constants/application.system.constants.js';
import allAppCV from './resources/constantsValidation/allApplicationConstantsValidationMetadata.js';
// External imports
import haystacks from '@haystacks/async';
import hayConst from '@haystacks/constants';
import url from 'url';
import dotenv from 'dotenv';
import path from 'path';
const {bas, msg, sys, wrd} = hayConst;
let rootPath = '';
let baseFileName = path.basename(import.meta.url, path.extname(import.meta.url));
// application.haystacks-tt.
let namespacePrefix = wrd.capplication + bas.cDot + baseFileName + bas.cDot;
// eslint-disable-next-line no-undef
global.appRoot = path.resolve(process.cwd());
dotenv.config();
// eslint-disable-next-line no-undef
const {NODE_ENV} = process.env;
let exitConditionArrayIndex = 0;
/**
* @function bootstrapApplication
* @description Setup all the run-time dependencies, execution environment, data, and configuration settings.
* @return {void}
* @author Seth Hollingsead
* @date 2023/02/23
*/
async function bootStrapApplication() {
// let functionName = bootStrapApplication.name;
// console.log(`BEGIN ${namespacePrefix}${functionName} function`);
rootPath = url.fileURLToPath(path.dirname(import.meta.url));
let rootPathArray = [];
let pathSeparator = '';
if (rootPath.includes(bas.cBackSlash) === true) {
pathSeparator = bas.cBackSlash;
} else if (rootPath.includes(bas.cForwardSlash) === true) {
pathSeparator = bas.cForwardSlash;
}
rootPathArray = rootPath.split(pathSeparator);
rootPathArray.pop(); // remove any bin or src folder from the path.
rootPath = rootPathArray.join(pathSeparator);
let appConfig = {};
if (NODE_ENV === wrd.cdevelopment) {
appConfig = {
FrameworkName: apc.cExpectedActualFrameworkDevName,
clientRootPath: rootPath,
appConfigResourcesPath: rootPath + apc.cFullDevResourcesPath,
appAccountsPath: rootPath + apc.cFullDevAccountsPath,
appConfigReferencePath: rootPath + apc.cFullDevConfigurationPath,
clientMetaDataPath: apc.cmetaDataDevPath,
clientCommandAliasesPath: rootPath + apc.cFullDevCommandsPath,
clientConstantsPath: rootPath + apc.cFullDevConstantsPath,
clientRegisteredPlugins: rootPath + apc.cFullDevPluginsRegistryPath,
clientWorkflowsPath: rootPath + apc.cFullDevWorkflowsPath,
appLessonsPath: rootPath + apc.cFullDevLessonsPath,
clientThemesPath: rootPath + apc.cFullDevThemesPath,
applicationConstantsValidationData: allAppCV.initializeAllClientConstantsValidationData,
clientBusinessRules: {},
clientCommands: {}
};
} else if (NODE_ENV === wrd.cproduction) {
appConfig = {
FrameworkName: apc.cExpectedActualFrameworkProdName,
clientRootPath: rootPath,
appConfigResourcesPath: rootPath + apc.cFullProdResourcesPath,
appAccountsPath: rootPath + apc.cFullProdAccountsPath,
appConfigReferencePath: rootPath + apc.cFullProdConfigurationPath,
clientMetaDataPath: apc.metaDataProdPath,
clientCommandAliasesPath: rootPath + apc.cFullProdCommandsPath,
clientConstantsPath: rootPath + apc.cFullProdConstantsPath,
clientRegisteredPlugins: rootPath + apc.cFullProdPluginsRegistryPath,
clientWorkflowsPath: rootPath + apc.cFullProdWorkflowsPath,
appLessonsPath: rootPath + apc.cFullProdLessonsPath,
clientThemesPath: rootPath + apc.cFullProdThemesPath,
applicationConstantsValidationData: allAppCV.initializeAllClientConstantsValidationData,
clientBusinessRules: {},
clientCommands: {}
};
} else {
// WARNING: No .env file found! Going to default to the DEVELOPMENT ENVIRONMENT!
console.log(msg.cApplicationWarningMessage1a + msg.cApplicationWarningMessage1b);
appConfig = {
FrameworkName: apc.cExpectedActualFrameworkDevName,
clientRootPath: rootPath,
appConfigResourcesPath: rootPath + apc.cFullDevResourcesPath,
appAccountsPath: rootPath + apc.cFullDevAccountsPath,
appConfigReferencePath: rootPath + apc.cFullDevConfigurationPath,
clientMetaDataPath: apc.cmetaDataDevPath,
clientCommandAliasesPath: rootPath + apc.cFullDevCommandsPath,
clientConstantsPath: rootPath + apc.cFullDevConstantsPath,
clientRegisteredPlugins: rootPath + apc.cFullDevPluginsRegistryPath,
clientWorkflowsPath: rootPath + apc.cFullDevWorkflowsPath,
appLessonsPath: rootPath + apc.cFullDevLessonsPath,
clientTemesPath: rootPath + apc.cFullDevThemesPath,
applicationConstantsValidationData: allAppCV.initializeAllClientConstantsValidationData,
clientBusinessRules: {},
clientCommands: {}
};
}
appConfig[sys.cclientBusinessRules] = await tutoringRules.initApplicationRulesLibrary();
appConfig[sys.cclientCommands] = await tutoringCommands.initApplicationCommandsLibrary();
// console.log('appConfig is: ', appConfig);
await haystacks.initFramework(appConfig);
await haystacks.setConfigurationSetting(wrd.csystem, app_cfg.cappAccountsPath, appConfig[app_cfg.cappAccountsPath]);
await haystacks.setConfigurationSetting(wrd.csystem, app_cfg.cappLessonsPath, appConfig[app_cfg.cappLessonsPath]);
let accountsData = await haystacks.loadAllJsonData(appConfig[app_cfg.cappAccountsPath], app_sys.cclientData + bas.cColon + app_sys.cuserAccounts);
// console.log('accountsData is: ' + JSON.stringify(accountsData));
let lessonsData = await haystacks.loadAllJsonData(appConfig[app_cfg.cappLessonsPath], app_sys.cclientData + bas.cColon + app_sys.capplicationLessons);
let accountDataStored = await haystacks.storeData(app_sys.cuserAccounts, accountsData);
let lessonDataStored = await haystacks.storeData(app_sys.capplicationLessons, lessonsData);
if (accountDataStored === false || !accountsData) {
// ERROR: No user accounts data was loaded, please ensure the accounts resources folder has accounts data. Path:
console.log(app_msg.cErrorNoUserAccountsDataLoadedMessage01 + appConfig[app_cfg.cappAccountsPath]);
}
if (lessonDataStored === false || !lessonsData) {
// ERROR: No typing lessons data was loaded, please ensure the lessons folder has lessons data. Path:
console.log(app_msg.cErrorNoLessonDataLoadedMessage01 + appConfig[app_cfg.cappLessonsPath]);
}
// console.log(`END ${namespacePrefix}${functionName} function`);
}
/**
* @function application
* @description This is the main program loop, the init for the Haystacks-TT application.
* @return {void}
* @author Seth Hollingsead
* @date 2023/02/23
*/
async function application() {
let functionName = application.name;
await haystacks.consoleLog(namespacePrefix, functionName, msg.cBEGIN_Function);
let commandInput;
let commandResult;
await haystacks.enqueueCommand(app_cmd.cApplicationStartupWorkflow);
// Make sure to process all of the startup command workflow commands before we go into the main program loop.
while (await haystacks.isCommandQueueEmpty() === false) {
commandResult = await haystacks.processCommandQueue();
} // End-while (await haystacks.isCommandQueueEmpty() === false)
// BEGIN the main program loop
await haystacks.consoleLog(namespacePrefix, functionName, app_msg.capplicationMessage01);
// BEGIN command parser
await haystacks.consoleLog(namespacePrefix, functionName, app_msg.capplicationMessage02);
while (programRunning === true) {
currentUser = await accountBroker.currentUserAccount();
currentCurriculumName = await accountBroker.getCurrentCurriculumName();
if (await haystacks.isCommandQueueEmpty() === true) {
if (currentCurriculumName === false) {
commandInput = await haystacks.executeBusinessRules([currentUser + bas.cGreaterThan, ''], [wrd.cprompt]);
} else {
commandInput = await haystacks.executeBusinessRules([currentUser + bas.cGreaterThan +
currentCurriculumName + bas.cGreaterThan, ''], [wrd.cprompt]);
}
await haystacks.enqueueCommand(commandInput);
} // End-if (await haystacks.isCommandQueueEmpty() === true)
commandResult = await haystacks.processCommandQueue();
if (commandResult[exitConditionArrayIndex] === false) {
// Save the account data
await accountBroker.saveAccountData();
// END command parser
await haystacks.consoleLog(namespacePrefix, functionName, app_msg.capplicationMessage03);
programRunning = false;
// END main program loop
await haystacks.consoleLog(namespacePrefix, functionName, app_msg.capplicationMessage04);
// Exiting Haystacks-TT application
await haystacks.consoleLog(namespacePrefix, functionName, app_msg.capplicationMessage05);
break;
} // End-if (commandResult[exitConditionArrayIndex] === false)
} // End-while (programRunning === true)
await haystacks.consoleLog(namespacePrefix, functionName, msg.cEND_Function);
}
// Launch the application!
let programRunning = false;
let currentUser = '';
let currentCurriculumName = '';
await bootStrapApplication();
programRunning = true;
await application();
process.exit();