sicua
Version:
A tool for analyzing project structure and dependencies
155 lines (154 loc) • 6 kB
JavaScript
;
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;