mod core;
mod files;
mod transpile_bindgen;
mod ts_bindgen;
pub mod esm_bindgen;
pub mod function_bindgen;
pub mod intrinsics;
pub mod names;
pub mod source;
pub use transpile_bindgen::{BindingsMode, InstantiationMode, TranspileOpts};
use anyhow::Result;
use transpile_bindgen::transpile_bindgen;
use anyhow::{bail, Context};
use wasmtime_environ::component::Export;
use wasmtime_environ::component::{ComponentTypesBuilder, StaticModuleIndex};
use wasmtime_environ::wasmparser::Validator;
use wasmtime_environ::{PrimaryMap, ScopeVec, Tunables};
use wit_component::DecodedWasm;
use ts_bindgen::ts_bindgen;
use wit_parser::{Resolve, Type, TypeDefKind, TypeId, WorldId};
#[macro_export]
macro_rules! uwrite {
($dst:expr, $($arg:tt)*) => {
write!($dst, $($arg)*).unwrap()
};
}
#[macro_export]
macro_rules! uwriteln {
($dst:expr, $($arg:tt)*) => {
writeln!($dst, $($arg)*).unwrap()
};
}
pub struct Transpiled {
pub files: Vec<(String, Vec<u8>)>,
pub imports: Vec<String>,
pub exports: Vec<(String, Export)>,
}
pub struct ComponentInfo {
pub imports: Vec<String>,
pub exports: Vec<(String, wasmtime_environ::component::Export)>,
}
pub fn generate_types(
name: String,
resolve: Resolve,
world_id: WorldId,
opts: TranspileOpts,
) -> Result<Vec<(String, Vec<u8>)>, anyhow::Error> {
let mut files = files::Files::default();
ts_bindgen(&name, &resolve, world_id, &opts, &mut files);
let mut files_out: Vec<(String, Vec<u8>)> = Vec::new();
for (name, source) in files.iter() {
files_out.push((name.to_string(), source.to_vec()));
}
Ok(files_out)
}
#[cfg(feature = "transpile-bindgen")]
pub fn transpile(component: &[u8], opts: TranspileOpts) -> Result<Transpiled, anyhow::Error> {
use wasmtime_environ::component::Translator;
let name = opts.name.clone();
let mut files = files::Files::default();
let decoded = wit_component::decode(component)
.context("failed to extract interface information from component")?;
let (resolve, world_id) = match decoded {
DecodedWasm::WitPackage(..) => bail!("unexpected wit package as input"),
DecodedWasm::Component(resolve, world_id) => (resolve, world_id),
};
let scope = ScopeVec::new();
let tunables = Tunables::default_u32();
let mut validator = Validator::default();
let mut types = ComponentTypesBuilder::new(&validator);
let (component, modules) = Translator::new(&tunables, &mut validator, &mut types, &scope)
.translate(component)
.context("failed to parse the input component")?;
let modules: PrimaryMap<StaticModuleIndex, core::Translation<'_>> = modules
.into_iter()
.map(|(_i, module)| core::Translation::new(module, opts.multi_memory))
.collect::<Result<_>>()?;
let types = types.finish(&PrimaryMap::new(), Vec::new(), Vec::new());
for (i, module) in modules.iter() {
files.push(&core_file_name(&name, i.as_u32()), module.wasm());
}
if !opts.no_typescript {
ts_bindgen(&name, &resolve, world_id, &opts, &mut files);
}
let (imports, exports) = transpile_bindgen(
&name, &component, &modules, &types.0, &resolve, world_id, opts, &mut files,
);
let mut files_out: Vec<(String, Vec<u8>)> = Vec::new();
for (name, source) in files.iter() {
files_out.push((name.to_string(), source.to_vec()));
}
Ok(Transpiled {
files: files_out,
imports,
exports,
})
}
fn core_file_name(name: &str, idx: u32) -> String {
let i_str = if idx == 0 {
String::from("")
} else {
(idx + 1).to_string()
};
format!("{}.core{i_str}.wasm", name)
}
pub fn dealias(resolve: &Resolve, mut id: TypeId) -> TypeId {
loop {
match &resolve.types[id].kind {
TypeDefKind::Type(Type::Id(that_id)) => id = *that_id,
_ => break id,
}
}
}