use std::path::PathBuf;
use crate::deno::util::*;
use crate::deno::{ClassDefs, FfiLib, FunctionDefs, RustTypeDefs, TsFormat, UserDefinedDefs};
use crate::rust::{File, Item, ItemMod};
#[derive(Clone, Debug)]
pub struct CodegenOpts {
pub file_name: String,
pub dylib_path: String,
pub lazy: bool,
pub extended: bool,
pub embedded: Option<PathBuf>,
}
#[derive(Clone, Debug, Default)]
pub struct TsModule {
pub ffi_lib: FfiLib, pub type_defs: RustTypeDefs,
pub user_defs: UserDefinedDefs,
pub functions: FunctionDefs,
pub class_defs: ClassDefs,
}
impl TsModule {
pub fn new(file: File, opts: &CodegenOpts) -> Self {
let mut module = TsModule::default();
module.ffi_lib.dylib_path = opts.dylib_path.clone();
module.ffi_lib.lazy = opts.lazy;
module.unwrap(file.items);
module.user_defs.dedup(&module.class_defs);
module
}
fn unwrap(&mut self, items: Vec<Item>) {
for item in items {
match item {
Item::Fn(item_fn) => {
let method = item_fn.unwrap(self);
self.functions.push(method);
},
Item::Impl(item_impl) => {
item_impl.unwrap(self);
},
Item::Mod(ItemMod { items, .. }) => {
self.unwrap(items);
},
_ => (),
}
}
}
pub fn generate_single(self, opts: &CodegenOpts) -> String {
let TsModule {
mut ffi_lib,
mut type_defs,
user_defs,
functions,
class_defs,
} = self;
type_defs.extended = opts.extended;
let (type_defs, mut ffi_symbols) = type_defs.print_inline();
ffi_lib.interface.append(&mut ffi_symbols);
let ffi_lib = ffi_lib.to_token_stream().to_string();
let user_defs = user_defs.to_token_stream().to_string();
let functions = functions.to_token_stream().to_string();
let class_defs = class_defs.to_token_stream().to_string();
TsFormat::format(format!(
"// deno-lint-ignore-file\n
{ffi_lib}
{type_defs}
{user_defs}
{class_defs}
{functions}
"
))
}
pub fn generate_multiple(
mut self,
opts: &CodegenOpts,
type_defs_name: &str,
) -> (String, String) {
let TsModule {
mut ffi_lib,
user_defs,
functions,
class_defs,
..
} = self;
self.type_defs.extended = opts.extended;
let (raw_type_defs, mut ffi_symbols) = self.type_defs.print_inline();
let mut type_defs_builder = String::from(format!("// deno-lint-ignore-file\n"));
if opts.extended {
if let Some(embedded) = &opts.embedded {
let mut embedded_ffi_lib = FfiLib::default();
embedded_ffi_lib.dylib_path = embedded
.to_str()
.expect("unknown utf8 character on embedded dylib path")
.to_string();
embedded_ffi_lib.interface.append(&mut ffi_symbols);
let embedded_ffi_lib =
TsFormat::format(embedded_ffi_lib.to_token_stream().to_string());
type_defs_builder.push_str(&embedded_ffi_lib);
} else {
ffi_lib.interface.append(&mut ffi_symbols);
ffi_lib.export = true;
let file_name = format!("./{}", opts.file_name);
type_defs_builder.push_str(&TsFormat::format(
quote! {
import { symbols } from #file_name;
}
.to_string(),
));
}
}
type_defs_builder.push_str(&raw_type_defs);
let (type_defs, imports) = self
.type_defs
.print_separate(type_defs_builder, type_defs_name);
let ffi_lib = ffi_lib.to_token_stream().to_string();
let user_defs = user_defs.to_token_stream().to_string();
let functions = functions.to_token_stream().to_string();
let class_defs = class_defs.to_token_stream().to_string();
let module = TsFormat::format(format!(
"
{imports}
{ffi_lib}
{user_defs}
{class_defs}
{functions}
"
));
(module, type_defs)
}
}