repopilot 0.9.0

Local-first CLI for repository audit, architecture risk detection, baseline tracking, and CI-friendly code review.
Documentation
use crate::output::html::escape::escape_html;
use crate::scan::types::ScanSummary;

pub(super) fn render_frameworks_section(summary: &ScanSummary) -> String {
    if summary.detected_frameworks.is_empty()
        && summary.framework_projects.is_empty()
        && summary.react_native.is_none()
    {
        return String::new();
    }

    let labels: Vec<String> = summary
        .detected_frameworks
        .iter()
        .map(|f| format!(r#"<li class="pill">{}</li>"#, escape_html(&f.label())))
        .collect();
    let mut output = String::from("<h2>Frameworks</h2>");
    if !labels.is_empty() {
        output.push_str(&format!(
            r#"<ul class="inline-list">{}</ul>"#,
            labels.join("")
        ));
    }

    render_framework_projects(summary, &mut output);
    render_react_native(summary, &mut output);

    output
}

fn render_framework_projects(summary: &ScanSummary, output: &mut String) {
    let nested_projects: Vec<_> = summary
        .framework_projects
        .iter()
        .filter(|project| project.path.as_path() != std::path::Path::new("."))
        .collect();
    if nested_projects.is_empty() {
        return;
    }

    output.push_str("<h3>Framework Projects</h3><table><thead><tr><th>Path</th><th>Frameworks</th></tr></thead><tbody>");
    for project in nested_projects {
        let frameworks = project
            .frameworks
            .iter()
            .map(|f| escape_html(&f.label()))
            .collect::<Vec<_>>()
            .join(", ");
        output.push_str(&format!(
            "<tr><td><code>{}</code></td><td>{}</td></tr>",
            escape_html(&project.path.to_string_lossy()),
            frameworks
        ));
    }
    output.push_str("</tbody></table>");
}

fn render_react_native(summary: &ScanSummary, output: &mut String) {
    if let Some(rn) = &summary.react_native {
        output.push_str(&format!(
            "<div class=\"panel\"><h3>React Native</h3><p class=\"meta\">Version {} | Android New Architecture {} | iOS New Architecture {} | Hermes {} | Codegen {}</p></div>",
            escape_html(rn.react_native_version.as_deref().unwrap_or("unknown")),
            escape_html(format_tristate(rn.android_new_arch_enabled)),
            escape_html(format_tristate(rn.ios_new_arch_enabled)),
            escape_html(format_tristate(rn.hermes_enabled)),
            if rn.has_codegen_config { "found" } else { "missing" }
        ));
    }
}

fn format_tristate(value: Option<bool>) -> &'static str {
    match value {
        Some(true) => "enabled",
        Some(false) => "disabled",
        None => "unknown",
    }
}