modrpc-codegen 0.0.4

Parse modrpc schemas and generate code from them
Documentation
use genco::prelude::*;
use mproto_codegen::codegen::{
    name_util::snake_to_camel_case,
    js::js_type_param_list,
};

use crate::{
    ast::Interface,
    Database,
};

pub use project::{js_project_gen, js_proto_package_gen};

pub mod project;

pub fn js_wit_object_class(
    db: &Database,
    object_interface: &Interface,
    object_role_name: &String,
) -> js::Tokens {
    let mproto_cx = &mproto_codegen::codegen::CodegenCx::new_with_type_params(
        db.mproto_db(), Some("./proto"), true, &object_interface.type_params,
    );

    let mut method_fields: js::Tokens = quote! { };
    let mut method_args: js::Tokens = quote! { };
    let mut method_set_fields: js::Tokens = quote! { };
    let mut methods: js::Tokens = quote! { };

    for methods_list in &object_interface.methods {
        if !methods_list.roles.contains(object_role_name) { continue; }

        for method in &methods_list.methods {
            let input_type =
                mproto_codegen::codegen::js::js_type_tokens(mproto_cx, &method.input_ty);
            let output_type =
                mproto_codegen::codegen::js::js_type_tokens(mproto_cx, &method.output_ty);

            let input_encoder =
                mproto_codegen::codegen::js::js_type_encoder(mproto_cx, &method.input_ty);
            let output_encoder =
                mproto_codegen::codegen::js::js_type_encoder(mproto_cx, &method.output_ty);

            let method_name_camel = &snake_to_camel_case(&method.name);

            if method.is_async {
                method_fields = quote! {
                    $method_fields
                    private $(method_name_camel)Wasm: (input: Uint8Array) => any;
                    private $(method_name_camel)Resolvers: { [id: number] : (r: any) => void };
                };

                method_args = quote! {
                    $method_args
                    $(method_name_camel)Wasm: (input: Uint8Array) => any,
                    $(method_name_camel)Resolvers: { [id: number] : (r: any) => void },
                };

                method_set_fields = quote! {
                    $method_set_fields
                    this.$(method_name_camel)Wasm = $(method_name_camel)Wasm;
                    this.$(method_name_camel)Resolvers = $(method_name_camel)Resolvers;
                };

                methods = quote! {
                    $methods

                    public async $method_name_camel(input: $input_type): Promise<$output_type> {
                      const inputBuf = new Uint8Array(mproto.encodeValue($input_encoder, input));

                      const id = this.$(method_name_camel)Wasm(inputBuf);
                      const promise: Promise<any> = new Promise(resolve => {
                        this.$(method_name_camel)Resolvers[id] = resolve;
                      });

                      const outputBuf = await promise;
                      return mproto.decodeValue($output_encoder, outputBuf.buffer);
                    }
                };
            }
        }
    }

    let mut type_param_encoder_fields: js::Tokens = quote! { };
    let mut type_param_encoder_args: js::Tokens = quote! { };
    let mut type_param_encoder_set_fields: js::Tokens = quote! { };

    for type_param in &object_interface.type_params {
        let type_param_name = type_param;
        type_param_encoder_fields = quote! {
            $type_param_encoder_fields
            private $(type_param_name)Encoder: mproto.EncoderDecoder<$(type_param_name)>;
        };
        type_param_encoder_args = quote! {
            $type_param_encoder_args
            $(type_param_name)Encoder: mproto.EncoderDecoder<$(type_param_name)>,
        };
        type_param_encoder_set_fields  = quote! {
            $type_param_encoder_set_fields
            this.$(type_param_name)Encoder = $(type_param_name)Encoder;
        };
    }

    let object_interface_role_name = &format!("{}{}", object_interface.name, object_role_name);
    let type_params_list = js_type_param_list(
        &object_interface.type_params,
    );

    quote! {
        class $object_interface_role_name$(type_params_list) {
          $type_param_encoder_fields
          $method_fields

          constructor(
            $type_param_encoder_args
            $method_args
          ) {
            $type_param_encoder_set_fields
            $method_set_fields
          }

          $methods
        }
    }
}

pub fn js_interface_init_state_tokens(
    db: &mut Database,
    interface: &Interface,
) -> js::Tokens {
    let init_state_struct = crate::codegen::interface_init_state(db, interface);
    let init_state_struct_id = db.mproto_db_mut().local_mut().new_type_def(init_state_struct);

    quote! {
        $(mproto_codegen::codegen::js::js_type_def(
            &mproto_codegen::codegen::CodegenCx::new(db.mproto_db(), None, true),
            db.mproto_db().local().type_def(init_state_struct_id)
        ))
    }
}