Skip to content

Commit 0600d5f

Browse files
committed
match with _ issue
1 parent 6e3725b commit 0600d5f

1 file changed

Lines changed: 82 additions & 2 deletions

File tree

crates/vespera_macro/src/schema_macro/file_lookup.rs

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,13 +186,40 @@ pub fn find_struct_by_name_in_all_files(
186186
.or_else(|| hint_lower.strip_suffix("request"))
187187
.unwrap_or(&hint_lower);
188188

189-
// Find files whose name contains the prefix
189+
// Normalize prefix: remove underscores for comparison
190+
// This allows "AdminUserSchema" (prefix "adminuser") to match "admin_user.rs"
191+
let prefix_normalized = prefix.replace('_', "");
192+
193+
// First, try exact filename match (normalized)
194+
// e.g., "admin_user.rs" normalized to "adminuser" matches prefix "adminuser"
195+
let exact_match: Vec<_> = found_structs
196+
.iter()
197+
.filter(|(path, _)| {
198+
path.file_stem()
199+
.and_then(|s| s.to_str())
200+
.is_some_and(|name| {
201+
name.to_lowercase().replace('_', "") == prefix_normalized
202+
})
203+
})
204+
.collect();
205+
206+
if exact_match.len() == 1 {
207+
let (path, metadata) = exact_match[0];
208+
let module_path = file_path_to_module_path(path, src_dir);
209+
return Some((metadata.clone(), module_path));
210+
}
211+
212+
// Fallback: Find files whose normalized name contains the prefix
190213
let matching: Vec<_> = found_structs
191214
.into_iter()
192215
.filter(|(path, _)| {
193216
path.file_stem()
194217
.and_then(|s| s.to_str())
195-
.is_some_and(|name| name.to_lowercase().contains(prefix))
218+
.is_some_and(|name| {
219+
name.to_lowercase()
220+
.replace('_', "")
221+
.contains(&prefix_normalized)
222+
})
196223
})
197224
.collect();
198225

@@ -763,6 +790,59 @@ pub struct Target { pub id: i32 }
763790
);
764791
}
765792

793+
#[test]
794+
#[serial]
795+
fn test_find_struct_disambiguation_snake_case_filename() {
796+
// Tests: CamelCase schema name matches snake_case filename
797+
// e.g., "AdminUserSchema" should match "admin_user.rs"
798+
let temp_dir = TempDir::new().unwrap();
799+
let src_dir = temp_dir.path();
800+
801+
std::fs::create_dir(src_dir.join("models")).unwrap();
802+
// Create admin_user.rs with Model
803+
std::fs::write(
804+
src_dir.join("models").join("admin_user.rs"),
805+
"pub struct Model { pub id: i32, pub role: String }",
806+
)
807+
.unwrap();
808+
// Create regular_user.rs with Model
809+
std::fs::write(
810+
src_dir.join("models").join("regular_user.rs"),
811+
"pub struct Model { pub id: i32, pub name: String }",
812+
)
813+
.unwrap();
814+
815+
// With hint "AdminUserSchema" - should find admin_user.rs
816+
// "AdminUserSchema" -> prefix "adminuser" -> matches "admin_user.rs" (normalized: "adminuser")
817+
let result = find_struct_by_name_in_all_files(src_dir, "Model", Some("AdminUserSchema"));
818+
assert!(
819+
result.is_some(),
820+
"AdminUserSchema hint should match admin_user.rs"
821+
);
822+
let (metadata, module_path) = result.unwrap();
823+
assert!(
824+
metadata.definition.contains("role"),
825+
"Should be admin_user Model with role field"
826+
);
827+
assert!(
828+
module_path.contains(&"admin_user".to_string()),
829+
"Module path should contain 'admin_user'"
830+
);
831+
832+
// With hint "RegularUserSchema" - should find regular_user.rs
833+
let result_regular =
834+
find_struct_by_name_in_all_files(src_dir, "Model", Some("RegularUserSchema"));
835+
assert!(
836+
result_regular.is_some(),
837+
"RegularUserSchema hint should match regular_user.rs"
838+
);
839+
let (metadata_regular, _) = result_regular.unwrap();
840+
assert!(
841+
metadata_regular.definition.contains("name"),
842+
"Should be regular_user Model with name field"
843+
);
844+
}
845+
766846
// ============================================================
767847
// Coverage tests for find_struct_from_schema_path
768848
// ============================================================

0 commit comments

Comments
 (0)