UNPKG

sicua

Version:

A tool for analyzing project structure and dependencies

155 lines (154 loc) 6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FunctionFilter = void 0; const typescript_1 = __importDefault(require("typescript")); const nodeTypeGuards_1 = require("../ast/nodeTypeGuards"); class FunctionFilter { constructor() { /** * Configuration for function filtering */ this.config = { // Minimum size thresholds minLines: 5, minStatements: 3, // Complexity indicators minCyclomaticComplexity: 2, // Function characteristics excludedPrefixes: ["get", "set", "handle", "on"], excludedSuffixes: ["Handler", "Listener", "Callback"], // Size limits maxBodyLength: 2000, // characters // Patterns that indicate business logic businessLogicPatterns: [ /calculate/i, /process/i, /validate/i, /transform/i, /convert/i, /analyze/i, /format/i, /normalize/i, /aggregate/i, /compute/i, ], }; } /** * Determines if a function should be included in the analysis */ shouldIncludeFunction(node, functionName) { // Skip functions with excluded prefixes/suffixes if (this.hasExcludedNaming(functionName)) { return false; } if (nodeTypeGuards_1.NodeTypeGuards.isJsxComponent(node)) { return false; } // Get function body text const body = this.getFunctionBody(node); if (!body) return false; // Check minimum size requirements if (!this.meetsMinimumSize(body)) { return false; } // Check maximum size limit if (body.length > this.config.maxBodyLength) { return false; } // Calculate cyclomatic complexity if (!this.hasSignificantComplexity(node)) { return false; } // Check for business logic patterns if (this.hasBusinessLogicPatterns(functionName, body)) { return true; } // Check for data processing indicators if (this.hasDataProcessingIndicators(body)) { return true; } return false; } hasExcludedNaming(functionName) { const lowerName = functionName.toLowerCase(); return (this.config.excludedPrefixes.some((prefix) => lowerName.startsWith(prefix)) || this.config.excludedSuffixes.some((suffix) => functionName.endsWith(suffix))); } getFunctionBody(node) { if (typescript_1.default.isFunctionDeclaration(node) || typescript_1.default.isMethodDeclaration(node) || typescript_1.default.isArrowFunction(node)) { return node.body?.getText() || null; } return null; } meetsMinimumSize(body) { const lines = body.split("\n").filter((line) => line.trim().length > 0); const statements = body.split(";").filter((stmt) => stmt.trim().length > 0); return (lines.length >= this.config.minLines && statements.length >= this.config.minStatements); } hasSignificantComplexity(node) { let complexity = 1; function countComplexity(n) { switch (n.kind) { case typescript_1.default.SyntaxKind.IfStatement: case typescript_1.default.SyntaxKind.ConditionalExpression: case typescript_1.default.SyntaxKind.ForStatement: case typescript_1.default.SyntaxKind.ForInStatement: case typescript_1.default.SyntaxKind.ForOfStatement: case typescript_1.default.SyntaxKind.WhileStatement: case typescript_1.default.SyntaxKind.DoStatement: case typescript_1.default.SyntaxKind.CaseClause: case typescript_1.default.SyntaxKind.CatchClause: complexity++; break; case typescript_1.default.SyntaxKind.BinaryExpression: const binExpr = n; if (binExpr.operatorToken.kind === typescript_1.default.SyntaxKind.AmpersandAmpersandToken || binExpr.operatorToken.kind === typescript_1.default.SyntaxKind.BarBarToken) { complexity++; } break; } typescript_1.default.forEachChild(n, countComplexity); } countComplexity(node); return complexity >= this.config.minCyclomaticComplexity; } hasBusinessLogicPatterns(functionName, body) { return this.config.businessLogicPatterns.some((pattern) => pattern.test(functionName) || pattern.test(body)); } hasDataProcessingIndicators(body) { // Check for array methods that indicate data processing const dataProcessingMethods = [ ".map(", ".filter(", ".reduce(", ".sort(", ".some(", ".every(", ".find(", ]; // Check for mathematical operations const mathOperations = ["Math.", "Number(", "parseInt(", "parseFloat("]; // Check for data transformation indicators const dataTransformations = [ "JSON.parse(", "JSON.stringify(", "Object.keys(", "Object.values(", "Object.entries(", ]; return (dataProcessingMethods.some((method) => body.includes(method)) || mathOperations.some((op) => body.includes(op)) || dataTransformations.some((transform) => body.includes(transform))); } } exports.FunctionFilter = FunctionFilter;