Skip to main content
Glama

CodeCompass MCP

validation.ts9.13 kB
import { ValidationResult } from '../types/index.js'; export class ValidationService { static validateGitHubUrl(url: string): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!url) { errors.push('URL is required'); return { isValid: false, errors, warnings }; } // Check if it's a valid GitHub URL const githubRegex = /^https:\/\/github\.com\/[\w\-\.]+\/[\w\-\.]+\/?$/; if (!githubRegex.test(url)) { errors.push('Invalid GitHub URL format. Expected: https://github.com/owner/repo'); } // Check for common issues if (url.includes('/tree/') || url.includes('/blob/')) { warnings.push('URL appears to point to a specific file or branch. Consider using the repository root URL.'); } if (url.endsWith('.git')) { warnings.push('URL ends with .git. This may cause issues with the GitHub API.'); } return { isValid: errors.length === 0, errors, warnings, }; } static validateFilePath(filePath: string): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!filePath) { errors.push('File path is required'); return { isValid: false, errors, warnings }; } // Check for security issues if (filePath.includes('..')) { errors.push('File path contains directory traversal sequences (..)'); } if (filePath.startsWith('/')) { errors.push('File path should not start with /'); } // Check for common issues if (filePath.includes('\\')) { warnings.push('File path contains backslashes. Use forward slashes instead.'); } return { isValid: errors.length === 0, errors, warnings, }; } static validateRefactorOptions(options: any): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!options) { return { isValid: true, errors, warnings }; } // Validate naming convention if (options.namingConvention) { const validConventions = ['camelCase', 'snake_case', 'kebab-case', 'PascalCase']; if (!validConventions.includes(options.namingConvention)) { errors.push(`Invalid naming convention. Must be one of: ${validConventions.join(', ')}`); } } // Validate modernization level if (options.modernizationLevel) { const validLevels = ['minimal', 'moderate', 'aggressive']; if (!validLevels.includes(options.modernizationLevel)) { errors.push(`Invalid modernization level. Must be one of: ${validLevels.join(', ')}`); } } // Validate target framework if (options.targetFramework) { const supportedFrameworks = ['react', 'vue', 'angular', 'express', 'fastify', 'koa']; if (!supportedFrameworks.includes(options.targetFramework.toLowerCase())) { warnings.push(`Framework '${options.targetFramework}' may not be fully supported. Supported frameworks: ${supportedFrameworks.join(', ')}`); } } return { isValid: errors.length === 0, errors, warnings, }; } static validateComponentTypes(types: string[]): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!types || types.length === 0) { return { isValid: true, errors, warnings }; } const validTypes = ['ui-components', 'hooks', 'utilities', 'services', 'models', 'types']; for (const type of types) { if (!validTypes.includes(type)) { errors.push(`Invalid component type: ${type}. Valid types: ${validTypes.join(', ')}`); } } return { isValid: errors.length === 0, errors, warnings, }; } static validateLanguage(language: string): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!language) { errors.push('Language is required'); return { isValid: false, errors, warnings }; } const supportedLanguages = [ 'javascript', 'typescript', 'python', 'java', 'cpp', 'c', 'go', 'rust', 'php', 'ruby', 'swift', 'kotlin', 'dart', ]; if (!supportedLanguages.includes(language.toLowerCase())) { warnings.push(`Language '${language}' may not be fully supported. Supported languages: ${supportedLanguages.join(', ')}`); } return { isValid: errors.length === 0, errors, warnings, }; } static validateTemplateOptions(options: any): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!options) { return { isValid: true, errors, warnings }; } // Validate template type if (options.templateType) { const validTypes = ['starter', 'component-library', 'microservice', 'fullstack', 'cli-tool', 'library']; if (!validTypes.includes(options.templateType)) { errors.push(`Invalid template type: ${options.templateType}. Valid types: ${validTypes.join(', ')}`); } } // Validate package manager if (options.packageManager) { const validManagers = ['npm', 'yarn', 'pnpm', 'bun']; if (!validManagers.includes(options.packageManager)) { errors.push(`Invalid package manager: ${options.packageManager}. Valid managers: ${validManagers.join(', ')}`); } } // Validate name if (options.name && !/^[a-z0-9-]+$/.test(options.name)) { errors.push('Template name must contain only lowercase letters, numbers, and hyphens'); } return { isValid: errors.length === 0, errors, warnings, }; } static validateSearchQuery(query: string): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!query) { errors.push('Search query is required'); return { isValid: false, errors, warnings }; } if (query.length < 2) { errors.push('Search query must be at least 2 characters long'); } if (query.length > 1000) { errors.push('Search query is too long (max 1000 characters)'); } // Check for potentially problematic regex patterns try { new RegExp(query); } catch (e) { warnings.push('Search query may contain invalid regex patterns'); } return { isValid: errors.length === 0, errors, warnings, }; } static validateCodeInput(code: string): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!code) { errors.push('Code input is required'); return { isValid: false, errors, warnings }; } if (code.length > 1000000) { // 1MB limit errors.push('Code input is too large (max 1MB)'); } // Check for potentially malicious patterns const maliciousPatterns = [ /eval\s*\(/, /Function\s*\(/, /document\.write/, /innerHTML\s*=/, /dangerouslySetInnerHTML/, ]; for (const pattern of maliciousPatterns) { if (pattern.test(code)) { warnings.push('Code contains potentially unsafe patterns'); break; } } return { isValid: errors.length === 0, errors, warnings, }; } static validateDependencyMappings(mappings: Record<string, string>): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!mappings) { return { isValid: true, errors, warnings }; } for (const [oldDep, newDep] of Object.entries(mappings)) { if (!oldDep || !newDep) { errors.push('Dependency mappings must have both old and new values'); continue; } // Check for valid package names const packageNameRegex = /^[@a-z0-9-~][a-z0-9-._~]*\/[a-z0-9-._~]*$|^[a-z0-9-~][a-z0-9-._~]*$/; if (!packageNameRegex.test(oldDep)) { warnings.push(`Old dependency name '${oldDep}' may not be valid`); } if (!packageNameRegex.test(newDep)) { warnings.push(`New dependency name '${newDep}' may not be valid`); } } return { isValid: errors.length === 0, errors, warnings, }; } static validateFileExtensions(extensions: string[]): ValidationResult { const errors: string[] = []; const warnings: string[] = []; if (!extensions || extensions.length === 0) { return { isValid: true, errors, warnings }; } for (const ext of extensions) { if (!ext.startsWith('.')) { errors.push(`File extension '${ext}' must start with a dot`); } if (ext.length < 2) { errors.push(`File extension '${ext}' is too short`); } if (!/^\.[\w]+$/.test(ext)) { errors.push(`File extension '${ext}' contains invalid characters`); } } return { isValid: errors.length === 0, errors, warnings, }; } }

Latest Blog Posts

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/TheAlchemist6/codecompass-mcp'

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