dx_forge/api/
codegen.rs

1//! Generated Code Governance APIs
2
3use anyhow::Result;
4use std::path::{Path, PathBuf};
5use std::collections::HashMap;
6use parking_lot::RwLock;
7use std::sync::{Arc, OnceLock};
8
9#[derive(Debug, Clone)]
10pub struct GeneratedRegion {
11    pub start_line: usize,
12    pub end_line: usize,
13    pub generator_tool: String,
14    pub allow_manual_edit: bool,
15}
16
17static CODE_REGIONS: OnceLock<Arc<RwLock<HashMap<PathBuf, Vec<GeneratedRegion>>>>> = OnceLock::new();
18static FILE_OWNERSHIP: OnceLock<Arc<RwLock<HashMap<PathBuf, String>>>> = OnceLock::new();
19
20fn get_regions() -> Arc<RwLock<HashMap<PathBuf, Vec<GeneratedRegion>>>> {
21    CODE_REGIONS.get_or_init(|| Arc::new(RwLock::new(HashMap::new()))).clone()
22}
23
24fn get_ownership() -> Arc<RwLock<HashMap<PathBuf, String>>> {
25    FILE_OWNERSHIP.get_or_init(|| Arc::new(RwLock::new(HashMap::new()))).clone()
26}
27
28pub fn mark_code_region_as_dx_generated(
29    file: &Path,
30    start_line: usize,
31    end_line: usize,
32    generator_tool: &str
33) -> Result<()> {
34    let regions = get_regions();
35    let mut regions = regions.write();
36    
37    let region = GeneratedRegion {
38        start_line,
39        end_line,
40        generator_tool: generator_tool.to_string(),
41        allow_manual_edit: false,
42    };
43    
44    regions.entry(file.to_path_buf())
45        .or_insert_with(Vec::new)
46        .push(region);
47    
48    tracing::debug!("🏷️  Marked lines {}-{} in {:?} as generated by {}",
49        start_line, end_line, file, generator_tool);
50    
51    Ok(())
52}
53
54pub fn is_region_dx_generated(file: &Path, line: usize) -> Result<bool> {
55    let regions = get_regions();
56    let regions = regions.read();
57    
58    if let Some(file_regions) = regions.get(file) {
59        Ok(file_regions.iter().any(|r| line >= r.start_line && line <= r.end_line))
60    } else {
61        Ok(false)
62    }
63}
64
65pub fn allow_safe_manual_edit_of_generated_code(file: &Path, line: usize) -> Result<()> {
66    let regions = get_regions();
67    let mut regions = regions.write();
68    
69    if let Some(file_regions) = regions.get_mut(file) {
70        for region in file_regions {
71            if line >= region.start_line && line <= region.end_line {
72                region.allow_manual_edit = true;
73                tracing::info!("✏️  Allowed manual editing of generated region in {:?}", file);
74                return Ok(());
75            }
76        }
77    }
78    
79    anyhow::bail!("No generated region found at line {} in {:?}", line, file)
80}
81
82pub fn claim_full_ownership_of_file(file: &Path, owner_tool: &str) -> Result<()> {
83    let ownership = get_ownership();
84    let mut ownership = ownership.write();
85    
86    tracing::info!("🔒 Tool '{}' claimed ownership of {:?}", owner_tool, file);
87    ownership.insert(file.to_path_buf(), owner_tool.to_string());
88    
89    Ok(())
90}
91
92pub fn release_ownership_of_file(file: &Path) -> Result<()> {
93    let ownership = get_ownership();
94    let mut ownership = ownership.write();
95    
96    if ownership.remove(file).is_some() {
97        tracing::info!("🔓 Released ownership of {:?}", file);
98    }
99    
100    Ok(())
101}