jsonParser.ts 11 KB

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