jsonParser.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. import { Node, parseTree } from "jsonc-parser";
  2. const calculateSize = (text: string | [string, string][], isParent = false, isFolded: boolean) => {
  3. let value = "";
  4. if (typeof text === "string") value = text;
  5. else value = text.map(([k, v]) => `${k}: ${v}`).join("\n");
  6. const lineCount = value.split("\n");
  7. const lineLengths = lineCount.map(line => line.length);
  8. const longestLine = lineLengths.sort((a, b) => b - a)[0];
  9. const getWidth = () => {
  10. if (Array.isArray(text) && !text.length) return 40;
  11. if (!isFolded) return 35 + longestLine * 8 + (isParent ? 60 : 0);
  12. if (isParent) return 170;
  13. return 200;
  14. };
  15. const getHeight = () => {
  16. if (lineCount.length * 17.8 < 30) return 40;
  17. return (lineCount.length + 1) * 18;
  18. };
  19. return {
  20. width: getWidth(),
  21. height: getHeight(),
  22. };
  23. };
  24. export const parser = (jsonStr: string, isFolded = false) => {
  25. try {
  26. let json = parseTree(jsonStr);
  27. let nodes: NodeData[] = [];
  28. let edges: EdgeData[] = [];
  29. const addNodes = (
  30. text: any,
  31. width: number,
  32. height: number,
  33. parent: "string" | "number" | "boolean" | "object" | "array" | "null" | false,
  34. isEmpty?: boolean
  35. ) => {
  36. let actualId = String(nodes.length + 1);
  37. nodes = [
  38. ...nodes,
  39. {
  40. id: actualId,
  41. text: text,
  42. width: width,
  43. height: height,
  44. data: {
  45. parent: parent === "array" || parent === "object" ? parent : false,
  46. childrenCount: parent ? 1 : 0,
  47. isEmpty: isEmpty,
  48. },
  49. },
  50. ];
  51. return actualId;
  52. };
  53. const addEdges = (from: string, to: string) => {
  54. edges = [
  55. ...edges,
  56. {
  57. id: `e${from}-${to}`,
  58. from: from,
  59. to: to,
  60. },
  61. ];
  62. };
  63. let parentName: string = "";
  64. let bracketOpen: { id: string; type: string }[] = [];
  65. let objectsFromArray: number[] = [];
  66. let objectsFromArrayId = 0;
  67. let notHaveParent: string[] = [];
  68. let brothersNode: [string, string][] = [];
  69. let brothersParentId: string | undefined = "";
  70. let brotherKey: string = "";
  71. let brothersNodeProps: {
  72. id: string;
  73. parentId: string | undefined;
  74. objectsFromArrayId: number | undefined;
  75. }[] = [];
  76. const traverse = (
  77. objectToTraverse: Node,
  78. parentType?: string,
  79. myParentId?: string,
  80. nextType?: string
  81. ) => {
  82. let { type, children, value } = objectToTraverse;
  83. if (!children) {
  84. if (value !== undefined) {
  85. if (parentType === "property" && nextType !== "object" && nextType !== "array") {
  86. brothersParentId = myParentId;
  87. if (nextType === undefined) {
  88. // add key and value to brothers node
  89. brothersNode = [...brothersNode, [brotherKey, value]];
  90. } else {
  91. brotherKey = value;
  92. }
  93. } else if (parentType === "array") {
  94. const { width, height } = calculateSize(String(value), false, isFolded);
  95. const nodeFromArrayId = addNodes(String(value), width, height, false);
  96. if (myParentId) {
  97. addEdges(myParentId, nodeFromArrayId);
  98. }
  99. }
  100. if (nextType && parentType !== "array") {
  101. if (nextType === "object" || nextType === "array") {
  102. parentName = value;
  103. }
  104. }
  105. }
  106. } else if (children) {
  107. let parentId: string | undefined;
  108. if (type !== "property" && parentName !== "") {
  109. // add last brothers node and add parent node
  110. if (brothersNode.length > 0) {
  111. // add or concat brothers node of same parent
  112. let findBrothersNode = brothersNodeProps.find(
  113. e =>
  114. e.parentId === brothersParentId &&
  115. e.objectsFromArrayId === objectsFromArray[objectsFromArray.length - 1]
  116. );
  117. if (findBrothersNode) {
  118. let ModifyNodes = [...nodes];
  119. let findNode = nodes.findIndex(e => e.id === findBrothersNode?.id);
  120. if (ModifyNodes[findNode]) {
  121. ModifyNodes[findNode].text = ModifyNodes[findNode].text.concat(brothersNode);
  122. const { width, height } = calculateSize(
  123. ModifyNodes[findNode].text,
  124. false,
  125. isFolded
  126. );
  127. ModifyNodes[findNode].width = width;
  128. ModifyNodes[findNode].height = height;
  129. nodes = [...ModifyNodes];
  130. brothersNode = [];
  131. }
  132. } else {
  133. const { width, height } = calculateSize(brothersNode, false, isFolded);
  134. const brothersNodeId = addNodes(brothersNode, width, height, false);
  135. brothersNode = [];
  136. if (brothersParentId) {
  137. addEdges(brothersParentId, brothersNodeId);
  138. } else {
  139. notHaveParent = [...notHaveParent, brothersNodeId];
  140. }
  141. brothersNodeProps = [
  142. ...brothersNodeProps,
  143. {
  144. id: brothersNodeId,
  145. parentId: brothersParentId,
  146. objectsFromArrayId: objectsFromArray[objectsFromArray.length - 1],
  147. },
  148. ];
  149. }
  150. }
  151. // add parent node
  152. const { width, height } = calculateSize(parentName, true, isFolded);
  153. parentId = addNodes(parentName, width, height, type);
  154. bracketOpen = [...bracketOpen, { id: parentId, type: type }];
  155. parentName = "";
  156. // add edges from parent node
  157. let brothersProps = brothersNodeProps.filter(
  158. e =>
  159. e.parentId === myParentId &&
  160. e.objectsFromArrayId === objectsFromArray[objectsFromArray.length - 1]
  161. );
  162. if (
  163. (brothersProps.length > 0 &&
  164. bracketOpen[bracketOpen.length - 2] &&
  165. bracketOpen[bracketOpen.length - 2].type !== "object") ||
  166. (brothersProps.length > 0 && bracketOpen.length === 1)
  167. ) {
  168. addEdges(brothersProps[brothersProps.length - 1].id, parentId);
  169. } else if (myParentId) {
  170. addEdges(myParentId, parentId);
  171. } else {
  172. notHaveParent = [...notHaveParent, parentId];
  173. }
  174. } else if (parentType === "array") {
  175. objectsFromArray = [...objectsFromArray, objectsFromArrayId++];
  176. }
  177. children.forEach((branch, index, array) => {
  178. if (array[index + 1]) {
  179. traverse(
  180. branch,
  181. type,
  182. bracketOpen[bracketOpen.length - 1]
  183. ? bracketOpen[bracketOpen.length - 1].id
  184. : undefined,
  185. array[index + 1].type
  186. );
  187. } else {
  188. traverse(
  189. branch,
  190. type,
  191. bracketOpen[bracketOpen.length - 1]
  192. ? bracketOpen[bracketOpen.length - 1].id
  193. : undefined
  194. );
  195. }
  196. });
  197. if (type !== "property") {
  198. // when children end
  199. // add or concat brothers node when it is the last parent node
  200. if (brothersNode.length > 0) {
  201. let findBrothersNode = brothersNodeProps.find(
  202. e =>
  203. e.parentId === brothersParentId &&
  204. e.objectsFromArrayId === objectsFromArray[objectsFromArray.length - 1]
  205. );
  206. if (findBrothersNode) {
  207. let ModifyNodes = [...nodes];
  208. let findNode = nodes.findIndex(e => e.id === findBrothersNode?.id);
  209. if (ModifyNodes[findNode]) {
  210. ModifyNodes[findNode].text = ModifyNodes[findNode].text.concat(brothersNode);
  211. const { width, height } = calculateSize(
  212. ModifyNodes[findNode].text,
  213. false,
  214. isFolded
  215. );
  216. ModifyNodes[findNode].width = width;
  217. ModifyNodes[findNode].height = height;
  218. nodes = [...ModifyNodes];
  219. brothersNode = [];
  220. }
  221. } else {
  222. const { width, height } = calculateSize(brothersNode, false, isFolded);
  223. const brothersNodeId = addNodes(brothersNode, width, height, false);
  224. brothersNode = [];
  225. if (brothersParentId) {
  226. addEdges(brothersParentId, brothersNodeId);
  227. } else {
  228. notHaveParent = [...notHaveParent, brothersNodeId];
  229. }
  230. brothersNodeProps = [
  231. ...brothersNodeProps,
  232. {
  233. id: brothersNodeId,
  234. parentId: brothersParentId,
  235. objectsFromArrayId: objectsFromArray[objectsFromArray.length - 1],
  236. },
  237. ];
  238. }
  239. }
  240. // close brackets
  241. if (parentType !== "array") {
  242. if (bracketOpen.length > 0) {
  243. let newBracketOpen = [...bracketOpen];
  244. newBracketOpen.splice(newBracketOpen.length - 1);
  245. bracketOpen = [...newBracketOpen];
  246. }
  247. } else if (parentType === "array") {
  248. if (objectsFromArray.length > 0) {
  249. let newobjectsFromArray = [...objectsFromArray];
  250. newobjectsFromArray.splice(newobjectsFromArray.length - 1);
  251. objectsFromArray = [...newobjectsFromArray];
  252. }
  253. }
  254. if (parentId) {
  255. let myChildrens = edges.filter(e => e.from === parentId);
  256. let myIndex = nodes.findIndex(e => e.id === parentId);
  257. let ModifyNodes = [...nodes];
  258. if (ModifyNodes[myIndex]) {
  259. ModifyNodes[myIndex].data.childrenCount = myChildrens.length;
  260. nodes = [...ModifyNodes];
  261. }
  262. }
  263. }
  264. }
  265. };
  266. if (json) {
  267. traverse(json);
  268. if (notHaveParent.length > 1) {
  269. if (json.type !== "array") {
  270. const text = "";
  271. const { width, height } = calculateSize(text, false, isFolded);
  272. const emptyId = addNodes(text, width, height, false, true);
  273. notHaveParent.forEach(children => {
  274. addEdges(emptyId, children);
  275. });
  276. }
  277. }
  278. if (nodes.length === 0) {
  279. if (json.type === "array") {
  280. const text = "[]";
  281. const { width, height } = calculateSize(text, false, isFolded);
  282. addNodes(text, width, height, false);
  283. } else {
  284. const text = "{}";
  285. const { width, height } = calculateSize(text, false, isFolded);
  286. addNodes(text, width, height, false);
  287. }
  288. }
  289. }
  290. return { nodes, edges };
  291. } catch (error) {
  292. console.error(error);
  293. return {
  294. nodes: [],
  295. edges: [],
  296. };
  297. }
  298. };