Spaces:
Running
Running
| import type { PreviewError } from "@/types/preview-error"; | |
| // Sanitize error messages to prevent prompt injection | |
| function sanitizeErrorMessage(message: string): string { | |
| return message | |
| .replace(/[<>]/g, "") // Remove potential HTML tags | |
| .replace(/```/g, "'''") // Escape code blocks | |
| .slice(0, 500); // Limit length | |
| } | |
| export function formatErrorsForAI( | |
| errors: PreviewError[], | |
| html: string | |
| ): string { | |
| if (!errors || errors.length === 0) return ""; | |
| // Validate errors array | |
| const validErrors = errors.filter((e) => e && typeof e.message === "string"); | |
| if (validErrors.length === 0) return ""; | |
| // Group errors by type for better organization | |
| const errorGroups = validErrors.reduce((acc, error) => { | |
| const type = error.errorType || error.type; | |
| if (!acc[type]) acc[type] = []; | |
| acc[type].push(error); | |
| return acc; | |
| }, {} as Record<string, PreviewError[]>); | |
| let formattedErrors = | |
| "The following errors were detected in the preview:\n\n"; | |
| // Format each error group | |
| Object.entries(errorGroups).forEach(([type, groupErrors]) => { | |
| formattedErrors += `### ${type} (${groupErrors.length} error${ | |
| groupErrors.length > 1 ? "s" : "" | |
| })\n\n`; | |
| groupErrors.forEach((error, index) => { | |
| const sanitizedMessage = sanitizeErrorMessage(error.message); | |
| formattedErrors += `${index + 1}. **${sanitizedMessage}**\n`; | |
| if (error.lineNumber) { | |
| formattedErrors += ` - Line: ${error.lineNumber}`; | |
| if (error.columnNumber) { | |
| formattedErrors += `, Column: ${error.columnNumber}`; | |
| } | |
| formattedErrors += "\n"; | |
| } | |
| if (error.fileName && error.fileName !== "undefined") { | |
| formattedErrors += ` - File: ${error.fileName}\n`; | |
| } | |
| // For resource errors, include the problematic resource | |
| if (error.type === "resource-error" && error.src) { | |
| formattedErrors += ` - Resource: ${error.src}\n`; | |
| formattedErrors += ` - Tag: <${error.tagName?.toLowerCase()}>\n`; | |
| } | |
| // Include relevant code snippet if we have line numbers | |
| if (error.lineNumber && html) { | |
| const lines = html.split("\n"); | |
| const startLine = Math.max(0, error.lineNumber - 3); | |
| const endLine = Math.min(lines.length, error.lineNumber + 2); | |
| if (lines[error.lineNumber - 1]) { | |
| formattedErrors += " - Code context:\n"; | |
| formattedErrors += " ```html\n"; | |
| for (let i = startLine; i < endLine; i++) { | |
| const marker = i === error.lineNumber - 1 ? ">" : " "; | |
| formattedErrors += ` ${marker} ${i + 1}: ${lines[i]}\n`; | |
| } | |
| formattedErrors += " ```\n"; | |
| } | |
| } | |
| formattedErrors += "\n"; | |
| }); | |
| }); | |
| return formattedErrors; | |
| } | |
| export function createErrorFixPrompt( | |
| errors: PreviewError[], | |
| html: string | |
| ): string { | |
| const formattedErrors = formatErrorsForAI(errors, html); | |
| return `${formattedErrors} | |
| Please fix these errors in the HTML code. Focus on: | |
| 1. Fixing JavaScript syntax errors | |
| 2. Resolving undefined variables or functions | |
| 3. Fixing broken resource links (404s) | |
| 4. Ensuring all referenced libraries are properly loaded | |
| 5. Fixing any HTML structure issues | |
| Make the minimum necessary changes to fix the errors while preserving the intended functionality.`; | |
| } | |
| // Check if errors are likely fixable by AI | |
| export function areErrorsFixable(errors: PreviewError[]): boolean { | |
| if (!errors || errors.length === 0) return false; | |
| // Filter out errors that are likely not fixable | |
| const fixableErrors = errors.filter((error) => { | |
| // Skip errors from external resources | |
| if ( | |
| error.fileName && | |
| (error.fileName.includes("http://") || | |
| error.fileName.includes("https://")) | |
| ) { | |
| return false; | |
| } | |
| // Skip certain console errors that might be intentional | |
| if ( | |
| error.type === "console-error" && | |
| error.message.includes("Development mode") | |
| ) { | |
| return false; | |
| } | |
| return true; | |
| }); | |
| return fixableErrors.length > 0; | |
| } | |
| // Deduplicate similar errors | |
| export function deduplicateErrors(errors: PreviewError[]): PreviewError[] { | |
| const seen = new Set<string>(); | |
| return errors.filter((error) => { | |
| const key = `${error.type}-${error.message}-${error.lineNumber || 0}`; | |
| if (seen.has(key)) return false; | |
| seen.add(key); | |
| return true; | |
| }); | |
| } | |