atikin-coderank
Version:
Analyze JavaScript/TypeScript code and rank functions by complexity (cyclomatic + length + depth). Created by Atikin Verse.
77 lines (66 loc) • 2.42 kB
JavaScript
const fs = require('fs');
const path = require('path');
const esprima = require('esprima');
function getFunctionComplexity(fnBody) {
let complexity = 1, depth = 0, maxDepth = 0;
function traverse(node, level = 0) {
if (!node || typeof node !== 'object') return;
if (['IfStatement', 'ForStatement', 'WhileStatement', 'SwitchCase', 'ConditionalExpression'].includes(node.type)) {
complexity++;
}
if (['BlockStatement', 'FunctionDeclaration', 'FunctionExpression'].includes(node.type)) {
level++;
if (level > maxDepth) maxDepth = level;
}
for (let key in node) {
if (Array.isArray(node[key])) {
node[key].forEach(n => traverse(n, level));
} else {
traverse(node[key], level);
}
}
}
traverse(fnBody);
return { complexity, depth: maxDepth };
}
function analyzeFile(filePath) {
const code = fs.readFileSync(filePath, 'utf8');
const ast = esprima.parseScript(code, { loc: true });
const results = [];
function visit(node) {
if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
const name = node.id ? node.id.name : 'anonymous';
const length = node.loc.end.line - node.loc.start.line + 1;
const { complexity, depth } = getFunctionComplexity(node.body);
results.push({
file: path.basename(filePath),
functionName: name,
lines: length,
cyclomaticComplexity: complexity,
nestingDepth: depth
});
}
for (let key in node) {
const child = node[key];
if (Array.isArray(child)) {
child.forEach(visit);
} else if (child && typeof child.type === 'string') {
visit(child);
}
}
}
visit(ast);
return results;
}
function analyzeProject(dirPath) {
const results = [];
const files = fs.readdirSync(dirPath);
files.forEach(file => {
const fullPath = path.join(dirPath, file);
if (fs.statSync(fullPath).isFile() && (file.endsWith('.js') || file.endsWith('.ts'))) {
results.push(...analyzeFile(fullPath));
}
});
console.log(JSON.stringify(results, null, 2));
}
module.exports = { analyzeProject };