function appMap2Hierarchy(appmap) {
const noPackage = "<no package>"
var newHierarchy = {name: "root", children: []}
newHierarchy.index_nodes = new Map()
newHierarchy.index_packages = new Map()
newHierarchy.metadata = appmap.metadata
function getClassPackage(event, language) {
var info = {};
if(language=="java") {
let split = /^(.*)\.(.*$)?/
let splitResult = event.defined_class.match(split)
if(splitResult == null) {
info.className=event.defined_class
info.packageName=noPackage
} else {
info.className=splitResult[2]
info.packageName=splitResult[1]
}
} else if(language=="ruby") {
info.className=event.defined_class
let split = /^([^\/].*)\/(.*)/
let splitResult = event.path.match(split)
info.packageName=(splitResult != null) ? splitResult[1] : noPackage
} else throw new Error("Unsupported language: " + language);
return info;
}
function addClass(hierarchy, node) {
var pkg
if(!hierarchy.index_packages.has(node.packageName)) {
pkg = { name: node.packageName, children_index: new Map() }
hierarchy.index_packages.set(node.packageName, pkg)
} else {
pkg = hierarchy.index_packages.get(node.packageName)
}
if(!pkg.children_index.has(node.className)) {
//this class has not been seen in this package before
pkg.children_index.set(node.className, node)
}
}
function appMap2HierarchyInner(appmap, hierarchy, currentIndex, currentCaller) {
var newNode = {}
var newCaller = {}
do {
if(appmap.events.length <= currentIndex) return -1; //at the end of the event array
newCaller = appmap.events[currentIndex]
if(newCaller.event=="return") {
return currentIndex + 1; //this call is ovah
}
if (newCaller.event=="call" && newCaller.defined_class != null) {
//now lets add this call to the hierarchy
//first getting unique node, have we seen this class before?
if(!hierarchy.index_nodes.has(newCaller.defined_class)) {
newNode = Object.assign(Object.create(newCaller))
newNode.id = newNode.defined_class
newNode.count = 1
newNode.calls = 0
newNode.ingressClasses = new Map()
newNode.egressClasses = new Map()
hierarchy.index_nodes.set(newCaller.defined_class, newNode)
//get package and class name
let info = getClassPackage(newNode, appmap.metadata.language.name)
newNode.className=info.className
newNode.name=info.className
newNode.packageName=info.packageName
} else {
newNode = hierarchy.index_nodes.get(newCaller.defined_class)
newNode.count++
}
addClass(newHierarchy, newNode)
if(currentCaller != null) {
// add the relationships to the node
newNode.ingressClasses.set(currentCaller.id, currentCaller)
currentCaller.egressClasses.set(newNode.id, newNode)
currentCaller.calls++
}
} else if (newCaller.event=="command") {
//sql tbd
}
currentIndex = appMap2HierarchyInner(appmap, hierarchy, currentIndex + 1, newNode)
} while (currentIndex > -1)
return currentIndex
}
appMap2HierarchyInner(appmap, newHierarchy, 0, null)
newHierarchy.children = [ ...newHierarchy.index_packages.values()].sort((a, b) => a.name < b.name? -1 : a.name > b.name ? 1 : 0)
newHierarchy.children.forEach( n => n.children = [ ...n.children_index.values()].sort((a, b) => a.name < b.name? -1 : a.name > b.name ? 1 : 0))
return newHierarchy
}