{#include main fluid=true}
{#style}
#topology-description {
resize: none;
font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
}
{/style}
{#scriptref}
{/scriptref}
{#script}
function toMermaid(topology) {
var lines = topology.split('\n');
var subTopologies = [];
var outside = [];
var currentGraphNodeName;
var subTopologiesList = [];
var topicSourcesList = [];
var topicSinksList = [];
var stateStoresList = [];
var name = (value) => value.replaceAll("-", "-
");
var subTopology = {
pattern: /Sub-topology: ([0-9]*)/,
startFormatter: (subTopology) => `subgraph Sub-Topology: $\{subTopology}`,
endFormatter: () => `end`,
visit: function(line) {
var match = line.match(this.pattern);
// Close the previous sub-topology before opening a new one;
if(subTopologies.length) {
subTopologies.push(this.endFormatter());
}
subTopologies.push(this.startFormatter(match[1]));
subTopologiesList.push(match[1]);
}
}
var source = {
pattern: /Source:\s+(\S+)\s+\(topics:\s+\[(.*)\]\)/,
formatter: (source, topic) => `$\{topic}[$\{topic}] --> $\{source}($\{name(source)})`,
visit: function(line) {
var match = line.match(this.pattern);
currentGraphNodeName = match[1].trim();
var topics = match[2]
topics.split(',').filter(String).map(topic => topic.trim()).forEach(topic => {
outside.push(this.formatter(currentGraphNodeName, topic));
topicSourcesList.push(topic);
});
}
};
var processor = {
pattern: /Processor:\s+(\S+)\s+\(stores:\s+\[(.*)\]\)/,
formatter: (processor, store) => (processor.includes("JOIN")) ? `$\{store}[($\{name(store)})] --> $\{processor}($\{name(processor)})` : `$\{processor}($\{name(processor)}) --> $\{store}[($\{name(store)})]`,
visit: function(line) {
var match = line.match(this.pattern);
currentGraphNodeName = match[1].trim();
var stores = match[2];
stores.split(',').filter(String).map(store => store.trim()).forEach(store => {
outside.push(this.formatter(currentGraphNodeName, store));
stateStoresList.push(store);
});
}
};
var sink = {
pattern: /Sink:\s+(\S+)\s+\(topic:\s+(.*)\)/,
formatter: (sink, topic) => `$\{sink}($\{name(sink)}) --> $\{topic}[$\{topic}]`,
visit: function(line) {
var match = line.match(this.pattern);
currentGraphNodeName = match[1].trim();
var topic = match[2].trim();
outside.push(this.formatter(currentGraphNodeName, topic));
topicSinksList.push(topic);
}
}
var rightArrow = {
pattern: /\s*-->\s+(.*)/,
formatter: (src, dst) => `$\{src}($\{name(src)}) --> $\{dst}($\{name(dst)})`,
visit: function(line) {
var match = line.match(this.pattern);
match[1].split(',').filter(String).map(target => target.trim()).filter(target => target !== "none").forEach(target => {
subTopologies.push(this.formatter(currentGraphNodeName, target))
});
}
};
for(const line of lines) {
switch(true) {
case subTopology.pattern.test(line):
subTopology.visit(line);
break;
case source.pattern.test(line):
source.visit(line);
break;
case processor.pattern.test(line):
processor.visit(line);
break;
case sink.pattern.test(line):
sink.visit(line);
break;
case rightArrow.pattern.test(line):
rightArrow.visit(line);
break;
default:
break;
}
}
if(subTopologies.length) {
subTopologies.push(subTopology.endFormatter());
}
var description = ["graph TD"].concat(outside).concat(subTopologies).concat(topicSourcesList).concat(topicSinksList).concat(stateStoresList).join('\n');
return {
description: description,
details: {
subTopologies: subTopologiesList,
topicSources: topicSourcesList,
topicSinks: topicSinksList,
stateStores: stateStoresList
}
};
}
mermaid.initialize(\{startOnLoad:false});
$(function(){
var topologyDescription = $('#topology-description').val();
var mermaidGraphDefinition = toMermaid(topologyDescription);
console.log(mermaidGraphDefinition.description);
mermaid.mermaidAPI.render("mermaid-graph-" + Date.now(), mermaidGraphDefinition.description, function(svgCode, bindFunctions){
$('#topology-graph').html(svgCode);
});
$('#sub-topologies-details').html(mermaidGraphDefinition.details.subTopologies.length);
$('#topic-sources-details').text(mermaidGraphDefinition.details.topicSources.length);
$('#topic-sinks-details').text(mermaidGraphDefinition.details.topicSinks.length);
$('#state-stores-details').text(mermaidGraphDefinition.details.stateStores.length);
mermaidGraphDefinition.details.topicSources.sort().forEach(topic => {
$('#topic-sources-list').append(`