Przeglądaj źródła

fix empty nodes

victorbrambati 2 lat temu
rodzic
commit
24d9715056
1 zmienionych plików z 216 dodań i 104 usunięć
  1. 216 104
      src/utils/jsonParser.ts

+ 216 - 104
src/utils/jsonParser.ts

@@ -1,4 +1,4 @@
-import { parse } from "jsonc-parser";
+import { Node, parseTree } from "jsonc-parser";
 
 const calculateSize = (
   text: string | [string, string][],
@@ -32,125 +32,237 @@ const calculateSize = (
   };
 };
 
-const filterChild = ([_, v]) => {
-  const isNull = v === null;
-  const isArray = Array.isArray(v) && v.length;
-  const isObject = v instanceof Object;
+export const parser = (jsonStr: string, isFolded = false) => {
+try{  
+  let json = parseTree(jsonStr);
+  console.log(json);
+  let nodes: NodeData[] = [];
+  let edges: EdgeData[] = [];
 
-  return !isNull && (isArray || isObject);
-};
+  const addNodes = (
+    text: any,
+    width: number,
+    height: number,
+    parent: boolean,
+    isEmpty?: boolean
+  ) => {
+    let actualId = String(nodes.length + 1);
+    nodes = [
+      ...nodes,
+      {
+        id: actualId,
+        text: text,
+        width: width,
+        height: height,
+        data: {
+          isParent: parent,
+          childrenCount: parent ? 1 : 0,
+          isEmpty: isEmpty,
+        },
+      },
+    ];
+    return actualId;
+  };
 
-const filterValues = ([k, v]) => {
-  if (Array.isArray(v) || v instanceof Object) return false;
-  return true;
-};
+  const addEdges = (from: string, to: string) => {
+    edges = [
+      ...edges,
+      {
+        id: `e${from}-${to}`,
+        from: from,
+        to: to,
+      },
+    ];
+  };
 
-function generateChildren(object: Object, isFolded = false, nextId: () => string) {
-  if (!(object instanceof Object)) object = [object];
-
-  return Object.entries(object)
-    .filter(filterChild)
-    .flatMap(([key, v]) => {
-      const { width, height } = calculateSize(key, true, isFolded);
-      const children = extract(v, isFolded, nextId);
-
-      return [
-        {
-          id: nextId(),
-          text: key,
-          children,
-          width,
-          height,
-          data: {
-            isParent: true,
-            childrenCount: children.length,
-          },
-        },
-      ];
-    });
-}
+  let parentName: string = "";
+  let bracketOpen: string[] = [];
+  let objectsFromArray: number[] = [];
+  let notHaveParent: string[] = [];
+  let brothersNode: [string, string][] = [];
+  let brothersParentId: string | undefined = "";
+  let brotherKey: string = "";
+  let brothersNodeProps: {
+    id: string;
+    parentId: string | undefined;
+    objectsFromArrayId: number | undefined;
+  }[] = [];
 
-function generateNodeData(object: Object) {
-  if (object instanceof Object) {
-    const entries = Object.entries(object).filter(filterValues);
-    return entries;
-  }
+  const traverse = (
+    objectToTraverse: Node,
+    parentType?: string,
+    myParentId?: string,
+    nextType?: string
+  ) => {
+    let { type, children, value } = objectToTraverse;
 
-  return String(object);
-}
+    if (!children) {
+      if (value !== undefined) {
+        if (
+          parentType === "property" &&
+          nextType !== "object" &&
+          nextType !== "array"
+        ) {
+          brothersParentId = myParentId;
+          if (nextType === undefined) {
+            // add key and value to brothers node
+            brothersNode = [...brothersNode, [brotherKey, value]];
+          } else {
+            brotherKey = value;
+          }
+        } else if (parentType === "array") {
+          const { width, height } = calculateSize(String(value), false, isFolded);
+          const nodeFromArrayId = addNodes(String(value), width, height, false);
+          if (myParentId) {
+            addEdges(myParentId, nodeFromArrayId);
+          }
+        }
+        if (nextType && parentType !== "array") {
+          if (nextType === "object" || nextType === "array") {
+            parentName = value;
+          }
+        }
+      }
+    } else if (children) {
+      let parentId: string | undefined;
 
-const extract = (
-  os: string[] | object[] | null,
-  isFolded = false,
-  nextId = (
-    id => () =>
-      String(++id)
-  )(0)
-) => {
-  if (!os) return [];
+      if (type !== "property" && parentName !== "") {
+        // add last brothers node and add parent node
+        if (brothersNode.length > 0) {
+          // end brothers node
+          const { width, height } = calculateSize(brothersNode, false, isFolded);
+          const brothersNodeId = addNodes(brothersNode, width, height, false);
+          brothersNode = [];
+          if (brothersParentId) {
+            addEdges(brothersParentId, brothersNodeId);
+          } else {
+            notHaveParent = [...notHaveParent, brothersNodeId];
+          }
 
-  return [os].flat().map(o => {
-    const text = generateNodeData(o);
-    const { width, height } = calculateSize(text, false, isFolded);
+          brothersNodeProps = [
+            ...brothersNodeProps,
+            {
+              id: brothersNodeId,
+              parentId: brothersParentId,
+              objectsFromArrayId: objectsFromArray[objectsFromArray.length - 1],
+            },
+          ];
+        }
+        // add parent node
+        const { width, height } = calculateSize(parentName, true, isFolded);
+        parentId = addNodes(parentName, width, height, true);
+        bracketOpen = [...bracketOpen, parentId];
+        parentName = "";
 
-    return {
-      id: nextId(),
-      text,
-      width,
-      height,
-      children: generateChildren(o, isFolded, nextId),
-      data: {
-        isParent: false,
-        childrenCount: 0,
-        isEmpty: !text.length,
-      },
-    };
-  });
-};
+        // add edges from parent node
+        let brothersProps = brothersNodeProps.filter(
+          e =>
+            e.parentId === myParentId &&
+            e.objectsFromArrayId === objectsFromArray[objectsFromArray.length - 1]
+        );
+        if (brothersProps.length > 0) {
+          addEdges(brothersProps[brothersProps.length - 1].id, parentId);
+        } else if (myParentId) {
+          addEdges(myParentId, parentId);
+        } else {
+          notHaveParent = [...notHaveParent, parentId];
+        }
+      } else if (parentType === "array") {
+        objectsFromArray = [...objectsFromArray, objectsFromArray.length + 1];
+      }
 
-const flatten = (xs: { id: string; children: never[] }[]) =>
-  xs.flatMap(({ children, ...rest }) => [rest, ...flatten(children)]);
-
-const relationships = (xs: { id: string; children: never[] }[]) => {
-  return xs.flatMap(({ id: from, children = [] }) => [
-    ...children.map(({ id: to }) => ({
-      id: `e${from}-${to}`,
-      from,
-      to,
-    })),
-    ...relationships(children),
-  ]);
-};
+      children.forEach((branch, index, array) => {
+        if (array[index + 1]) {
+          traverse(
+            branch,
+            type,
+            bracketOpen[bracketOpen.length - 1],
+            array[index + 1].type
+          );
+        } else {
+          traverse(branch, type, bracketOpen[bracketOpen.length - 1]);
+        }
+      });
 
-export const parser = (jsonStr: string, isFolded = false) => {
-  try {
-    let json = parse(jsonStr);
-    if (!Array.isArray(json)) json = [json];
-    const nodes: NodeData[] = [];
-    const edges: EdgeData[] = [];
-
-    const mappedElements = extract(json, isFolded);
-    const res = [...flatten(mappedElements), ...relationships(mappedElements)];
-
-    res.forEach(data => {
-      if (isNode(data)) {
-        nodes.push(data);
-      } else {
-        edges.push(data);
+      if (type !== "property") {
+        // when children end
+        if (parentType !== "array") {
+          if (bracketOpen.length > 0) {
+            let newBracketOpen = [...bracketOpen];
+            newBracketOpen.splice(newBracketOpen.length - 1);
+            bracketOpen = [...newBracketOpen];
+          }
+        } else if (parentType === "array") {
+          if (objectsFromArray.length > 0) {
+            let newobjectsFromArray = [...objectsFromArray];
+            newobjectsFromArray.splice(newobjectsFromArray.length - 1);
+            objectsFromArray = [...newobjectsFromArray];
+          }
+        }
+
+        // add brothers node when is the last node
+        if (brothersNode.length > 0) {
+          const { width, height } = calculateSize(brothersNode, false, isFolded);
+          const brothersNodeId = addNodes(brothersNode, width, height, false);
+          brothersNode = [];
+          if (brothersParentId) {
+            addEdges(brothersParentId, brothersNodeId);
+          } else {
+            notHaveParent = [...notHaveParent, brothersNodeId];
+          }
+          brothersNodeProps = [
+            ...brothersNodeProps,
+            {
+              id: brothersNodeId,
+              parentId: brothersParentId,
+              objectsFromArrayId: objectsFromArray[objectsFromArray.length - 1],
+            },
+          ];
+        }
+
+        if (parentId) {
+          let myChildrens = edges.filter(e => e.from === parentId);
+          let myIndex = nodes.findIndex(e => e.id === parentId);
+
+          let ModifyNodes = [...nodes];
+          if (ModifyNodes[myIndex]) {
+            ModifyNodes[myIndex].data.childrenCount = myChildrens.length;
+            nodes = [...ModifyNodes];
+          }
+        }
       }
+    }
+  };
+  if (json) {
+    traverse(json);
+  }
+  if (notHaveParent.length > 1) {
+    console.log(notHaveParent);
+    const text = "";
+    const { width, height } = calculateSize(text, false, isFolded);
+    const emptyId = addNodes(text, width, height, false, true);
+    notHaveParent.forEach(children => {
+      addEdges(emptyId, children);
     });
+  }
+  if (nodes.length === 0 && json) {
+    if (json.type === "array") {
+      const text = "[]";
+      const { width, height } = calculateSize(text, false, isFolded);
+      addNodes(text, width, height, false);
+    } else {
+      const text = "{}";
+      const { width, height } = calculateSize(text, false, isFolded);
+      addNodes(text, width, height, false);
+    }
+  }
 
-    return { nodes, edges };
-  } catch (error) {
+  return { nodes, edges };
+} catch (error) {
     console.error(error);
     return {
       nodes: [],
       edges: [],
     };
   }
-};
-
-function isNode(element: NodeData | EdgeData) {
-  if ("text" in element) return true;
-  return false;
-}
+};