#!/usr/bin/env node
/**
* π€ AI Code Review - 2025 Standards
*
* This script demonstrates the 2025 approach where AI performs comprehensive
* code reviews automatically. In a full implementation, this would use Claude
* or GPT-4 to analyze code changes and provide detailed feedback.
*
* Current implementation: Basic analysis framework
* Future: Full AI-powered code review with suggestions
*/
const fs = require('fs');
const path = require('path');
class AICodeReviewer {
constructor() {
this.projectRoot = path.join(__dirname, '..');
this.srcDir = path.join(this.projectRoot, 'src');
this.backendDir = path.join(this.projectRoot, 'backend');
}
async reviewCodebase() {
console.log('π€ AI Code Review - 2025 Standards');
console.log('===================================');
console.log('π Productivity Impact: 10x for average devs, 20x for novices');
console.log('π§ Domain experts (scientific/maths background): Jobs safe until 2027');
console.log('');
const results = {
overall_score: 0,
issues: [],
strengths: [],
recommendations: [],
metrics: {}
};
// Analyze backend code
console.log('π Analyzing backend code...');
const backendResults = await this.analyzeBackend();
results.issues.push(...backendResults.issues);
results.strengths.push(...backendResults.strengths);
// Analyze frontend code
console.log('π Analyzing frontend code...');
const frontendResults = await this.analyzeFrontend();
results.issues.push(...frontendResults.issues);
results.strengths.push(...frontendResults.strengths);
// Calculate overall score
results.overall_score = this.calculateOverallScore(results.issues);
results.metrics = this.calculateMetrics(results.issues);
// Generate recommendations
results.recommendations = await this.generateRecommendations(results);
// Display results
this.displayResults(results);
return results;
}
async analyzeBackend() {
const issues = [];
const strengths = [];
// Check Python files
const pythonFiles = this.getFiles(this.backendDir, '.py');
for (const file of pythonFiles) {
const content = fs.readFileSync(file, 'utf8');
const relativePath = path.relative(this.projectRoot, file);
// AI would perform sophisticated analysis here
// For now, basic checks
// Check for imports
if (!content.includes('import') && !content.includes('from')) {
issues.push({
severity: 'minor',
category: 'structure',
description: 'File has no imports',
file: relativePath,
line: 1,
suggestion: 'Consider adding necessary imports'
});
}
// Check for docstrings
if (content.includes('def ') && !content.includes('"""')) {
issues.push({
severity: 'suggestion',
category: 'documentation',
description: 'Function without docstring',
file: relativePath,
line: content.indexOf('def ') + 1,
suggestion: 'Add docstring to function'
});
}
// Check for error handling
if (content.includes('try:') && !content.includes('except:')) {
issues.push({
severity: 'major',
category: 'error_handling',
description: 'Try block without except',
file: relativePath,
line: content.indexOf('try:') + 1,
suggestion: 'Add proper exception handling'
});
}
}
// Check for FastAPI structure
if (pythonFiles.some(f => f.includes('main.py'))) {
strengths.push('FastAPI application structure detected');
}
return { issues, strengths };
}
async analyzeFrontend() {
const issues = [];
const strengths = [];
// Check TypeScript/React files
const tsFiles = this.getFiles(this.srcDir, '.ts', '.tsx');
for (const file of tsFiles) {
const content = fs.readFileSync(file, 'utf8');
const relativePath = path.relative(this.projectRoot, file);
// Check for TypeScript types
if (content.includes('function') && !content.includes(':') && !content.includes('any')) {
issues.push({
severity: 'suggestion',
category: 'typescript',
description: 'Function parameter without type annotation',
file: relativePath,
line: content.indexOf('function') + 1,
suggestion: 'Add TypeScript type annotations'
});
}
// Check for React keys in lists
if (content.includes('.map(') && !content.includes('key=')) {
issues.push({
severity: 'minor',
category: 'react',
description: 'React list without key prop',
file: relativePath,
line: content.indexOf('.map(') + 1,
suggestion: 'Add key prop to list items'
});
}
// Check for console.log in production code
if (content.includes('console.log')) {
issues.push({
severity: 'suggestion',
category: 'logging',
description: 'console.log found in code',
file: relativePath,
line: content.indexOf('console.log') + 1,
suggestion: 'Use proper logging or remove debug statements'
});
}
}
// Check for Next.js structure
if (tsFiles.some(f => f.includes('page.tsx'))) {
strengths.push('Next.js App Router structure detected');
}
return { issues, strengths };
}
getFiles(dir, ...extensions) {
const files = [];
function scan(directory) {
if (!fs.existsSync(directory)) return;
const items = fs.readdirSync(directory);
for (const item of items) {
const fullPath = path.join(directory, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory() && !item.startsWith('.') && item !== 'node_modules') {
scan(fullPath);
} else if (stat.isFile() && extensions.some(ext => item.endsWith(ext))) {
files.push(fullPath);
}
}
}
scan(dir);
return files;
}
calculateOverallScore(issues) {
if (issues.length === 0) return 10;
const weights = {
critical: 5,
major: 3,
minor: 1,
suggestion: 0.5
};
const totalPenalty = issues.reduce((sum, issue) =>
sum + weights[issue.severity] || 0, 0
);
const score = Math.max(0, 10 - totalPenalty);
return Math.round(score * 10) / 10;
}
calculateMetrics(issues) {
const severityCounts = {
critical: 0,
major: 0,
minor: 0,
suggestion: 0
};
const categoryCounts = {};
for (const issue of issues) {
severityCounts[issue.severity]++;
categoryCounts[issue.category] = (categoryCounts[issue.category] || 0) + 1;
}
return {
total_issues: issues.length,
severity_breakdown: severityCounts,
category_breakdown: categoryCounts,
issues_per_file: issues.length / Math.max(1, this.getFiles(this.srcDir, '.ts', '.tsx', '.js', '.jsx').length +
this.getFiles(this.backendDir, '.py').length)
};
}
async generateRecommendations(results) {
const recommendations = [];
// Based on metrics, generate AI recommendations
if (results.metrics.severity_breakdown.critical > 0) {
recommendations.push('π¨ Address critical issues immediately - they may affect functionality');
}
if (results.metrics.category_breakdown.typescript > 5) {
recommendations.push('π§ Consider enabling strict TypeScript mode for better type safety');
}
if (results.metrics.category_breakdown.error_handling > 3) {
recommendations.push('π‘οΈ Improve error handling patterns across the codebase');
}
if (results.overall_score < 7) {
recommendations.push('π Schedule code quality improvement session with development team');
}
if (results.overall_score > 9) {
recommendations.push('π Excellent code quality! Consider documenting best practices');
}
return recommendations;
}
displayResults(results) {
console.log('\nπ Code Review Results');
console.log('=====================');
console.log(`\nπ Overall Score: ${results.overall_score}/10`);
console.log('\nπ Metrics:');
console.log(` Total Issues: ${results.metrics.total_issues}`);
console.log(` Critical: ${results.metrics.severity_breakdown.critical}`);
console.log(` Major: ${results.metrics.severity_breakdown.major}`);
console.log(` Minor: ${results.metrics.severity_breakdown.minor}`);
console.log(` Suggestions: ${results.metrics.severity_breakdown.suggestion}`);
if (results.strengths.length > 0) {
console.log('\nπͺ Strengths:');
results.strengths.forEach(strength => {
console.log(` β
${strength}`);
});
}
if (results.issues.length > 0) {
console.log('\nβ οΈ Top Issues:');
results.issues.slice(0, 10).forEach((issue, index) => {
const icon = { critical: 'π¨', major: 'β οΈ', minor: 'βΉοΈ', suggestion: 'π‘' }[issue.severity];
console.log(` ${icon} ${issue.description}`);
console.log(` π ${issue.file}:${issue.line}`);
console.log(` π‘ ${issue.suggestion}`);
console.log('');
});
}
if (results.recommendations.length > 0) {
console.log('\nπ― AI Recommendations:');
results.recommendations.forEach(rec => {
console.log(` π€ ${rec}`);
});
}
console.log('\n⨠Review Complete - 2025 AI Standards Applied');
}
}
// Run if called directly
if (require.main === module) {
const reviewer = new AICodeReviewer();
reviewer.reviewCodebase().catch(console.error);
}
module.exports = AICodeReviewer;