dodo_bindgen_codegen/
file.rs1use std::path::PathBuf;
2
3use crate::util::*;
4use crate::{ClassDefs, FfiLib, FunctionDefs, RustTypeDefs, TsFormat, UserDefinedDefs};
5use dodo_bindgen_rust_ir::{File, Item, ItemMod};
6
7use super::class::ItemImplExt as _;
8use super::fn_::ItemFnExt as _;
9
10#[derive(Clone, Debug)]
13pub struct CodegenOpts {
14 pub file_name: String,
15 pub dylib_path: String,
16 pub lazy: bool,
17 pub extended: bool,
23 pub embedded: Option<PathBuf>,
27}
28
29#[derive(Clone, Debug, Default)]
30pub struct TsModule {
31 pub ffi_lib: FfiLib, pub type_defs: RustTypeDefs, pub user_defs: UserDefinedDefs,
35 pub functions: FunctionDefs,
36 pub class_defs: ClassDefs,
37}
38
39impl TsModule {
42 pub fn new(file: File, opts: &CodegenOpts) -> Self {
43 let mut module = TsModule::default();
44 module.ffi_lib.dylib_path = opts.dylib_path.clone();
45 module.ffi_lib.lazy = opts.lazy;
46
47 module.unwrap(file.items);
48 module.user_defs.dedup(&module.class_defs);
49 module
50 }
51
52 fn unwrap(&mut self, items: Vec<Item>) {
55 for item in items {
56 match item {
57 Item::Fn(item_fn) => {
58 let method = item_fn.unwrap(self);
59 self.functions.push(method);
60 },
61 Item::Impl(item_impl) => {
62 item_impl.unwrap(self);
63 },
64 Item::Mod(ItemMod { items, .. }) => {
65 self.unwrap(items);
66 },
67 _ => (),
68 }
69 }
70 }
71
72 pub fn generate_single(self, opts: &CodegenOpts) -> String {
74 let TsModule {
75 mut ffi_lib,
76 mut type_defs,
77 user_defs,
78 functions,
79 class_defs,
80 } = self;
81
82 type_defs.extended = opts.extended;
83 let (type_defs, mut ffi_symbols) = type_defs.print_inline();
84 ffi_lib.interface.append(&mut ffi_symbols);
85
86 let ffi_lib = ffi_lib.to_token_stream().to_string();
87 let user_defs = user_defs.to_token_stream().to_string();
88 let functions = functions.to_token_stream().to_string();
89 let class_defs = class_defs.to_token_stream().to_string();
90
91 TsFormat::format(format!(
92 "// deno-lint-ignore-file\n
93 {ffi_lib}
94 {type_defs}
95 {user_defs}
96 {class_defs}
97 {functions}
98 "
99 ))
100 }
101
102 pub fn generate_multiple(
105 mut self,
106 opts: &CodegenOpts,
107 type_defs_name: &str,
108 ) -> (String, String) {
109 let TsModule {
110 mut ffi_lib,
111 user_defs,
112 functions,
113 class_defs,
114 ..
115 } = self;
116
117 self.type_defs.extended = opts.extended;
118
119 let (raw_type_defs, mut ffi_symbols) = self.type_defs.print_inline();
120 let mut type_defs_builder = String::from(format!("// deno-lint-ignore-file\n"));
121
122 if opts.extended {
124 if let Some(embedded) = &opts.embedded {
126 let mut embedded_ffi_lib = FfiLib::default();
127
128 embedded_ffi_lib.dylib_path = embedded
129 .to_str()
130 .expect("unknown utf8 character on embedded dylib path")
131 .to_string();
132 embedded_ffi_lib.interface.append(&mut ffi_symbols);
133
134 let embedded_ffi_lib =
135 TsFormat::format(embedded_ffi_lib.to_token_stream().to_string());
136
137 type_defs_builder.push_str(&embedded_ffi_lib);
139
140 } else {
142 ffi_lib.interface.append(&mut ffi_symbols);
143 ffi_lib.export = true;
144
145 let file_name = format!("./{}", opts.file_name);
146
147 type_defs_builder.push_str(&TsFormat::format(
148 quote! {
149 import { symbols } from #file_name;
150 }
151 .to_string(),
152 ));
153 }
154 }
155
156 type_defs_builder.push_str(&raw_type_defs);
157
158 let (type_defs, imports) = self
159 .type_defs
160 .print_separate(type_defs_builder, type_defs_name);
161
162 let ffi_lib = ffi_lib.to_token_stream().to_string();
163 let user_defs = user_defs.to_token_stream().to_string();
164 let functions = functions.to_token_stream().to_string();
165 let class_defs = class_defs.to_token_stream().to_string();
166
167 let module = TsFormat::format(format!(
168 "
169 {imports}
170 {ffi_lib}
171 {user_defs}
172 {class_defs}
173 {functions}
174 "
175 ));
176
177 (module, type_defs)
178 }
179}