rpc_rs/router/
export.rs

1//! The [`specta`] export module.
2
3use 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    /// Export a function's TypeScript version with [`specta`].
15    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    /// Export the entire router's bindings.
43    /// Warning: This **does** consume the router!
44    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}