diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 4b375e4b1ed..632fab2819f 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -461,7 +461,13 @@ impl<'a> Context<'a> { Ok(imports) } - fn ts_for_init_fn(has_memory: bool, has_module_or_path_optional: bool) -> String { + fn ts_for_init_fn( + &self, + has_memory: bool, + has_module_or_path_optional: bool, + ) -> Result { + let output = crate::wasm2es6js::interface(&self.module)?; + let (memory_doc, memory_param) = if has_memory { ( "* @param {WebAssembly.Memory} maybe_memory\n", @@ -471,22 +477,28 @@ impl<'a> Context<'a> { ("", "") }; let arg_optional = if has_module_or_path_optional { "?" } else { "" }; - format!( + Ok(format!( "\n\ + export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;\n\ + \n\ + export interface InitOutput {{\n\ + {output}}}\n\ + \n\ /**\n\ - * If `module_or_path` is {{RequestInfo}}, makes a request and\n\ + * If `module_or_path` is {{RequestInfo}} or {{URL}}, makes a request and\n\ * for everything else, calls `WebAssembly.instantiate` directly.\n\ *\n\ - * @param {{RequestInfo | BufferSource | WebAssembly.Module}} module_or_path\n\ + * @param {{InitInput | Promise}} module_or_path\n\ {}\ *\n\ - * @returns {{Promise}}\n\ + * @returns {{Promise}}\n\ */\n\ export default function init \ - (module_or_path{}: RequestInfo | BufferSource | WebAssembly.Module{}): Promise; + (module_or_path{}: InitInput | Promise{}): Promise; ", - memory_doc, arg_optional, memory_param - ) + memory_doc, arg_optional, memory_param, + output = output, + )) } fn gen_init( @@ -541,7 +553,7 @@ impl<'a> Context<'a> { _ => "", }; - let ts = Self::ts_for_init_fn(has_memory, !default_module_path.is_empty()); + let ts = self.ts_for_init_fn(has_memory, !default_module_path.is_empty())?; // Initialize the `imports` object for all import definitions that we're // directed to wire up. diff --git a/crates/cli-support/src/wasm2es6js.rs b/crates/cli-support/src/wasm2es6js.rs index f50a1b38ac5..e67a6394b3e 100644 --- a/crates/cli-support/src/wasm2es6js.rs +++ b/crates/cli-support/src/wasm2es6js.rs @@ -44,6 +44,49 @@ impl Config { } } +pub fn interface(module: &Module) -> Result { + let mut exports = String::new(); + + for entry in module.exports.iter() { + let id = match entry.item { + walrus::ExportItem::Function(i) => i, + walrus::ExportItem::Memory(_) => { + exports.push_str(&format!(" readonly {}: WebAssembly.Memory;\n", entry.name,)); + continue; + } + walrus::ExportItem::Table(_) => { + exports.push_str(&format!(" readonly {}: WebAssembly.Table;\n", entry.name,)); + continue; + } + walrus::ExportItem::Global(_) => continue, + }; + + let func = module.funcs.get(id); + let ty = module.types.get(func.ty()); + let mut args = String::new(); + for (i, _) in ty.params().iter().enumerate() { + if i > 0 { + args.push_str(", "); + } + args.push((b'a' + (i as u8)) as char); + args.push_str(": number"); + } + + exports.push_str(&format!( + " readonly {name}: ({args}) => {ret};\n", + name = entry.name, + args = args, + ret = match ty.results().len() { + 0 => "void", + 1 => "number", + _ => "Array", + }, + )); + } + + Ok(exports) +} + pub fn typescript(module: &Module) -> Result { let mut exports = format!("/* tslint:disable */\n/* eslint-disable */\n");