File size: 2,991 Bytes
641b62c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
// ─── repairCodeBlocks.ts ──────────────────────────────────────────────────────
// Fase 5 — ripara blocchi di codice malformati nel testo LLM.
// Browser-safe, zero deps, iPhone compatible.
//
// Problemi gestiti:
//   1. Code block aperto senza chiusura
//   2. Code block senza label lingua (aggiunge "text" come default)
//   3. Indentazione mista (tab + spazi) normalizzata a spazi
//   4. Backtick singoli usati per blocchi multi-riga (→ tripli)

export interface RepairCodeResult {
  text:    string;
  changed: boolean;
  repairs: string[];
}

// ── Linguaggi comuni (per rilevamento automatico) ─────────────────────────────
const LANG_HINTS: Array<[RegExp, string]> = [
  [/^(import|export|const|let|var|function|class|type|interface)\s/m, "typescript"],
  [/^(def |class |import |from |print\()/m, "python"],
  [/^(<html|<!DOCTYPE|<div|<span|<head)/im, "html"],
  [/^(\{|\}|"[^"]+"\s*:)/m, "json"],
  [/^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP)\s/im, "sql"],
  [/^(#!\/bin\/bash|echo |cd |ls |grep )/m, "bash"],
  [/^(\.|\#)[a-zA-Z].*\{/m, "css"],
];

function detectLang(code: string): string {
  for (const [re, lang] of LANG_HINTS) {
    if (re.test(code)) return lang;
  }
  return "text";
}

// ── Riparazione blocchi ────────────────────────────────────────────────────────

export function repairCodeBlocks(raw: string): RepairCodeResult {
  if (typeof raw !== "string") {
    return { text: "", changed: true, repairs: ["input non stringa"] };
  }

  const repairs: string[] = [];
  let t = raw;

  // 1. Normalizza tab → 2 spazi all'interno dei blocchi
  t = t.replace(/```([\s\S]*?)```/g, (match) => {
    const normalized = match.replace(/\t/g, "  ");
    if (normalized !== match) repairs.push("normalizzati tab → spazi in code block");
    return normalized;
  });

  // 2. Aggiunge lingua mancante ai code block ``` senza label
  t = t.replace(/```(\s*\n)([\s\S]*?)```/g, (_m, nl, code) => {
    const lang = detectLang(code);
    if (lang !== "text") repairs.push(`rilevato linguaggio: ${lang}`);
    return "```" + lang + nl + code + "```";
  });

  // 3. Backtick singoli su testo multi-riga → triple backtick
  t = t.replace(/`([^`\n]{40,})`/g, (_, code) => {
    repairs.push("convertito backtick singolo → triplo (testo lungo)");
    return "```\n" + code + "\n```";
  });

  // 4. Chiudi blocchi aperti (numero dispari di ```)
  const count = (t.match(/```/g) ?? []).length;
  if (count % 2 !== 0) {
    t += "\n```";
    repairs.push("chiuso code block aperto finale");
  }

  return { text: t, changed: repairs.length > 0, repairs };
}

/** Versione semplice */
export function repairCode(raw: string): string {
  return repairCodeBlocks(raw).text;
}