use regex::Regex;
use std::sync::OnceLock;
use super::external_library_loader::apply_loader_fix_from_stem;
pub fn rewrite_frb_sealed_variants(source: &str) -> String {
let source = apply_loader_fix_from_stem(source);
let source = source.as_str();
let variant_re = variant_regex();
variant_re
.replace_all(source, |caps: ®ex::Captures<'_>| {
let prefix = &caps["prefix"];
let params = &caps["params"];
let suffix = &caps["suffix"];
let variant_pascal = &caps["variant"];
let rewritten_params = rewrite_param_list(params, variant_pascal);
format!("{prefix}{rewritten_params}{suffix}")
})
.into_owned()
}
fn variant_regex() -> &'static Regex {
static RE: OnceLock<Regex> = OnceLock::new();
RE.get_or_init(|| {
Regex::new(
r"(?s)(?P<prefix>const\s+factory\s+[A-Za-z_][A-Za-z0-9_]*\.[A-Za-z_][A-Za-z0-9_]*\s*\(\s*\{)(?P<params>[^{}]*)(?P<suffix>\}\s*\)\s*=\s*[A-Za-z_][A-Za-z0-9_]*_(?P<variant>[A-Za-z][A-Za-z0-9]*)\s*;)",
)
.expect("variant regex must compile")
})
}
fn rewrite_param_list(params: &str, variant_pascal: &str) -> String {
let param_re = param_regex();
let matches: Vec<regex::Captures<'_>> = param_re.captures_iter(params).collect();
let total_fields = matches
.iter()
.filter(|m| {
let name = m.name("name").map(|m| m.as_str()).unwrap_or("");
is_positional_field(name)
})
.count();
if total_fields == 0 {
return params.to_string();
}
let mut out = String::with_capacity(params.len());
let mut cursor = 0usize;
for caps in &matches {
let whole = caps.get(0).expect("regex match must have group 0");
let name_match = caps.name("name").expect("name capture is required");
let raw_name = name_match.as_str();
out.push_str(¶ms[cursor..name_match.start()]);
if let Some(field_idx) = field_index(raw_name) {
let type_name = caps.name("type").map(|m| m.as_str()).unwrap_or("").trim();
let new_name = payload_param_name(type_name, variant_pascal, field_idx, total_fields);
out.push_str(&new_name);
} else {
out.push_str(raw_name);
}
cursor = name_match.end();
let _ = whole; }
out.push_str(¶ms[cursor..]);
out
}
fn param_regex() -> &'static Regex {
static RE: OnceLock<Regex> = OnceLock::new();
RE.get_or_init(|| {
Regex::new(r"required\s+(?P<type>[^,{}]+?)\s+(?P<name>[A-Za-z_][A-Za-z0-9_]*)\s*(?:,|$)")
.expect("param regex must compile")
})
}
fn field_index(name: &str) -> Option<usize> {
let rest = name.strip_prefix("field")?;
rest.parse::<usize>().ok()
}
fn is_positional_field(name: &str) -> bool {
field_index(name).is_some()
}
fn payload_param_name(type_name: &str, variant_pascal: &str, field_idx: usize, total_fields: usize) -> String {
let _ = (type_name, variant_pascal, total_fields);
format!("field{field_idx}")
}
#[allow(dead_code)]
fn to_lower_camel(s: &str) -> String {
let mut chars = s.chars();
match chars.next() {
Some(first) => first.to_lowercase().collect::<String>() + chars.as_str(),
None => String::new(),
}
}
#[allow(dead_code)]
fn is_dart_primitive(type_name: &str) -> bool {
matches!(
type_name,
"String"
| "int"
| "double"
| "bool"
| "num"
| "void"
| "dynamic"
| "Object"
| "Uint8List"
| "List"
| "Map"
| "Set"
| "BigInt"
| "DateTime"
| "Duration"
)
}