This commit is contained in:
2026-07-10 04:24:32 +03:30
parent 76f57aff36
commit 369e6f0863
25 changed files with 1679 additions and 24 deletions
+19
View File
@@ -0,0 +1,19 @@
/**
* XMQL Helper CLI Tools ...
* a module for handle MQL5 Commands running ...
*
* Maintainer
*
* Hadi Khazaee Asl <https://saherelm.ir> (hadi_khazaee_asl@yahoo.com)
*/
//
// Import Requirements ...
const XProjectTools = require("./x-mql-project.tools");
//
// Read Command Arguments ...
let cmdName = process.argv[2];
//
XProjectTools.runCommand(cmdName);
@@ -0,0 +1,29 @@
//
// Import Requirements ...
const XProjectTools = require("./x-mql-project.tools");
//
// define constants ...
const projectName = "X121XKIEA";
//
// Projects Resources ...
const projectResources = [
"Libraries/*", // Required Libraries
"Classes/*", // Required Classes
"X121XKIEA/*", // X121XKIEA Projects ...
"Indicators/x-saherelm.x121.xki", // Required Indicators
"Helpers/x-saherelm.x121.xki.helper", // Indicator's Helpers Classes
"Experts/x-saherelm.x121.xki.backtester.ea", // Expert Advisers
];
//
run();
/**
* Main Project Function ...
*/
async function run() {
//
await XProjectTools.prepareProject(projectName, projectResources);
}
@@ -0,0 +1,35 @@
//
// Import Requirements ...
const XProjectTools = require("./x-mql-project.tools");
//
// define constants ...
const projectName = "XCATBEA";
//
// Projects Resources ...
const projectResources = [
"Libraries/*", // Required Libraries
"Classes/*", // Required Classes
"XCATBEA/*", // XCATBEA Projects ...
"Indicators/x-saherelm.x121.xcatb", // Required Indicators
"Helpers/x-saherelm.x121.xcatb.helper", // Indicator's Helpers Classes
"Experts/x-saherelm.x121.xcatb.ea", // Expert Advisers
];
//
run();
/**
* Main Project Function ...
*/
async function run() {
//
await XProjectTools.prepareProject(
projectName,
projectResources
);
}
@@ -0,0 +1,31 @@
//
// Import Requirements ...
const XProjectTools = require("./x-mql-project.tools");
//
// define constants ...
const projectName = "XFIMAEA";
//
// Projects Resources ...
const projectResources = [
"Libraries/*", // Required Libraries
"Classes/*", // Required Classes
"XFIMAEA/*", // XOM1EA Projects ...
"Indicators/x-saherelm.xfima", // Required Indicators
"Indicators/x-saherelm.x121.xct", // Required Indicators
"Helpers/x-saherelm.xfima.helper", // Indicator's Helpers Classes
"Experts/x-saherelm.xfima.backtester.ea", // Expert Advisers
"Experts/x-saherelm.xfima.ea", // Expert Advisers
];
//
run();
/**
* Main Project Function ...
*/
async function run() {
//
await XProjectTools.prepareProject(projectName, projectResources);
}
@@ -0,0 +1,29 @@
//
// Import Requirements ...
const XProjectTools = require("./x-mql-project.tools");
//
// define constants ...
const projectName = "XOM1EA";
//
// Projects Resources ...
const projectResources = [
"Libraries/*", // Required Libraries
"Classes/*", // Required Classes
"XOM1EA/*", // XOM1EA Projects ...
"Indicators/x-saherelm.xom1", // Required Indicators
"Helpers/x-saherelm.xom1.helper", // Indicator's Helpers Classes
"Experts/x-saherelm.xom1.ea", // Expert Advisers
];
//
run();
/**
* Main Project Function ...
*/
async function run() {
//
await XProjectTools.prepareProject(projectName, projectResources);
}
@@ -0,0 +1,27 @@
//
// Import Requirements ...
const XProjectTools = require("./x-mql-project.tools");
//
// define constants ...
const projectName = "XRRTools";
//
// Projects Resources ...
const projectResources = [
"Libraries/*", // Required Libraries
"Classes/*", // Required Classes
"Indicators/x-saherelm.x121.xcc", // Required Indicators
"Experts/x-saherelm.rr.tools", // Expert Advisers
];
//
run();
/**
* Main Project Function ...
*/
async function run() {
//
await XProjectTools.prepareProject(projectName, projectResources);
}
@@ -0,0 +1,497 @@
/**
* 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
+45
View File
@@ -0,0 +1,45 @@
/**
* XMQL Document Helper CLI Tools ...
* a module for handle MQL5 Documents Generating ...
*
* Maintainer
*
* Hadi Khazaee Asl <https://saherelm.ir> (hadi_khazaee_asl@yahoo.com)
*/
//
// Import Requirements ...
const XColorTools = require("./x-color.tools");
const XDocumentTools = require("./x-mql-document.tools");
const args = process.argv.slice(2);
if (args.length < 1) {
//
// Log ...
console.log(
XColorTools.applyForegroundColor(
"Invalid Usage Command ...",
XColorTools.COLOR_NAMES.Red
)
);
console.log(
XColorTools.applyForegroundColor(
"Usage: node mql5-doc-extractor.js <path_to_mql5_file> [output_md_file]",
XColorTools.COLOR_NAMES.Yellow
)
);
console.log(
XColorTools.applyForegroundColor(
"Example: node mqlDocumentHelper.js ./MyEA.mq5 ./docs/MyEA.md",
XColorTools.COLOR_NAMES.LightBlue
)
);
//
process.exit(1);
}
const inputFile = args[0];
const outputFile = args[1] || inputFile.replace(/\.(mq5|mqh)$/i, '_DOCS.md');
XDocumentTools.extractMQL5Documentation(inputFile, outputFile);
+183
View File
@@ -0,0 +1,183 @@
const fs = require('fs');
const path = require('path');
//
//#region Tools ...
/**
* Extracts Doxygen-style documentation from MQL5 files and generates Markdown.
* @param {string} filePath - Path to the .mq5 or .mqh file
* @param {string} outputPath - Path to save the generated .md file
*/
function extractMQL5Documentation(filePath, outputPath) {
//
if (!fs.existsSync(filePath)) {
console.error(`Error: File not found at ${filePath}`);
return;
}
//
const content = fs.readFileSync(filePath, 'utf8');
const lines = content.split('\n');
const extractedDocs = [];
//
let currentCommentBlock = [];
let isInsideBlockComment = false;
//
// State machine to parse comments and map them to the next line of code
for (let i = 0; i < lines.length; i++) {
//
const line = lines[i];
const trimmedLine = line.trim();
//
// 1. Handle Block Comments (/* ... */)
if (trimmedLine.startsWith('/*') || trimmedLine.startsWith('/**')) {
//
isInsideBlockComment = true;
currentCommentBlock.push(trimmedLine);
if (trimmedLine.endsWith('*/')) {
isInsideBlockComment = false;
}
continue;
}
//
if (isInsideBlockComment) {
//
currentCommentBlock.push(trimmedLine);
if (trimmedLine.endsWith('*/')) {
isInsideBlockComment = false;
}
continue;
}
//
// 2. Handle Line Comments (/// or //)
if (trimmedLine.startsWith('///') || trimmedLine.startsWith('//')) {
//
currentCommentBlock.push(trimmedLine);
continue;
}
//
// 3. Handle Empty Lines (Keep them to preserve spacing before code)
if (trimmedLine === '') {
//
if (currentCommentBlock.length > 0) {
currentCommentBlock.push('');
}
continue;
}
//
// 4. We hit actual code. If we have a comment block, map it.
if (currentCommentBlock.length > 0) {
//
// Clean up trailing empty lines in the comment block
while (currentCommentBlock.length > 0 &&
currentCommentBlock[currentCommentBlock.length - 1].trim() === ''
) {
currentCommentBlock.pop();
}
//
if (currentCommentBlock.length > 0) {
//
extractedDocs.push({
comment: currentCommentBlock.join('\n'),
code: trimmedLine
});
}
//
currentCommentBlock = [];
}
}
//
// Generate Markdown Output
generateMarkdown(filePath, extractedDocs, outputPath);
}
/**
* Formats the extracted data into a clean Markdown document.
*/
function generateMarkdown(filePath, docs, outputPath) {
//
const fileName = path.basename(filePath);
let md = `# Documentation for \`${fileName}\`\n\n`;
md += `*Extracted on: ${new Date().toLocaleDateString()}*\n\n---\n\n`;
//
let fileHeaderFound = false;
//
docs.forEach((doc, index) => {
//
// Check if this is the file-level header (usually the very first block)
if (index === 0 &&
(doc.code.startsWith('#property') || doc.code.startsWith('//+--'))) {
//
md += `## File Overview\n`;
md += formatComment(doc.comment) + '\n\n';
fileHeaderFound = true;
return;
}
//
// Only document actual functions, classes, structs, or important variables
const isDocumentableCode = /^(void|int|double|bool|string|long|ulong|uint|class|struct|enum|input)\s+/.test(doc.code)
|| doc.code.includes('class ')
|| doc.code.includes('struct ');
if (isDocumentableCode) {
//
md += `### \`${extractSignature(doc.code)}\`\n\n`;
md += `**Declaration:**\n\`\`\`cpp\n${doc.code}\n\`\`\`\n\n`;
md += `**Documentation:**\n${formatComment(doc.comment)}\n\n---\n\n`;
}
});
//
fs.writeFileSync(outputPath, md, 'utf8');
console.log(`✅ Successfully extracted documentation to: ${outputPath}`);
}
/**
* Cleans up Doxygen tags for better Markdown readability.
*/
function formatComment(comment) {
return comment
.replace(/\/\*\*?|\*\//g, '') // Remove block comment markers
.replace(/^\s*\*\s?/gm, '') // Remove leading asterisks
.replace(/^\/\/\/?\s?/gm, '') // Remove line comment markers
.replace(/@param\s+(\w+)\s*/g, '**Param `$1`:** ')
.replace(/@return\s*/g, '**Returns:** ')
.replace(/@brief\s*/g, '**Summary:** ')
.replace(/@note\s*/g, '*Note:* ')
.replace(/@warning\s*/g, '> **Warning:** ')
.trim();
}
/**
* Extracts a clean function/class signature from the code line.
*/
function extractSignature(codeLine) {
//
// Basic extraction, stops at the first opening parenthesis or brace
const match = codeLine.match(/^(.*?)[\({]/);
return match ? match[1].trim() : codeLine;
}
//#endregion
//
//#region Module Exports ...
module.exports = {
formatComment,
generateMarkdown,
extractSignature,
extractMQL5Documentation,
}
//#endregion
+23 -20
View File
@@ -24,7 +24,10 @@ const workspacePaths = [
"Helpers", // Indicator's Helpers Classes
"Indicators", // Required Indicators
"Libraries", // Required Libraries
"XOM1EA", // XOM1EA Projects ...
"XFIMAEA", // XOM1EA Projects ...
"XCATBEA", // XCATBEA Projects ...
"X121XKIEA", // X121XKIEA Projects ...
];
//
@@ -70,6 +73,24 @@ async function prepareProject(
);
}
//
// 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);
@@ -112,24 +133,6 @@ async function prepareProject(
return;
}
//
// 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);
//
// Loop through Files ...
for (const f of packList) {
@@ -188,7 +191,7 @@ async function prepareProject(
//
// Compile Indicators ...
if (forceCompileIndicators) {
await compile("Indicators");
await runCommand("Indicators");
}
}
@@ -490,5 +493,5 @@ module.exports = {
cleanupWorkSpace,
compileWorkSpace,
prepareProject
}
};
//#endregion