import _ from 'lodash';
import { useCopy } from '@/composable/copy';
import type { Difference, ArrayDifference, ObjectDifference } from '../json-diff.types';
export const DiffRootViewer = ({ diff }: { diff: Difference }) => {
return (
{DiffViewer({ diff, showKeys: false })}
);
};
const 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 });
};
const 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 })}
,
);
};
const ComparisonViewer = ({ diff, showKeys }: { diff: Difference; showKeys?: boolean }) => {
const { value, key, oldValue } = diff;
return (
{showKeys && (
<>
{key}
{': '}
>
)}
{Value({ value: oldValue, status: 'removed' })}
{Value({ value, status: 'added' })},
);
};
const 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);
}
const Value = ({ value, status }: { value: unknown; status: string }) => {
const formatedValue = formatValue(value);
const { copy } = useCopy({ source: formatedValue });
return (
{formatedValue}
);
};