Skip to main content
Glama

AI Agent Template MCP Server

by bswa006
pattern-validator.tsโ€ข5.51 kB
interface ValidationResult { isValid: boolean; errors: string[]; warnings: string[]; suggestions: string[]; } export async function validatePattern( code: string, patternType: 'component' | 'hook' | 'service' | 'api' ): Promise<ValidationResult> { const result: ValidationResult = { isValid: true, errors: [], warnings: [], suggestions: [], }; // Common validations validateCommonPatterns(code, result); // Pattern-specific validations switch (patternType) { case 'component': validateComponentPattern(code, result); break; case 'hook': validateHookPattern(code, result); break; case 'service': validateServicePattern(code, result); break; case 'api': validateApiPattern(code, result); break; } result.isValid = result.errors.length === 0; return result; } function validateCommonPatterns(code: string, result: ValidationResult) { // Check for any type usage if (code.includes(': any') || code.includes('<any>')) { result.errors.push('Avoid using "any" type - use specific types instead'); } // Check for console.log in production code if (code.includes('console.log(') && !code.includes('// eslint-disable')) { result.warnings.push('Remove console.log statements from production code'); } // Check for hardcoded secrets const secretPatterns = [ /api[_-]?key\s*=\s*["'][^"']+["']/i, /password\s*=\s*["'][^"']+["']/i, /secret\s*=\s*["'][^"']+["']/i, ]; for (const pattern of secretPatterns) { if (pattern.test(code)) { result.errors.push('Never hardcode secrets or API keys - use environment variables'); } } // Check for proper error handling if (code.includes('async') && !code.includes('try') && !code.includes('.catch')) { result.warnings.push('Add error handling for async operations'); } } function validateComponentPattern(code: string, result: ValidationResult) { // Check for functional component pattern if (code.includes('class') && code.includes('extends') && code.includes('Component')) { result.errors.push('Use functional components instead of class components'); } // Check for React.FC usage (if TypeScript) if (code.includes('interface') && code.includes('Props') && !code.includes('React.FC')) { result.suggestions.push('Consider using React.FC<Props> for component type'); } // Check for proper exports if (!code.includes('export default') && !code.includes('export {')) { result.warnings.push('Component should be exported'); } // Check for loading/error/empty states const hasLoadingState = code.includes('loading') || code.includes('isLoading'); const hasErrorState = code.includes('error') || code.includes('isError'); if (!hasLoadingState) { result.suggestions.push('Consider handling loading state'); } if (!hasErrorState) { result.suggestions.push('Consider handling error state'); } } function validateHookPattern(code: string, result: ValidationResult) { // Check hook naming convention if (!code.match(/function use[A-Z]/)) { result.errors.push('Custom hooks must start with "use" followed by uppercase letter'); } // Check for rules of hooks violations if (code.includes('if') && code.includes('useState')) { const ifIndex = code.indexOf('if'); const useStateIndex = code.indexOf('useState'); if (ifIndex < useStateIndex) { result.warnings.push('Hooks must not be called conditionally'); } } // Check for cleanup in useEffect if (code.includes('useEffect') && code.includes('addEventListener') && !code.includes('return')) { result.warnings.push('useEffect with subscriptions should return a cleanup function'); } } function validateServicePattern(code: string, result: ValidationResult) { // Check for proper error handling in services if (code.includes('fetch') || code.includes('axios')) { if (!code.includes('try') && !code.includes('.catch')) { result.errors.push('API calls must include error handling'); } } // Check for consistent return types if (code.includes('async function')) { result.suggestions.push('Ensure consistent return types for async functions'); } // Check for proper typing if (!code.includes('interface') && !code.includes('type')) { result.warnings.push('Define types for service parameters and return values'); } } function validateApiPattern(code: string, result: ValidationResult) { // Check for RESTful conventions if (code.includes('/api/')) { const hasPlurals = code.match(/\/api\/[a-z]+s(?:\/|$)/); if (!hasPlurals) { result.suggestions.push('Use plural nouns for REST endpoints (e.g., /api/users)'); } } // Check for proper HTTP methods const httpMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']; const hasHttpMethod = httpMethods.some(method => code.includes(method)); if (!hasHttpMethod && code.includes('fetch')) { result.warnings.push('Specify HTTP method explicitly'); } // Check for proper status codes if (code.includes('status(') || code.includes('statusCode')) { const validStatusCodes = [200, 201, 204, 400, 401, 403, 404, 500]; result.suggestions.push('Use standard HTTP status codes'); } // Check for input validation if (code.includes('req.body') || code.includes('request.body')) { if (!code.includes('validate') && !code.includes('schema')) { result.errors.push('Validate request body before processing'); } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bswa006/mcp-context-manager'

If you have feedback or need assistance with the MCP directory API, please join our Discord server