@samiyev/guardian
Version:
Research-backed code quality guardian for AI-assisted development. Detects hardcodes, secrets, circular deps, framework leaks, entity exposure, and 9 architecture violations. Enforces Clean Architecture/DDD principles. Works with GitHub Copilot, Cursor, W
90 lines • 3.33 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AstTreeTraverser = void 0;
const HardcodedValue_1 = require("../../domain/value-objects/HardcodedValue");
/**
* AST tree traverser for detecting hardcoded values
*
* Walks through the Abstract Syntax Tree and uses analyzers
* to detect hardcoded numbers, strings, booleans, and configuration objects.
* Also tracks value usage to identify "almost constants" - values used 2+ times.
*/
class AstTreeTraverser {
numberAnalyzer;
stringAnalyzer;
booleanAnalyzer;
configObjectAnalyzer;
constructor(numberAnalyzer, stringAnalyzer, booleanAnalyzer, configObjectAnalyzer) {
this.numberAnalyzer = numberAnalyzer;
this.stringAnalyzer = stringAnalyzer;
this.booleanAnalyzer = booleanAnalyzer;
this.configObjectAnalyzer = configObjectAnalyzer;
}
/**
* Traverses the AST tree and collects hardcoded values
*/
traverse(tree, sourceCode) {
const results = [];
const lines = sourceCode.split("\n");
const cursor = tree.walk();
this.visit(cursor, lines, results);
this.markAlmostConstants(results);
return results;
}
/**
* Marks values that appear multiple times in the same file
*/
markAlmostConstants(results) {
const valueUsage = new Map();
for (const result of results) {
const key = `${result.type}:${String(result.value)}`;
valueUsage.set(key, (valueUsage.get(key) || 0) + 1);
}
for (let i = 0; i < results.length; i++) {
const result = results[i];
const key = `${result.type}:${String(result.value)}`;
const count = valueUsage.get(key) || 0;
if (count >= 2 && !result.withinFileUsageCount) {
results[i] = HardcodedValue_1.HardcodedValue.create(result.value, result.type, result.line, result.column, result.context, result.valueType, result.duplicateLocations, count);
}
}
}
/**
* Recursively visits AST nodes
*/
visit(cursor, lines, results) {
const node = cursor.currentNode;
if (node.type === "object") {
const violation = this.configObjectAnalyzer.analyze(node, lines);
if (violation) {
results.push(violation);
}
}
else if (node.type === "number") {
const violation = this.numberAnalyzer.analyze(node, lines);
if (violation) {
results.push(violation);
}
}
else if (node.type === "string") {
const violation = this.stringAnalyzer.analyze(node, lines);
if (violation) {
results.push(violation);
}
}
else if (node.type === "true" || node.type === "false") {
const violation = this.booleanAnalyzer.analyze(node, lines);
if (violation) {
results.push(violation);
}
}
if (cursor.gotoFirstChild()) {
do {
this.visit(cursor, lines, results);
} while (cursor.gotoNextSibling());
cursor.gotoParent();
}
}
}
exports.AstTreeTraverser = AstTreeTraverser;
//# sourceMappingURL=AstTreeTraverser.js.map