@@ -111,6 +111,9 @@ fn build_output_path(root: &Path, rel_path: &Path, orm: Orm) -> PathBuf {
111111 ( file_name, "" )
112112 } ;
113113
114+ // Strip ".vespertide" suffix if present (e.g., "user.vespertide" -> "user")
115+ let stem = stem. strip_suffix ( ".vespertide" ) . unwrap_or ( stem) ;
116+
114117 let sanitized = sanitize_filename ( stem) ;
115118 let ext = match orm {
116119 Orm :: SeaOrm => "rs" ,
@@ -145,8 +148,19 @@ fn load_models_recursive(base: &Path) -> Result<Vec<(TableDef, PathBuf)>> {
145148
146149fn ensure_mod_chain ( root : & Path , rel_path : & Path ) -> Result < ( ) > {
147150 // Only needed for SeaORM (Rust) exports to wire modules.
148- let mut comps: Vec < String > = rel_path
149- . with_extension ( "" )
151+ // Strip extension and ".vespertide" suffix from filename
152+ let path_without_ext = rel_path. with_extension ( "" ) ;
153+ let path_stripped = if let Some ( stem) = path_without_ext. file_stem ( ) . and_then ( |s| s. to_str ( ) ) {
154+ let stripped_stem = stem. strip_suffix ( ".vespertide" ) . unwrap_or ( stem) ;
155+ if let Some ( parent) = path_without_ext. parent ( ) {
156+ parent. join ( stripped_stem)
157+ } else {
158+ PathBuf :: from ( stripped_stem)
159+ }
160+ } else {
161+ path_without_ext
162+ } ;
163+ let mut comps: Vec < String > = path_stripped
150164 . components ( )
151165 . filter_map ( |c| {
152166 c. as_os_str ( )
@@ -504,4 +518,54 @@ mod tests {
504518 let out2 = build_output_path ( root, rel_path2, Orm :: SeaOrm ) ;
505519 assert ! ( out2. to_string_lossy( ) . contains( "items" ) ) ;
506520 }
521+
522+ #[ test]
523+ fn build_output_path_strips_vespertide_suffix ( ) {
524+ use std:: path:: Path ;
525+ let root = Path :: new ( "src/models" ) ;
526+
527+ // .vespertide.json -> .rs (strips ".vespertide" from stem)
528+ let rel_path = Path :: new ( "user.vespertide.json" ) ;
529+ let out = build_output_path ( root, rel_path, Orm :: SeaOrm ) ;
530+ assert_eq ! ( out, Path :: new( "src/models/user.rs" ) ) ;
531+
532+ // Nested path with .vespertide.json
533+ let rel_path2 = Path :: new ( "blog/post.vespertide.json" ) ;
534+ let out2 = build_output_path ( root, rel_path2, Orm :: SeaOrm ) ;
535+ assert_eq ! ( out2, Path :: new( "src/models/blog/post.rs" ) ) ;
536+
537+ // .vespertide.yaml -> .py
538+ let rel_path3 = Path :: new ( "order.vespertide.yaml" ) ;
539+ let out3 = build_output_path ( root, rel_path3, Orm :: SqlAlchemy ) ;
540+ assert_eq ! ( out3, Path :: new( "src/models/order.py" ) ) ;
541+
542+ // Regular .json without .vespertide suffix still works
543+ let rel_path4 = Path :: new ( "item.json" ) ;
544+ let out4 = build_output_path ( root, rel_path4, Orm :: SeaOrm ) ;
545+ assert_eq ! ( out4, Path :: new( "src/models/item.rs" ) ) ;
546+ }
547+
548+ #[ test]
549+ #[ serial]
550+ fn ensure_mod_chain_strips_vespertide_suffix ( ) {
551+ let tmp = tempdir ( ) . unwrap ( ) ;
552+ let root = tmp. path ( ) . join ( "src/models" ) ;
553+ fs:: create_dir_all ( & root) . unwrap ( ) ;
554+
555+ // File with .vespertide suffix should produce mod declaration without it
556+ ensure_mod_chain ( & root, Path :: new ( "user.vespertide.json" ) ) . unwrap ( ) ;
557+
558+ let root_mod = fs:: read_to_string ( root. join ( "mod.rs" ) ) . unwrap ( ) ;
559+ // Should be "pub mod user;" not "pub mod user_vespertide;"
560+ assert ! ( root_mod. contains( "pub mod user;" ) ) ;
561+ assert ! ( !root_mod. contains( "user_vespertide" ) ) ;
562+
563+ // Nested path with .vespertide suffix
564+ ensure_mod_chain ( & root, Path :: new ( "blog/post.vespertide.json" ) ) . unwrap ( ) ;
565+ let root_mod = fs:: read_to_string ( root. join ( "mod.rs" ) ) . unwrap ( ) ;
566+ let blog_mod = fs:: read_to_string ( root. join ( "blog/mod.rs" ) ) . unwrap ( ) ;
567+ assert ! ( root_mod. contains( "pub mod blog;" ) ) ;
568+ assert ! ( blog_mod. contains( "pub mod post;" ) ) ;
569+ assert ! ( !blog_mod. contains( "post_vespertide" ) ) ;
570+ }
507571}
0 commit comments