UNPKG

@langchain/core

Version:
1 lines 11.6 kB
{"version":3,"file":"graph_mermaid.cjs","names":["nodeLabel: string","nodeColors: Record<string, string>","nodes: Record<string, Node>","edges: Edge[]","config?: {\n firstNode?: string;\n lastNode?: string;\n curveStyle?: string;\n withStyles?: boolean;\n nodeColors?: Record<string, string>;\n wrapLabelNWords?: number;\n }","formatDict: Record<string, string>","edgeGroups: Record<string, Edge[]>","prefixes: string[]","prefix: string","edges","mermaidSyntax: string","config?: {\n /**\n * The type of image to render.\n * @default \"png\"\n */\n imageType?: \"png\" | \"jpeg\" | \"webp\";\n backgroundColor?: string;\n }","toBase64Url"],"sources":["../../src/runnables/graph_mermaid.ts"],"sourcesContent":["import { Edge, Node } from \"./types.js\";\nimport { toBase64Url } from \"./utils.js\";\n\nfunction _escapeNodeLabel(nodeLabel: string): string {\n // Escapes the node label for Mermaid syntax.\n return nodeLabel.replace(/[^a-zA-Z-_0-9]/g, \"_\");\n}\n\nconst MARKDOWN_SPECIAL_CHARS = [\"*\", \"_\", \"`\"];\n\nfunction _generateMermaidGraphStyles(\n nodeColors: Record<string, string>\n): string {\n let styles = \"\";\n for (const [className, color] of Object.entries(nodeColors)) {\n styles += `\\tclassDef ${className} ${color};\\n`;\n }\n return styles;\n}\n\n/**\n * Draws a Mermaid graph using the provided graph data\n */\nexport function drawMermaid(\n nodes: Record<string, Node>,\n edges: Edge[],\n config?: {\n firstNode?: string;\n lastNode?: string;\n curveStyle?: string;\n withStyles?: boolean;\n nodeColors?: Record<string, string>;\n wrapLabelNWords?: number;\n }\n): string {\n const {\n firstNode,\n lastNode,\n nodeColors,\n withStyles = true,\n curveStyle = \"linear\",\n wrapLabelNWords = 9,\n } = config ?? {};\n // Initialize Mermaid graph configuration\n let mermaidGraph = withStyles\n ? `%%{init: {'flowchart': {'curve': '${curveStyle}'}}}%%\\ngraph TD;\\n`\n : \"graph TD;\\n\";\n if (withStyles) {\n // Node formatting templates\n const defaultClassLabel = \"default\";\n const formatDict: Record<string, string> = {\n [defaultClassLabel]: \"{0}({1})\",\n };\n if (firstNode !== undefined) {\n formatDict[firstNode] = \"{0}([{1}]):::first\";\n }\n if (lastNode !== undefined) {\n formatDict[lastNode] = \"{0}([{1}]):::last\";\n }\n\n // Add nodes to the graph\n for (const [key, node] of Object.entries(nodes)) {\n const nodeName = node.name.split(\":\").pop() ?? \"\";\n const label = MARKDOWN_SPECIAL_CHARS.some(\n (char) => nodeName.startsWith(char) && nodeName.endsWith(char)\n )\n ? `<p>${nodeName}</p>`\n : nodeName;\n\n let finalLabel = label;\n if (Object.keys(node.metadata ?? {}).length) {\n finalLabel += `<hr/><small><em>${Object.entries(node.metadata ?? {})\n .map(([k, v]) => `${k} = ${v}`)\n .join(\"\\n\")}</em></small>`;\n }\n\n const nodeLabel = (formatDict[key] ?? formatDict[defaultClassLabel])\n .replace(\"{0}\", _escapeNodeLabel(key))\n .replace(\"{1}\", finalLabel);\n\n mermaidGraph += `\\t${nodeLabel}\\n`;\n }\n }\n\n // Group edges by their common prefixes\n const edgeGroups: Record<string, Edge[]> = {};\n for (const edge of edges) {\n const srcParts = edge.source.split(\":\");\n const tgtParts = edge.target.split(\":\");\n const commonPrefix = srcParts\n .filter((src, i) => src === tgtParts[i])\n .join(\":\");\n if (!edgeGroups[commonPrefix]) {\n edgeGroups[commonPrefix] = [];\n }\n edgeGroups[commonPrefix].push(edge);\n }\n\n const seenSubgraphs = new Set<string>();\n\n // sort prefixes by path length for correct nesting\n function sortPrefixesByDepth(prefixes: string[]): string[] {\n return [...prefixes].sort((a, b) => {\n return a.split(\":\").length - b.split(\":\").length;\n });\n }\n\n function addSubgraph(edges: Edge[], prefix: string): void {\n const selfLoop = edges.length === 1 && edges[0].source === edges[0].target;\n if (prefix && !selfLoop) {\n const subgraph = prefix.split(\":\").pop()!;\n\n if (seenSubgraphs.has(prefix)) {\n throw new Error(\n `Found duplicate subgraph '${subgraph}' at '${prefix} -- this likely means that ` +\n \"you're reusing a subgraph node with the same name. \" +\n \"Please adjust your graph to have subgraph nodes with unique names.\"\n );\n }\n\n seenSubgraphs.add(prefix);\n mermaidGraph += `\\tsubgraph ${subgraph}\\n`;\n }\n\n // all nested prefixes for this level, sorted by depth\n const nestedPrefixes = sortPrefixesByDepth(\n Object.keys(edgeGroups).filter(\n (nestedPrefix) =>\n nestedPrefix.startsWith(`${prefix}:`) &&\n nestedPrefix !== prefix &&\n nestedPrefix.split(\":\").length === prefix.split(\":\").length + 1\n )\n );\n\n for (const nestedPrefix of nestedPrefixes) {\n addSubgraph(edgeGroups[nestedPrefix], nestedPrefix);\n }\n\n for (const edge of edges) {\n const { source, target, data, conditional } = edge;\n\n let edgeLabel = \"\";\n if (data !== undefined) {\n let edgeData = data;\n const words = edgeData.split(\" \");\n if (words.length > wrapLabelNWords) {\n edgeData = Array.from(\n { length: Math.ceil(words.length / wrapLabelNWords) },\n (_, i) =>\n words\n .slice(i * wrapLabelNWords, (i + 1) * wrapLabelNWords)\n .join(\" \")\n ).join(\"&nbsp;<br>&nbsp;\");\n }\n edgeLabel = conditional\n ? ` -. &nbsp;${edgeData}&nbsp; .-> `\n : ` -- &nbsp;${edgeData}&nbsp; --> `;\n } else {\n edgeLabel = conditional ? \" -.-> \" : \" --> \";\n }\n\n mermaidGraph += `\\t${_escapeNodeLabel(\n source\n )}${edgeLabel}${_escapeNodeLabel(target)};\\n`;\n }\n\n if (prefix && !selfLoop) {\n mermaidGraph += \"\\tend\\n\";\n }\n }\n\n // Start with the top-level edges (no common prefix)\n addSubgraph(edgeGroups[\"\"] ?? [], \"\");\n\n // Add remaining top-level subgraphs\n for (const prefix in edgeGroups) {\n if (!prefix.includes(\":\") && prefix !== \"\") {\n addSubgraph(edgeGroups[prefix], prefix);\n }\n }\n\n // Add custom styles for nodes\n if (withStyles) {\n mermaidGraph += _generateMermaidGraphStyles(nodeColors ?? {});\n }\n\n return mermaidGraph;\n}\n\n/**\n * Renders Mermaid graph using the Mermaid.INK API.\n *\n * @example\n * ```javascript\n * const image = await drawMermaidImage(mermaidSyntax, {\n * backgroundColor: \"white\",\n * imageType: \"png\",\n * });\n * fs.writeFileSync(\"image.png\", image);\n * ```\n *\n * @param mermaidSyntax - The Mermaid syntax to render.\n * @param config - The configuration for the image.\n * @returns The image as a Blob.\n */\nexport async function drawMermaidImage(\n mermaidSyntax: string,\n config?: {\n /**\n * The type of image to render.\n * @default \"png\"\n */\n imageType?: \"png\" | \"jpeg\" | \"webp\";\n backgroundColor?: string;\n }\n) {\n let backgroundColor = config?.backgroundColor ?? \"white\";\n const imageType = config?.imageType ?? \"png\";\n\n const mermaidSyntaxEncoded = toBase64Url(mermaidSyntax);\n\n // Check if the background color is a hexadecimal color code using regex\n if (backgroundColor !== undefined) {\n const hexColorPattern = /^#(?:[0-9a-fA-F]{3}){1,2}$/;\n if (!hexColorPattern.test(backgroundColor)) {\n backgroundColor = `!${backgroundColor}`;\n }\n }\n const imageUrl = `https://mermaid.ink/img/${mermaidSyntaxEncoded}?bgColor=${backgroundColor}&type=${imageType}`;\n const res = await fetch(imageUrl);\n if (!res.ok) {\n throw new Error(\n [\n `Failed to render the graph using the Mermaid.INK API.`,\n `Status code: ${res.status}`,\n `Status text: ${res.statusText}`,\n ].join(\"\\n\")\n );\n }\n const content = await res.blob();\n return content;\n}\n"],"mappings":";;;AAGA,SAAS,iBAAiBA,WAA2B;AAEnD,QAAO,UAAU,QAAQ,mBAAmB,IAAI;AACjD;AAED,MAAM,yBAAyB;CAAC;CAAK;CAAK;AAAI;AAE9C,SAAS,4BACPC,YACQ;CACR,IAAI,SAAS;AACb,MAAK,MAAM,CAAC,WAAW,MAAM,IAAI,OAAO,QAAQ,WAAW,EACzD,UAAU,CAAC,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,CAAC;AAEjD,QAAO;AACR;;;;AAKD,SAAgB,YACdC,OACAC,OACAC,QAQQ;CACR,MAAM,EACJ,WACA,UACA,YACA,aAAa,MACb,aAAa,UACb,kBAAkB,GACnB,GAAG,UAAU,CAAE;CAEhB,IAAI,eAAe,aACf,CAAC,kCAAkC,EAAE,WAAW,mBAAmB,CAAC,GACpE;AACJ,KAAI,YAAY;EAEd,MAAM,oBAAoB;EAC1B,MAAMC,aAAqC,GACxC,oBAAoB,WACtB;AACD,MAAI,cAAc,QAChB,WAAW,aAAa;AAE1B,MAAI,aAAa,QACf,WAAW,YAAY;AAIzB,OAAK,MAAM,CAAC,KAAK,KAAK,IAAI,OAAO,QAAQ,MAAM,EAAE;GAC/C,MAAM,WAAW,KAAK,KAAK,MAAM,IAAI,CAAC,KAAK,IAAI;GAC/C,MAAM,QAAQ,uBAAuB,KACnC,CAAC,SAAS,SAAS,WAAW,KAAK,IAAI,SAAS,SAAS,KAAK,CAC/D,GACG,CAAC,GAAG,EAAE,SAAS,IAAI,CAAC,GACpB;GAEJ,IAAI,aAAa;AACjB,OAAI,OAAO,KAAK,KAAK,YAAY,CAAE,EAAC,CAAC,QACnC,cAAc,CAAC,gBAAgB,EAAE,OAAO,QAAQ,KAAK,YAAY,CAAE,EAAC,CACjE,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAC9B,KAAK,KAAK,CAAC,aAAa,CAAC;GAG9B,MAAM,aAAa,WAAW,QAAQ,WAAW,oBAC9C,QAAQ,OAAO,iBAAiB,IAAI,CAAC,CACrC,QAAQ,OAAO,WAAW;GAE7B,gBAAgB,CAAC,EAAE,EAAE,UAAU,EAAE,CAAC;EACnC;CACF;CAGD,MAAMC,aAAqC,CAAE;AAC7C,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,WAAW,KAAK,OAAO,MAAM,IAAI;EACvC,MAAM,WAAW,KAAK,OAAO,MAAM,IAAI;EACvC,MAAM,eAAe,SAClB,OAAO,CAAC,KAAK,MAAM,QAAQ,SAAS,GAAG,CACvC,KAAK,IAAI;AACZ,MAAI,CAAC,WAAW,eACd,WAAW,gBAAgB,CAAE;EAE/B,WAAW,cAAc,KAAK,KAAK;CACpC;CAED,MAAM,gCAAgB,IAAI;CAG1B,SAAS,oBAAoBC,UAA8B;AACzD,SAAO,CAAC,GAAG,QAAS,EAAC,KAAK,CAAC,GAAG,MAAM;AAClC,UAAO,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE,MAAM,IAAI,CAAC;EAC3C,EAAC;CACH;CAED,SAAS,YAAYJ,SAAeK,QAAsB;EACxD,MAAM,WAAWC,QAAM,WAAW,KAAKA,QAAM,GAAG,WAAWA,QAAM,GAAG;AACpE,MAAI,UAAU,CAAC,UAAU;GACvB,MAAM,WAAW,OAAO,MAAM,IAAI,CAAC,KAAK;AAExC,OAAI,cAAc,IAAI,OAAO,CAC3B,OAAM,IAAI,MACR,CAAC,0BAA0B,EAAE,SAAS,MAAM,EAAE,OAAO,gJAA2B,CAEV;GAI1E,cAAc,IAAI,OAAO;GACzB,gBAAgB,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC;EAC3C;EAGD,MAAM,iBAAiB,oBACrB,OAAO,KAAK,WAAW,CAAC,OACtB,CAAC,iBACC,aAAa,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,IACrC,iBAAiB,UACjB,aAAa,MAAM,IAAI,CAAC,WAAW,OAAO,MAAM,IAAI,CAAC,SAAS,EACjE,CACF;AAED,OAAK,MAAM,gBAAgB,gBACzB,YAAY,WAAW,eAAe,aAAa;AAGrD,OAAK,MAAM,QAAQA,SAAO;GACxB,MAAM,EAAE,QAAQ,QAAQ,MAAM,aAAa,GAAG;GAE9C,IAAI,YAAY;AAChB,OAAI,SAAS,QAAW;IACtB,IAAI,WAAW;IACf,MAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,QAAI,MAAM,SAAS,iBACjB,WAAW,MAAM,KACf,EAAE,QAAQ,KAAK,KAAK,MAAM,SAAS,gBAAgB,CAAE,GACrD,CAAC,GAAG,MACF,MACG,MAAM,IAAI,kBAAkB,IAAI,KAAK,gBAAgB,CACrD,KAAK,IAAI,CACf,CAAC,KAAK,mBAAmB;IAE5B,YAAY,cACR,CAAC,UAAU,EAAE,SAAS,WAAW,CAAC,GAClC,CAAC,UAAU,EAAE,SAAS,WAAW,CAAC;GACvC,OACC,YAAY,cAAc,WAAW;GAGvC,gBAAgB,CAAC,EAAE,EAAE,iBACnB,OACD,GAAG,YAAY,iBAAiB,OAAO,CAAC,GAAG,CAAC;EAC9C;AAED,MAAI,UAAU,CAAC,UACb,gBAAgB;CAEnB;CAGD,YAAY,WAAW,OAAO,CAAE,GAAE,GAAG;AAGrC,MAAK,MAAM,UAAU,WACnB,KAAI,CAAC,OAAO,SAAS,IAAI,IAAI,WAAW,IACtC,YAAY,WAAW,SAAS,OAAO;AAK3C,KAAI,YACF,gBAAgB,4BAA4B,cAAc,CAAE,EAAC;AAG/D,QAAO;AACR;;;;;;;;;;;;;;;;;AAkBD,eAAsB,iBACpBC,eACAC,QAQA;CACA,IAAI,kBAAkB,QAAQ,mBAAmB;CACjD,MAAM,YAAY,QAAQ,aAAa;CAEvC,MAAM,uBAAuBC,0BAAY,cAAc;AAGvD,KAAI,oBAAoB,QAAW;EACjC,MAAM,kBAAkB;AACxB,MAAI,CAAC,gBAAgB,KAAK,gBAAgB,EACxC,kBAAkB,CAAC,CAAC,EAAE,iBAAiB;CAE1C;CACD,MAAM,WAAW,CAAC,wBAAwB,EAAE,qBAAqB,SAAS,EAAE,gBAAgB,MAAM,EAAE,WAAW;CAC/G,MAAM,MAAM,MAAM,MAAM,SAAS;AACjC,KAAI,CAAC,IAAI,GACP,OAAM,IAAI,MACR;EACE,CAAC,qDAAqD,CAAC;EACvD,CAAC,aAAa,EAAE,IAAI,QAAQ;EAC5B,CAAC,aAAa,EAAE,IAAI,YAAY;CACjC,EAAC,KAAK,KAAK;CAGhB,MAAM,UAAU,MAAM,IAAI,MAAM;AAChC,QAAO;AACR"}