use crate::import_analyzer;
use crate::parse_utils;
pub fn has_markers(content: &str) -> bool {
content.contains("dynami::generate!")
}
pub fn extract_user_content(content: &str) -> (String, String) {
if let Some(marker_pos) = content.find("dynami::generate!") {
let after_marker = marker_pos + "dynami::generate!".len();
if let Some((_, _open_pos, close_pos)) =
parse_utils::extract_braced_content(content, after_marker)
{
let before = content[..marker_pos].trim_end().to_string();
let after = if close_pos + 1 < content.len() {
let after_content = &content[close_pos + 1..];
if after_content.starts_with('\n') {
after_content[1..].to_string()
} else if after_content.starts_with("\r\n") {
after_content[2..].to_string()
} else {
after_content.to_string()
}
} else {
String::new()
};
return (before, after);
}
}
(content.to_string(), String::new())
}
pub fn inject_generated_with_imports(
before: &str,
generated: &str,
after: &str,
routing_import: Option<String>,
) -> String {
let mut result = String::new();
if !before.is_empty() {
let cleaned_before = import_analyzer::remove_routing_imports(before);
if let Some(import) = &routing_import {
let injected = inject_import_in_proper_location(&cleaned_before, import);
result.push_str(&injected);
} else {
result.push_str(&cleaned_before);
}
result.push('\n');
} else if let Some(import) = &routing_import {
result.push_str(import);
result.push('\n');
result.push('\n');
}
result.push_str(" dynami::generate! {\n");
if !generated.is_empty() {
result.push_str(generated);
result.push('\n');
}
result.push_str(" }");
if !after.is_empty() {
result.push('\n');
result.push_str(after);
}
result
}
fn inject_import_in_proper_location(content: &str, import: &str) -> String {
if content.contains(import) {
return content.to_string();
}
let lines: Vec<&str> = content.lines().collect();
let mut result = Vec::new();
let mut import_inserted = false;
let mut last_import_index = None;
for (i, line) in lines.iter().enumerate() {
let trimmed = line.trim();
if trimmed.starts_with("use ") || trimmed.starts_with("pub use ") {
last_import_index = Some(i);
}
}
for (i, line) in lines.iter().enumerate() {
result.push(line.to_string());
if !import_inserted {
if let Some(last_idx) = last_import_index {
if i == last_idx {
result.push(import.to_string());
import_inserted = true;
}
} else if i == 0 {
result.push(String::new());
result.push(import.to_string());
import_inserted = true;
}
}
}
if !import_inserted {
result.push(String::new());
result.push(import.to_string());
}
result.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_has_markers() {
let content = r#"
pub fn router() -> Router {
let mut router = Router::new();
dynami::generate! {
router = router.route("/", get(get::handler))
}
router
}
"#;
assert!(has_markers(content));
let content_no_markers = "some code";
assert!(!has_markers(content_no_markers));
}
#[test]
fn test_extract_user_content() {
let content = r#"use axum::Router;
pub fn router() -> Router {
let mut router = Router::new();
dynami::generate! {
router = router.route("/", get(get::handler))
}
router
}"#;
let (before, after) = extract_user_content(content);
assert!(before.contains("let mut router = Router::new();"));
assert!(after.contains("router"));
assert!(!after.contains("dynami::generate!"));
}
#[test]
fn test_inject_generated() {
let before = r#"pub fn router() -> Router {
let mut router = Router::new();"#;
let generated = " router = router.route(\"/\", get(get::handler));";
let after = " router\n}";
let result = inject_generated_with_imports(before, generated, after, None);
assert!(result.contains("dynami::generate!"));
assert!(result.contains("router = router.route"));
assert!(result.contains("let mut router"));
}
#[test]
fn test_extract_nested_braces() {
let content = r#"
pub fn router() -> Router {
let mut router = Router::new();
dynami::generate! {
router = router.route("/", get(|| async { "nested" }));
}
router
}
"#;
let (before, after) = extract_user_content(content);
assert!(before.contains("let mut router"));
assert!(after.trim().starts_with("router"));
}
}