This commit is contained in:
2026-08-14 07:49:18 +03:30
parent 9d23e2cba1
commit 4707856302
6 changed files with 3833 additions and 56 deletions
+156 -17
View File
@@ -57,8 +57,10 @@ class XCPivotDetector : public XCBase
//
// Constructor ...
XCPivotDetector(
XCAlert *_alert = NULL, //
int _maxAllowedProcessableZones = 10 //
XCAlert *_alert = NULL, // Alert instance Pointer ...
string _pivotPrefix = "XPivot", // Detected Zones Prefix ...
bool _supportInvertedZones = false, // Specified Support Inverted Zone or not ...
int _maxAllowedProcessableZones = 0 // Max Allowed Processable Zones ...
)
{
//
@@ -66,10 +68,12 @@ class XCPivotDetector : public XCBase
//
// Normalize ...
if (_maxAllowedProcessableZones <= 5)
if (_maxAllowedProcessableZones < 0)
{
_maxAllowedProcessableZones = 5;
_maxAllowedProcessableZones = 0;
}
mPivotPrefix = _pivotPrefix;
mSupportInvertedZones = _supportInvertedZones;
mMaxAllowedProcessableZones = _maxAllowedProcessableZones;
//
@@ -167,13 +171,13 @@ class XCPivotDetector : public XCBase
}
//
hasPeak = false;
hasVale = false;
hasPeak = true;
hasVale = true;
//
// Loop through Bars for Approved Side ...
int jStart = i + 1;
int jEnd = i + pivotApproved;
int jEnd = i + pivotApproved + 1;
for (int j = jStart; j < jEnd; j++)
{
//
@@ -182,8 +186,8 @@ class XCPivotDetector : public XCBase
jHigh = iHigh(iBar.symbol, iBar.period, j);
//
hasVale = iBar.low < jLow;
hasPeak = iBar.high > jHigh;
hasVale = hasVale && (iBar.low < jLow);
hasPeak = hasPeak && (iBar.high > jHigh);
has = hasVale || hasPeak;
if (!has)
{
@@ -204,7 +208,7 @@ class XCPivotDetector : public XCBase
//
// Loop through Barse for Approved Side ...
jStart = i - pivotApproved;
jEnd = i - 1;
jEnd = i;
for (int j = jStart; j < jEnd; j++)
{
//
@@ -251,7 +255,7 @@ class XCPivotDetector : public XCBase
tmpPrice = EMPTY_VALUE;
tmpZonePrice = EMPTY_VALUE;
jStart = i - pivotApproved;
jEnd = i + pivotApproved;
jEnd = i + pivotApproved + 1;
for (int j = jStart; j < jEnd; j++)
{
//
@@ -297,7 +301,7 @@ class XCPivotDetector : public XCBase
tmpPrice = EMPTY_VALUE;
tmpZonePrice = EMPTY_VALUE;
jStart = i - pivotApproved;
jEnd = i + pivotApproved;
jEnd = i + pivotApproved + 1;
for (int j = jStart; j < jEnd; j++)
{
//
@@ -341,6 +345,46 @@ class XCPivotDetector : public XCBase
}
// #endregion
}
bool HasPeaks()
{
return HasChild(peaks);
}
bool HasVales()
{
return HasChild(vales);
}
int GetYoungestPeak()
{
//
int result = -1;
//
if (HasPeaks())
{
result = GetYoungest(peaks);
}
//
return result;
}
int GetYoungestVale()
{
//
int result = -1;
//
if (HasVales())
{
result = GetYoungest(vales);
}
//
return result;
}
// #endregion
// #region Event Listener Registration ...
@@ -427,9 +471,6 @@ class XCPivotDetector : public XCBase
//
Clean(mOnPeakDetectedHandlers);
Clean(mOnValeDetectedHandlers);
//
mPivotPrefix = "XSDT";
}
/**
@@ -448,6 +489,13 @@ class XCPivotDetector : public XCBase
return;
}
//
// Validate Peak Box based on Price ...
if (!IsBoxValid(peakBox, 0, X_BOUNDARY_PRICE_UP_DOWN))
{
return;
}
//
// Update To ...
peakBox.to = TimeCurrent();
@@ -486,7 +534,7 @@ class XCPivotDetector : public XCBase
{
//
// Validate New Peak based on Youngest One ...
hasPeaks = peakBox.upper > peaks[idx].upper;
hasPeaks = peakBox.upper < peaks[idx].upper;
if (hasPeaks)
{
//
@@ -524,6 +572,13 @@ class XCPivotDetector : public XCBase
return;
}
//
// Validate Peak Box based on Price ...
if (!IsBoxValid(valeBox, 0, X_BOUNDARY_PRICE_UP_DOWN))
{
return;
}
//
// Update To ...
valeBox.to = TimeCurrent();
@@ -561,7 +616,7 @@ class XCPivotDetector : public XCBase
{
//
// Validate New Vale based on Youngest One ...
hasVales = valeBox.lower < vales[idx].lower;
hasVales = valeBox.lower > vales[idx].lower;
if (hasVales)
{
//
@@ -738,6 +793,7 @@ class XCPivotDetector : public XCBase
//
// Props ...
string mPivotPrefix; // Prefix ...
bool mSupportInvertedZones; // Support Inverted Zones ...
int mMaxAllowedProcessableZones; // Max Allowed Processable Zones ...
/**
@@ -826,6 +882,7 @@ class XCPivotDetector : public XCBase
//
Add(i, removeIDX);
NotifyPeakBreaked(peaks[i]);
HandleBreakedZone(peaks[i], cBar);
}
}
@@ -850,6 +907,7 @@ class XCPivotDetector : public XCBase
//
Add(i, removeIDX);
NotifyValeBreaked(vales[i]);
HandleBreakedZone(vales[i], cBar);
}
}
@@ -894,6 +952,87 @@ class XCPivotDetector : public XCBase
CleanupPeaks();
CleanupVales();
}
/**
* Handle Breaked Zones ...
*
* @param box: XBoxZone instance ...
* @param bar: XOHCL instance ...
*/
void HandleBreakedZone(
XBoxZone &box,
XOHCL &bar //
)
{
//
// Validate ...
if (!box.IsValid() ||
!mSupportInvertedZones //
)
{
return;
}
//
XBoxZone inverted;
int maxAllowedInversion = 1;
int count = ArraySize(box.breaks);
bool has = count < maxAllowedInversion;
if (!has)
{
return;
}
//
// Invert to Peak ...
if (box.IsBullish())
{
//
// Initialize Inverted Box ...
has = inverted.Init(
box.symbol,
box.period,
box.upper,
box.lower,
bar.time, // From ...
TimeCurrent(), // To ...
X_DIRECTION_BEARISH,
"i" + mPivotPrefix // Type ...
);
if (has)
{
//
Add(bar.time, inverted.breaks);
AddRef(inverted, peaks);
}
}
//
// Invert to Vale ...
else if (box.IsBearish())
{
//
// Initialize Inverted Box ...
has = inverted.Init(
box.symbol,
box.period,
box.upper,
box.lower,
bar.time, // From ...
TimeCurrent(), // To ...
X_DIRECTION_BULLISH,
"i" + mPivotPrefix // Type ...
);
if (has)
{
//
Add(bar.time, inverted.breaks);
AddRef(inverted, vales);
}
}
//
inverted.Clean();
}
};
//
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+301 -34
View File
@@ -30,13 +30,24 @@
XCAlert *eaAlert;
XCPOIDrawer *eaDrawer;
CArrayObj eaDrawnObjects;
XCPivotDetector *eaPivotDetector;
XCSessionDetector *eaSessionDetector;
//
XCPivotDetector *eaMajorPivotDetector;
XCPivotDetector *eaMinorPivotDetector;
//
// Last Processing Pivots Time ...
datetime eaLastPivotProcessing = NULL;
bool eaDrawMajorPivots = true;
bool eaDrawMinorPivots = true;
XPOIDrawConfig eaMajorPivotsDrawConfig;
XPOIDrawConfig eaMinorPivotsDrawConfig;
datetime eaLastMajorPivotProcessing = NULL;
datetime eaLastMinorPivotProcessing = NULL;
XPOIDrawConfig eaPointedMajorPivotsDrawConfig;
XPOIDrawConfig eaPointedMinorPivotsDrawConfig;
ENUM_X_DIRECTION eaMajorBias = X_DIRECTION_NONE;
ENUM_X_DIRECTION eaMinorBias = X_DIRECTION_NONE;
// #endregion
// #region Global Event Handlers ...
@@ -84,12 +95,19 @@ void OnDeinit(const int reason)
// Destroy Timer ...
// If Initialized ...
//
eaMajorPivotsDrawConfig.Clean();
eaMinorPivotsDrawConfig.Clean();
eaPointedMajorPivotsDrawConfig.Clean();
eaPointedMinorPivotsDrawConfig.Clean();
//
// Cleanup Resources ...
ZeroMemory(eaAlert);
ZeroMemory(eaDrawer);
ZeroMemory(eaPivotDetector);
ZeroMemory(eaSessionDetector);
ZeroMemory(eaMajorPivotDetector);
ZeroMemory(eaMinorPivotDetector);
}
/**
@@ -103,7 +121,12 @@ void OnTick()
//
// Process Pivot Detector ...
HandleProcessPviots();
HandleProcessMajorPviots();
HandleProcessMinorPviots();
//
// Detecting Bias ...
HanldeBiasDetection();
}
/**
@@ -142,8 +165,8 @@ bool InitializeRequirements()
// Initialize Alert ...
eaAlert = new XCAlert(
ShortName,
true, // Enable Alert ...
true, // Log Alert ...
false, // Enable Alert ...
false, // Log Alert ...
false, // Terminal Alert ...
false, // Mail Alert ...
false, // Push Alerts ...
@@ -179,20 +202,82 @@ bool InitializeRequirements()
}
//
// Initialize Pivot Detector ...
eaPivotDetector = new XCPivotDetector(
eaAlert // Alert ...
// Initialize Major Pivot Detector ...
eaMajorPivotDetector = new XCPivotDetector(
eaAlert, // Alert ...
"X121SDTMajor", // Pivot Prefix ...
false, // Support Inverted Zones ...
0 // Processable Zones ...
);
//
// Register Event Handlers ...
eaPivotDetector.AddOnPeakBreakedHandler(OnPeakBreakedHandler);
eaPivotDetector.AddOnValeBreakedHandler(OnValeBreakedHandler);
eaPivotDetector.AddOnPeakDetectedHandler(OnPeakDetectedHandler);
eaPivotDetector.AddOnValeDetectedHandler(OnValeDetectedHandler);
eaMajorPivotDetector.AddOnPeakBreakedHandler(OnMajorPeakBreakedHandler);
eaMajorPivotDetector.AddOnValeBreakedHandler(OnMajorValeBreakedHandler);
eaMajorPivotDetector.AddOnPeakDetectedHandler(OnMajorPeakDetectedHandler);
eaMajorPivotDetector.AddOnValeDetectedHandler(OnMajorValeDetectedHandler);
//
result = eaPivotDetector != NULL;
// Pivot Draw Config ...
eaMajorPivotsDrawConfig.zonesWidth = 2;
eaMajorPivotsDrawConfig.zonesFill = false;
eaMajorPivotsDrawConfig.ignoreZonesAt = true;
eaMajorPivotsDrawConfig.zonesStyle = STYLE_SOLID;
eaMajorPivotsDrawConfig.bullishColor = clrAqua;
eaMajorPivotsDrawConfig.bearishColor = clrMagenta;
//
// Pointed Pivot Draw Config ...
eaPointedMajorPivotsDrawConfig.zonesWidth = 2;
eaPointedMajorPivotsDrawConfig.zonesFill = false;
eaPointedMajorPivotsDrawConfig.ignoreZonesAt = true;
eaPointedMajorPivotsDrawConfig.zonesStyle = STYLE_SOLID;
eaPointedMajorPivotsDrawConfig.bullishColor = clrYellow;
eaPointedMajorPivotsDrawConfig.bearishColor = clrOrange;
//
result = eaMajorPivotDetector != NULL;
if (!result)
{
return result;
}
//
// Initialize Minor Pivot Detector ...
eaMinorPivotDetector = new XCPivotDetector(
eaAlert, // Alert ...
"X121SDTMinor", // Pivot Prefix ...
false, // Support Inverted Zones ...
0 // Processable Zones ...
);
//
// Register Event Handlers ...
eaMinorPivotDetector.AddOnPeakBreakedHandler(OnMinorPeakBreakedHandler);
eaMinorPivotDetector.AddOnValeBreakedHandler(OnMinorValeBreakedHandler);
eaMinorPivotDetector.AddOnPeakDetectedHandler(OnMinorPeakDetectedHandler);
eaMinorPivotDetector.AddOnValeDetectedHandler(OnMinorValeDetectedHandler);
//
// Pivot Draw Config ...
eaMinorPivotsDrawConfig.zonesWidth = 1;
eaMinorPivotsDrawConfig.zonesFill = false;
eaMinorPivotsDrawConfig.ignoreZonesAt = true;
eaMinorPivotsDrawConfig.bearishColor = clrRed;
eaMinorPivotsDrawConfig.bullishColor = clrLime;
eaMinorPivotsDrawConfig.zonesStyle = STYLE_DASHDOT;
//
// Pointed Pivot Draw Config ...
eaPointedMinorPivotsDrawConfig.zonesWidth = 2;
eaPointedMinorPivotsDrawConfig.zonesFill = false;
eaPointedMinorPivotsDrawConfig.ignoreZonesAt = true;
eaPointedMinorPivotsDrawConfig.bearishColor = clrOrange;
eaPointedMinorPivotsDrawConfig.bullishColor = clrYellow;
eaPointedMinorPivotsDrawConfig.zonesStyle = STYLE_DASHDOT;
//
result = eaMinorPivotDetector != NULL;
if (!result)
{
return result;
@@ -205,7 +290,7 @@ bool InitializeRequirements()
/**
* Process Pivots ...
*/
void HandleProcessPviots()
void HandleProcessMajorPviots()
{
//
// Initialize Pivot Processing Bar ...
@@ -213,7 +298,7 @@ void HandleProcessPviots()
bool has = bar.Init(
_Symbol,
PERIOD_H4,
1 // Last Completed 4H Bar ...
1 // Last Completed Bar ...
);
if (!has)
{
@@ -223,15 +308,18 @@ void HandleProcessPviots()
//
// Validate Passing Bar ...
has =
!IsXValid(eaLastPivotProcessing) ||
bar.time > eaLastPivotProcessing;
!IsXValid(eaLastMajorPivotProcessing) ||
bar.time > eaLastMajorPivotProcessing;
if (!has)
{
return;
}
//
eaPivotDetector.Process(
eaLastMajorPivotProcessing = bar.time;
//
eaMajorPivotDetector.Process(
bar, // XOHCL Bar ...
2, // Pivot Approvation Length ...
20 // Loopback ...
@@ -239,30 +327,141 @@ void HandleProcessPviots()
//
// Handle Draw Pivots ...
if (!eaDrawMajorPivots)
{
return;
}
//
XBoxZone tmps[];
CArrayObj *objects;
FillNotExists(
tmps, // Dest ...
eaPivotDetector.peaks, // Source ...
eaMajorPivotDetector.peaks, // Source ...
false // Force Clean ...
);
FillNotExists(
tmps, // Dest ...
eaPivotDetector.vales, // Source ...
eaMajorPivotDetector.vales, // Source ...
false // Force Clean ...
);
if (HasChild(tmps))
{
eaDrawer.DrawBoxes(
eaDrawer.DrawZones(
tmps, // Boxes ...
objects, // Objects to Hold ...
false // Ignore Type Name ...
eaMajorPivotsDrawConfig // Draw Config ...
);
}
XClean(tmps);
AddObjects(objects, eaDrawnObjects);
if (eaDrawnObjects.Total() > 0) {
DebugBreak();
}
/**
* Process Pivots ...
*/
void HandleProcessMinorPviots()
{
//
// Initialize Pivot Processing Bar ...
XOHCL bar;
bool has = bar.Init(
_Symbol,
PERIOD_M15,
1 // Last Completed Bar ...
);
if (!has)
{
return;
}
//
// Validate Passing Bar ...
has =
!IsXValid(eaLastMinorPivotProcessing) ||
bar.time > eaLastMinorPivotProcessing;
if (!has)
{
return;
}
//
eaLastMinorPivotProcessing = bar.time;
//
eaMinorPivotDetector.Process(
bar, // XOHCL Bar ...
5, // Pivot Approvation Length ...
40 // Loopback ...
);
//
// Handle Draw Pivots ...
if (!eaDrawMinorPivots)
{
return;
}
//
XBoxZone tmps[];
FillNotExists(
tmps, // Dest ...
eaMinorPivotDetector.peaks, // Source ...
false // Force Clean ...
);
FillNotExists(
tmps, // Dest ...
eaMinorPivotDetector.vales, // Source ...
false // Force Clean ...
);
if (HasChild(tmps))
{
eaDrawer.DrawZones(
tmps, // Boxes ...
eaMinorPivotsDrawConfig // Draw Config ...
);
}
XClean(tmps);
}
/**
* Detect Bias based on Pivots ...
*/
void HanldeBiasDetection()
{
//
bool has = false;
//
// Major Bias ...
has =
eaMajorPivotDetector.HasPeaks() &&
eaMajorPivotDetector.HasVales();
if (has)
{
//
int youngestPeakIDX = eaMajorPivotDetector.GetYoungestPeak();
int youngestValeIDX = eaMajorPivotDetector.GetYoungestVale();
has =
IsValidIndex(youngestPeakIDX) &&
IsValidIndex(youngestValeIDX);
if (has)
{
//
eaMajorBias =
eaMajorPivotDetector.peaks[youngestPeakIDX].from > eaMajorPivotDetector.vales[youngestValeIDX].from
? X_DIRECTION_BEARISH
: eaMajorPivotDetector.vales[youngestValeIDX].from > eaMajorPivotDetector.peaks[youngestPeakIDX].from
? X_DIRECTION_BULLISH
: X_DIRECTION_NONE;
}
}
//
if (HasDirection(eaMajorBias))
{
Comment("Major Bias: ", ToXString(eaMajorBias));
}
else
{
Comment("");
}
}
// #endregion
@@ -275,7 +474,7 @@ void HandleProcessPviots()
*
* @param box: XBoxZone instance ...
*/
void OnPeakBreakedHandler(XBoxZone &box)
void OnMajorPeakBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
@@ -285,7 +484,7 @@ void OnPeakBreakedHandler(XBoxZone &box)
*
* @param box: XBoxZone instance ...
*/
void OnValeBreakedHandler(XBoxZone &box)
void OnMajorValeBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
@@ -295,9 +494,16 @@ void OnValeBreakedHandler(XBoxZone &box)
*
* @param box: XBoxZone instance ...
*/
void OnPeakDetectedHandler(XBoxZone &box)
void OnMajorPeakDetectedHandler(XBoxZone &box)
{
// DebugBreak();
//
eaDrawer.DrawZone(
box, //
eaPointedMajorPivotsDrawConfig //
);
//
DebugBreak();
}
/**
@@ -305,10 +511,71 @@ void OnPeakDetectedHandler(XBoxZone &box)
*
* @param box: XBoxZone instance ...
*/
void OnValeDetectedHandler(XBoxZone &box)
void OnMajorValeDetectedHandler(XBoxZone &box)
{
//
eaDrawer.DrawZone(
box, //
eaPointedMajorPivotsDrawConfig //
);
//
DebugBreak();
}
/**
* Calls when a Peak Breaked ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorPeakBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
/**
* Calls when a Vale Breaked ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorValeBreakedHandler(XBoxZone &box)
{
// DebugBreak();
}
/**
* Calls when a New Peak Detected ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorPeakDetectedHandler(XBoxZone &box)
{
//
eaDrawer.DrawZone(
box, //
eaPointedMinorPivotsDrawConfig //
);
//
DebugBreak();
}
/**
* Calls when a New Vale Detected ...
*
* @param box: XBoxZone instance ...
*/
void OnMinorValeDetectedHandler(XBoxZone &box)
{
//
eaDrawer.DrawZone(
box, //
eaPointedMinorPivotsDrawConfig //
);
//
DebugBreak();
}
// #endregion
// #region Session Detector Event Handlers ...
@@ -3722,6 +3722,125 @@ bool IsBoxValid(
return result;
}
/**
* Validate a Box based on Price ...
*
* @param box: XBoxZone instance, box to Validate ...
* @param barIndex: int, Start Validating Bar's Index ...
* @param pType: ENUM_X_BOUNDARY_PRICE, Price Type for Validation ...
*
* @return ( bool )
*/
bool IsBoxValid(
XBoxZone &box,
int barIndex = 0,
ENUM_X_BOUNDARY_PRICE pType = X_BOUNDARY_PRICE_UP_DOWN //
)
{
//
bool result = false;
//
// Normalize Bar Index ...
barIndex = NormalizeInt(barIndex, 0);
//
// Validaet ...
result =
box.IsValid() &&
IsXValid(pType);
if (!result)
{
return result;
}
//
bool isBullish = box.IsBullish();
//
int fromIDX = box.FromIndex();
result =
IsValidIndex(fromIDX) &&
barIndex < fromIDX;
if (!result)
{
return result;
}
//
// Loop through ...
XOHCL iBar;
bool has = false;
double appliedPrice = EMPTY_VALUE;
for (int i = barIndex; i < fromIDX; i++)
{
//
// Initialize Bar ...
iBar.Clean();
has = iBar.Init(box.symbol, box.period, i);
if (!has)
{
//
result = false;
break;
}
//
// Calculate Applied Price ...
switch (pType)
{
//
case X_BOUNDARY_PRICE_UP_DOWN:
//
appliedPrice =
isBullish
? iBar.GetDown()
: iBar.GetUp();
break;
//
case X_BOUNDARY_PRICE_HIGH_LOW:
//
appliedPrice =
isBullish
? iBar.low
: iBar.high;
break;
//
default:
appliedPrice = EMPTY_VALUE;
break;
}
has = NotEmptyZero(appliedPrice);
if (!has)
{
//
result = false;
break;
}
//
has =
has &&
result &&
(isBullish
? appliedPrice >= box.lower
: appliedPrice <= box.upper);
if (!has) {
//
result = false;
break;
}
//
iBar.Clean();
}
//
return result;
}
//
void SortBoxes(
XBoxZone &items[],
+298
View File
@@ -0,0 +1,298 @@
#!/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 = "x121XSDT";
const allowedPatterns = [
//
// Base Pilot Files ...
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.pivot-detector.class.mq5$/i
},
{
kind: "file",
mode: "allow",
match: "name",
pattern: /^x-saherelm.x-pivot-detector.test.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