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
JavaScript
/**
* 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;