1use std::{collections::HashMap, fs, path::PathBuf, sync::Arc};
4
5use specta::ts::{export_named_datatype, Result};
6
7use super::{func::export_function_header, router::Router, Method};
8use crate::{proc::GenericProcedure, util::TripleS};
9
10pub(crate) const MODULE_STUB: &str = include_str!("./module_stub.ts");
11pub(crate) const CORE: &str = include_str!("./core.ts");
12
13impl<Cx: TripleS + Clone> Router<Cx> {
14 pub(crate) fn export_func(
16 &mut self,
17 script: &mut Vec<String>,
18 route_prefix: &String,
19 func_name: &String,
20 module_name: &String,
21 method: Method,
22 func: Arc<Box<dyn GenericProcedure<Cx> + TripleS>>,
23 ) -> Result<()> {
24 let func_ty = func.specta_type(func_name.clone().into(), &mut self.type_map);
25 let arg = func_ty.args.first().unwrap().0.clone();
26 let data = export_function_header(func_ty, &self.export_cfg)?;
27
28 let data = format!(
29 "{} {{\nreturn await __rpc_call(\"{}\", \"{}\", \"{}\", {});\n}}",
30 data,
31 route_prefix,
32 method.as_str(),
33 module_name,
34 arg
35 );
36
37 script.push(data);
38
39 Ok(())
40 }
41
42 pub fn export(mut self, route_prefix: impl AsRef<str>, path: impl Into<PathBuf>) -> Result<()> {
45 let path = path.into();
46 let route_prefix = route_prefix.as_ref().to_string();
47 let mut code = Vec::new();
48 let mut group_code = Vec::new();
49
50 code.push(CORE.into());
51
52 for (name, module) in self.modules.clone() {
53 let funcs: HashMap<Method, Arc<Box<dyn GenericProcedure<Cx> + TripleS>>> =
54 HashMap::from_iter([
55 (Method::Create, module.create),
56 (Method::Read, module.read),
57 (Method::Update, module.update),
58 (Method::Delete, module.delete),
59 ]);
60
61 for (method, func) in funcs {
62 let new_name = format!("__rpc_call_{}_{}", &name, method.as_str());
63
64 self.export_func(&mut code, &route_prefix, &new_name, &name, method, func)?;
65 }
66
67 let group = MODULE_STUB.replace("$name$", &name);
68
69 code.push(group);
70 group_code.push(format!("{}: __rpc_module_{},", &name, name));
71 }
72
73 for (_, ty) in self.type_map.clone().iter() {
74 code.push(export_named_datatype(
75 &self.export_cfg,
76 ty,
77 &mut self.type_map,
78 )?);
79 }
80
81 code.push(format!(
82 "export const RPC = {{\n{}\n}};\n\nexport default RPC;",
83 group_code.join("\n")
84 ));
85
86 let code = code.join("\n\n");
87
88 fs::write(path, code)?;
89
90 Ok(())
91 }
92}