Skip to content

Commit 91d8c3f

Browse files
authored
Only extract the nearest comment (#4)
* Only extract the nearest comment * fix multi line test
1 parent a6ed41a commit 91d8c3f

File tree

2 files changed

+184
-8
lines changed

2 files changed

+184
-8
lines changed

src/graphvizsvg.test.js

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,4 +1007,167 @@ describe("GraphvizSvg", () => {
10071007
graphviz.tooltip(node, false);
10081008
expect(link.attr("data-tooltip-keepvisible")).toBeUndefined();
10091009
});
1010+
1011+
test("should handle node comments", (done) => {
1012+
const svgContent = `
1013+
<svg width="100pt" height="100pt">
1014+
<g>
1015+
<!-- User comment for A -->
1016+
<g class="node">
1017+
<title>A</title>
1018+
<ellipse cx="50" cy="50" rx="30" ry="30"/>
1019+
</g>
1020+
<!-- Another comment for B -->
1021+
<g class="node">
1022+
<title>B</title>
1023+
<ellipse cx="150" cy="50" rx="30" ry="30"/>
1024+
</g>
1025+
<g class="node">
1026+
<title>C</title>
1027+
<ellipse cx="250" cy="50" rx="30" ry="30"/>
1028+
</g>
1029+
</g>
1030+
</svg>`;
1031+
1032+
const options = {
1033+
svg: svgContent,
1034+
ready() {
1035+
// Debug output
1036+
console.log("Comments map:", this._commentsByName);
1037+
console.log("Node C:", $(this._nodesByName["C"]).attr("data-comment"));
1038+
1039+
// Original test assertions
1040+
expect(this._commentsByName["A"]).toBe("User comment for A");
1041+
expect(this._commentsByName["B"]).toBe("Another comment for B");
1042+
expect(this._commentsByName["C"]).toBeUndefined();
1043+
1044+
done();
1045+
},
1046+
};
1047+
1048+
container.graphviz(options);
1049+
});
1050+
1051+
test("should handle comments on nodes, edges and clusters", (done) => {
1052+
const svgContent = `
1053+
<svg width="100pt" height="100pt">
1054+
<g>
1055+
<!-- Node A comment -->
1056+
<g class="node">
1057+
<title>A</title>
1058+
<ellipse cx="50" cy="50" rx="30" ry="30"/>
1059+
</g>
1060+
<!-- Node B comment -->
1061+
<g class="node">
1062+
<title>B</title>
1063+
<ellipse cx="150" cy="50" rx="30" ry="30"/>
1064+
</g>
1065+
<!-- Edge A->B comment -->
1066+
<g class="edge">
1067+
<title>A->B</title>
1068+
<path d="M50,50 L150,50"/>
1069+
</g>
1070+
</g>
1071+
</svg>`;
1072+
1073+
const options = {
1074+
svg: svgContent,
1075+
ready() {
1076+
// Test node comments
1077+
expect(this._commentsByName["A"]).toBe("Node A comment");
1078+
expect(this._commentsByName["B"]).toBe("Node B comment");
1079+
1080+
// Test node data-comment attributes
1081+
const nodeA = $(this._nodesByName["A"]);
1082+
const nodeB = $(this._nodesByName["B"]);
1083+
expect(nodeA.attr("data-comment")).toBe("Node A comment");
1084+
expect(nodeB.attr("data-comment")).toBe("Node B comment");
1085+
1086+
// Test edge comments
1087+
const edge = $('g.edge[data-name="A->B"]');
1088+
expect(edge.attr("data-comment")).toBe("Edge A->B comment");
1089+
1090+
done();
1091+
},
1092+
};
1093+
1094+
container.graphviz(options);
1095+
});
1096+
1097+
test("should handle multiple comments and whitespace", (done) => {
1098+
const svgContent = `
1099+
<svg width="100pt" height="100pt">
1100+
<g>
1101+
<!-- First comment -->
1102+
<!-- Node A comment -->
1103+
<g class="node">
1104+
<title>A</title>
1105+
<ellipse cx="50" cy="50" rx="30" ry="30"/>
1106+
</g>
1107+
1108+
<!--
1109+
Multi-line
1110+
Node B
1111+
comment
1112+
-->
1113+
<g class="node">
1114+
<title>B</title>
1115+
<ellipse cx="150" cy="50" rx="30" ry="30"/>
1116+
</g>
1117+
</g>
1118+
</svg>`;
1119+
1120+
const options = {
1121+
svg: svgContent,
1122+
ready() {
1123+
// Should only capture the immediate previous comment
1124+
expect(this._commentsByName["A"]).toBe("Node A comment");
1125+
1126+
// Should handle multi-line comments - normalize whitespace for comparison
1127+
const comment = this._commentsByName["B"];
1128+
const normalizedComment = comment
1129+
.split("\n")
1130+
.map((line) => line.trim())
1131+
.join("\n");
1132+
expect(normalizedComment).toBe("Multi-line\nNode B\ncomment");
1133+
1134+
done();
1135+
},
1136+
};
1137+
1138+
container.graphviz(options);
1139+
});
1140+
1141+
test("should handle nodes without comments", (done) => {
1142+
const svgContent = `
1143+
<svg width="100pt" height="100pt">
1144+
<g>
1145+
<!-- Node A comment -->
1146+
<g class="node">
1147+
<title>A</title>
1148+
<ellipse cx="50" cy="50" rx="30" ry="30"/>
1149+
</g>
1150+
<g class="node">
1151+
<title>B</title>
1152+
<ellipse cx="150" cy="50" rx="30" ry="30"/>
1153+
</g>
1154+
</g>
1155+
</svg>`;
1156+
1157+
const options = {
1158+
svg: svgContent,
1159+
ready() {
1160+
// Node A should have a comment
1161+
expect(this._commentsByName["A"]).toBe("Node A comment");
1162+
1163+
// Node B should not have a comment
1164+
expect(this._commentsByName["B"]).toBeUndefined();
1165+
expect($(this._nodesByName["B"]).attr("data-comment")).toBeUndefined();
1166+
1167+
done();
1168+
},
1169+
};
1170+
1171+
container.graphviz(options);
1172+
});
10101173
});

src/setup.js

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// setup.js
2-
import $ from 'jquery';
2+
import $ from "jquery";
33

44
export function setup(context) {
55
const options = context.options;
@@ -14,6 +14,7 @@ export function setup(context) {
1414
context.$edges = $graph.children(".edge");
1515
context._nodesByName = {};
1616
context._edgesByName = {};
17+
context._commentsByName = {};
1718

1819
// Add top-level class and copy background color to element
1920
context.$element.addClass("graphviz-svg");
@@ -25,6 +26,16 @@ export function setup(context) {
2526
context.$nodes.each((_, el) => _setupNodesEdges($(el), true, context));
2627
context.$edges.each((_, el) => _setupNodesEdges($(el), false, context));
2728

29+
// After setting up nodes, collect comments
30+
context.$nodes.each((_, node) => {
31+
const $node = $(node);
32+
const name = $node.attr("data-name");
33+
const comment = $node.attr("data-comment");
34+
if (comment) {
35+
context._commentsByName[name] = comment;
36+
}
37+
});
38+
2839
// Remove the graph title element
2940
const $title = context.$graph.children("title");
3041
context.$graph.attr("data-name", $title.text());
@@ -68,19 +79,21 @@ function _setupNodesEdges($el, isNode, context) {
6879
}
6980
// Check for user-added comments
7081
let previousSibling = $el[0].previousSibling;
71-
while (previousSibling && previousSibling.nodeType !== 8) {
82+
while (previousSibling && previousSibling.nodeType === 3) {
83+
// Skip text nodes
7284
previousSibling = previousSibling.previousSibling;
7385
}
86+
7487
if (previousSibling && previousSibling.nodeType === 8) {
75-
const htmlDecode = (input) => {
76-
const e = document.createElement("div");
77-
e.innerHTML = input;
78-
return e.childNodes[0].nodeValue;
79-
};
80-
const value = htmlDecode(previousSibling.nodeValue.trim());
88+
// 8 is comment node
89+
const value = previousSibling.nodeValue.trim();
90+
console.log("Found comment:", value);
8191
if (value !== title) {
8292
// User-added comment
8393
$el.attr("data-comment", value);
94+
if (isNode) {
95+
context._commentsByName[title] = value;
96+
}
8497
}
8598
}
8699
}

0 commit comments

Comments
 (0)