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; | |
}); | |
} | |