Files
MQL5Data/Documents/JsModules/x-mql-project.tools.js
T
2026-07-10 04:24:32 +03:30

497 lines
13 KiB
JavaScript

/**
* XProject Tools Module ...
* a module for handle MQL5 Projects Compile and Packing ...
*
* Maintainer
*
* Hadi Khazaee Asl <https://saherelm.ir> (hadi_khazaee_asl@yahoo.com)
*/
//
// Import Requirements ...
const execSync = require("child_process").execSync;
const XFileTools = require("./Documents/JsModules/x-file.tools");
const XShellTools = require("./Documents/JsModules/x-shell.tools");
const XColorTools = require("./Documents/JsModules/x-color.tools");
const XTypeTools = require("./Documents/JsModules/x-type-detector.tools");
//
// Definitions ...
const packsPath = XFileTools.joinPath(".", "Packs");
const workspacePaths = [
"Classes", // Required Classes
"Experts", // Expert Advisers
"Helpers", // Indicator's Helpers Classes
"Indicators", // Required Indicators
"Libraries", // Required Libraries
"XOM1EA", // XOM1EA Projects ...
"XFIMAEA", // XOM1EA Projects ...
"XCATBEA", // XCATBEA Projects ...
"X121XKIEA", // X121XKIEA Projects ...
];
//
//#region Tools ...
/**
* Handle Compile and Pack Projects ...
*
* @param {string} projectName
* @param {string[]} resources
* @param {boolean} forceCleanup
* @param {boolean} forceCompileIndicators
*/
async function prepareProject(
projectName = "",
resources = [],
forceCleanup = true,
forceCompileIndicators = true
) {
//
// Check Resources Has Child ...
let isValidArgs =
resources.length > 0 &&
XTypeTools.isArray(resources);
if (!isValidArgs) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Invalid Resource List ...", XColorTools.COLOR_NAMES.Red)
);
}
//
// Check Project Name is Valid ...
isValidArgs =
projectName.length > 0 &&
XTypeTools.isString(projectName);
if (!isValidArgs) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Empty Project Name ...", XColorTools.COLOR_NAMES.Red)
);
}
//
// Prepare Pack Folder Exists ...
let isExists = XFileTools.isDirectoryExists(packsPath);
if (!isExists) {
XFileTools.createDirectory(packsPath);
}
//
// Check Folder Exists or not ...
// if Exists Remove it ...
// Create Project Folder on Packs ...
const prjFolderOnPacks = XFileTools.joinPath(packsPath, projectName);
isExists = XFileTools.isDirectoryExists(prjFolderOnPacks);
if (isExists) {
await XFileTools.removeDirectory(prjFolderOnPacks, true);
}
XFileTools.createDirectory(prjFolderOnPacks);
//
// Extract Required to Compile Resources List ...
let compileList = await extractResources(resources, true);
if (!compileList || compileList.length == 0) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Resource List Extraction to Compile Failed ...", XColorTools.COLOR_NAMES.Red)
);
//
return;
}
//
// Compile Resources Files ...
for (const f of compileList) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("try to Compile: ", XColorTools.COLOR_NAMES.Yellow),
XColorTools.applyForegroundColor(f, XColorTools.COLOR_NAMES.Blue)
);
//
await recursiveTriesToCompileFile(f, 0);
}
//
// Extract Required to Pack Resources List ...
let packList = await extractResources(resources, false);
if (!packList || packList.length == 0) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Resource List Extraction to Pack Failed ...", XColorTools.COLOR_NAMES.Red)
);
//
return;
}
//
// Loop through Files ...
for (const f of packList) {
//
// Prepare Destination Path ...
const fBasePath = XFileTools.basename(f);
let fDestPath = f.replace(fBasePath, "");
fDestPath = fDestPath.substring(0, fDestPath.length - 1);
fDestPath = XFileTools.joinPath(prjFolderOnPacks, fDestPath);
//
const isFDestPathExists = XFileTools.isDirectoryExists(fDestPath);
if (!isFDestPathExists) {
XFileTools.createDirectory(fDestPath);
}
//
// Log ...
console.log(
XColorTools.applyForegroundColor("try to copy: ", XColorTools.COLOR_NAMES.Yellow),
XColorTools.applyForegroundColor(f, XColorTools.COLOR_NAMES.Blue),
XColorTools.applyForegroundColor(" to : ", XColorTools.COLOR_NAMES.Yellow),
XColorTools.applyForegroundColor(fDestPath, XColorTools.COLOR_NAMES.Magenta)
);
//
let result = await XFileTools.copyFile(f, fDestPath);
if (result) {
//
const msg = "copy successfully ...";
console.log(
XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Green)
);
} else {
//
const msg = "copy failed ...";
console.log(XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Red));
throw msg;
}
}
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Project: ", XColorTools.COLOR_NAMES.Green),
XColorTools.applyForegroundColor(projectName, XColorTools.COLOR_NAMES.Yellow),
XColorTools.applyForegroundColor(" Compiled and Packed Successfully ...", XColorTools.COLOR_NAMES.Green),
);
//
// Cleanup WorkSpace if Provided ...
if (forceCleanup) {
await cleanupWorkSpace();
}
//
// Compile Indicators ...
if (forceCompileIndicators) {
await runCommand("Indicators");
}
}
/**
* Extract required Files List ...
*
* @param {boolean} forCompile
*
* @returns Promise<string[]>
*/
async function extractResources(
resources = [],
forCompile = true
) {
//
let result = [];
//
// Loop Through Project Resources and Extract Files List to Compile ...
for (const resource of resources) {
//
// Prepare Normalized Resource Path ...
let resourcePath = XFileTools.joinPath(".", resource);
//
// Handle Wild Card Resources ...
if (resourcePath.endsWith("//*") ||
resourcePath.endsWith("\\*")) {
//
resourcePath = resourcePath.substring(0, resourcePath.length - 2);
const files = await XFileTools.extractFiles(
resourcePath,
forCompile ? [".mq5", ".mq4"] : [".ex5", ".ex4"]
);
//
result = result.concat(files);
}
//
// Handle Direct File Resources ...
else {
//
// Check MQL 5 Version ...
let fileResourcePath = resourcePath + (forCompile ? ".mq5" : ".ex5");
//
// Check File Exists ...
let isExists = XFileTools.isFileExists(fileResourcePath);
if (!isExists) {
//
// Check MQL 4 Version ...
fileResourcePath = resourcePath + (forCompile ? ".mq4" : ".ex4");
isExists = XFileTools.isFileExists(fileResourcePath);
}
//
// Add File Path to Files List if Exists ...
if (isExists) {
result.push(fileResourcePath);
}
}
}
//
return result;
}
/**
* try to compile a file ...
* @param {string} f
* @param {number} numberOfTries
*/
async function recursiveTriesToCompileFile(f = "", numberOfTries = 0) {
//
let result = await handleFileCompile(f);
if (result) {
//
const msg = "compiled successfully ...";
console.log(XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Green));
return result;
} else {
//
if (numberOfTries < 10) {
//
numberOfTries++;
//
const msg = "retry (" + (numberOfTries + 1) + ") ...";
console.log(XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.LightMagenta));
await recursiveTriesToCompileFile(f, numberOfTries);
} else {
//
const msg = "failed ...";
console.log(XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Red));
throw msg;
//
return false;
}
}
}
/**
* execute compile task on Specific File ...
* @param {string} f file path to Execute Compile task ...
* @returns
*/
async function handleFileCompile(f = "") {
//
let result = false;
//
let exResult = await compileMQLFile(f);
if (exResult.includes("0 errors")) {
result = true;
} else {
result = false;
}
//
return result;
}
/**
* Compile Specific MQL File ...
*
* @param {string} path MQL file path ...
* @returns
*/
async function compileMQLFile(path = "") {
//
// Check File Exists ...
const isExists = XFileTools.isFileExists(path);
if (!isExists) {
//
const msg = "file not found ...";
console.log(XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Red));
throw msg;
}
//
const ext = XFileTools.getFileExtension(path);
if (ext !== ".mq5" && ext !== "mq4") {
//
const msg = "invalid file extension ...";
console.log(XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Red));
throw msg;
}
//
const cwd = __dirname;
const cmd = "compile.cmd " + path;
//
const result = await XShellTools.execute(cmd, cwd);
return result;
}
/**
* Run Specified Command in workspace ...
*
* @param {string} cmd
* @returns
*/
async function runCommand(cmd = "") {
//
// Validate Args ...
let isValidArgs = cmd.length > 0 &&
XTypeTools.isString(cmd);
//
// Validate Commands ...
if (isValidArgs) {
//
// Check Available Commands ...
isValidArgs =
cmd === "*" ||
cmd === "cleanup" ||
workspacePaths.includes(cmd) ||
workspacePaths.map(x => x.toLowerCase(x)).includes(cmd.toLowerCase());
}
if (!isValidArgs) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Invalid Command ...", XColorTools.COLOR_NAMES.Red)
);
}
//
// Compile ...
if (cmd == "*") {
await compileWorkSpace();
} else if (cmd == "cleanup") {
await cleanupWorkSpace();
} else {
//
// Select Workspace to Compile ...
const folder = workspacePaths
.find(x => x.toLowerCase() === cmd.toLowerCase());
isValidArgs =
XTypeTools.isString(folder) &&
folder.length > 0;
if (!isValidArgs) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Invalid Command ...", XColorTools.COLOR_NAMES.Red)
);
}
//
// Extract Required to Compile Resources List ...
let compileList = await XFileTools.extractFiles(
folder,
[".mq5", ".mq4"]
);
if (!compileList || compileList.length == 0) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("Extraction to Compile Failed ...", XColorTools.COLOR_NAMES.Red)
);
//
return;
}
//
// Compile Resources Files ...
for (const f of compileList) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("try to Compile: ", XColorTools.COLOR_NAMES.Yellow),
XColorTools.applyForegroundColor(f, XColorTools.COLOR_NAMES.Blue)
);
//
await recursiveTriesToCompileFile(f, 0);
}
}
}
/**
* Cleanup Workspace compiled files ...
*/
async function cleanupWorkSpace() {
//
for (const path of workspacePaths) {
//
const fSourcePath = XFileTools.joinPath(".", path);
const filesToRemove = await XFileTools.extractFiles(fSourcePath, [".ex5", ".ex4"]);
for (const f of filesToRemove) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor("try to Remove: ", XColorTools.COLOR_NAMES.Yellow),
XColorTools.applyForegroundColor(f, XColorTools.COLOR_NAMES.Blue)
);
//
let result = await XFileTools.removeFile(f);
if (result) {
//
const msg = "removed successfully ...";
console.log(
XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Green)
);
} else {
//
const msg = "removed failed ...";
console.log(XColorTools.applyForegroundColor(msg, XColorTools.COLOR_NAMES.Red));
throw msg;
}
}
}
}
/**
* Compile Workspace ...
*/
async function compileWorkSpace() {
//
for (const path of workspacePaths) {
await runCommand(path);
}
}
//#endregion
//
//#region Module Exports ...
module.exports = {
extractResources,
recursiveTriesToCompileFile,
handleFileCompile,
compileMQLFile,
runCommand,
cleanupWorkSpace,
compileWorkSpace,
prepareProject
};
//#endregion