use crate::core::backend::GeneratedFile;
use crate::core::config::{Language, ResolvedCrateConfig};
pub(crate) fn scaffold_license_files(config: &ResolvedCrateConfig, languages: &[Language]) -> Vec<GeneratedFile> {
let license_path = config
.workspace_root
.as_deref()
.map(|r| r.join("LICENSE"))
.unwrap_or_else(|| std::path::PathBuf::from("LICENSE"));
let license_content = match std::fs::read_to_string(&license_path) {
Ok(content) => content,
Err(_) => {
tracing::warn!(
"No LICENSE file found at {} — skipping LICENSE sync into package directories",
license_path.display()
);
return vec![];
}
};
let mut seen = std::collections::BTreeSet::new();
let mut files = vec![];
for &lang in languages {
match lang {
Language::Rust | Language::C | Language::Ffi | Language::Jni => continue,
_ => {}
}
let pkg_dir = config.package_dir(lang);
if seen.insert(pkg_dir.clone()) {
files.push(GeneratedFile {
path: std::path::Path::new(&pkg_dir).join("LICENSE"),
content: license_content.clone(),
generated_header: false,
});
}
}
files
}
pub(crate) fn scaffold_gitattributes(config: &ResolvedCrateConfig, languages: &[Language]) -> Vec<GeneratedFile> {
let mut dirs: std::collections::BTreeSet<String> = std::collections::BTreeSet::new();
for &lang in languages {
match lang {
Language::Rust | Language::C => {}
Language::Ffi => {
dirs.insert(format!("crates/{}-ffi", config.core_crate_dir()));
}
Language::Jni => {
dirs.insert(format!("crates/{}-jni", config.name));
}
Language::Python => {
dirs.insert(config.package_dir(lang));
dirs.insert(format!("crates/{}-py", config.core_crate_dir()));
}
Language::Php => {
dirs.insert(config.package_dir(lang));
dirs.insert(format!("crates/{}-php", config.core_crate_dir()));
}
Language::Kotlin => {
let dir = if let Some(k) = config.kotlin.as_ref() {
if k.mode.as_deref() == Some("kmp") || k.target == crate::core::config::KotlinTarget::Multiplatform
{
"packages/kotlin-mpp".to_string()
} else if k.target == crate::core::config::KotlinTarget::Native {
"packages/kotlin-native".to_string()
} else {
config.package_dir(lang)
}
} else {
config.package_dir(lang)
};
dirs.insert(dir);
}
Language::Node => {
let dir = config
.node
.as_ref()
.and_then(|c| c.crate_dir.as_ref())
.map(|s| s.to_string())
.unwrap_or_else(|| format!("crates/{}-node", config.name));
dirs.insert(dir);
}
_ => {
dirs.insert(config.package_dir(lang));
}
}
}
let e2e_dir = config.e2e.as_ref().map(|e| e.output.as_str()).unwrap_or("e2e");
dirs.insert(e2e_dir.to_string());
let test_apps_dir = config
.e2e
.as_ref()
.map(|e| e.registry.output.as_str())
.unwrap_or("test_apps");
dirs.insert(test_apps_dir.to_string());
let mut content = String::from("# Generated by alef scaffold.\n");
for dir in dirs {
let dir = dir.trim_end_matches('/');
content.push_str(&format!("{dir}/** linguist-generated=true\n"));
}
vec![GeneratedFile {
path: std::path::PathBuf::from(".gitattributes"),
content,
generated_header: false,
}]
}