import _ from 'lodash';
import type { ArrayDifference, Difference, ObjectDifference } from '../json-diff.types';
import { useCopy } from '@/composable/copy';
export function DiffRootViewer({ diff }: { diff: Difference }) {
return (
{DiffViewer({ diff, showKeys: false })}
);
}
function DiffViewer({ diff, showKeys = true }: { diff: Difference; showKeys?: boolean }) {
const { type, status } = diff;
if (status === 'updated') {
return ComparisonViewer({ diff, showKeys });
}
if (type === 'array') {
return ChildrenViewer({ diff, showKeys, showChildrenKeys: false, openTag: '[', closeTag: ']' });
}
if (type === 'object') {
return ChildrenViewer({ diff, showKeys, openTag: '{', closeTag: '}' });
}
return LineDiffViewer({ diff, showKeys });
}
function LineDiffViewer({ diff, showKeys }: { diff: Difference; showKeys?: boolean }) {
const { value, key, status, oldValue } = diff;
const valueToDisplay = status === 'removed' ? oldValue : value;
return (
{showKeys && (
<>
{key}
{': '}
>
)}
{Value({ value: valueToDisplay, status })}
,
);
}
function ComparisonViewer({ diff, showKeys }: { diff: Difference; showKeys?: boolean }) {
const { value, key, oldValue } = diff;
return (
{showKeys && (
<>
{key}
{': '}
>
)}
{Value({ value: oldValue, status: 'removed' })}
{Value({ value, status: 'added' })},
);
}
function ChildrenViewer({
diff,
openTag,
closeTag,
showKeys,
showChildrenKeys = true,
}: {
diff: ArrayDifference | ObjectDifference
showKeys: boolean
showChildrenKeys?: boolean
openTag: string
closeTag: string
}) {
const { children, key, status, type } = diff;
return (
{showKeys && (
<>
{key}
{': '}
>
)}
{openTag}
{children.length > 0 &&
{children.map(diff => DiffViewer({ diff, showKeys: showChildrenKeys }))}
}
{`${closeTag},`}
);
}
function formatValue(value: unknown) {
if (_.isNull(value)) {
return 'null';
}
return JSON.stringify(value);
}
function Value({ value, status }: { value: unknown; status: string }) {
const formatedValue = formatValue(value);
const { copy } = useCopy({ source: formatedValue });
return (
{formatedValue}
);
}