add and Test Context Generator ...

This commit is contained in:
2026-08-13 00:36:57 +03:30
parent 422e019acc
commit d50eef35bc
2 changed files with 78250 additions and 0 deletions
+557
View File
@@ -0,0 +1,557 @@
#!/usr/bin/env node
/**
* Context Generator Module ...
* a module for Generating Context ...
*
* Maintainer
*
* Hadi Khazaee Asl <https://saherelm.ir> (hadi_khazaee_asl@yahoo.com)
*/
//
//#region Imports ...
const fs = require("fs");
const path = require("path");
//#endregion
//
//#region Constants ...
const outputFilePrefix = "xDashboard";
const allowedPatterns = [
// {
// kind: "file",
// mode: "allow",
// match: "name",
// pattern: /^*.mq5$/i
// },
// {
// kind: "directory",
// mode: "deny",
// match: "name",
// pattern: /^node_modules$/i
// },
// {
// kind: "file",
// mode: "allow",
// match: "path",
// pattern: /^x-saherelm.*.mq5$/i
// },
//
// Base Pilot Files ...
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.base.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.session-detector.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-account.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-alert.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-app-dialog.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-backtester.expert.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-bar.analyser.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-chart.helper.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-cobject.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-data.collector.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-expert.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-guard.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-helper.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-http.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-market.pattern.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-md5.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-poi.drawer.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-position.drawer.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-restrictions.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-rm.panel.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-signaller.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-target.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-trade-manager.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-trade.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-volume.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.backtester.ea.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-expert.ea.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x121.xcc.helper.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x121.xct.helper.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x121.xcc.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x121.xct.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.common.extensions.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.common.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.common.models.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.draw.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-enums.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-guard.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-ohcl.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-pivot.analysis.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-poi.extensions.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-poi.lib.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-trade.lib.mq5$/i
},
]
//#endregion
//
// Reading Required Info
const inputPath = process.argv[2];
const searchPath = path.resolve(inputPath || process.cwd());
// Check Given Path is Valid or not ...
if (!fs.existsSync(searchPath)) {
console.error(`Error: path not found: ${searchPath}`);
process.exit(1);
}
//
// Retrieve Stats of Given Path ...
const stat = fs.statSync(searchPath);
if (!stat.isDirectory()) {
console.error(`Error: path is not a directory: ${searchPath}`);
process.exit(1);
}
//
// Generate Required Data ...
const timestamp = getTimestamp(new Date());
const folderName = path.basename(searchPath) || "root";
const safeFolderName = sanitizeFileName(folderName);
// Generate Output file Name ...
const outputFileName = inputPath
? `${outputFilePrefix}-${safeFolderName}-${timestamp}.txt`
: `${outputFilePrefix}-${timestamp}.txt`;
//
const outputPath = path.join(
process.cwd(),
"Documents",
"GeneratedContext",
outputFileName
);
// Create Output File ...
fs.writeFileSync(outputPath, "", "utf8");
// Navigate to Context Generation ...
walk(searchPath);
//
console.log(`Context generated: ${outputPath}`);
//
//#region Required Tools ...
/**
* Validate Timestamp ...
*
* @param {*} value
* @returns
*/
function pad(value) {
return String(value).padStart(2, "0");
}
/**
* Retrieve Validate ...
*
* @param {*} date
* @returns
*/
function getTimestamp(date) {
//
const year = date.getFullYear();
const month = pad(date.getMonth() + 1);
const day = pad(date.getDate());
const hours = pad(date.getHours());
const minutes = pad(date.getMinutes());
const seconds = pad(date.getSeconds());
//
return `${year}${month}${day}_${hours}${minutes}${seconds}`;
}
/**
* Retrieve Leaf Folder ...
*
* @param {*} value
* @returns
*/
function sanitizeFileName(value) {
return value.replace(/[\\/:*?"<>|]/g, "_");
}
/**
* Match Value ...
*
* @param {*} rule
* @param {*} targetPath
* @returns
*/
function getMatchValue(rule, targetPath) {
//
const normalizedPath = targetPath.replace(/\\/g, "/");
if (rule.match === "path") {
return normalizedPath;
}
//
return path.basename(targetPath);
}
/**
* Match Patterns ...
*
* @param {*} targetPath
* @param {*} rules
* @returns
*/
function matchesPatterns(targetPath, rules) {
//
return rules.some(rule => {
const value = getMatchValue(rule, targetPath);
return rule.pattern.test(value);
});
}
/**
* Check a Directory Path is Valid for Parsing or not ...
*
* @param {*} fileName
* @returns
*/
function isAllowedFile(filePath) {
//
// Extract Deny Rules ...
const denyRules = allowedPatterns.filter(
p => p.kind === "file" && p.mode === "deny"
);
//
// Extract Allowed Rules ...
const allowRules = allowedPatterns.filter(
p => p.kind === "file" && p.mode === "allow"
);
// Check Deny Rules First ...
if (matchesPatterns(filePath, denyRules)) {
return false;
}
// Check Allowed Rules ...
return matchesPatterns(filePath, allowRules);
}
/**
* Check a Directory Path is Valid for Parsing or not ...
*
* @param {*} directoryPath
* @returns
*/
function isAllowedDirectory(directoryPath) {
//
// Extract Deny Rules ...
const denyRules = allowedPatterns.filter(
p => p.kind === "directory" && p.mode === "deny"
);
//
// Extract Allowed Rules ...
const allowRules = allowedPatterns.filter(
p => p.kind === "directory" && p.mode === "allow"
);
//
// Check Deny Patterns as First ...
if (matchesPatterns(directoryPath, denyRules)) {
return false;
}
//
// Check Allow Patterns Exists ...
if (allowRules.length === 0) {
return true;
}
//
// Chck Allowed Patterns Matched ...
return matchesPatterns(directoryPath, allowRules);
}
/**
* Loop through a Directory and Navigate files for including in Context ...
*
* @param {*} dir
* @returns
*/
function walk(dir) {
//
// Reading Directory Content ...
let entries;
try {
entries = fs.readdirSync(dir, { withFileTypes: true });
} catch (error) {
fs.appendFileSync(
outputPath,
`\n### ERROR reading directory: ${dir}\n${error.message}\n`,
"utf8"
);
return;
}
//
// Loop through Entries ...
for (const entry of entries) {
//
const fullPath = path.join(dir, entry.name);
//
// Ignore if Symlink ...
if (entry.isSymbolicLink()) {
continue;
}
//
// Handle if requested Path is Directory ...
if (entry.isDirectory()) {
//
// Allowed Folders ...
if (!isAllowedDirectory(fullPath)) {
continue;
}
//
walk(fullPath);
}
else
//
// Handle if requested Path is File ...
if (entry.isFile()) {
//
// Allowed File ...
if (!isAllowedFile(fullPath)) {
continue;
}
//
// Holds File Content ...
let content;
try {
content = fs.readFileSync(fullPath, "utf8");
} catch (error) {
content = `// Error reading file: ${error.message}`;
}
//
// Append File Content for Context ...
fs.appendFileSync(
outputPath,
`\n### FILE: ${fullPath}\n\n${content}\n`,
"utf8"
);
}
}
}
//#endregion
File diff suppressed because it is too large Load Diff