/** * Cross-Platform Code Translation Engine * Core competitive differentiator for AeThex Studio */ import { PlatformId, getPlatform } from './platforms'; import { toast } from 'sonner'; import { trackEvent, trackError } from './analytics'; export interface TranslationRequest { sourceCode: string; sourcePlatform: PlatformId; targetPlatform: PlatformId; context?: string; } export interface TranslationResult { success: boolean; translatedCode?: string; explanation?: string; warnings?: string[]; error?: string; } /** * Platform-specific translation prompts */ const getTranslationPrompt = ( sourceCode: string, sourcePlatform: PlatformId, targetPlatform: PlatformId, context?: string ): string => { const sourcePlat = getPlatform(sourcePlatform); const targetPlat = getPlatform(targetPlatform); return `You are an expert game developer specializing in cross-platform game development. **Task**: Translate the following ${sourcePlat.language} code (${sourcePlat.displayName}) to ${targetPlat.language} (${targetPlat.displayName}). **Source Platform**: ${sourcePlat.displayName} - Language: ${sourcePlat.language} - API Documentation: ${sourcePlat.apiDocs} **Target Platform**: ${targetPlat.displayName} - Language: ${targetPlat.language} - API Documentation: ${targetPlat.apiDocs} **Source Code**: \`\`\`${sourcePlat.language.toLowerCase()} ${sourceCode} \`\`\` ${context ? `**Additional Context**: ${context}\n` : ''} **Instructions**: 1. Translate the code to ${targetPlat.language} while preserving the logic and functionality 2. Use ${targetPlat.displayName}-native APIs and best practices 3. Add comments explaining platform-specific differences 4. Ensure the code follows ${targetPlat.language} conventions and style 5. If certain features don't have direct equivalents, provide the closest alternative and explain **Output Format**: Return ONLY the translated code wrapped in triple backticks with the language identifier. Then provide a brief explanation of key changes and any warnings. Example: \`\`\`${targetPlat.fileExtension.replace('.', '')} // Translated code here \`\`\` **Explanation**: [Brief explanation of translation] **Warnings**: [Any caveats or limitations, if applicable]`; }; /** * Platform-specific translation rules */ const platformTranslationRules: Record = { 'roblox-to-uefn': [ 'game:GetService() → Use Verse imports', 'Instance.new() → object{} syntax in Verse', 'Connect() → Subscribe() in Verse', 'wait() → Sleep() in Verse', 'print() → Print() in Verse', ], 'uefn-to-roblox': [ 'Verse imports → game:GetService()', 'object{} → Instance.new()', 'Subscribe() → Connect()', 'Sleep() → wait()', 'Print() → print()', ], 'roblox-to-spatial': [ 'Lua → TypeScript syntax', 'game:GetService() → Spatial SDK imports', 'Instance.new() → new SpatialObject()', 'Connect() → addEventListener()', 'wait() → await setTimeout()', ], 'spatial-to-roblox': [ 'TypeScript → Lua syntax', 'Spatial SDK → game:GetService()', 'new SpatialObject() → Instance.new()', 'addEventListener() → Connect()', 'await setTimeout() → wait()', ], }; /** * Mock translation service (for development without API key) * Replace with actual Claude API call in production */ async function translateWithMockService( request: TranslationRequest ): Promise { const ruleKey = `${request.sourcePlatform}-to-${request.targetPlatform}`; const rules = platformTranslationRules[ruleKey] || []; return { success: true, translatedCode: `-- Translated from ${request.sourcePlatform} to ${request.targetPlatform} -- Translation Rules Applied: ${rules.map(r => `-- ${r}`).join('\n')} -- Original Code (needs actual translation): ${request.sourceCode} -- TODO: Replace with actual ${request.targetPlatform} implementation`, explanation: `This is a mock translation. The actual translation engine will use Claude API to intelligently convert ${request.sourcePlatform} code to ${request.targetPlatform}.`, warnings: [ 'Mock translation active - integrate Claude API for production', `Translation rules: ${rules.join(', ')}`, ], }; } /** * Translate code using Claude API * This is the production implementation */ async function translateWithClaudeAPI( request: TranslationRequest ): Promise { try { // Check if API key is configured const apiKey = process.env.NEXT_PUBLIC_CLAUDE_API_KEY; if (!apiKey) { console.warn('Claude API key not configured, using mock translation'); return await translateWithMockService(request); } const prompt = getTranslationPrompt( request.sourceCode, request.sourcePlatform, request.targetPlatform, request.context ); // Call Claude API const response = await fetch('https://api.anthropic.com/v1/messages', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-api-key': apiKey, 'anthropic-version': '2023-06-01', }, body: JSON.stringify({ model: 'claude-3-5-sonnet-20241022', max_tokens: 4096, messages: [ { role: 'user', content: prompt, }, ], }), }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error( `API request failed: ${response.statusText} (${response.status})${ errorData.error?.message ? ` - ${errorData.error.message}` : '' }` ); } const data = await response.json(); const content = data.content?.[0]?.text; if (!content) { throw new Error('No content in API response'); } // Parse the response to extract code, explanation, and warnings const result = parseClaudeResponse(content, request.targetPlatform); return result; } catch (error) { trackError(error as Error, { context: 'translation_api', sourcePlatform: request.sourcePlatform, targetPlatform: request.targetPlatform, }); // Fallback to mock if API fails console.warn('Claude API failed, falling back to mock:', error); return await translateWithMockService(request); } } /** * Parse Claude API response to extract code, explanation, and warnings */ function parseClaudeResponse( content: string, targetPlatform: PlatformId ): TranslationResult { try { // Extract code block (supports multiple formats) const codeMatch = content.match(/```(?:verse|lua|typescript|ts|javascript|js)?\n([\s\S]*?)```/); if (!codeMatch) { // If no code block found, treat entire response as code return { success: true, translatedCode: content.trim(), explanation: 'Translation completed', }; } const translatedCode = codeMatch[1].trim(); // Extract explanation (multiple formats) const explanationMatch = content.match(/\*\*Explanation\*\*:\s*(.*?)(?:\n\*\*|$)/s) || content.match(/Explanation:\s*(.*?)(?:\n\*\*|$)/s) || content.match(/## Explanation\s*(.*?)(?:\n##|$)/s); // Extract warnings (multiple formats) const warningsMatch = content.match(/\*\*Warnings\*\*:\s*([\s\S]*?)(?:\n\*\*|$)/) || content.match(/Warnings:\s*([\s\S]*?)(?:\n\*\*|$)/) || content.match(/## Warnings\s*([\s\S]*?)(?:\n##|$)/); const warnings = warningsMatch ? warningsMatch[1] .split('\n') .map(w => w.trim().replace(/^[-•*]\s*/, '')) .filter(w => w.length > 0) : undefined; return { success: true, translatedCode, explanation: explanationMatch ? explanationMatch[1].trim() : undefined, warnings: warnings && warnings.length > 0 ? warnings : undefined, }; } catch (error) { console.error('Error parsing Claude response:', error); return { success: true, translatedCode: content.trim(), explanation: 'Translation completed (parsing error)', warnings: ['Response parsing encountered issues, code may need review'], }; } } /** * Main translation function */ export async function translateCode( request: TranslationRequest ): Promise { try { // Validate platforms if (request.sourcePlatform === request.targetPlatform) { return { success: false, error: 'Source and target platforms must be different', }; } if (!request.sourceCode || request.sourceCode.trim() === '') { return { success: false, error: 'Source code cannot be empty', }; } // Log translation attempt trackEvent('translation_started', { sourcePlatform: request.sourcePlatform, targetPlatform: request.targetPlatform, codeLength: request.sourceCode.length, }); // Perform translation const result = await translateWithClaudeAPI(request); // Log result if (result.success) { trackEvent('translation_success', { sourcePlatform: request.sourcePlatform, targetPlatform: request.targetPlatform, }); toast.success( `Translated ${request.sourcePlatform} → ${request.targetPlatform}` ); } else { trackEvent('translation_failed', { sourcePlatform: request.sourcePlatform, targetPlatform: request.targetPlatform, error: result.error, }); toast.error(`Translation failed: ${result.error}`); } return result; } catch (error) { trackError(error as Error, { context: 'translate_code' }); return { success: false, error: `Unexpected error: ${(error as Error).message}`, }; } } /** * Get supported translation pairs */ export function getSupportedTranslations(): Array<{ source: PlatformId; target: PlatformId; }> { return [ { source: 'roblox', target: 'uefn' }, { source: 'uefn', target: 'roblox' }, { source: 'roblox', target: 'spatial' }, { source: 'spatial', target: 'roblox' }, { source: 'uefn', target: 'spatial' }, { source: 'spatial', target: 'uefn' }, ]; } /** * Check if translation is supported */ export function isTranslationSupported( source: PlatformId, target: PlatformId ): boolean { return getSupportedTranslations().some( (pair) => pair.source === source && pair.target === target ); }