85 lines
2.9 KiB
TypeScript
85 lines
2.9 KiB
TypeScript
import { Exam } from "@/interfaces/exam";
|
|
import { diff, Diff } from "deep-diff";
|
|
|
|
const EXCLUDED_FIELDS = new Set(["_id", "id", "createdAt", "createdBy", "entities", "isDiagnostic", "private"]);
|
|
|
|
export function generateExamDifferences(oldExam: Exam, newExam: Exam): string[] {
|
|
const differences = diff(oldExam, newExam) || [];
|
|
return differences.map((change) => formatDifference(change)).filter(Boolean) as string[];
|
|
}
|
|
|
|
function formatDifference(change: Diff<any, any>): string | undefined {
|
|
if (!change.path) {
|
|
return;
|
|
}
|
|
|
|
if (change.path.some((segment) => EXCLUDED_FIELDS.has(segment))) {
|
|
return;
|
|
}
|
|
|
|
// Convert path array to something human-readable
|
|
const pathString = change.path.join(" \u2192 "); // e.g. "parts → 0 → exercises → 1 → prompt"
|
|
|
|
switch (change.kind) {
|
|
case "N":
|
|
// A new property/element was added
|
|
return `\u{2022} Added \`${pathString}\` with value: ${formatValue(change.rhs)}`;
|
|
|
|
case "D":
|
|
// A property/element was deleted
|
|
return `\u{2022} Removed \`${pathString}\` which had value: ${formatValue(change.lhs)}`;
|
|
|
|
case "E":
|
|
// A property/element was edited
|
|
return `\u{2022} Changed \`${pathString}\` from ${formatValue(change.lhs)} to ${formatValue(change.rhs)}`;
|
|
|
|
case "A":
|
|
// An array change; change.item describes what happened at array index change.index
|
|
return formatArrayChange(change);
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
function formatArrayChange(change: Diff<any, any>): string | undefined {
|
|
if (!change.path) return;
|
|
if (change.path.some((segment) => EXCLUDED_FIELDS.has(segment))) {
|
|
return;
|
|
}
|
|
|
|
const pathString = change.path.join(" \u2192 ");
|
|
|
|
const arrayChange = (change as any).item;
|
|
const idx = (change as any).index;
|
|
|
|
if (!arrayChange) return;
|
|
|
|
switch (arrayChange.kind) {
|
|
case "N":
|
|
return `\u{2022} Added an item at index [${idx}] in \`${pathString}\`: ${formatValue(arrayChange.rhs)}`;
|
|
case "D":
|
|
return `\u{2022} Removed an item at index [${idx}] in \`${pathString}\`: ${formatValue(arrayChange.lhs)}`;
|
|
case "E":
|
|
return `\u{2022} Edited an item at index [${idx}] in \`${pathString}\` from ${formatValue(arrayChange.lhs)} to ${formatValue(arrayChange.rhs)}`;
|
|
case "A":
|
|
// Nested array changes could happen theoretically; handle or ignore similarly
|
|
return `\u{2022} Complex array change at index [${idx}] in \`${pathString}\`: ${JSON.stringify(arrayChange)}`;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
function formatValue(value: any): string {
|
|
if (value === null) return "null";
|
|
if (value === undefined) return "undefined";
|
|
if (typeof value === "object") {
|
|
try {
|
|
return JSON.stringify(value);
|
|
} catch {
|
|
return String(value);
|
|
}
|
|
}
|
|
return JSON.stringify(value);
|
|
}
|