From 362f2fa280fdab210074e9a7e01dde6187924d29 Mon Sep 17 00:00:00 2001
From: Corentin Thomasset <corentin.thomasset74@gmail.com>
Date: Sat, 22 Apr 2023 00:49:03 +0200
Subject: feat(new-tool): diff of two json objects

---
 .../json-diff/diff-viewer/diff-viewer.models.tsx   | 119 +++++++++++++++++++++
 1 file changed, 119 insertions(+)
 create mode 100644 src/tools/json-diff/diff-viewer/diff-viewer.models.tsx

(limited to 'src/tools/json-diff/diff-viewer/diff-viewer.models.tsx')

diff --git a/src/tools/json-diff/diff-viewer/diff-viewer.models.tsx b/src/tools/json-diff/diff-viewer/diff-viewer.models.tsx
new file mode 100644
index 0000000..5a19feb
--- /dev/null
+++ b/src/tools/json-diff/diff-viewer/diff-viewer.models.tsx
@@ -0,0 +1,119 @@
+import _ from 'lodash';
+import { useCopy } from '@/composable/copy';
+import type { Difference, ArrayDifference, ObjectDifference } from '../json-diff.types';
+
+export const DiffRootViewer = ({ diff }: { diff: Difference }) => {
+  return (
+    <div class={'diffs-viewer'}>
+      <ul>{DiffViewer({ diff, showKeys: false })}</ul>
+    </div>
+  );
+};
+
+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 (
+    <li>
+      <span class={[status, 'result']}>
+        {showKeys && (
+          <>
+            <span class={'key'}>{key}</span>
+            {': '}
+          </>
+        )}
+        {Value({ value: valueToDisplay, status })}
+      </span>
+      ,
+    </li>
+  );
+};
+
+const ComparisonViewer = ({ diff, showKeys }: { diff: Difference; showKeys?: boolean }) => {
+  const { value, key, oldValue } = diff;
+
+  return (
+    <li class={'updated-line'}>
+      {showKeys && (
+        <>
+          <span class={'key'}>{key}</span>
+          {': '}
+        </>
+      )}
+      {Value({ value: oldValue, status: 'removed' })}
+      {Value({ value, status: 'added' })},
+    </li>
+  );
+};
+
+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 (
+    <li>
+      <div class={[type, status]} style={{ display: 'inline-block' }}>
+        {showKeys && (
+          <>
+            <span class={'key'}>{key}</span>
+            {': '}
+          </>
+        )}
+
+        {openTag}
+        {children.length > 0 && <ul>{children.map((diff) => DiffViewer({ diff, showKeys: showChildrenKeys }))}</ul>}
+        {closeTag + ','}
+      </div>
+    </li>
+  );
+};
+
+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 (
+    <span class={['value', status]} onClick={copy}>
+      {formatedValue}
+    </span>
+  );
+};
-- 
cgit v1.2.3

