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

223 lines 7.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AstContextChecker = void 0; const ast_node_types_1 = require("../../shared/constants/ast-node-types"); /** * AST context checker for analyzing node contexts * * Provides reusable methods to check if a node is in specific contexts * like exports, type declarations, function calls, etc. */ class AstContextChecker { /** * Checks if node is in an exported constant with "as const" */ isInExportedConstant(node) { let current = node.parent; while (current) { if (current.type === "export_statement") { if (this.checkExportedConstant(current)) { return true; } } current = current.parent; } return false; } /** * Helper to check if export statement contains "as const" */ checkExportedConstant(exportNode) { const declaration = exportNode.childForFieldName(ast_node_types_1.AST_FIELD_NAMES.DECLARATION); if (!declaration) { return false; } if (declaration.type !== "lexical_declaration") { return false; } const declarator = this.findDescendant(declaration, ast_node_types_1.AST_VARIABLE_TYPES.VARIABLE_DECLARATOR); if (!declarator) { return false; } const value = declarator.childForFieldName(ast_node_types_1.AST_FIELD_NAMES.VALUE); if (value?.type !== "as_expression") { return false; } const asType = value.children.find((c) => c.type === ast_node_types_1.AST_MODIFIER_TYPES.CONST); return asType !== undefined; } /** * Checks if node is in a type context (union type, type alias, interface) */ isInTypeContext(node) { let current = node.parent; while (current) { if (current.type === "type_alias_declaration" || current.type === "union_type" || current.type === "literal_type" || current.type === "interface_declaration" || current.type === "type_annotation") { return true; } current = current.parent; } return false; } /** * Checks if node is in an import statement or import() call */ isInImportStatement(node) { let current = node.parent; while (current) { if (current.type === "import_statement") { return true; } if (current.type === "call_expression") { const functionNode = current.childForFieldName(ast_node_types_1.AST_FIELD_NAMES.FUNCTION) || current.children.find((c) => c.type === ast_node_types_1.AST_IDENTIFIER_TYPES.IDENTIFIER || c.type === ast_node_types_1.AST_IDENTIFIER_TYPES.IMPORT); if (functionNode && (functionNode.text === "import" || functionNode.type === ast_node_types_1.AST_IDENTIFIER_TYPES.IMPORT)) { return true; } } current = current.parent; } return false; } /** * Checks if node is in a test description (test(), describe(), it()) */ isInTestDescription(node) { let current = node.parent; while (current) { if (current.type === "call_expression") { const callee = current.childForFieldName("function"); if (callee?.type === "identifier") { const funcName = callee.text; if (funcName === "test" || funcName === "describe" || funcName === "it" || funcName === "expect") { return true; } } } current = current.parent; } return false; } /** * Checks if node is in a console.log or console.error call */ isInConsoleCall(node) { let current = node.parent; while (current) { if (current.type === "call_expression") { const callee = current.childForFieldName("function"); if (callee?.type === "member_expression") { const object = callee.childForFieldName("object"); const property = callee.childForFieldName("property"); if (object?.text === "console" && property && (property.text === "log" || property.text === "error" || property.text === "warn")) { return true; } } } current = current.parent; } return false; } /** * Checks if node is in a Symbol() call */ isInSymbolCall(node) { let current = node.parent; while (current) { if (current.type === "call_expression") { const callee = current.childForFieldName("function"); if (callee?.type === "identifier" && callee.text === "Symbol") { return true; } } current = current.parent; } return false; } /** * Checks if node is in a typeof check */ isInTypeofCheck(node) { let current = node.parent; while (current) { if (current.type === "binary_expression") { const left = current.childForFieldName("left"); const right = current.childForFieldName("right"); if (left?.type === "unary_expression") { const operator = left.childForFieldName("operator"); if (operator?.text === "typeof") { return true; } } if (right?.type === "unary_expression") { const operator = right.childForFieldName("operator"); if (operator?.text === "typeof") { return true; } } } current = current.parent; } return false; } /** * Checks if parent is a call expression with specific function names */ isInCallExpression(parent, functionNames) { if (parent.type === "arguments") { const callExpr = parent.parent; if (callExpr?.type === "call_expression") { const callee = callExpr.childForFieldName("function"); if (callee?.type === "identifier") { return functionNames.includes(callee.text); } } } return false; } /** * Gets context text around a node */ getNodeContext(node) { let current = node; while (current && current.type !== "lexical_declaration" && current.type !== "pair" && current.type !== "call_expression" && current.type !== "return_statement") { current = current.parent; } return current ? current.text.toLowerCase() : ""; } /** * Finds a descendant node by type */ findDescendant(node, type) { if (node.type === type) { return node; } for (const child of node.children) { const result = this.findDescendant(child, type); if (result) { return result; } } return null; } } exports.AstContextChecker = AstContextChecker; //# sourceMappingURL=AstContextChecker.js.map