@graph-render/core 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/.eslintrc.json +6 -0
  2. package/CHANGELOG.md +45 -0
  3. package/dist/edges/collision.d.ts +8 -0
  4. package/dist/edges/collision.d.ts.map +1 -0
  5. package/dist/edges/collision.js +26 -0
  6. package/dist/edges/collision.js.map +1 -0
  7. package/dist/edges/geometry.d.ts +22 -0
  8. package/dist/edges/geometry.d.ts.map +1 -0
  9. package/dist/edges/geometry.js +75 -0
  10. package/dist/edges/geometry.js.map +1 -0
  11. package/dist/edges/index.d.ts +4 -0
  12. package/dist/edges/index.d.ts.map +1 -0
  13. package/dist/edges/index.js +4 -0
  14. package/dist/edges/index.js.map +1 -0
  15. package/dist/edges/pathBuilder.d.ts +11 -0
  16. package/dist/edges/pathBuilder.d.ts.map +1 -0
  17. package/dist/edges/pathBuilder.js +114 -0
  18. package/dist/edges/pathBuilder.js.map +1 -0
  19. package/dist/edges/pathCalculation.d.ts +14 -0
  20. package/dist/edges/pathCalculation.d.ts.map +1 -0
  21. package/dist/edges/pathCalculation.js +47 -0
  22. package/dist/edges/pathCalculation.js.map +1 -0
  23. package/dist/edges/routing.d.ts +6 -0
  24. package/dist/edges/routing.d.ts.map +1 -0
  25. package/dist/edges/routing.js +243 -0
  26. package/dist/edges/routing.js.map +1 -0
  27. package/dist/edges/sideSelection.d.ts +17 -0
  28. package/dist/edges/sideSelection.d.ts.map +1 -0
  29. package/dist/edges/sideSelection.js +45 -0
  30. package/dist/edges/sideSelection.js.map +1 -0
  31. package/dist/index.d.ts +7 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +6 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/layouts/centered.d.ts +6 -0
  36. package/dist/layouts/centered.d.ts.map +1 -0
  37. package/dist/layouts/centered.js +69 -0
  38. package/dist/layouts/centered.js.map +1 -0
  39. package/dist/layouts/compactBracket.d.ts +3 -0
  40. package/dist/layouts/compactBracket.d.ts.map +1 -0
  41. package/dist/layouts/compactBracket.js +7 -0
  42. package/dist/layouts/compactBracket.js.map +1 -0
  43. package/dist/layouts/dag.d.ts +3 -0
  44. package/dist/layouts/dag.d.ts.map +1 -0
  45. package/dist/layouts/dag.js +52 -0
  46. package/dist/layouts/dag.js.map +1 -0
  47. package/dist/layouts/forceDirected.d.ts +3 -0
  48. package/dist/layouts/forceDirected.d.ts.map +1 -0
  49. package/dist/layouts/forceDirected.js +176 -0
  50. package/dist/layouts/forceDirected.js.map +1 -0
  51. package/dist/layouts/grid.d.ts +6 -0
  52. package/dist/layouts/grid.d.ts.map +1 -0
  53. package/dist/layouts/grid.js +34 -0
  54. package/dist/layouts/grid.js.map +1 -0
  55. package/dist/layouts/index.d.ts +12 -0
  56. package/dist/layouts/index.d.ts.map +1 -0
  57. package/dist/layouts/index.js +88 -0
  58. package/dist/layouts/index.js.map +1 -0
  59. package/dist/layouts/orthogonalFlow.d.ts +3 -0
  60. package/dist/layouts/orthogonalFlow.d.ts.map +1 -0
  61. package/dist/layouts/orthogonalFlow.js +81 -0
  62. package/dist/layouts/orthogonalFlow.js.map +1 -0
  63. package/dist/layouts/radialTree.d.ts +3 -0
  64. package/dist/layouts/radialTree.d.ts.map +1 -0
  65. package/dist/layouts/radialTree.js +45 -0
  66. package/dist/layouts/radialTree.js.map +1 -0
  67. package/dist/layouts/tree.d.ts +6 -0
  68. package/dist/layouts/tree.d.ts.map +1 -0
  69. package/dist/layouts/tree.js +19 -0
  70. package/dist/layouts/tree.js.map +1 -0
  71. package/dist/layouts/treeAlignment.d.ts +10 -0
  72. package/dist/layouts/treeAlignment.d.ts.map +1 -0
  73. package/dist/layouts/treeAlignment.js +69 -0
  74. package/dist/layouts/treeAlignment.js.map +1 -0
  75. package/dist/layouts/treePositioning.d.ts +14 -0
  76. package/dist/layouts/treePositioning.d.ts.map +1 -0
  77. package/dist/layouts/treePositioning.js +30 -0
  78. package/dist/layouts/treePositioning.js.map +1 -0
  79. package/dist/layouts/treeTopology.d.ts +29 -0
  80. package/dist/layouts/treeTopology.d.ts.map +1 -0
  81. package/dist/layouts/treeTopology.js +137 -0
  82. package/dist/layouts/treeTopology.js.map +1 -0
  83. package/dist/rendering/defaultRenderers.d.ts +10 -0
  84. package/dist/rendering/defaultRenderers.d.ts.map +1 -0
  85. package/dist/rendering/defaultRenderers.js +85 -0
  86. package/dist/rendering/defaultRenderers.js.map +1 -0
  87. package/dist/rendering/index.d.ts +4 -0
  88. package/dist/rendering/index.d.ts.map +1 -0
  89. package/dist/rendering/index.js +4 -0
  90. package/dist/rendering/index.js.map +1 -0
  91. package/dist/rendering/svg.d.ts +7 -0
  92. package/dist/rendering/svg.d.ts.map +1 -0
  93. package/dist/rendering/svg.js +256 -0
  94. package/dist/rendering/svg.js.map +1 -0
  95. package/dist/rendering/utils.d.ts +5 -0
  96. package/dist/rendering/utils.d.ts.map +1 -0
  97. package/dist/rendering/utils.js +33 -0
  98. package/dist/rendering/utils.js.map +1 -0
  99. package/dist/utils/config.d.ts +36 -0
  100. package/dist/utils/config.d.ts.map +1 -0
  101. package/dist/utils/config.js +115 -0
  102. package/dist/utils/config.js.map +1 -0
  103. package/dist/utils/constants.d.ts +15 -0
  104. package/dist/utils/constants.d.ts.map +1 -0
  105. package/dist/utils/constants.js +19 -0
  106. package/dist/utils/constants.js.map +1 -0
  107. package/dist/utils/graphParser.d.ts +16 -0
  108. package/dist/utils/graphParser.d.ts.map +1 -0
  109. package/dist/utils/graphParser.js +277 -0
  110. package/dist/utils/graphParser.js.map +1 -0
  111. package/dist/utils/graphTraversal.d.ts +13 -0
  112. package/dist/utils/graphTraversal.d.ts.map +1 -0
  113. package/dist/utils/graphTraversal.js +28 -0
  114. package/dist/utils/graphTraversal.js.map +1 -0
  115. package/dist/utils/index.d.ts +8 -0
  116. package/dist/utils/index.d.ts.map +1 -0
  117. package/dist/utils/index.js +7 -0
  118. package/dist/utils/index.js.map +1 -0
  119. package/dist/utils/nodeMetrics.d.ts +8 -0
  120. package/dist/utils/nodeMetrics.d.ts.map +1 -0
  121. package/dist/utils/nodeMetrics.js +12 -0
  122. package/dist/utils/nodeMetrics.js.map +1 -0
  123. package/dist/utils/nodeSizing.d.ts +3 -0
  124. package/dist/utils/nodeSizing.d.ts.map +1 -0
  125. package/dist/utils/nodeSizing.js +77 -0
  126. package/dist/utils/nodeSizing.js.map +1 -0
  127. package/package.json +29 -0
  128. package/project.json +32 -0
  129. package/src/edges/collision.ts +31 -0
  130. package/src/edges/geometry.ts +85 -0
  131. package/src/edges/index.ts +3 -0
  132. package/src/edges/pathBuilder.ts +136 -0
  133. package/src/edges/pathCalculation.ts +69 -0
  134. package/src/edges/routing.ts +459 -0
  135. package/src/edges/sideSelection.ts +67 -0
  136. package/src/index.ts +50 -0
  137. package/src/layouts/centered.ts +114 -0
  138. package/src/layouts/compactBracket.ts +14 -0
  139. package/src/layouts/dag.ts +76 -0
  140. package/src/layouts/forceDirected.ts +224 -0
  141. package/src/layouts/grid.ts +50 -0
  142. package/src/layouts/index.ts +148 -0
  143. package/src/layouts/orthogonalFlow.ts +112 -0
  144. package/src/layouts/radialTree.ts +77 -0
  145. package/src/layouts/tree.ts +35 -0
  146. package/src/layouts/treeAlignment.ts +107 -0
  147. package/src/layouts/treePositioning.ts +55 -0
  148. package/src/layouts/treeTopology.ts +184 -0
  149. package/src/rendering/defaultRenderers.ts +110 -0
  150. package/src/rendering/index.ts +3 -0
  151. package/src/rendering/svg.ts +346 -0
  152. package/src/rendering/utils.ts +41 -0
  153. package/src/utils/config.ts +198 -0
  154. package/src/utils/constants.ts +24 -0
  155. package/src/utils/graphParser.ts +495 -0
  156. package/src/utils/graphTraversal.ts +32 -0
  157. package/src/utils/index.ts +19 -0
  158. package/src/utils/nodeMetrics.ts +23 -0
  159. package/src/utils/nodeSizing.ts +97 -0
  160. package/tsconfig.json +11 -0
  161. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,69 @@
1
+ import { DEFAULT_NODE_SIZE } from '../utils';
2
+ import { calculateXPosition, calculateYPosition } from './treePositioning';
3
+ /**
4
+ * Position all nodes initially based on their level
5
+ */
6
+ export const positionNodesInLevels = (nodes, levels, levelMap, metrics, gap, padding, direction) => {
7
+ return nodes.map((node) => {
8
+ if (node.position)
9
+ return node;
10
+ const level = levelMap.get(node.id) ?? 0;
11
+ const levelNodes = levels[level] ?? [];
12
+ const idx = levelNodes.indexOf(node.id);
13
+ const nodeWidth = node.size?.width ?? DEFAULT_NODE_SIZE.width;
14
+ const x = calculateXPosition(level, metrics.maxLevel, nodeWidth, gap, padding, direction);
15
+ const y = calculateYPosition(idx, levelNodes, metrics.maxNodeHeight, gap, metrics.totalHeight, metrics.baseY);
16
+ return { ...node, position: { x, y } };
17
+ });
18
+ };
19
+ // FIX: deleted the file-private `getParentNodes` helper. It was replaced by
20
+ // the `incomingByTarget` Map built inside `alignNodesToParents` (O(n+e) vs the
21
+ // previous O(n×e)) and was never exported, so no external callers exist.
22
+ /**
23
+ * Calculate average Y center of parent nodes
24
+ */
25
+ const calculateParentCentersAverage = (parentIds, posMap) => {
26
+ const centers = parentIds
27
+ .map((src) => posMap.get(src))
28
+ .filter((n) => !!n)
29
+ .map((n) => n.position.y + (n.size?.height ?? DEFAULT_NODE_SIZE.height) / 2);
30
+ if (!centers.length)
31
+ return null;
32
+ return centers.reduce((a, b) => a + b, 0) / centers.length;
33
+ };
34
+ /**
35
+ * Align nodes with multiple parents to their parent's average position
36
+ */
37
+ export const alignNodesToParents = (positioned, edges, levels, maxLevel) => {
38
+ const posMap = new Map();
39
+ positioned.forEach((n) => posMap.set(n.id, n));
40
+ // FIX: build a target→sources index once instead of calling
41
+ // edges.filter(e => e.target === id) for every node (was O(nodes × edges)).
42
+ const incomingByTarget = new Map();
43
+ edges.forEach((e) => {
44
+ incomingByTarget.set(e.target, [...(incomingByTarget.get(e.target) ?? []), e.source]);
45
+ });
46
+ for (let level = 1; level <= maxLevel; level += 1) {
47
+ const ids = levels[level] ?? [];
48
+ ids.forEach((id) => {
49
+ const node = posMap.get(id);
50
+ if (!node)
51
+ return;
52
+ const parentIds = incomingByTarget.get(id) ?? [];
53
+ if (parentIds.length < 2)
54
+ return;
55
+ const avgCenterY = calculateParentCentersAverage(parentIds, posMap);
56
+ if (avgCenterY === null)
57
+ return;
58
+ const h = node.size?.height ?? DEFAULT_NODE_SIZE.height;
59
+ const newY = avgCenterY - h / 2;
60
+ const updated = {
61
+ ...node,
62
+ position: { ...node.position, y: newY },
63
+ };
64
+ posMap.set(id, updated);
65
+ });
66
+ }
67
+ return Array.from(posMap.values());
68
+ };
69
+ //# sourceMappingURL=treeAlignment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeAlignment.js","sourceRoot":"","sources":["../../src/layouts/treeAlignment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { NodeData, TreeMetrics, LayoutDirection } from '@graph-render/types';
2
+ /**
3
+ * Calculate tree layout metrics
4
+ */
5
+ export declare const calculateTreeMetrics: (nodes: NodeData[], levels: string[][], gap: number, padding: number, containerHeight?: number) => TreeMetrics;
6
+ /**
7
+ * Calculate X position based on level and direction
8
+ */
9
+ export declare const calculateXPosition: (level: number, maxLevel: number, nodeWidth: number, gap: number, padding: number, direction: LayoutDirection) => number;
10
+ /**
11
+ * Calculate Y position for a node in a level
12
+ */
13
+ export declare const calculateYPosition: (nodeIndex: number, levelNodes: string[], maxNodeHeight: number, gap: number, totalHeight: number, baseY: number) => number;
14
+ //# sourceMappingURL=treePositioning.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treePositioning.d.ts","sourceRoot":"","sources":["../../src/layouts/treePositioning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG7E;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,QAAQ,EAAE,EACjB,QAAQ,MAAM,EAAE,EAAE,EAClB,KAAK,MAAM,EACX,SAAS,MAAM,EACf,kBAAkB,MAAM,KACvB,WASF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,EACb,UAAU,MAAM,EAChB,WAAW,MAAM,EACjB,KAAK,MAAM,EACX,SAAS,MAAM,EACf,WAAW,eAAe,KACzB,MAIF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,YAAY,MAAM,EAAE,EACpB,eAAe,MAAM,EACrB,KAAK,MAAM,EACX,aAAa,MAAM,EACnB,OAAO,MAAM,KACZ,MAKF,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { LayoutDirection } from '@graph-render/types';
2
+ import { getMaxNodeHeight } from '../utils';
3
+ /**
4
+ * Calculate tree layout metrics
5
+ */
6
+ export const calculateTreeMetrics = (nodes, levels, gap, padding, containerHeight) => {
7
+ const maxLevel = levels.length ? levels.length - 1 : 0;
8
+ const maxNodeHeight = getMaxNodeHeight(nodes);
9
+ const maxLevelCount = Math.max(1, ...levels.map((l) => l?.length ?? 0));
10
+ const totalHeight = maxLevelCount * maxNodeHeight + (maxLevelCount - 1) * gap;
11
+ const baseY = containerHeight != null ? Math.max(padding, (containerHeight - totalHeight) / 2) : padding;
12
+ return { maxLevel, maxNodeHeight, maxLevelCount, totalHeight, baseY };
13
+ };
14
+ /**
15
+ * Calculate X position based on level and direction
16
+ */
17
+ export const calculateXPosition = (level, maxLevel, nodeWidth, gap, padding, direction) => {
18
+ const ltrX = padding + level * (nodeWidth + gap);
19
+ const rtlX = padding + (maxLevel - level) * (nodeWidth + gap);
20
+ return direction === LayoutDirection.RTL ? rtlX : ltrX;
21
+ };
22
+ /**
23
+ * Calculate Y position for a node in a level
24
+ */
25
+ export const calculateYPosition = (nodeIndex, levelNodes, maxNodeHeight, gap, totalHeight, baseY) => {
26
+ const levelHeight = (levelNodes.length || 1) * maxNodeHeight + Math.max(0, (levelNodes.length || 1) - 1) * gap;
27
+ const levelStartY = baseY + (totalHeight - levelHeight) / 2;
28
+ return levelStartY + nodeIndex * (maxNodeHeight + gap);
29
+ };
30
+ //# sourceMappingURL=treePositioning.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treePositioning.js","sourceRoot":"","sources":["../../src/layouts/treePositioning.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE5C;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,KAAiB,EACjB,MAAkB,EAClB,GAAW,EACX,OAAe,EACf,eAAwB,EACX,EAAE;IACf,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,WAAW,GAAG,aAAa,GAAG,aAAa,GAAG,CAAC,aAAa,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IAC9E,MAAM,KAAK,GACT,eAAe,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAE7F,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;AACxE,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAa,EACb,QAAgB,EAChB,SAAiB,EACjB,GAAW,EACX,OAAe,EACf,SAA0B,EAClB,EAAE;IACV,MAAM,IAAI,GAAG,OAAO,GAAG,KAAK,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC;IAC9D,OAAO,SAAS,KAAK,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACzD,CAAC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,SAAiB,EACjB,UAAoB,EACpB,aAAqB,EACrB,GAAW,EACX,WAAmB,EACnB,KAAa,EACL,EAAE;IACV,MAAM,WAAW,GACf,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IAC7F,MAAM,WAAW,GAAG,KAAK,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5D,OAAO,WAAW,GAAG,SAAS,GAAG,CAAC,aAAa,GAAG,GAAG,CAAC,CAAC;AACzD,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { NodeData, EdgeData, GraphTopology } from '@graph-render/types';
2
+ export declare const assertHierarchicalGraph: (nodes: NodeData[], edges: EdgeData[]) => void;
3
+ /**
4
+ * Build graph topology from edges
5
+ */
6
+ export declare const buildGraphTopology: (edges: EdgeData[]) => GraphTopology;
7
+ /**
8
+ * Find root nodes (nodes with no incoming edges)
9
+ */
10
+ export declare const findRootNodes: (nodes: NodeData[], incoming: Map<string, number>) => string[];
11
+ /**
12
+ * Assign nodes to levels using BFS
13
+ */
14
+ export declare const assignNodesToLevels: (nodes: NodeData[], rootIds: string[], outgoing: Map<string, string[]>) => Map<string, number>;
15
+ /**
16
+ * Assign DAG-style max-depth levels using a single Kahn's BFS pass.
17
+ * Validates edge references and detects cycles in the same traversal,
18
+ * replacing the three-pass pattern of assertHierarchicalGraph +
19
+ * buildGraphTopology + an inline BFS.
20
+ */
21
+ export declare const assignDagLevels: (nodes: NodeData[], edges: EdgeData[]) => {
22
+ levels: Map<string, number>;
23
+ outgoing: Map<string, string[]>;
24
+ };
25
+ /**
26
+ * Group nodes by their level
27
+ */
28
+ export declare const groupNodesByLevel: (nodes: NodeData[], levelMap: Map<string, number>) => string[][];
29
+ //# sourceMappingURL=treeTopology.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeTopology.d.ts","sourceRoot":"","sources":["../../src/layouts/treeTopology.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAExE,eAAO,MAAM,uBAAuB,GAAI,OAAO,QAAQ,EAAE,EAAE,OAAO,QAAQ,EAAE,KAAG,IAgD9E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,QAAQ,EAAE,KAAG,aAUtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,QAAQ,EAAE,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAM,EAGtF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,GAC9B,OAAO,QAAQ,EAAE,EACjB,SAAS,MAAM,EAAE,EACjB,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,KAC9B,GAAG,CAAC,MAAM,EAAE,MAAM,CAiBpB,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,GAC1B,OAAO,QAAQ,EAAE,EACjB,OAAO,QAAQ,EAAE,KAChB;IAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAuDhE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAAI,OAAO,QAAQ,EAAE,EAAE,UAAU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAM,EAAE,EAa5F,CAAC"}
@@ -0,0 +1,137 @@
1
+ export const assertHierarchicalGraph = (nodes, edges) => {
2
+ if (!nodes.length) {
3
+ return;
4
+ }
5
+ const inDegree = new Map(nodes.map((node) => [node.id, 0]));
6
+ const outgoing = new Map();
7
+ for (const edge of edges) {
8
+ if (!inDegree.has(edge.source) || !inDegree.has(edge.target)) {
9
+ throw new Error(`Tree layout requires every edge to reference existing nodes. Invalid edge: ${edge.source} -> ${edge.target}.`);
10
+ }
11
+ inDegree.set(edge.target, (inDegree.get(edge.target) ?? 0) + 1);
12
+ outgoing.set(edge.source, [...(outgoing.get(edge.source) ?? []), edge.target]);
13
+ }
14
+ const queue = Array.from(inDegree.entries())
15
+ .filter(([, degree]) => degree === 0)
16
+ .map(([nodeId]) => nodeId);
17
+ if (!queue.length) {
18
+ throw new Error('Tree layout requires at least one root node and does not support cyclic graphs.');
19
+ }
20
+ let processed = 0;
21
+ for (let index = 0; index < queue.length; index += 1) {
22
+ const current = queue[index];
23
+ processed += 1;
24
+ for (const child of outgoing.get(current) ?? []) {
25
+ const nextDegree = (inDegree.get(child) ?? 0) - 1;
26
+ inDegree.set(child, nextDegree);
27
+ if (nextDegree === 0) {
28
+ queue.push(child);
29
+ }
30
+ }
31
+ }
32
+ if (processed !== nodes.length) {
33
+ throw new Error('Tree layout requires an acyclic graph. Cycles were detected in the input graph.');
34
+ }
35
+ };
36
+ /**
37
+ * Build graph topology from edges
38
+ */
39
+ export const buildGraphTopology = (edges) => {
40
+ const incoming = new Map();
41
+ const outgoing = new Map();
42
+ edges.forEach((e) => {
43
+ incoming.set(e.target, (incoming.get(e.target) ?? 0) + 1);
44
+ outgoing.set(e.source, [...(outgoing.get(e.source) ?? []), e.target]);
45
+ });
46
+ return { incoming, outgoing };
47
+ };
48
+ /**
49
+ * Find root nodes (nodes with no incoming edges)
50
+ */
51
+ export const findRootNodes = (nodes, incoming) => {
52
+ const roots = nodes.filter((n) => (incoming.get(n.id) ?? 0) === 0);
53
+ return roots.map((r) => r.id);
54
+ };
55
+ /**
56
+ * Assign nodes to levels using BFS
57
+ */
58
+ export const assignNodesToLevels = (nodes, rootIds, outgoing) => {
59
+ const levelMap = new Map();
60
+ const queue = [...rootIds];
61
+ rootIds.forEach((id) => levelMap.set(id, 0));
62
+ for (let index = 0; index < queue.length; index += 1) {
63
+ const current = queue[index];
64
+ const level = levelMap.get(current) ?? 0;
65
+ for (const child of outgoing.get(current) ?? []) {
66
+ if (!levelMap.has(child)) {
67
+ levelMap.set(child, level + 1);
68
+ queue.push(child);
69
+ }
70
+ }
71
+ }
72
+ return levelMap;
73
+ };
74
+ /**
75
+ * Assign DAG-style max-depth levels using a single Kahn's BFS pass.
76
+ * Validates edge references and detects cycles in the same traversal,
77
+ * replacing the three-pass pattern of assertHierarchicalGraph +
78
+ * buildGraphTopology + an inline BFS.
79
+ */
80
+ export const assignDagLevels = (nodes, edges) => {
81
+ if (!nodes.length) {
82
+ return { levels: new Map(), outgoing: new Map() };
83
+ }
84
+ const nodeSet = new Set(nodes.map((n) => n.id));
85
+ const inDegree = new Map(nodes.map((n) => [n.id, 0]));
86
+ const outgoing = new Map();
87
+ for (const edge of edges) {
88
+ if (!nodeSet.has(edge.source) || !nodeSet.has(edge.target)) {
89
+ throw new Error(`DAG layout requires every edge to reference existing nodes. Invalid edge: ${edge.source} -> ${edge.target}.`);
90
+ }
91
+ inDegree.set(edge.target, (inDegree.get(edge.target) ?? 0) + 1);
92
+ const children = outgoing.get(edge.source) ?? [];
93
+ children.push(edge.target);
94
+ outgoing.set(edge.source, children);
95
+ }
96
+ const levels = new Map();
97
+ const queue = nodes.filter((n) => inDegree.get(n.id) === 0).map((n) => n.id);
98
+ if (!queue.length) {
99
+ throw new Error('DAG layout requires at least one root node and does not support cyclic graphs.');
100
+ }
101
+ queue.forEach((id) => levels.set(id, 0));
102
+ let processed = 0;
103
+ for (let index = 0; index < queue.length; index += 1) {
104
+ const current = queue[index];
105
+ processed += 1;
106
+ const currentLevel = levels.get(current) ?? 0;
107
+ for (const child of outgoing.get(current) ?? []) {
108
+ levels.set(child, Math.max(levels.get(child) ?? 0, currentLevel + 1));
109
+ const nextInDegree = (inDegree.get(child) ?? 0) - 1;
110
+ inDegree.set(child, nextInDegree);
111
+ if (nextInDegree === 0) {
112
+ queue.push(child);
113
+ }
114
+ }
115
+ }
116
+ if (processed !== nodes.length) {
117
+ throw new Error('DAG layout requires an acyclic graph. Cycles were detected in the input graph.');
118
+ }
119
+ return { levels, outgoing };
120
+ };
121
+ /**
122
+ * Group nodes by their level
123
+ */
124
+ export const groupNodesByLevel = (nodes, levelMap) => {
125
+ const levels = [];
126
+ nodes.forEach((n) => {
127
+ const l = levelMap.get(n.id);
128
+ if (l == null) {
129
+ throw new Error(`Tree layout could not assign a level to node "${n.id}". Ensure the graph is connected from at least one root and acyclic.`);
130
+ }
131
+ if (!levels[l])
132
+ levels[l] = [];
133
+ levels[l].push(n.id);
134
+ });
135
+ return levels;
136
+ };
137
+ //# sourceMappingURL=treeTopology.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeTopology.js","sourceRoot":"","sources":["../../src/layouts/treeTopology.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { NodeRenderer, EdgeRenderer } from '@graph-render/types';
2
+ /**
3
+ * Default node renderer - creates a rounded rectangle with centered text
4
+ */
5
+ export declare const defaultNodeRenderer: NodeRenderer;
6
+ /**
7
+ * Default edge renderer - creates an SVG path with optional arrow marker
8
+ */
9
+ export declare const defaultEdgeRenderer: EdgeRenderer;
10
+ //# sourceMappingURL=defaultRenderers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaultRenderers.d.ts","sourceRoot":"","sources":["../../src/rendering/defaultRenderers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAuEtE;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,YAMjC,CAAC;AAgBF;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,YASjC,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { EdgeType } from '@graph-render/types';
2
+ import { escapeXml } from './utils';
3
+ import { DEFAULT_NODE_WIDTH, DEFAULT_NODE_HEIGHT, DEFAULT_NODE_RADIUS, DEFAULT_NODE_FILL, DEFAULT_NODE_STROKE, DEFAULT_TEXT_FILL, DEFAULT_TEXT_SIZE, } from '../utils';
4
+ const MAX_RENDER_LABEL_LENGTH = 2000;
5
+ const MAX_RENDER_LABEL_LINES = 8;
6
+ /**
7
+ * Extract label from node data
8
+ */
9
+ const getNodeLabel = (node) => {
10
+ if (typeof node.label === 'string' || typeof node.label === 'number') {
11
+ return String(node.label);
12
+ }
13
+ return node.id;
14
+ };
15
+ const getRenderableLabelLines = (label) => {
16
+ const truncated = label.slice(0, MAX_RENDER_LABEL_LENGTH);
17
+ const lines = truncated
18
+ .split(/\r?\n/)
19
+ .slice(0, MAX_RENDER_LABEL_LINES)
20
+ .map((line) => line.trim())
21
+ .filter((line) => line.length > 0);
22
+ return lines.length ? lines : [''];
23
+ };
24
+ /**
25
+ * Get node dimensions
26
+ */
27
+ const getNodeDimensions = (node) => {
28
+ return {
29
+ width: node.size?.width ?? DEFAULT_NODE_WIDTH,
30
+ height: node.size?.height ?? DEFAULT_NODE_HEIGHT,
31
+ };
32
+ };
33
+ /**
34
+ * Create SVG rectangle element for node
35
+ */
36
+ const createNodeRect = (width, height, radius) => {
37
+ return `<rect x="0" y="0" width="${width}" height="${height}" rx="${radius}" ry="${radius}" fill="${DEFAULT_NODE_FILL}" stroke="${DEFAULT_NODE_STROKE}" stroke-width="1" />`;
38
+ };
39
+ /**
40
+ * Create SVG text element for node label
41
+ */
42
+ const createNodeText = (label, width, height) => {
43
+ const lines = getRenderableLabelLines(label);
44
+ const x = width / 2;
45
+ const lineHeight = DEFAULT_TEXT_SIZE + 4;
46
+ const firstLineY = height / 2 - ((lines.length - 1) * lineHeight) / 2 + 4;
47
+ const tspans = lines
48
+ .map((line, index) => `<tspan x="${x}" y="${firstLineY + index * lineHeight}">${escapeXml(line)}</tspan>`)
49
+ .join('');
50
+ return `<text x="${x}" fill="${DEFAULT_TEXT_FILL}" font-size="${DEFAULT_TEXT_SIZE}" font-weight="600" text-anchor="middle">${tspans}</text>`;
51
+ };
52
+ /**
53
+ * Default node renderer - creates a rounded rectangle with centered text
54
+ */
55
+ export const defaultNodeRenderer = (node) => {
56
+ const { width, height } = getNodeDimensions(node);
57
+ const label = getNodeLabel(node);
58
+ const rect = createNodeRect(width, height, DEFAULT_NODE_RADIUS);
59
+ const text = createNodeText(label, width, height);
60
+ return [rect, text].join('');
61
+ };
62
+ /**
63
+ * Determine if edge should have an arrow marker
64
+ */
65
+ const shouldShowArrow = (edgeType) => {
66
+ return edgeType === EdgeType.Directed;
67
+ };
68
+ /**
69
+ * Create marker-end attribute for directed edges
70
+ */
71
+ const createMarkerAttribute = (markerId) => {
72
+ return ` marker-end="url(#${markerId})"`;
73
+ };
74
+ /**
75
+ * Default edge renderer - creates an SVG path with optional arrow marker
76
+ */
77
+ export const defaultEdgeRenderer = (edge, pathD, theme) => {
78
+ const marker = shouldShowArrow(edge.type) && theme.markerId ? createMarkerAttribute(theme.markerId) : '';
79
+ const path = `<path d="${pathD}" stroke="${theme.edgeColor}" stroke-width="${theme.edgeWidth}" fill="none"${marker}/>`;
80
+ const label = edge.label != null && edge.labelPosition
81
+ ? `<text x="${edge.labelPosition.x}" y="${edge.labelPosition.y - 6}" fill="${theme.edgeLabelColor}" font-size="12" font-weight="600" text-anchor="middle">${escapeXml(String(edge.label))}</text>`
82
+ : '';
83
+ return `${path}${label}`;
84
+ };
85
+ //# sourceMappingURL=defaultRenderers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaultRenderers.js","sourceRoot":"","sources":["../../src/rendering/defaultRenderers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { renderGraphToSvg } from './svg';
2
+ export { defaultNodeRenderer, defaultEdgeRenderer } from './defaultRenderers';
3
+ export { escapeXml } from './utils';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rendering/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { renderGraphToSvg } from './svg';
2
+ export { defaultNodeRenderer, defaultEdgeRenderer } from './defaultRenderers';
3
+ export { escapeXml } from './utils';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rendering/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { NxGraphInput } from '@graph-render/types';
2
+ import type { RenderGraphToSvgOptions, RenderGraphToSvgResult } from '@graph-render/types';
3
+ /**
4
+ * Render a graph to SVG format
5
+ */
6
+ export declare const renderGraphToSvg: (graph: NxGraphInput, options?: RenderGraphToSvgOptions) => RenderGraphToSvgResult;
7
+ //# sourceMappingURL=svg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../src/rendering/svg.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EASb,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EACV,uBAAuB,EACvB,sBAAsB,EAGvB,MAAM,qBAAqB,CAAC;AAkR7B;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,OAAO,YAAY,EACnB,UAAU,uBAAuB,KAChC,sBAgDF,CAAC"}