use anyhow::Context as _;
use std::path::Path;
pub(crate) fn canonical_frb_generated(
lib_rs_source: &str,
frb_generated_source: &str,
frb_generated_path: &Path,
) -> String {
let gated = crate::backends::dart::carry_lib_rs_cfg_gates_into_frb_generated(lib_rs_source, frb_generated_source);
crate::cli::pipeline::normalize_content(frb_generated_path, &gated)
}
pub(super) fn run(source_file: &Path, target_file: &Path) -> anyhow::Result<()> {
if !source_file.exists() || !target_file.exists() {
tracing::debug!(
"CarryFrbCfgGates source or target not found: {} / {}",
source_file.display(),
target_file.display()
);
return Ok(());
}
let source_content = std::fs::read_to_string(source_file)
.with_context(|| format!("failed to read cfg-gate source {}", source_file.display()))?;
let target_content = std::fs::read_to_string(target_file)
.with_context(|| format!("failed to read cfg-gate target {}", target_file.display()))?;
let canonical = canonical_frb_generated(&source_content, &target_content, target_file);
if canonical != target_content {
std::fs::write(target_file, &canonical)
.with_context(|| format!("failed to write cfg-gated file {}", target_file.display()))?;
tracing::info!(
"Carried #[cfg] gates from {} into {} and normalized its formatting",
source_file.display(),
target_file.display()
);
} else {
tracing::debug!("CarryFrbCfgGates {}: no changes needed", target_file.display());
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn canonical_frb_generated_converges_raw_and_formatted_import_order() {
let _cwd_lock = crate::test_support::CWD_LOCK
.lock()
.unwrap_or_else(|error| error.into_inner());
if !crate::cli::pipeline::is_tool_available("rustfmt") {
return;
}
let lib_rs = "pub fn add(a: i64, b: i64) -> i64 {\n a + b\n}\n";
let raw_from_tool = "use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};\n\
fn wire__crate__add_impl() {}\n";
let already_formatted = "use flutter_rust_bridge::for_generated::{Lifetimeable, Lockable, transform_result_dco};\n\
fn wire__crate__add_impl() {}\n";
assert_ne!(
raw_from_tool, already_formatted,
"fixture setup: these must start out textually different for the test to mean anything"
);
let path = Path::new("frb_generated.rs");
let from_raw = canonical_frb_generated(lib_rs, raw_from_tool, path);
let from_formatted = canonical_frb_generated(lib_rs, already_formatted, path);
assert_eq!(
from_raw, from_formatted,
"canonical_frb_generated must converge regardless of which alef command last wrote \
the raw file -- this is what a repeated `alef build`/`alef generate` regeneration on \
unchanged input must never disagree on"
);
}
#[test]
fn canonical_frb_generated_is_idempotent() {
let _cwd_lock = crate::test_support::CWD_LOCK
.lock()
.unwrap_or_else(|error| error.into_inner());
if !crate::cli::pipeline::is_tool_available("rustfmt") {
return;
}
let lib_rs = "pub fn add(a: i64, b: i64) -> i64 {\n a + b\n}\n";
let raw = "use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};\n\
fn wire__crate__add_impl() {}\n";
let path = Path::new("frb_generated.rs");
let once = canonical_frb_generated(lib_rs, raw, path);
let twice = canonical_frb_generated(lib_rs, &once, path);
assert_eq!(
once, twice,
"canonicalizing already-canonical content must be a fixed point"
);
}
}