All files / app/codeCharta/ui/ribbonBar/artificialIntelligence/selectors artificialIntelligence.selector.ts

100% Statements 45/45
100% Branches 19/19
100% Functions 5/5
100% Lines 43/43

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 1003x               3x             3x 3x 3x 3x 3x 3x 3x                   3x       5x 1x     4x               4x 4x 4x 4x 4x   4x 25x 25x 13x 13x 13x   13x 28x 12x 12x 12x         4x 3x     4x 4x   4x 3x 3x 3x 3x     4x       25x       13x 31x           3x  
import {
    AREA_METRIC,
    aggregateRiskProfile,
    EXCLUDED_FILE_EXTENSION,
    HEIGHT_METRICS,
    RiskProfile,
    getPercentagesOfRiskProfile
} from "./util/riskProfileHelper"
import {
    calculateSuspiciousMetrics,
    findGoodAndBadMetrics,
    setMetricValuesByLanguage,
    MetricSuggestionParameters,
    MetricValuesByLanguage
} from "./util/suspiciousMetricsHelper"
import { hierarchy } from "d3-hierarchy"
import { BlacklistItem, CodeMapNode, NodeType } from "../../../../codeCharta.model"
import { getMostFrequentLanguage } from "./util/mainProgrammingLanguageHelper"
import { isPathBlacklisted } from "../../../../util/codeMapHelper"
import { blacklistSelector } from "../../../../state/store/fileSettings/blacklist/blacklist.selector"
import { AccumulatedData, accumulatedDataSelector } from "../../../../state/selectors/accumulatedData/accumulatedData.selector"
import { createSelector } from "@ngrx/store"
 
export type ArtificialIntelligenceData = {
    analyzedProgrammingLanguage: string
    suspiciousMetricSuggestionLinks: MetricSuggestionParameters[]
    unsuspiciousMetrics: string[]
    untrackedMetrics: string[]
    riskProfile: RiskProfile
}
 
export const calculate = (
    accumulatedData: Pick<AccumulatedData, "unifiedMapNode">,
    blacklist: BlacklistItem[]
): ArtificialIntelligenceData | undefined => {
    if (!accumulatedData.unifiedMapNode) {
        return
    }
 
    const artificialIntelligenceViewModel: ArtificialIntelligenceData = {
        analyzedProgrammingLanguage: undefined,
        suspiciousMetricSuggestionLinks: [],
        unsuspiciousMetrics: [],
        untrackedMetrics: [],
        riskProfile: undefined
    }
 
    const numberOfFilesByLanguage = new Map<string, number>()
    const rlocRisk = { lowRisk: 0, moderateRisk: 0, highRisk: 0, veryHighRisk: 0 }
    let totalRloc = 0
    let totalComplexity = 0
    const metricValuesByLanguage: MetricValuesByLanguage = {}
 
    for (const { data } of hierarchy(accumulatedData.unifiedMapNode)) {
        const fileExtension = getFileExtension(data.name)
        if (data.type === NodeType.FILE && fileExtension !== undefined && !isPathBlacklisted(data.path, blacklist, "exclude")) {
            const filesPerLanguage = numberOfFilesByLanguage.get(fileExtension) ?? 0
            numberOfFilesByLanguage.set(fileExtension, filesPerLanguage + 1)
            setMetricValuesByLanguage(data, metricValuesByLanguage, fileExtension)
 
            if (isFileValid(data, fileExtension)) {
                const firstDefinedMetric = HEIGHT_METRICS.find(metric => data.attributes[metric] !== undefined)
                totalComplexity += data.attributes[firstDefinedMetric]
                totalRloc += data.attributes[AREA_METRIC]
                aggregateRiskProfile(data, rlocRisk, fileExtension)
            }
        }
    }
 
    if (totalRloc > 0 && totalComplexity > 0) {
        artificialIntelligenceViewModel.riskProfile = getPercentagesOfRiskProfile(rlocRisk)
    }
 
    const mainProgrammingLanguage = getMostFrequentLanguage(numberOfFilesByLanguage)
    artificialIntelligenceViewModel.analyzedProgrammingLanguage = mainProgrammingLanguage
 
    if (mainProgrammingLanguage !== undefined) {
        const metricAssessmentResults = findGoodAndBadMetrics(metricValuesByLanguage, mainProgrammingLanguage)
        artificialIntelligenceViewModel.unsuspiciousMetrics = metricAssessmentResults.unsuspiciousMetrics
        artificialIntelligenceViewModel.untrackedMetrics = metricAssessmentResults.untrackedMetrics
        artificialIntelligenceViewModel.suspiciousMetricSuggestionLinks = calculateSuspiciousMetrics(metricAssessmentResults)
    }
 
    return artificialIntelligenceViewModel
}
 
function getFileExtension(fileName: string) {
    return fileName.includes(".") ? fileName.slice(fileName.lastIndexOf(".") + 1) : undefined
}
 
function isFileValid(node: CodeMapNode, fileExtension: string) {
    return (
        HEIGHT_METRICS.some(metric => node.attributes[metric] !== undefined) &&
        node.attributes[AREA_METRIC] !== undefined &&
        !EXCLUDED_FILE_EXTENSION.has(fileExtension)
    )
}
 
export const artificialIntelligenceSelector = createSelector(accumulatedDataSelector, blacklistSelector, calculate)