UNPKG

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
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 };