File size: 4,384 Bytes
473668f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
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;
  });
}