@@ -4,7 +4,7 @@ use std::fs;
44use std:: path:: { Path , PathBuf } ;
55
66pub fn generate_package_json ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
7- let project_root = get_project_root ( output_dir) ;
7+ let project_root = get_project_root ( output_dir) ? ;
88 let project_name = extract_project_name ( & project_root) ;
99
1010 let content = format ! (
@@ -45,7 +45,7 @@ pub fn generate_package_json(_schema: &Schema, output_dir: &Path) -> Result<()>
4545}
4646
4747pub fn generate_tsconfig_json ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
48- let project_root = get_project_root ( output_dir) ;
48+ let project_root = get_project_root ( output_dir) ? ;
4949 let content = r#"{
5050 "compilerOptions": {
5151 "target": "ES2022",
@@ -88,7 +88,7 @@ pub fn generate_tsconfig_json(_schema: &Schema, output_dir: &Path) -> Result<()>
8888}
8989
9090pub fn generate_requirements_txt ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
91- let project_root = get_project_root ( output_dir) ;
91+ let project_root = get_project_root ( output_dir) ? ;
9292 let content = r#"# Python dependencies for Rohas project
9393# Add your project-specific dependencies here
9494
@@ -102,7 +102,7 @@ typing-extensions>=4.0.0
102102}
103103
104104pub fn generate_pyproject_toml ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
105- let project_root = get_project_root ( output_dir) ;
105+ let project_root = get_project_root ( output_dir) ? ;
106106 let project_name = extract_project_name ( & project_root) ;
107107
108108 let content = format ! (
@@ -146,7 +146,7 @@ target-version = "py39"
146146}
147147
148148pub fn generate_cargo_toml ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
149- let project_root = get_project_root ( output_dir) ;
149+ let project_root = get_project_root ( output_dir) ? ;
150150 let project_name = extract_project_name ( & project_root) ;
151151
152152 let lib_name = project_name. replace ( '-' , "_" ) ;
@@ -183,7 +183,28 @@ tokio-test = "0.4"
183183}
184184
185185pub fn generate_gitignore ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
186- let project_root = get_project_root ( output_dir) ;
186+ let project_root = get_project_root ( output_dir)
187+ . map_err ( |e| crate :: error:: CodegenError :: GenerationFailed ( format ! (
188+ "Failed to get project root from output_dir {}: {}" ,
189+ output_dir. display( ) ,
190+ e
191+ ) ) ) ?;
192+
193+ let gitignore_path = project_root. join ( ".gitignore" ) ;
194+
195+ if let Some ( parent) = gitignore_path. parent ( ) {
196+ fs:: create_dir_all ( parent) . map_err ( |e| {
197+ crate :: error:: CodegenError :: Io ( std:: io:: Error :: new (
198+ e. kind ( ) ,
199+ format ! (
200+ "Failed to create parent directory {} for .gitignore: {}" ,
201+ parent. display( ) ,
202+ e
203+ )
204+ ) )
205+ } ) ?;
206+ }
207+
187208 let content = r#"# Dependencies
188209node_modules/
189210__pycache__/
@@ -238,12 +259,22 @@ coverage/
238259src/generated/
239260"# ;
240261
241- fs:: write ( project_root. join ( ".gitignore" ) , content) ?;
262+ fs:: write ( & gitignore_path, content)
263+ . map_err ( |e| crate :: error:: CodegenError :: Io ( std:: io:: Error :: new (
264+ e. kind ( ) ,
265+ format ! ( "Failed to write .gitignore to {}: {}" , gitignore_path. display( ) , e)
266+ ) ) ) ?;
242267 Ok ( ( ) )
243268}
244269
245270pub fn generate_editorconfig ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
246- let project_root = get_project_root ( output_dir) ;
271+ let project_root = get_project_root ( output_dir) ?;
272+ let editorconfig_path = project_root. join ( ".editorconfig" ) ;
273+
274+ if let Some ( parent) = editorconfig_path. parent ( ) {
275+ fs:: create_dir_all ( parent) ?;
276+ }
277+
247278 let content = r#"# EditorConfig is awesome: https://EditorConfig.org
248279
249280root = true
@@ -270,12 +301,21 @@ indent_size = 2
270301trim_trailing_whitespace = false
271302"# ;
272303
273- fs:: write ( project_root. join ( ".editorconfig" ) , content) ?;
304+ fs:: write ( & editorconfig_path, content)
305+ . map_err ( |e| crate :: error:: CodegenError :: Io ( std:: io:: Error :: new (
306+ e. kind ( ) ,
307+ format ! ( "Failed to write .editorconfig to {}: {}" , editorconfig_path. display( ) , e)
308+ ) ) ) ?;
274309 Ok ( ( ) )
275310}
276311
277312pub fn generate_readme ( schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
278- let project_root = get_project_root ( output_dir) ;
313+ let project_root = get_project_root ( output_dir)
314+ . map_err ( |e| crate :: error:: CodegenError :: GenerationFailed ( format ! (
315+ "Failed to get project root from output_dir {} in generate_readme: {}" ,
316+ output_dir. display( ) ,
317+ e
318+ ) ) ) ?;
279319 let project_name = extract_project_name ( & project_root) ;
280320 let has_apis = !schema. apis . is_empty ( ) ;
281321 let has_events = !schema. events . is_empty ( ) ;
@@ -400,22 +440,31 @@ MIT
400440 ) ;
401441
402442 let readme_path = project_root. join ( "README.md" ) ;
443+
444+ if let Some ( parent) = readme_path. parent ( ) {
445+ fs:: create_dir_all ( parent) ?;
446+ }
447+
403448 if !readme_path. exists ( ) {
404- fs:: write ( readme_path, content) ?;
449+ fs:: write ( & readme_path, content)
450+ . map_err ( |e| crate :: error:: CodegenError :: Io ( std:: io:: Error :: new (
451+ e. kind ( ) ,
452+ format ! ( "Failed to write README.md to {}: {}" , readme_path. display( ) , e)
453+ ) ) ) ?;
405454 }
406455
407456 Ok ( ( ) )
408457}
409458
410459pub fn generate_nvmrc ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
411- let project_root = get_project_root ( output_dir) ;
460+ let project_root = get_project_root ( output_dir) ? ;
412461 let content = "18.0.0\n " ;
413462 fs:: write ( project_root. join ( ".nvmrc" ) , content) ?;
414463 Ok ( ( ) )
415464}
416465
417466pub fn generate_prettierrc ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
418- let project_root = get_project_root ( output_dir) ;
467+ let project_root = get_project_root ( output_dir) ? ;
419468 let content = r#"{
420469 "semi": true,
421470 "trailingComma": "es5",
@@ -432,7 +481,7 @@ pub fn generate_prettierrc(_schema: &Schema, output_dir: &Path) -> Result<()> {
432481}
433482
434483pub fn generate_prettierignore ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
435- let project_root = get_project_root ( output_dir) ;
484+ let project_root = get_project_root ( output_dir) ? ;
436485 let content = r#"node_modules/
437486dist/
438487build/
@@ -447,7 +496,7 @@ src/generated/
447496}
448497
449498pub fn generate_rspack_config ( _schema : & Schema , output_dir : & Path ) -> Result < ( ) > {
450- let project_root = get_project_root ( output_dir) ;
499+ let project_root = get_project_root ( output_dir) ? ;
451500 let content = r#"const path = require('path');
452501const fs = require('fs');
453502
@@ -548,12 +597,63 @@ module.exports = {
548597 Ok ( ( ) )
549598}
550599
551- fn get_project_root ( output_dir : & Path ) -> PathBuf {
552- if output_dir. file_name ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "src" ) {
553- output_dir. parent ( ) . unwrap_or ( output_dir) . to_path_buf ( )
600+ fn get_project_root ( output_dir : & Path ) -> Result < PathBuf > {
601+ let project_root = if output_dir. file_name ( ) . and_then ( |s| s. to_str ( ) ) == Some ( "src" ) {
602+ match output_dir. parent ( ) {
603+ Some ( parent) => {
604+ let parent_path = parent. to_path_buf ( ) ;
605+ if parent_path. as_os_str ( ) . is_empty ( ) || parent_path == Path :: new ( "/" ) {
606+ output_dir. to_path_buf ( )
607+ } else {
608+ parent_path
609+ }
610+ }
611+ None => {
612+ return Err ( crate :: error:: CodegenError :: GenerationFailed ( format ! (
613+ "Cannot determine project root from output_dir: {}" ,
614+ output_dir. display( )
615+ ) ) ) ;
616+ }
617+ }
554618 } else {
555619 output_dir. to_path_buf ( )
620+ } ;
621+ match fs:: metadata ( & project_root) {
622+ Ok ( metadata) => {
623+ if !metadata. is_dir ( ) {
624+ return Err ( crate :: error:: CodegenError :: GenerationFailed ( format ! (
625+ "Project root path exists but is not a directory: {}" ,
626+ project_root. display( )
627+ ) ) ) ;
628+ }
629+ }
630+ Err ( e) if e. kind ( ) == std:: io:: ErrorKind :: NotFound => {
631+ fs:: create_dir_all ( & project_root) . map_err ( |e| {
632+ crate :: error:: CodegenError :: Io ( std:: io:: Error :: new (
633+ e. kind ( ) ,
634+ format ! (
635+ "Failed to create project root directory {} (from output_dir {}): {}" ,
636+ project_root. display( ) ,
637+ output_dir. display( ) ,
638+ e
639+ )
640+ ) )
641+ } ) ?;
642+ }
643+ Err ( e) => {
644+ return Err ( crate :: error:: CodegenError :: Io ( std:: io:: Error :: new (
645+ e. kind ( ) ,
646+ format ! (
647+ "Failed to check project root directory {} (from output_dir {}): {}" ,
648+ project_root. display( ) ,
649+ output_dir. display( ) ,
650+ e
651+ )
652+ ) ) ) ;
653+ }
556654 }
655+
656+ Ok ( project_root)
557657}
558658
559659fn extract_project_name ( project_root : & Path ) -> String {
0 commit comments