modrpc_codegen/codegen/js/
project.rs1use std::path::Path;
2use std::fs;
3use std::io::Write;
4
5use genco::{self, prelude::*};
6
7use crate::{
8 ast::Schema,
9 codegen,
10 Database,
11};
12
13const PROTO_PACKAGE_JSON: &'static str = include_str!("templates/proto/package.json");
14const PROTO_TSCONFIG_JSON: &'static str = include_str!("templates/proto/tsconfig.json");
15const PROTO_INDEX_TS: &'static str = include_str!("templates/proto/index.ts");
16
17pub fn js_project_gen(
18 root_dir: impl AsRef<Path>,
19 project_name: &str,
20 schema: &Schema,
21) -> std::io::Result<()> {
22 let pkg_name = &format!("{}-modrpc", project_name);
23 let pkg_root = root_dir.as_ref().join(pkg_name).join("typescript");
24
25 fs::create_dir_all(&pkg_root)?;
26
27 js_proto_package_gen(&pkg_root, &format!("{}-modrpc", project_name), schema)?;
28
29 Ok(())
30}
31
32pub fn js_proto_package_gen(
33 pkg_root: impl AsRef<Path>,
34 pkg_name: &str,
35 schema: &Schema,
36) -> std::io::Result<()> {
37 let pkg_root = pkg_root.as_ref();
38
39 let local_mproto_module = mproto_codegen::Module::from_type_defs(
40 schema.type_defs.clone(),
41 );
42 let mproto_db = mproto_codegen::Database::new(local_mproto_module);
43
44 let mut db = Database::new(mproto_db);
45 codegen::load_imports_recursive(&mut db, schema).unwrap();
46 for interface in &schema.interfaces {
47 let _ = db.local().add_interface(interface.clone());
48
49 codegen::define_interface_config_and_state_structs(
51 &mut db,
52 interface,
53 );
54 }
55
56 let src_dir = pkg_root.join("src");
57
58 fs::create_dir_all(&pkg_root)?;
59 fs::create_dir_all(&src_dir)?;
60
61 let package_json_path = pkg_root.join("package.json");
63 if !package_json_path.exists() {
64 fs::write(
65 package_json_path,
66 PROTO_PACKAGE_JSON.replace("PKG_NAME", pkg_name).as_bytes(),
67 )?;
68 } else {
69 println!(
70 "{} already exists - skipping as it might contain hand-written code.",
71 package_json_path.display(),
72 );
73 }
74
75 fs::write(pkg_root.join("tsconfig.json"), PROTO_TSCONFIG_JSON.as_bytes())?;
77
78 fs::write(src_dir.join("index.ts"), PROTO_INDEX_TS.as_bytes())?;
80
81 let mut proto_tokens = genco::lang::js::Tokens::new();
83 for type_def in db.mproto_db().local().type_defs() {
91 let mproto_cx = &mproto_codegen::codegen::CodegenCx::new(db.mproto_db(), None, true);
92 proto_tokens = quote! {
93 $proto_tokens
94
95 $(mproto_codegen::codegen::js::js_type_def(mproto_cx, type_def))
96 };
97 }
98 write_js_file(
99 src_dir.join("proto.ts"),
100 "",
101 &proto_tokens
102 )?;
103
104 let mut object_class_tokens = quote! {
106 import * as mproto from "mproto";
107 };
108 for interface in &schema.interfaces {
109 if interface.methods.len() == 0 { continue; }
110
111 for role_name in &interface.roles {
112 object_class_tokens = quote! {
113 $object_class_tokens
114
115 $(codegen::js::js_wit_object_class(&db, interface, role_name))
116 };
117 }
118 }
119 write_js_file(
120 src_dir.join("objects.ts"),
121 "",
122 &object_class_tokens
123 )?;
124
125 Ok(())
126}
127
128fn write_js_file(
129 path: impl AsRef<Path> + std::fmt::Debug,
130 header: &str,
131 tokens: &genco::lang::js::Tokens,
132) -> std::io::Result<()> {
133 let fmt = genco::fmt::Config::from_lang::<genco::lang::JavaScript>()
134 .with_indentation(genco::fmt::Indentation::Space(2));
135 let config = genco::lang::js::Config::default();
136 let mut file = fs::File::create(&path)?;
137
138 file.write_all(header.as_bytes())?;
139
140 let mut w = genco::fmt::IoWriter::new(file);
141 tokens
142 .format_file(&mut w.as_formatter(&fmt), &config)
143 .expect(&format!("format {:?} file", path));
144
145 Ok(())
146}