import styles from "./FileDiff.module.css"; const ROWS = [ { old: 12, cur: 12, type: "ctx", text: "export function getToken() {" }, { old: 13, cur: null, type: "del", text: " return localStorage.token;" }, { old: null, cur: 13, type: "add", text: ' const t = cookies.get("session");' }, { old: null, cur: 14, type: "add", text: ' if (!t) throw new Error("no session");' }, { old: null, cur: 15, type: "add", text: " return t;" }, { old: 14, cur: 16, type: "ctx", text: "}" }, ]; const KEYWORDS = new Set([ "export","function","return","const","let","var","if","else","throw","new", "import","from","async","await","class","extends","typeof","void","true", "false","null","undefined","for","while","switch","case","break","continue", "try","catch","finally","this","super","static","type","interface","enum","as","of","in", ]); function tokenize(line: string) { const raw = []; const re = /(\s+)|(\/\/.*)|(\/\*[\s\S]*?\*\/)|("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')|(\b\d+(?:\.\d+)?\b)|(\b[A-Za-z_$][\w$]*\b)|(\S)/g; let m; while ((m = re.exec(line))) { if (m[1]) raw.push({ kind: "txt", v: m[1] }); else if (m[2] || m[3]) raw.push({ kind: "cm", v: m[0] }); else if (m[4]) raw.push({ kind: "str", v: m[0] }); else if (m[5]) raw.push({ kind: "num", v: m[0] }); else if (m[6]) raw.push({ kind: "id", v: m[0] }); else raw.push({ kind: "txt", v: m[0] }); } const out = []; for (let i = 0; i < raw.length; i++) { const cur = raw[i]; if (cur.kind !== "id") { out.push({ t: cur.kind, v: cur.v }); continue; } if (KEYWORDS.has(cur.v)) { out.push({ t: "kw", v: cur.v }); continue; } let j = i + 1; while (j < raw.length && raw[j].kind === "txt" && /^\s+$/.test(raw[j].v)) j++; const next = raw[j]; out.push({ t: next && next.v.startsWith("(") ? "fn" : "txt", v: cur.v }); } return out; } export function FileDiff({ file = "src/auth.ts", rows = ROWS }) { const added = rows.filter((r) => r.type === "add").length; const removed = rows.filter((r) => r.type === "del").length; return (
{file} +{added} -{removed}
{rows.map((r, i) => (
{r.old ?? ""} {r.cur ?? ""} {r.type === "add" ? "+" : r.type === "del" ? "-" : ""} {tokenize(r.text).map((tok, j) => ( {tok.v} ))}
))}
); }