11use clap:: ValueEnum ;
22use sha2:: { Digest , Sha256 } ;
3- use std:: { fs, io:: Write , path:: Path } ;
3+ use std:: { fs, io:: Write , path:: { Path , PathBuf } } ;
44
55use handlebars:: handlebars_helper;
66use luna_api:: models:: { RepositoryData , asset:: Version } ;
@@ -87,13 +87,72 @@ fn build_engine() -> Result<HandlebarsTemplateEngine<'static>, DocsError> {
8787 engine. registry ( ) . register_helper ( "dec" , Box :: new ( dec) ) ;
8888 engine. registry ( ) . register_helper ( "sub" , Box :: new ( sub) ) ;
8989 engine. registry ( ) . register_helper ( "slug" , Box :: new ( slug) ) ;
90- engine
91- . registry ( )
92- . register_embed_templates :: < Templates > ( )
93- . map_err ( |e| DocsError :: Template ( Box :: new ( e) ) ) ?;
90+ register_embed_templates ( & mut engine) ?;
9491 Ok ( engine)
9592}
9693
94+ fn register_embed_templates ( engine : & mut HandlebarsTemplateEngine < ' static > ) -> Result < ( ) , DocsError > {
95+ for file in Templates :: iter ( ) {
96+ let path = file. as_ref ( ) ;
97+ let content = Templates :: get ( path) . unwrap ( ) ;
98+ let content = std:: str:: from_utf8 ( & content. data )
99+ . map_err ( |e| DocsError :: Template ( Box :: new ( e) ) ) ?;
100+ engine
101+ . registry ( )
102+ . register_template_string ( path, content)
103+ . map_err ( |e| DocsError :: Template ( Box :: new ( e) ) ) ?;
104+ }
105+
106+ Ok ( ( ) )
107+ }
108+
109+ fn register_custom_templates (
110+ engine : & mut HandlebarsTemplateEngine < ' static > ,
111+ custom_root : Option < & Path > ,
112+ ) -> Result < ( ) , DocsError > {
113+
114+ let Some ( custom_root) = custom_root else {
115+ return Ok ( ( ) ) ;
116+ } ;
117+ if !custom_root. exists ( ) {
118+ return Ok ( ( ) ) ;
119+ }
120+
121+ for file in collect_files ( custom_root) ? {
122+ if file. extension ( ) . and_then ( |e| e. to_str ( ) ) != Some ( "hbs" ) {
123+ continue ;
124+ }
125+ let rel_path = file
126+ . strip_prefix ( custom_root)
127+ . map_err ( std:: io:: Error :: other) ?;
128+ let template_name = rel_path. to_string_lossy ( ) . replace ( '\\' , "/" ) ;
129+ let content = fs:: read_to_string ( & file) ?;
130+ engine
131+ . registry ( )
132+ . register_template_string ( & template_name, content)
133+ . map_err ( |e| DocsError :: Template ( Box :: new ( e) ) ) ?;
134+ }
135+
136+ Ok ( ( ) )
137+ }
138+
139+ fn collect_files ( path : & Path ) -> Result < Vec < PathBuf > , DocsError > {
140+ let mut files = Vec :: new ( ) ;
141+ if !path. exists ( ) {
142+ return Ok ( files) ;
143+ }
144+ for entry in fs:: read_dir ( path) ? {
145+ let entry = entry?;
146+ let entry_path = entry. path ( ) ;
147+ if entry_path. is_dir ( ) {
148+ files. extend ( collect_files ( & entry_path) ?) ;
149+ } else {
150+ files. push ( entry_path) ;
151+ }
152+ }
153+ Ok ( files)
154+ }
155+
97156fn bundle_assets (
98157 data : & mut RepositoryData ,
99158 output : & Path ,
@@ -252,6 +311,7 @@ pub fn generate_docs(
252311 output : String ,
253312 page_size : usize ,
254313 bundle : BundleStrategy ,
314+ custom_root : Option < String > ,
255315) -> Result < ( ) , DocsError > {
256316 let output_path = Path :: new ( & output) ;
257317 if !output_path. exists ( ) {
@@ -267,7 +327,9 @@ pub fn generate_docs(
267327 let _ = page_size;
268328 let mut router = LunaRouter :: new ( ) ;
269329 let root = "/" . to_string ( ) ;
270- let engine = build_engine ( ) ?;
330+ let custom_root = custom_root. map ( PathBuf :: from) ;
331+ let mut engine = build_engine ( ) ?;
332+ register_custom_templates ( & mut engine, custom_root. as_deref ( ) ) ?;
271333
272334 let add_route = |router : & mut LunaRouter ,
273335 path : & str ,
@@ -459,13 +521,13 @@ pub fn generate_docs(
459521 }
460522 }
461523
462- copy_public ( & output) ?;
524+ copy_public ( & output, custom_root . as_deref ( ) ) ?;
463525 router. generate ( & output) ?;
464526
465527 Ok ( ( ) )
466528}
467529
468- fn copy_public ( output : & str ) -> Result < ( ) , DocsError > {
530+ fn copy_public ( output : & str , custom_root : Option < & Path > ) -> Result < ( ) , DocsError > {
469531 for file in Public :: iter ( ) {
470532 let path = file. as_ref ( ) ;
471533 let content = Public :: get ( path) . unwrap ( ) ;
@@ -477,5 +539,20 @@ fn copy_public(output: &str) -> Result<(), DocsError> {
477539 let mut file = fs:: File :: create ( path) ?;
478540 file. write_all ( & content. data ) ?;
479541 }
542+
543+ if let Some ( custom_root) = custom_root {
544+ let public_root = custom_root. join ( "public" ) ;
545+ for file in collect_files ( & public_root) ? {
546+ let rel = file
547+ . strip_prefix ( & public_root)
548+ . map_err ( std:: io:: Error :: other) ?;
549+ let target = Path :: new ( output) . join ( rel) ;
550+ if let Some ( parent) = target. parent ( ) {
551+ fs:: create_dir_all ( parent) ?;
552+ }
553+ fs:: copy ( file, target) ?;
554+ }
555+ }
556+
480557 Ok ( ( ) )
481558}
0 commit comments