UNPKG

shipdeck

Version:

Ship MVPs in 48 hours. Fix bugs in 30 seconds. The command deck for developers who ship.

304 lines (251 loc) • 9.76 kB
/** * Frontend Agent Validation Script * Validates the structure and methods without requiring external dependencies */ const fs = require('fs'); const path = require('path'); class FrontendAgentValidator { constructor() { this.results = { passed: 0, failed: 0, tests: [] }; } log(status, test, message = '') { const result = { status, test, message }; this.results.tests.push(result); if (status === 'PASS') { console.log(`āœ… ${test}`); this.results.passed++; } else { console.log(`āŒ ${test}`); if (message) console.log(` ${message}`); this.results.failed++; } } async validate() { console.log('šŸ” Validating Frontend Agent Structure and Code Quality\n'); // 1. File Structure Validation await this.validateFileStructure(); // 2. Code Structure Validation await this.validateCodeStructure(); // 3. Template System Validation await this.validateTemplateSystem(); // 4. Method Signatures Validation await this.validateMethodSignatures(); // 5. TypeScript Compliance await this.validateTypeScriptCompliance(); // 6. Best Practices Compliance await this.validateBestPractices(); console.log(`\nšŸ“Š Validation Results:`); console.log(` āœ… Passed: ${this.results.passed}`); console.log(` āŒ Failed: ${this.results.failed}`); console.log(` šŸ“ˆ Success Rate: ${Math.round((this.results.passed / (this.results.passed + this.results.failed)) * 100)}%`); return this.results.failed === 0; } async validateFileStructure() { console.log('šŸ“ File Structure Validation'); const frontendAgentPath = path.join(__dirname, 'lib/ultimate/agents/frontend-agent.js'); if (fs.existsSync(frontendAgentPath)) { this.log('PASS', 'Frontend agent file exists'); } else { this.log('FAIL', 'Frontend agent file missing', frontendAgentPath); return; } const content = fs.readFileSync(frontendAgentPath, 'utf8'); if (content.length > 500) { this.log('PASS', 'Frontend agent has substantial content'); } else { this.log('FAIL', 'Frontend agent content seems insufficient'); } } async validateCodeStructure() { console.log('\nšŸ—ļø Code Structure Validation'); const frontendAgentPath = path.join(__dirname, 'lib/ultimate/agents/frontend-agent.js'); const content = fs.readFileSync(frontendAgentPath, 'utf8'); // Check class declaration if (content.includes('class FrontendAgent extends BaseAgent')) { this.log('PASS', 'Properly extends BaseAgent'); } else { this.log('FAIL', 'Does not properly extend BaseAgent'); } // Check constructor if (content.includes('constructor(options = {})')) { this.log('PASS', 'Has proper constructor'); } else { this.log('FAIL', 'Missing proper constructor'); } // Check essential methods const requiredMethods = [ 'getCapabilities()', 'execute(task, context = {})', 'getSystemPrompt()', 'parseFrontendResponse(' ]; requiredMethods.forEach(method => { if (content.includes(method)) { this.log('PASS', `Has required method: ${method}`); } else { this.log('FAIL', `Missing required method: ${method}`); } }); // Check module export if (content.includes('module.exports = FrontendAgent')) { this.log('PASS', 'Properly exports as CommonJS module'); } else { this.log('FAIL', 'Missing proper module export'); } } async validateTemplateSystem() { console.log('\nšŸ“ Template System Validation'); const frontendAgentPath = path.join(__dirname, 'lib/ultimate/agents/frontend-agent.js'); const content = fs.readFileSync(frontendAgentPath, 'utf8'); // Check template initialization if (content.includes('initializeTemplates()')) { this.log('PASS', 'Has template initialization system'); } else { this.log('FAIL', 'Missing template initialization'); } // Check essential templates const requiredTemplates = [ 'getFunctionalComponentTemplate()', 'getPageComponentTemplate()', 'getFormComponentTemplate()', 'getNavigationTemplate()', 'getHeroSectionTemplate()', 'getCardGridTemplate()', 'getModalDialogTemplate()' ]; requiredTemplates.forEach(template => { if (content.includes(template)) { this.log('PASS', `Has template method: ${template}`); } else { this.log('FAIL', `Missing template method: ${template}`); } }); // Check template content quality if (content.includes('React.FC') && content.includes('interface')) { this.log('PASS', 'Templates include TypeScript patterns'); } else { this.log('FAIL', 'Templates missing TypeScript patterns'); } if (content.includes('className=') && content.includes('tailwind')) { this.log('PASS', 'Templates include Tailwind CSS patterns'); } else { this.log('FAIL', 'Templates missing Tailwind CSS patterns'); } } async validateMethodSignatures() { console.log('\nšŸ”§ Method Signatures Validation'); const frontendAgentPath = path.join(__dirname, 'lib/ultimate/agents/frontend-agent.js'); const content = fs.readFileSync(frontendAgentPath, 'utf8'); // Check capabilities method if (content.includes("return ['ui', 'components', 'styling', 'forms', 'navigation'")) { this.log('PASS', 'getCapabilities() returns expected capabilities'); } else if (content.includes("'ui'") && content.includes("'components'") && content.includes("'forms'")) { this.log('PASS', 'getCapabilities() includes core frontend capabilities'); } else { this.log('FAIL', 'getCapabilities() missing expected capabilities'); } // Check execute method handles different task types const taskTypes = [ 'generate-component', 'generate-page', 'generate-form', 'generate-navigation', 'generate-hero', 'generate-modal' ]; taskTypes.forEach(taskType => { if (content.includes(`'${taskType}'`)) { this.log('PASS', `Handles task type: ${taskType}`); } else { this.log('FAIL', `Missing task type: ${taskType}`); } }); } async validateTypeScriptCompliance() { console.log('\nšŸ“˜ TypeScript Compliance Validation'); const frontendAgentPath = path.join(__dirname, 'lib/ultimate/agents/frontend-agent.js'); const content = fs.readFileSync(frontendAgentPath, 'utf8'); // Check for TypeScript awareness if (content.includes('TypeScript') && content.includes('interface')) { this.log('PASS', 'Shows TypeScript awareness'); } else { this.log('FAIL', 'Missing TypeScript awareness'); } // Check for anti-patterns warnings if (content.includes("NEVER use 'any' type")) { this.log('PASS', 'Warns against TypeScript anti-patterns'); } else { this.log('FAIL', 'Missing TypeScript anti-pattern warnings'); } // Check for proper typing in templates if (content.includes('React.FC<') && content.includes('Props>')) { this.log('PASS', 'Templates use proper React TypeScript patterns'); } else { this.log('FAIL', 'Templates missing React TypeScript patterns'); } } async validateBestPractices() { console.log('\nšŸŽÆ Best Practices Validation'); const frontendAgentPath = path.join(__dirname, 'lib/ultimate/agents/frontend-agent.js'); const content = fs.readFileSync(frontendAgentPath, 'utf8'); // Check for accessibility mentions if (content.includes('accessibility') && content.includes('ARIA')) { this.log('PASS', 'Includes accessibility best practices'); } else { this.log('FAIL', 'Missing accessibility best practices'); } // Check for responsive design if (content.includes('responsive') && content.includes('mobile-first')) { this.log('PASS', 'Includes responsive design practices'); } else { this.log('FAIL', 'Missing responsive design practices'); } // Check for error handling if (content.includes('try {') && content.includes('catch (error)')) { this.log('PASS', 'Includes proper error handling'); } else { this.log('FAIL', 'Missing proper error handling'); } // Check for React best practices const reactBestPractices = [ 'hooks', 'useState', 'useEffect', 'loading', 'error states' ]; let practiceCount = 0; reactBestPractices.forEach(practice => { if (content.toLowerCase().includes(practice.toLowerCase())) { practiceCount++; } }); if (practiceCount >= 4) { this.log('PASS', 'Includes React best practices'); } else { this.log('FAIL', `Missing React best practices (${practiceCount}/5)`); } // Check for testing integration if (content.includes('test') && content.includes('@testing-library')) { this.log('PASS', 'Includes testing integration'); } else { this.log('FAIL', 'Missing testing integration'); } } } // Run validation if this file is executed directly if (require.main === module) { const validator = new FrontendAgentValidator(); validator.validate().then(success => { console.log(`\n${success ? 'šŸŽ‰' : 'šŸ’„'} Validation ${success ? 'completed successfully' : 'failed'}`); process.exit(success ? 0 : 1); }).catch(error => { console.error(`āŒ Validation error: ${error.message}`); process.exit(1); }); } module.exports = FrontendAgentValidator;