diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-03-17 14:47:25 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-03-17 14:47:25 +0800 |
| commit | 92670ec92b555383fc31cf42b15d4ea38f8e9c8f (patch) | |
| tree | b2f1479247411027fb41b346d2195e79e38729a1 /gen/gen_specific_renderer.rs | |
| parent | 7fcc38d0e76fc4088269cd3ea22c56a60e5db109 (diff) | |
Extract build-time generation code into separate crate
Diffstat (limited to 'gen/gen_specific_renderer.rs')
| -rw-r--r-- | gen/gen_specific_renderer.rs | 355 |
1 files changed, 0 insertions, 355 deletions
diff --git a/gen/gen_specific_renderer.rs b/gen/gen_specific_renderer.rs deleted file mode 100644 index 95e6900..0000000 --- a/gen/gen_specific_renderer.rs +++ /dev/null @@ -1,355 +0,0 @@ -use std::{collections::HashMap, path::PathBuf}; - -use just_template::{Template, tmpl}; -use regex::Regex; - -use crate::r#gen::{ - constants::{RENDERERS_PATH, SPECIFIC_RENDERER_MATCHING, SPECIFIC_RENDERER_MATCHING_TEMPLATE}, - resolve_types::resolve_type_paths, -}; - -const RENDERER_TYPE_PREFIX: &str = "crate::"; - -/// Generate specific renderer matching file using just_template -pub async fn generate_specific_renderer(repo_root: &PathBuf) { - // Matches: HashMap<RendererTypeFullName, OutputTypeFullName> - let mut renderer_matches: HashMap<String, String> = HashMap::new(); - - let renderer_path = repo_root.join(RENDERERS_PATH); - collect_renderers(&renderer_path, &mut renderer_matches); - - let template_path = repo_root.join(SPECIFIC_RENDERER_MATCHING_TEMPLATE); - let output_path = repo_root.join(SPECIFIC_RENDERER_MATCHING); - - // Read the template - let template_content = tokio::fs::read_to_string(&template_path).await.unwrap(); - - // Create template - let mut template = Template::from(template_content); - - for (renderer, output) in &renderer_matches { - let output_name = output.split("::").last().unwrap_or(output); - tmpl!(template += { - renderer_match_arms { - (output_type_name = output_name, output_type = output, renderer_type = renderer) - } - }); - } - - let final_content = template.expand().unwrap(); - - // Write the generated code - tokio::fs::write(output_path, final_content).await.unwrap(); - - println!( - "Generated specific renderer matching with {} renderers using just_template", - renderer_matches.len() - ); -} - -fn collect_renderers(dir_path: &PathBuf, matches: &mut HashMap<String, String>) { - if let Ok(entries) = std::fs::read_dir(dir_path) { - for entry in entries { - if let Ok(entry) = entry { - let path = entry.path(); - if path.is_dir() { - collect_renderers(&path, matches); - } else if path.is_file() && path.extension().map_or(false, |ext| ext == "rs") { - process_rs_file(&path, matches); - } - } - } - } -} - -fn process_rs_file(file_path: &PathBuf, matches: &mut HashMap<String, String>) { - let content = match std::fs::read_to_string(file_path) { - Ok(content) => content, - Err(_) => return, - }; - - let renderer_info = match get_renderer_types(&content) { - Some(info) => info, - None => return, - }; - - let (renderer_type, output_type) = renderer_info; - - let full_renderer_type = build_full_renderer_type(file_path, &renderer_type); - let full_output_type = resolve_type_paths(&content, vec![output_type]) - .unwrap() - .get(0) - .unwrap() - .clone(); - - matches.insert(full_renderer_type, full_output_type); -} - -fn build_full_renderer_type(file_path: &PathBuf, renderer_type: &str) -> String { - let relative_path = file_path - .strip_prefix(std::env::current_dir().unwrap()) - .unwrap_or(file_path); - let relative_path = relative_path.with_extension(""); - let path_str = relative_path.to_string_lossy(); - - // Normalize path separators and remove "./" prefix if present - let normalized_path = path_str - .replace('\\', "/") - .trim_start_matches("./") - .to_string(); - - let mut module_path = normalized_path.split('/').collect::<Vec<&str>>().join("::"); - - if module_path.starts_with("src") { - module_path = module_path.trim_start_matches("src").to_string(); - if module_path.starts_with("::") { - module_path = module_path.trim_start_matches("::").to_string(); - } - } - - format!("{}{}::{}", RENDERER_TYPE_PREFIX, module_path, renderer_type) -} - -pub fn get_renderer_types(code: &String) -> Option<(String, String)> { - let renderer_re = Regex::new(r"#\[result_renderer\(([^)]+)\)\]").unwrap(); - - let func_re = - Regex::new(r"(?:pub\s+)?(?:async\s+)?fn\s+\w+\s*\(\s*(?:mut\s+)?\w+\s*:\s*&([^),]+)\s*") - .unwrap(); - - let code_without_comments = code - .lines() - .filter(|line| !line.trim_start().starts_with("//")) - .collect::<Vec<&str>>() - .join("\n"); - - let renderer_captures = renderer_re.captures(&code_without_comments); - let func_captures = func_re.captures(&code_without_comments); - - match (renderer_captures, func_captures) { - (Some(renderer_cap), Some(func_cap)) => { - let renderer_type = renderer_cap[1].trim().to_string(); - let output_type = func_cap[1].trim().to_string(); - Some((renderer_type, output_type)) - } - _ => None, - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test1() { - const SITUATION: &str = " - #[result_renderer(MyRenderer)] - pub async fn render(data: &SomeOutput) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer"); - assert_eq!(output, "SomeOutput"); - } - - #[test] - fn test2() { - const SITUATION: &str = " - #[result_renderer(MyRenderer)] - pub async fn some_render(output: &SomeOutput) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer"); - assert_eq!(output, "SomeOutput"); - } - - #[test] - fn test3() { - const SITUATION: &str = " - #[result_renderer(MyRenderer)] - async fn some_render(output: &SomeOutput) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer"); - assert_eq!(output, "SomeOutput"); - } - - #[test] - fn test4() { - const SITUATION: &str = " - #[result_renderer(MyRenderer)] - async pub fn some_render(output: &SomeOutput) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer"); - assert_eq!(output, "SomeOutput"); - } - - #[test] - fn test5() { - const SITUATION: &str = " - #[result_renderer(MyRenderer)] - fn some_render(output: &SomeOutput2) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer"); - assert_eq!(output, "SomeOutput2"); - } - - #[test] - fn test6() { - const SITUATION: &str = " - #[result__renderer(MyRenderer)] - fn some_render(output: &SomeOutput2) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!( - result.is_none(), - "Should fail to parse when annotation doesn't match" - ); - } - - #[test] - fn test7() { - const SITUATION: &str = " - #[result_renderer(MyRenderer)] - fn some_render() -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!( - result.is_none(), - "Should fail to parse when no function parameter" - ); - } - - #[test] - fn test8() { - const SITUATION: &str = " - #[result_renderer(MyRenderer)] - fn some_render(output: &SomeOutput, context: &Context) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer"); - assert_eq!(output, "SomeOutput"); - } - - #[test] - fn test9() { - const SITUATION: &str = " - #[result_renderer(MyRenderer<T>)] - fn some_render(output: &SomeOutput<T>) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer<T>"); - assert_eq!(output, "SomeOutput<T>"); - } - - #[test] - fn test10() { - const SITUATION: &str = " - #[result_renderer(MyRenderer<'a>)] - fn some_render(output: &SomeOutput<'a>) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer<'a>"); - assert_eq!(output, "SomeOutput<'a>"); - } - - #[test] - fn test11() { - const SITUATION: &str = " - #[result_renderer( MyRenderer )] - fn some_render( output : & SomeOutput ) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MyRenderer"); - assert_eq!(output, "SomeOutput"); - } - - #[test] - fn test12() { - const SITUATION: &str = " - #[result_renderer(AnotherRenderer)] - fn some_render(output: &DifferentOutput) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "AnotherRenderer"); - assert_eq!(output, "DifferentOutput"); - } - - #[test] - fn test13() { - const SITUATION: &str = " - // #[result_renderer(WrongRenderer)] - #[result_renderer(CorrectRenderer)] - fn some_render(output: &CorrectOutput) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "CorrectRenderer"); - assert_eq!(output, "CorrectOutput"); - } - - #[test] - fn test14() { - const SITUATION: &str = " - #[result_renderer(MultiLineRenderer)] - fn some_render( - output: &MultiLineOutput - ) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MultiLineRenderer"); - assert_eq!(output, "MultiLineOutput"); - } - - #[test] - fn test15() { - const SITUATION: &str = " - #[result_renderer(MutRenderer)] - fn some_render(mut output: &MutOutput) -> Result<JVRenderResult, CmdRenderError> - "; - - let result = get_renderer_types(&SITUATION.to_string()); - assert!(result.is_some(), "Parse failed"); - let (renderer, output) = result.unwrap(); - assert_eq!(renderer, "MutRenderer"); - assert_eq!(output, "MutOutput"); - } -} |
