tokmd-analysis 1.14.0

Analysis logic and enrichers for tokmd receipts.
Documentation
#![cfg_attr(
    not(all(feature = "content", feature = "walk")),
    allow(unused_variables)
)]
use std::path::{Path, PathBuf};

use tokmd_analysis_types::AnalysisLimits;
use tokmd_types::ExportData;

use crate::grid::PresetPlan;

use super::super::outputs::AnalysisOutputs;

#[cfg_attr(not(all(feature = "content", feature = "walk")), allow(dead_code))]
pub(in crate::analysis) struct CodeQualityInput<'a> {
    pub(in crate::analysis) root: &'a Path,
    pub(in crate::analysis) export: &'a ExportData,
    pub(in crate::analysis) files: Option<&'a [PathBuf]>,
    pub(in crate::analysis) plan: &'a PresetPlan,
    pub(in crate::analysis) limits: &'a AnalysisLimits,
    pub(in crate::analysis) detail_functions: bool,
}

pub(in crate::analysis) fn run(
    input: CodeQualityInput<'_>,
    outputs: &mut AnalysisOutputs,
    warnings: &mut Vec<String>,
) {
    run_entropy(&input, outputs, warnings);
    run_license(&input, outputs, warnings);
    run_complexity(&input, outputs, warnings);
    run_api_surface(&input, outputs, warnings);
    attach_halstead(&input, outputs, warnings);
}

fn run_entropy(
    input: &CodeQualityInput<'_>,
    outputs: &mut AnalysisOutputs,
    warnings: &mut Vec<String>,
) {
    if input.plan.entropy {
        #[cfg(all(feature = "content", feature = "walk"))]
        if let Some(list) = input.files {
            match crate::entropy::build_entropy_report(input.root, list, input.export, input.limits)
            {
                Ok(report) => outputs.entropy = Some(report),
                Err(err) => warnings.push(format!("entropy scan failed: {}", err)),
            }
        }
        #[cfg(not(all(feature = "content", feature = "walk")))]
        warnings.push(
            crate::grid::DisabledFeature::EntropyProfiling
                .warning()
                .to_string(),
        );
    }
}

fn run_license(
    input: &CodeQualityInput<'_>,
    outputs: &mut AnalysisOutputs,
    warnings: &mut Vec<String>,
) {
    if input.plan.license {
        #[cfg(all(feature = "content", feature = "walk"))]
        if let Some(list) = input.files {
            match crate::license::build_license_report(input.root, list, input.limits) {
                Ok(report) => outputs.license = Some(report),
                Err(err) => warnings.push(format!("license scan failed: {}", err)),
            }
        }
        #[cfg(not(all(feature = "content", feature = "walk")))]
        warnings.push(
            crate::grid::DisabledFeature::LicenseRadar
                .warning()
                .to_string(),
        );
    }
}

fn run_complexity(
    input: &CodeQualityInput<'_>,
    outputs: &mut AnalysisOutputs,
    warnings: &mut Vec<String>,
) {
    if input.plan.complexity {
        #[cfg(all(feature = "content", feature = "walk"))]
        if let Some(list) = input.files {
            match crate::complexity::build_complexity_report(
                input.root,
                list,
                input.export,
                input.limits,
                input.detail_functions,
            ) {
                Ok(report) => {
                    outputs.complexity = Some(report);
                    for warning in crate::complexity::bounded_complexity_warnings(
                        input.root,
                        list,
                        input.export,
                        input.limits,
                    ) {
                        if warnings.iter().all(|existing| existing != &warning) {
                            warnings.push(warning);
                        }
                    }
                }
                Err(err) => warnings.push(format!("complexity scan failed: {}", err)),
            }
        }
        #[cfg(not(all(feature = "content", feature = "walk")))]
        warnings.push(
            crate::grid::DisabledFeature::ComplexityAnalysis
                .warning()
                .to_string(),
        );
    }
}

fn run_api_surface(
    input: &CodeQualityInput<'_>,
    outputs: &mut AnalysisOutputs,
    warnings: &mut Vec<String>,
) {
    if input.plan.api_surface {
        #[cfg(all(feature = "content", feature = "walk"))]
        if let Some(list) = input.files {
            match crate::api_surface::build_api_surface_report(
                input.root,
                list,
                input.export,
                input.limits,
            ) {
                Ok(report) => outputs.api_surface = Some(report),
                Err(err) => warnings.push(format!("api surface scan failed: {}", err)),
            }
        }
        #[cfg(not(all(feature = "content", feature = "walk")))]
        warnings.push(
            crate::grid::DisabledFeature::ApiSurfaceAnalysis
                .warning()
                .to_string(),
        );
    }
}

fn attach_halstead(
    input: &CodeQualityInput<'_>,
    outputs: &mut AnalysisOutputs,
    warnings: &mut Vec<String>,
) {
    #[cfg(all(feature = "halstead", feature = "content", feature = "walk"))]
    if input.plan.halstead
        && let Some(list) = input.files
    {
        match crate::halstead::build_halstead_report(input.root, list, input.export, input.limits) {
            Ok(halstead_report) => {
                if let Some(ref mut complexity) = outputs.complexity {
                    crate::maintainability::attach_halstead_metrics(complexity, halstead_report);
                }
            }
            Err(err) => warnings.push(format!("halstead scan failed: {}", err)),
        }
    }
    #[cfg(not(all(feature = "halstead", feature = "content", feature = "walk")))]
    let _ = (input, outputs, warnings);
}