123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import { parse } from "jsonc-parser";
- const calculateSize = (
- text: string | [string, string][],
- isParent = false,
- isExpanded: boolean
- ) => {
- let value = "";
- if (typeof text === "string") value = text;
- else value = text.map(([k, v]) => `${k}: ${v}`).join("\n");
- const lineCount = value.split("\n");
- const lineLengths = lineCount.map(line => line.length);
- const longestLine = lineLengths.sort((a, b) => b - a)[0];
- const getWidth = () => {
- if (Array.isArray(text) && !text.length) return 40;
- if (isExpanded) return 35 + longestLine * 8 + (isParent ? 60 : 0);
- if (isParent) return 170;
- return 200;
- };
- const getHeight = () => {
- if (lineCount.length * 17.8 < 30) return 40;
- return (lineCount.length + 1) * 18;
- };
- return {
- width: getWidth(),
- height: getHeight(),
- };
- };
- const filterChild = ([_, v]) => {
- const isNull = v === null;
- const isArray = Array.isArray(v) && v.length;
- const isObject = v instanceof Object;
- return !isNull && (isArray || isObject);
- };
- const filterValues = ([k, v]) => {
- if (Array.isArray(v) || v instanceof Object) return false;
- return true;
- };
- function generateChildren(object: Object, isExpanded = true, nextId: () => string) {
- if (!(object instanceof Object)) object = [object];
- return Object.entries(object)
- .filter(filterChild)
- .flatMap(([key, v]) => {
- const { width, height } = calculateSize(key, true, isExpanded);
- const children = extract(v, isExpanded, nextId);
- return [
- {
- id: nextId(),
- text: key,
- children,
- width,
- height,
- data: {
- isParent: true,
- hasChild: !!children.length,
- },
- },
- ];
- });
- }
- function generateNodeData(object: Object) {
- if (object instanceof Object) {
- const entries = Object.entries(object).filter(filterValues);
- return entries;
- }
- return String(object);
- }
- const extract = (
- os: string[] | object[] | null,
- isExpanded = true,
- nextId = (
- id => () =>
- String(++id)
- )(0)
- ) => {
- if (!os) return [];
- return [os].flat().map(o => {
- const text = generateNodeData(o);
- const { width, height } = calculateSize(text, false, isExpanded);
- return {
- id: nextId(),
- text,
- width,
- height,
- children: generateChildren(o, isExpanded, nextId),
- data: {
- isParent: false,
- hasChild: false,
- isEmpty: !text.length,
- },
- };
- });
- };
- 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),
- ]);
- };
- export const parser = (jsonStr: string, isExpanded = true) => {
- try {
- let json = parse(jsonStr);
- if (!Array.isArray(json)) json = [json];
- const nodes: NodeData[] = [];
- const edges: EdgeData[] = [];
- const mappedElements = extract(json, isExpanded);
- const res = [...flatten(mappedElements), ...relationships(mappedElements)];
- res.forEach(data => {
- if (isNode(data)) {
- nodes.push(data);
- } else {
- edges.push(data);
- }
- });
- return { nodes, edges };
- } catch (error) {
- console.error(error);
- return {
- nodes: [],
- edges: [],
- };
- }
- };
- function isNode(element: NodeData | EdgeData) {
- if ("text" in element) return true;
- return false;
- }
|