UNPKG

@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.87 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AstVariableNameAnalyzer = void 0; const NamingViolation_1 = require("../../../domain/value-objects/NamingViolation"); const constants_1 = require("../../../shared/constants"); const rules_1 = require("../../../shared/constants/rules"); const detectorPatterns_1 = require("../../constants/detectorPatterns"); /** * AST-based analyzer for detecting variable naming violations * * Analyzes variable declarations to ensure proper naming conventions: * - Regular variables: camelCase * - Constants (exported UPPER_CASE): UPPER_SNAKE_CASE * - Class properties: camelCase * - Private properties with underscore prefix are allowed */ class AstVariableNameAnalyzer { /** * Analyzes a variable declaration node */ analyze(node, layer, filePath, _lines) { const variableNodeTypes = [ constants_1.AST_VARIABLE_TYPES.VARIABLE_DECLARATOR, constants_1.AST_VARIABLE_TYPES.REQUIRED_PARAMETER, constants_1.AST_VARIABLE_TYPES.OPTIONAL_PARAMETER, constants_1.AST_VARIABLE_TYPES.PUBLIC_FIELD_DEFINITION, constants_1.AST_VARIABLE_TYPES.PROPERTY_SIGNATURE, ]; if (!variableNodeTypes.includes(node.type)) { return null; } const nameNode = node.childForFieldName(constants_1.AST_FIELD_NAMES.NAME); if (!nameNode) { return null; } if (this.isDestructuringPattern(nameNode)) { return null; } const variableName = nameNode.text; const lineNumber = nameNode.startPosition.row + 1; if (variableName.startsWith("_")) { return null; } const isConstant = this.isConstantVariable(node); if (isConstant) { if (!/^[A-Z][A-Z0-9_]*$/.test(variableName)) { return NamingViolation_1.NamingViolation.create(variableName, rules_1.NAMING_VIOLATION_TYPES.WRONG_CASE, layer, `${filePath}:${String(lineNumber)}`, detectorPatterns_1.NAMING_ERROR_MESSAGES.CONSTANT_UPPER_SNAKE_CASE, variableName, detectorPatterns_1.NAMING_ERROR_MESSAGES.USE_UPPER_SNAKE_CASE_CONSTANT); } } else { if (!/^[a-z][a-zA-Z0-9]*$/.test(variableName)) { return NamingViolation_1.NamingViolation.create(variableName, rules_1.NAMING_VIOLATION_TYPES.WRONG_CASE, layer, `${filePath}:${String(lineNumber)}`, detectorPatterns_1.NAMING_ERROR_MESSAGES.VARIABLE_CAMEL_CASE, variableName, detectorPatterns_1.NAMING_ERROR_MESSAGES.USE_CAMEL_CASE_VARIABLE); } } return null; } /** * Checks if node is a destructuring pattern (object or array) */ isDestructuringPattern(node) { return (node.type === constants_1.AST_PATTERN_TYPES.OBJECT_PATTERN || node.type === constants_1.AST_PATTERN_TYPES.ARRAY_PATTERN); } /** * Checks if a variable is a constant (exported UPPER_CASE) */ isConstantVariable(node) { const variableName = node.childForFieldName(constants_1.AST_FIELD_NAMES.NAME)?.text; if (!variableName || !/^[A-Z]/.test(variableName)) { return false; } if (node.type === constants_1.AST_VARIABLE_TYPES.PUBLIC_FIELD_DEFINITION || node.type === constants_1.AST_FIELD_TYPES.FIELD_DEFINITION) { return this.hasConstModifiers(node); } let current = node.parent; while (current) { if (current.type === constants_1.AST_STATEMENT_TYPES.LEXICAL_DECLARATION) { const firstChild = current.child(0); if (firstChild?.type === constants_1.AST_MODIFIER_TYPES.CONST) { return true; } } if (current.type === constants_1.AST_VARIABLE_TYPES.PUBLIC_FIELD_DEFINITION || current.type === constants_1.AST_FIELD_TYPES.FIELD_DEFINITION) { return this.hasConstModifiers(current); } current = current.parent; } return false; } /** * Checks if field has readonly or static modifiers (indicating a constant) */ hasConstModifiers(fieldNode) { for (let i = 0; i < fieldNode.childCount; i++) { const child = fieldNode.child(i); const childText = child?.text; if (child?.type === constants_1.AST_MODIFIER_TYPES.READONLY || child?.type === constants_1.AST_MODIFIER_TYPES.STATIC || childText === constants_1.AST_MODIFIER_TYPES.READONLY || childText === constants_1.AST_MODIFIER_TYPES.STATIC) { return true; } } return false; } } exports.AstVariableNameAnalyzer = AstVariableNameAnalyzer; //# sourceMappingURL=AstVariableNameAnalyzer.js.map