mirror of
https://github.com/ChiChou/entdb.git
synced 2026-06-10 23:07:47 +02:00
Use @pierre/diffs library for side-by-side diff view
- Replace custom diff implementation with @pierre/diffs FileDiff component - Add proper indentation to normalized plist output for accurate diffing - Keep key-level diff summary for quick overview
This commit is contained in:
Generated
+1144
-35
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@
|
||||
"lint": "eslint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pierre/diffs": "^1.1.15",
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-collapsible": "^1.1.12",
|
||||
|
||||
+16
-115
@@ -1,49 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo } from "react";
|
||||
import { FileDiff } from "@pierre/diffs/react";
|
||||
import { parseDiffFromFile } from "@pierre/diffs";
|
||||
|
||||
import { diffPlistKeys, type PlistDiff } from "@/lib/plist";
|
||||
|
||||
interface DiffLine {
|
||||
type: "unchanged" | "added" | "removed" | "changed";
|
||||
oldLine?: string;
|
||||
newLine?: string;
|
||||
key?: string;
|
||||
}
|
||||
|
||||
function computeLineDiff(oldLines: string[], newLines: string[]): DiffLine[] {
|
||||
const result: DiffLine[] = [];
|
||||
const oldSet = new Set(oldLines);
|
||||
const newSet = new Set(newLines);
|
||||
|
||||
const maxLen = Math.max(oldLines.length, newLines.length);
|
||||
|
||||
let oi = 0;
|
||||
let ni = 0;
|
||||
|
||||
while (oi < oldLines.length || ni < newLines.length) {
|
||||
const oldLine = oldLines[oi];
|
||||
const newLine = newLines[ni];
|
||||
|
||||
if (oldLine === newLine) {
|
||||
result.push({ type: "unchanged", oldLine, newLine });
|
||||
oi++;
|
||||
ni++;
|
||||
} else if (oldLine && !newSet.has(oldLine)) {
|
||||
result.push({ type: "removed", oldLine, newLine: undefined });
|
||||
oi++;
|
||||
} else if (newLine && !oldSet.has(newLine)) {
|
||||
result.push({ type: "added", oldLine: undefined, newLine });
|
||||
ni++;
|
||||
} else {
|
||||
result.push({ type: "changed", oldLine, newLine });
|
||||
oi++;
|
||||
ni++;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
interface DiffViewerProps {
|
||||
oldXml: string;
|
||||
newXml: string;
|
||||
@@ -57,91 +19,30 @@ export function DiffViewer({
|
||||
oldLabel,
|
||||
newLabel,
|
||||
}: DiffViewerProps) {
|
||||
const diff = useMemo(() => diffPlistKeys(oldXml, newXml), [oldXml, newXml]);
|
||||
|
||||
const oldLines = useMemo(
|
||||
() => oldXml.split("\n").filter((l) => l.trim()),
|
||||
[oldXml],
|
||||
);
|
||||
const newLines = useMemo(
|
||||
() => newXml.split("\n").filter((l) => l.trim()),
|
||||
[newXml],
|
||||
const keysDiff = useMemo(
|
||||
() => diffPlistKeys(oldXml, newXml),
|
||||
[oldXml, newXml],
|
||||
);
|
||||
|
||||
const lineDiff = useMemo(
|
||||
() => computeLineDiff(oldLines, newLines),
|
||||
[oldLines, newLines],
|
||||
const fileDiff = useMemo(
|
||||
() =>
|
||||
parseDiffFromFile(
|
||||
{ name: `${oldLabel}.plist`, contents: oldXml },
|
||||
{ name: `${newLabel}.plist`, contents: newXml },
|
||||
),
|
||||
[oldXml, newXml, oldLabel, newLabel],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<DiffSummary diff={diff} />
|
||||
<div className="grid grid-cols-2 gap-2 font-mono text-xs">
|
||||
<div className="bg-gray-100 dark:bg-gray-800 rounded-t px-3 py-2 font-semibold border-b">
|
||||
{oldLabel}
|
||||
</div>
|
||||
<div className="bg-gray-100 dark:bg-gray-800 rounded-t px-3 py-2 font-semibold border-b">
|
||||
{newLabel}
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{lineDiff.map((line, i) => (
|
||||
<DiffLineRow key={i} line={line} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<DiffSummary diff={keysDiff} />
|
||||
<div className="rounded-lg overflow-hidden border text-sm">
|
||||
<FileDiff fileDiff={fileDiff} options={{ diffStyle: "split" }} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DiffLineRow({ line }: { line: DiffLine }) {
|
||||
const baseClasses = "px-3 py-0.5 font-mono text-xs whitespace-pre overflow-x-auto";
|
||||
|
||||
switch (line.type) {
|
||||
case "unchanged":
|
||||
return (
|
||||
<>
|
||||
<div className={`${baseClasses} bg-gray-50 dark:bg-gray-900`}>
|
||||
{line.oldLine}
|
||||
</div>
|
||||
<div className={`${baseClasses} bg-gray-50 dark:bg-gray-900`}>
|
||||
{line.newLine}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
case "removed":
|
||||
return (
|
||||
<>
|
||||
<div className={`${baseClasses} bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-200`}>
|
||||
{line.oldLine}
|
||||
</div>
|
||||
<div className={`${baseClasses} bg-gray-100 dark:bg-gray-800`} />
|
||||
</>
|
||||
);
|
||||
case "added":
|
||||
return (
|
||||
<>
|
||||
<div className={`${baseClasses} bg-gray-100 dark:bg-gray-800`} />
|
||||
<div className={`${baseClasses} bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-200`}>
|
||||
{line.newLine}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
case "changed":
|
||||
return (
|
||||
<>
|
||||
<div className={`${baseClasses} bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200`}>
|
||||
{line.oldLine}
|
||||
</div>
|
||||
<div className={`${baseClasses} bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-200`}>
|
||||
{line.newLine}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function DiffSummary({ diff }: { diff: PlistDiff }) {
|
||||
const hasChanges =
|
||||
diff.added.length > 0 || diff.removed.length > 0 || diff.changed.length > 0;
|
||||
|
||||
+16
-3
@@ -32,15 +32,28 @@ export function normalizePlist(xml: string): string {
|
||||
const lines = [
|
||||
'<?xml version="1.0" encoding="UTF-8"?>',
|
||||
'<plist version="1.0">',
|
||||
"<dict>",
|
||||
...entries.map((e) => `<key>${e.key}</key>\n${e.value}`),
|
||||
"</dict>",
|
||||
" <dict>",
|
||||
...entries.map((e) => ` <key>${e.key}</key>\n ${indentValue(e.value)}`),
|
||||
" </dict>",
|
||||
"</plist>",
|
||||
];
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function indentValue(xml: string): string {
|
||||
// Simple indentation for single-line values
|
||||
if (!xml.includes("\n") && !xml.includes("><")) {
|
||||
return xml;
|
||||
}
|
||||
// For complex values, add indentation after each closing >
|
||||
return xml
|
||||
.replace(/></g, ">\n <")
|
||||
.split("\n")
|
||||
.map((line, i) => (i === 0 ? line : " " + line))
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
export interface PlistDiff {
|
||||
added: string[];
|
||||
removed: string[];
|
||||
|
||||
Reference in New Issue
Block a user