@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
110 lines • 4.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.HardcodeDetector = void 0;
const constants_1 = require("../../shared/constants");
const CodeParser_1 = require("../parsers/CodeParser");
const AstBooleanAnalyzer_1 = require("../strategies/AstBooleanAnalyzer");
const AstConfigObjectAnalyzer_1 = require("../strategies/AstConfigObjectAnalyzer");
const AstContextChecker_1 = require("../strategies/AstContextChecker");
const AstNumberAnalyzer_1 = require("../strategies/AstNumberAnalyzer");
const AstStringAnalyzer_1 = require("../strategies/AstStringAnalyzer");
const ConstantsFileChecker_1 = require("../strategies/ConstantsFileChecker");
const AstTreeTraverser_1 = require("./AstTreeTraverser");
/**
* Detects hardcoded values (magic numbers and strings) in TypeScript/JavaScript code
*
* This detector uses Abstract Syntax Tree (AST) analysis via tree-sitter to identify
* configuration values, URLs, timeouts, ports, and other constants that should be
* extracted to configuration files. AST-based detection provides more accurate context
* understanding and reduces false positives compared to regex-based approaches.
*
* The detector uses a modular architecture with specialized components:
* - AstContextChecker: Checks if nodes are in specific contexts (exports, types, etc.)
* - AstNumberAnalyzer: Analyzes number literals to detect magic numbers
* - AstStringAnalyzer: Analyzes string literals to detect magic strings
* - AstTreeTraverser: Traverses the AST and coordinates analyzers
*
* @example
* ```typescript
* const detector = new HardcodeDetector()
* const code = `
* const timeout = 5000
* const url = "http://localhost:8080"
* `
* const violations = detector.detectAll(code, 'config.ts')
* // Returns array of HardcodedValue objects
* ```
*/
class HardcodeDetector {
constantsChecker;
parser;
traverser;
constructor() {
this.constantsChecker = new ConstantsFileChecker_1.ConstantsFileChecker();
this.parser = new CodeParser_1.CodeParser();
const contextChecker = new AstContextChecker_1.AstContextChecker();
const numberAnalyzer = new AstNumberAnalyzer_1.AstNumberAnalyzer(contextChecker);
const stringAnalyzer = new AstStringAnalyzer_1.AstStringAnalyzer(contextChecker);
const booleanAnalyzer = new AstBooleanAnalyzer_1.AstBooleanAnalyzer(contextChecker);
const configObjectAnalyzer = new AstConfigObjectAnalyzer_1.AstConfigObjectAnalyzer(contextChecker);
this.traverser = new AstTreeTraverser_1.AstTreeTraverser(numberAnalyzer, stringAnalyzer, booleanAnalyzer, configObjectAnalyzer);
}
/**
* Detects all hardcoded values (both numbers and strings) in the given code
*
* @param code - Source code to analyze
* @param filePath - File path for context (used in violation reports)
* @returns Array of detected hardcoded values with suggestions
*/
detectAll(code, filePath) {
if (this.constantsChecker.isConstantsFile(filePath)) {
return [];
}
const tree = this.parseCode(code, filePath);
return this.traverser.traverse(tree, code);
}
/**
* Detects magic numbers in code
*
* @param code - Source code to analyze
* @param filePath - File path (used for constants file check)
* @returns Array of detected magic numbers
*/
detectMagicNumbers(code, filePath) {
if (this.constantsChecker.isConstantsFile(filePath)) {
return [];
}
const tree = this.parseCode(code, filePath);
const allViolations = this.traverser.traverse(tree, code);
return allViolations.filter((v) => v.isMagicNumber());
}
/**
* Detects magic strings in code
*
* @param code - Source code to analyze
* @param filePath - File path (used for constants file check)
* @returns Array of detected magic strings
*/
detectMagicStrings(code, filePath) {
if (this.constantsChecker.isConstantsFile(filePath)) {
return [];
}
const tree = this.parseCode(code, filePath);
const allViolations = this.traverser.traverse(tree, code);
return allViolations.filter((v) => v.isMagicString());
}
/**
* Parses code based on file extension
*/
parseCode(code, filePath) {
if (filePath.endsWith(constants_1.FILE_EXTENSIONS.TYPESCRIPT_JSX)) {
return this.parser.parseTsx(code);
}
else if (filePath.endsWith(constants_1.FILE_EXTENSIONS.TYPESCRIPT)) {
return this.parser.parseTypeScript(code);
}
return this.parser.parseJavaScript(code);
}
}
exports.HardcodeDetector = HardcodeDetector;
//# sourceMappingURL=HardcodeDetector.js.map