UNPKG

remcode

Version:

Turn your AI assistant into a codebase expert. Intelligent code analysis, semantic search, and software engineering guidance through MCP integration.

190 lines (189 loc) 7.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SWEGuidelines = void 0; const logger_1 = require("../utils/logger"); const logger = (0, logger_1.getLogger)('SWEGuidelines'); /** * Software Engineering Guidelines implementation */ class SWEGuidelines { /** * Get all available coding standards */ getCodingStandards() { return [ { id: 'naming-conventions', title: 'Naming Conventions', description: 'Consistent naming across the codebase', rules: [ 'Use camelCase for variables and function names', 'Use PascalCase for classes, interfaces, and type names', 'Use UPPER_SNAKE_CASE for constants', 'Boolean variables should be prefixed with is, has, should, etc.', 'Use descriptive names that reflect the purpose' ], priority: 'high', examples: { good: 'const isUserLoggedIn = true;\nclass UserRepository {}', bad: 'const flag = true;\nclass repo {}' }, category: 'code-style', tags: ['naming', 'readability'] }, { id: 'error-handling', title: 'Error Handling', description: 'Robust error handling patterns', rules: [ 'Always handle errors in async functions with try-catch', 'Log meaningful error messages with contextual information', 'Consider using custom error classes for different error types', 'Propagate errors when appropriate, handle them when possible', 'Never swallow errors without logging' ], priority: 'critical', examples: { good: 'try {\n await api.getData();\n} catch (error) {\n logger.error(\'Failed to get data\', error);\n}', bad: 'api.getData().catch(() => {});' }, category: 'reliability', tags: ['error-handling', 'robustness'] }, { id: 'code-comments', title: 'Code Comments', description: 'Effective use of comments to explain complex logic', rules: [ 'Use JSDoc for public APIs and interfaces', 'Explain "why" not "what" in comments', 'Keep comments up-to-date with code changes', 'Use TODO, FIXME with specific details and ticket numbers', 'Document non-obvious decisions and edge cases' ], priority: 'medium', examples: { good: '// Throttle API calls to avoid rate limiting\nconst throttledFn = throttle(apiCall, 1000);', bad: '// Call function\ncallFn();' }, category: 'documentation', tags: ['comments', 'documentation'] }, { id: 'type-safety', title: 'Type Safety', description: 'Proper use of TypeScript types for safer code', rules: [ 'Avoid using `any` type when possible', 'Use interfaces for complex object structures', 'Define return types for functions explicitly', 'Use type guards for runtime type checking', 'Leverage union types and generics for flexible APIs' ], priority: 'high', category: 'code-quality', tags: ['typescript', 'type-safety'] }, { id: 'testing-practices', title: 'Testing Practices', description: 'Comprehensive testing strategies', rules: [ 'Write unit tests for business logic', 'Include edge cases in test coverage', 'Use descriptive test names that explain the expected behavior', 'Follow AAA pattern (Arrange-Act-Assert)', 'Mock external dependencies in unit tests' ], priority: 'high', category: 'quality-assurance', tags: ['testing', 'quality'] }, { id: 'security-practices', title: 'Security Practices', description: 'Code patterns for secure applications', rules: [ 'Validate and sanitize all user inputs', 'Use parameterized queries for database operations', 'Implement proper authentication and authorization checks', 'Never store sensitive information in client-side code', 'Apply the principle of least privilege' ], priority: 'critical', category: 'security', tags: ['security', 'validation'] } ]; } /** * Get a specific guideline by ID */ getGuideline(id) { return this.getCodingStandards().find(g => g.id === id) || null; } /** * Get guidelines by category */ getGuidelinesByCategory(category) { return this.getCodingStandards().filter(g => g.category === category); } /** * Get guidelines by priority */ getGuidelinesByPriority(priority) { return this.getCodingStandards().filter(g => g.priority === priority); } /** * Validate code against the guidelines */ validateCode(code) { logger.info('Validating code against guidelines'); const issues = []; // Naming conventions check if (code.match(/const [A-Z]/) || code.match(/let [A-Z]/)) { issues.push({ guidelineId: 'naming-conventions', message: 'Variable names should use camelCase, not PascalCase', severity: 'medium' }); } // Error handling check const asyncWithoutTryCatch = code.includes('async') && !code.includes('try') && (code.includes('await') || code.includes('.then(')); if (asyncWithoutTryCatch) { issues.push({ guidelineId: 'error-handling', message: 'Async operations should use try-catch for error handling', severity: 'high' }); } // Type safety check if (code.includes(': any') || code.includes('as any')) { issues.push({ guidelineId: 'type-safety', message: 'Avoid using the "any" type when possible', severity: 'medium' }); } // Empty catch blocks if (code.match(/catch[\s\S]*?\([\s\S]*?\)[\s\S]*?{[\s\S]*?}/)) { const emptyCatchRegex = /catch[\s\S]*?\([\s\S]*?\)[\s\S]*?{[\s\S]*?}/g; const catches = code.match(emptyCatchRegex) || []; for (const catchBlock of catches) { if (catchBlock.replace(/\s+/g, '').match(/catch\([^)]*\){}/)) { issues.push({ guidelineId: 'error-handling', message: 'Empty catch blocks should at least include logging', severity: 'high' }); break; } } } logger.debug(`Validation complete: found ${issues.length} issues`); return issues; } } exports.SWEGuidelines = SWEGuidelines;