Skip to main content

modrpc_codegen/codegen/js/
mod.rs

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