Navigate a directory full of directories, identifying repos and worktrees
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Normalize variant detection: strip non-alphanums and lowercase for project name matching

rektide b9eeaebe b4daaa41

+70 -17
+70 -17
src/detect/variant.rs
··· 17 17 } 18 18 19 19 fn compute_variant(workspace_name: &str, project_name: &str) -> String { 20 - if let Some(suffix) = workspace_name.strip_prefix(project_name) { 21 - strip_separator(suffix).to_string() 22 - } else if let Some(suffix) = extract_embedded_suffix(workspace_name, project_name) { 23 - strip_separator(&suffix).to_string() 24 - } else { 25 - String::new() 20 + if let Some(suffix) = try_strip_project(workspace_name, project_name) { 21 + return strip_separator(&suffix).to_string(); 26 22 } 23 + String::new() 24 + } 25 + 26 + fn normalize(s: &str) -> String { 27 + s.chars() 28 + .filter(|c| c.is_ascii_alphanumeric()) 29 + .flat_map(|c| c.to_lowercase()) 30 + .collect() 31 + } 32 + 33 + fn try_strip_project(workspace_name: &str, project_name: &str) -> Option<String> { 34 + let norm_workspace = normalize(workspace_name); 35 + let norm_project = normalize(project_name); 36 + 37 + let prefix_len = norm_project.len(); 38 + if norm_workspace.len() <= prefix_len { 39 + return None; 40 + } 41 + if !norm_workspace.starts_with(&norm_project) { 42 + return None; 43 + } 44 + 45 + let norm_suffix = &norm_workspace[prefix_len..]; 46 + let suffix_len = norm_suffix.len(); 47 + 48 + Some(workspace_name[workspace_name.len() - suffix_len..].to_string()) 27 49 } 28 50 29 51 fn strip_separator(s: &str) -> &str { 30 52 s.strip_prefix('-') 31 53 .or_else(|| s.strip_prefix('_')) 54 + .or_else(|| s.strip_prefix('.')) 32 55 .unwrap_or(s) 33 56 } 34 57 35 - fn extract_embedded_suffix(workspace_name: &str, project_name: &str) -> Option<String> { 36 - let dash_pattern = format!("-{}-", project_name); 37 - let underscore_pattern = format!("_{}_", project_name); 58 + #[cfg(test)] 59 + mod tests { 60 + use super::*; 61 + 62 + #[test] 63 + fn simple_dash_suffix() { 64 + assert_eq!(compute_variant("myproject-foo", "myproject"), "foo"); 65 + } 66 + 67 + #[test] 68 + fn dot_in_project_name() { 69 + assert_eq!(compute_variant("usegpu-viteplus", "use.gpu"), "viteplus"); 70 + } 71 + 72 + #[test] 73 + fn dot_in_project_name_dom() { 74 + assert_eq!(compute_variant("usegpu-dom", "use.gpu"), "dom"); 75 + } 76 + 77 + #[test] 78 + fn dot_in_project_name_rolldown() { 79 + assert_eq!(compute_variant("usegpu-rolldown", "use.gpu"), "rolldown"); 80 + } 81 + 82 + #[test] 83 + fn no_match() { 84 + assert_eq!(compute_variant("unrelated-name", "other-project"), ""); 85 + } 86 + 87 + #[test] 88 + fn exact_match_no_variant() { 89 + assert_eq!(compute_variant("myproject", "myproject"), ""); 90 + } 91 + 92 + #[test] 93 + fn underscore_suffix() { 94 + assert_eq!(compute_variant("myproject_foo", "myproject"), "foo"); 95 + } 38 96 39 - if let Some(pos) = workspace_name.find(&dash_pattern) { 40 - let suffix_start = pos + dash_pattern.len(); 41 - Some(workspace_name[suffix_start..].to_string()) 42 - } else if let Some(pos) = workspace_name.find(&underscore_pattern) { 43 - let suffix_start = pos + underscore_pattern.len(); 44 - Some(workspace_name[suffix_start..].to_string()) 45 - } else { 46 - None 97 + #[test] 98 + fn dot_suffix() { 99 + assert_eq!(compute_variant("myproject.foo", "myproject"), "foo"); 47 100 } 48 101 }