modrpc_codegen/codegen/js/
mod.rs

1use genco::prelude::*;
2use mproto_codegen::codegen::{js::js_type_param_list, name_util::snake_to_camel_case};
3
4use crate::{Database, ast::Interface};
5
6pub use project::{js_project_gen, js_proto_package_gen};
7
8pub mod project;
9
10pub fn js_wit_object_class(
11    db: &Database,
12    object_interface: &Interface,
13    object_role_name: &String,
14) -> js::Tokens {
15    let mproto_cx = &mproto_codegen::codegen::CodegenCx::new_with_type_params(
16        db.mproto_db(),
17        Some("./proto"),
18        true,
19        &object_interface.type_params,
20    );
21
22    let mut method_fields: js::Tokens = quote! {};
23    let mut method_args: js::Tokens = quote! {};
24    let mut method_set_fields: js::Tokens = quote! {};
25    let mut methods: js::Tokens = quote! {};
26
27    for methods_list in &object_interface.methods {
28        if !methods_list.roles.contains(object_role_name) {
29            continue;
30        }
31
32        for method in &methods_list.methods {
33            let input_type =
34                mproto_codegen::codegen::js::js_type_tokens(mproto_cx, &method.input_ty);
35            let output_type =
36                mproto_codegen::codegen::js::js_type_tokens(mproto_cx, &method.output_ty);
37
38            let input_encoder =
39                mproto_codegen::codegen::js::js_type_encoder(mproto_cx, &method.input_ty);
40            let output_encoder =
41                mproto_codegen::codegen::js::js_type_encoder(mproto_cx, &method.output_ty);
42
43            let method_name_camel = &snake_to_camel_case(&method.name);
44
45            if method.is_async {
46                method_fields = quote! {
47                    $method_fields
48                    private $(method_name_camel)Wasm: (input: Uint8Array) => any;
49                    private $(method_name_camel)Resolvers: { [id: number] : (r: any) => void };
50                };
51
52                method_args = quote! {
53                    $method_args
54                    $(method_name_camel)Wasm: (input: Uint8Array) => any,
55                    $(method_name_camel)Resolvers: { [id: number] : (r: any) => void },
56                };
57
58                method_set_fields = quote! {
59                    $method_set_fields
60                    this.$(method_name_camel)Wasm = $(method_name_camel)Wasm;
61                    this.$(method_name_camel)Resolvers = $(method_name_camel)Resolvers;
62                };
63
64                methods = quote! {
65                    $methods
66
67                    public async $method_name_camel(input: $input_type): Promise<$output_type> {
68                      const inputBuf = new Uint8Array(mproto.encodeValue($input_encoder, input));
69
70                      const id = this.$(method_name_camel)Wasm(inputBuf);
71                      const promise: Promise<any> = new Promise(resolve => {
72                        this.$(method_name_camel)Resolvers[id] = resolve;
73                      });
74
75                      const outputBuf = await promise;
76                      return mproto.decodeValue($output_encoder, outputBuf.buffer);
77                    }
78                };
79            }
80        }
81    }
82
83    let mut type_param_encoder_fields: js::Tokens = quote! {};
84    let mut type_param_encoder_args: js::Tokens = quote! {};
85    let mut type_param_encoder_set_fields: js::Tokens = quote! {};
86
87    for type_param in &object_interface.type_params {
88        let type_param_name = type_param;
89        type_param_encoder_fields = quote! {
90            $type_param_encoder_fields
91            private $(type_param_name)Encoder: mproto.EncoderDecoder<$(type_param_name)>;
92        };
93        type_param_encoder_args = quote! {
94            $type_param_encoder_args
95            $(type_param_name)Encoder: mproto.EncoderDecoder<$(type_param_name)>,
96        };
97        type_param_encoder_set_fields = quote! {
98            $type_param_encoder_set_fields
99            this.$(type_param_name)Encoder = $(type_param_name)Encoder;
100        };
101    }
102
103    let object_interface_role_name = &format!("{}{}", object_interface.name, object_role_name);
104    let type_params_list = js_type_param_list(&object_interface.type_params);
105
106    quote! {
107        class $object_interface_role_name$(type_params_list) {
108          $type_param_encoder_fields
109          $method_fields
110
111          constructor(
112            $type_param_encoder_args
113            $method_args
114          ) {
115            $type_param_encoder_set_fields
116            $method_set_fields
117          }
118
119          $methods
120        }
121    }
122}
123
124pub fn js_interface_init_state_tokens(db: &mut Database, interface: &Interface) -> js::Tokens {
125    let init_state_struct = crate::codegen::interface_init_state(db, interface);
126    let init_state_struct_id = db
127        .mproto_db_mut()
128        .local_mut()
129        .new_type_def(init_state_struct);
130
131    quote! {
132        $(mproto_codegen::codegen::js::js_type_def(
133            &mproto_codegen::codegen::CodegenCx::new(db.mproto_db(), None, true),
134            db.mproto_db().local().type_def(init_state_struct_id)
135        ))
136    }
137}