All files / app/codeCharta/state/selectors/accumulatedData/metricData edgeMetricData.calculator.ts

98.07% Statements 51/52
92.85% Branches 13/14
100% Functions 6/6
98.07% Lines 51/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 11091x     91x 91x         91x 29x   29x   29x 8x 48x       29x 8x 24x   16x 32x 32x                 29x 29x 29x           91x 66x 17x   49x       24x 16x   8x       32x 32x 21x 21x   32x       32x 32x 32x         32x 32x 24x   8x         29x   29x 21x 21x 21x 21x 56x 56x 56x 28x   56x 48x     21x               29x    
import { hierarchy } from "d3-hierarchy"
import { BlacklistItem, Edge, EdgeMetricCount, EdgeMetricData } from "../../../../codeCharta.model"
import { FileState } from "../../../../model/files/files"
import { isPathBlacklisted } from "../../../../util/codeMapHelper"
import { sortByMetricName } from "./sortByMetricName"
 
export type EdgeMetricCountMap = Map<string, EdgeMetricCount>
export type NodeEdgeMetricsMap = Map<string, EdgeMetricCountMap>
 
export function calculateEdgeMetricData(visibleFileStates: FileState[], blacklist: BlacklistItem[]) {
    const nodeEdgeMetricsMap: NodeEdgeMetricsMap = new Map()
 
    const allFilePaths: Set<string> = new Set()
 
    for (const { file } of visibleFileStates) {
        for (const { data } of hierarchy(file.map)) {
            allFilePaths.add(data.path)
        }
    }
 
    for (const fileState of visibleFileStates) {
        for (const edge of fileState.file.settings.fileSettings.edges) {
            if (bothNodesAssociatedAreVisible(edge, allFilePaths, blacklist)) {
                // TODO: We likely only need the attributes once per file.
                for (const edgeMetric of Object.keys(edge.attributes)) {
                    const edgeMetricEntry = updateEntryForMetric(nodeEdgeMetricsMap, edgeMetric)
                    addEdgeToNodes(
                        edgeMetricEntry,
                        calculateNodePath(visibleFileStates.length, fileState, edge.fromNodeName),
                        calculateNodePath(visibleFileStates.length, fileState, edge.toNodeName)
                    )
                }
            }
        }
    }
    const newEdgeMetricData = getMetricDataFromMap(nodeEdgeMetricsMap)
    sortByMetricName(newEdgeMetricData)
    return {
        edgeMetricData: newEdgeMetricData,
        nodeEdgeMetricsMap
    }
}
 
export function calculateNodePath(visibleFiles: number, fileState: FileState, nodeName: string) {
    if (visibleFiles > 1) {
        return `/root/${fileState.file.fileMeta.fileName}${nodeName.replace("/root", "")}`
    }
    return nodeName
}
 
function bothNodesAssociatedAreVisible(edge: Edge, filePaths: Set<string>, blacklist: BlacklistItem[]) {
    if (filePaths.has(edge.fromNodeName) && filePaths.has(edge.toNodeName)) {
        return !isPathBlacklisted(edge.fromNodeName, blacklist, "exclude") && !isPathBlacklisted(edge.toNodeName, blacklist, "exclude")
    }
    return false
}
 
function updateEntryForMetric(nodeEdgeMetricsMap: NodeEdgeMetricsMap, edgeMetricName: string) {
    let nodeEdgeMetric = nodeEdgeMetricsMap.get(edgeMetricName)
    if (!nodeEdgeMetric) {
        nodeEdgeMetric = new Map()
        nodeEdgeMetricsMap.set(edgeMetricName, nodeEdgeMetric)
    }
    return nodeEdgeMetric
}
 
function addEdgeToNodes(edgeMetricEntry: EdgeMetricCountMap, fromNode: string, toNode: string) {
    const fromNodeEdgeMetric = edgeMetricEntry.get(fromNode)
    if (fromNodeEdgeMetric === undefined) {
        edgeMetricEntry.set(fromNode, { incoming: 0, outgoing: 1 })
    } else E{
        fromNodeEdgeMetric.outgoing += 1
    }
 
    const toNodeEdgeMetric = edgeMetricEntry.get(toNode)
    if (toNodeEdgeMetric === undefined) {
        edgeMetricEntry.set(toNode, { incoming: 1, outgoing: 0 })
    } else {
        toNodeEdgeMetric.incoming += 1
    }
}
 
function getMetricDataFromMap(nodeEdgeMetricsMap: NodeEdgeMetricsMap) {
    const metricData: EdgeMetricData[] = []
 
    for (const [edgeMetric, occurrences] of nodeEdgeMetricsMap) {
        const metricValues = []
        let maximumMetricValue = 0
        let minimumMetricValue = Number.MAX_SAFE_INTEGER
        for (const value of occurrences.values()) {
            const combinedValue = value.incoming + value.outgoing
            metricValues.push(combinedValue)
            if (combinedValue > maximumMetricValue) {
                maximumMetricValue = combinedValue
            }
            if (combinedValue <= minimumMetricValue) {
                minimumMetricValue = combinedValue
            }
        }
        metricData.push({
            name: edgeMetric,
            values: metricValues,
            maxValue: maximumMetricValue,
            minValue: minimumMetricValue
        })
    }
 
    return metricData
}