Skip to content

Commit

Permalink
added ts for async
Browse files Browse the repository at this point in the history
  • Loading branch information
calvinrp committed Nov 1, 2024
1 parent 489699e commit 7310483
Showing 1 changed file with 60 additions and 15 deletions.
75 changes: 60 additions & 15 deletions crates/js-component-bindgen/src/ts_bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::files::Files;
use crate::function_bindgen::{array_ty, as_nullable, maybe_null};
use crate::names::{is_js_identifier, maybe_quote_id, LocalNames, RESERVED_KEYWORDS};
use crate::source::Source;
use crate::transpile_bindgen::{parse_world_key, InstantiationMode, TranspileOpts};
use crate::transpile_bindgen::{parse_world_key, AsyncMode, InstantiationMode, TranspileOpts};
use crate::{dealias, feature_gate_allowed, uwrite, uwriteln};
use anyhow::{Context as _, Result};
use heck::*;
Expand All @@ -29,6 +29,9 @@ struct TsBindgen {
import_object: Source,
/// TypeScript definitions which will become the export object
export_object: Source,

async_imports: HashSet<String>,
async_exports: HashSet<String>,
}

/// Used to generate a `*.d.ts` file for each imported and exported interface for
Expand All @@ -53,12 +56,23 @@ pub fn ts_bindgen(
opts: &TranspileOpts,
files: &mut Files,
) -> Result<()> {
let (async_imports, async_exports) = match opts.async_mode.clone() {
None | Some(AsyncMode::Sync) => (Default::default(), Default::default()),
Some(AsyncMode::JavaScriptPromiseIntegration { imports, exports }) => {
(imports.into_iter().collect(), exports.into_iter().collect())
}
Some(AsyncMode::Asyncify { imports, exports }) => {
(imports.into_iter().collect(), exports.into_iter().collect())
}
};
let mut bindgen = TsBindgen {
src: Source::default(),
interface_names: LocalNames::default(),
local_names: LocalNames::default(),
import_object: Source::default(),
export_object: Source::default(),
async_imports,
async_exports,
};

let world = &resolve.worlds[id];
Expand Down Expand Up @@ -368,7 +382,7 @@ impl TsBindgen {
files: &mut Files,
) -> String {
// in case an imported type is used as an exported type
let local_name = self.generate_interface(name, resolve, id, files);
let local_name = self.generate_interface(name, resolve, id, files, false);
uwriteln!(
self.import_object,
"{}: typeof {local_name},",
Expand All @@ -388,15 +402,15 @@ impl TsBindgen {
if iface_name == "*" {
uwrite!(self.import_object, "{}: ", maybe_quote_id(import_name));
let name = resolve.interfaces[id].name.as_ref().unwrap();
let local_name = self.generate_interface(name, resolve, id, files);
let local_name = self.generate_interface(name, resolve, id, files, false);
uwriteln!(self.import_object, "typeof {local_name},",);
return;
}
}
uwriteln!(self.import_object, "{}: {{", maybe_quote_id(import_name));
for (iface_name, &id) in ifaces {
let name = resolve.interfaces[id].name.as_ref().unwrap();
let local_name = self.generate_interface(name, resolve, id, files);
let local_name = self.generate_interface(name, resolve, id, files, false);
uwriteln!(
self.import_object,
"{}: typeof {local_name},",
Expand All @@ -415,7 +429,7 @@ impl TsBindgen {
) {
uwriteln!(self.import_object, "{}: {{", maybe_quote_id(import_name));
let mut gen = self.ts_interface(resolve, false);
gen.ts_func(func, true, false);
gen.ts_func(func, true, false, false);
let src = gen.finish();
self.import_object.push_str(&src);
uwriteln!(self.import_object, "}},");
Expand All @@ -429,7 +443,7 @@ impl TsBindgen {
files: &mut Files,
instantiation: bool,
) -> String {
let local_name = self.generate_interface(export_name, resolve, id, files);
let local_name = self.generate_interface(export_name, resolve, id, files, true);
if instantiation {
uwriteln!(
self.export_object,
Expand Down Expand Up @@ -460,7 +474,7 @@ impl TsBindgen {
) {
let mut gen = self.ts_interface(resolve, false);
for (_, func) in funcs {
gen.ts_func(func, false, declaration);
gen.ts_func(func, false, declaration, false);
}
let src = gen.finish();
self.export_object.push_str(&src);
Expand All @@ -472,6 +486,7 @@ impl TsBindgen {
resolve: &Resolve,
id: InterfaceId,
files: &mut Files,
is_world_export: bool,
) -> String {
let iface = resolve
.interfaces
Expand Down Expand Up @@ -520,6 +535,11 @@ impl TsBindgen {
return local_name;
}

let async_funcs = if is_world_export {
self.async_exports.clone()
} else {
self.async_imports.clone()
};
let mut gen = self.ts_interface(resolve, false);

uwriteln!(gen.src, "export namespace {camel} {{");
Expand All @@ -530,7 +550,16 @@ impl TsBindgen {
{
continue;
}
gen.ts_func(func, false, true);
let func_name = &func.name;
let is_async = is_world_export && async_funcs.contains(func_name)
|| async_funcs.contains(&format!("{id_name}#{func_name}"))
|| id_name
.find('@')
.map(|i| {
async_funcs.contains(&format!("{}#{func_name}", id_name.get(0..i).unwrap()))
})
.unwrap_or(false);
gen.ts_func(func, false, true, is_async);
}
// Export resources for the interface
for (_, ty) in resolve.interfaces[id].types.iter() {
Expand Down Expand Up @@ -729,7 +758,7 @@ impl<'a> TsInterface<'a> {
self.src.push_str("]");
}

fn ts_func(&mut self, func: &Function, default: bool, declaration: bool) {
fn ts_func(&mut self, func: &Function, default: bool, declaration: bool, is_async: bool) {
let iface = if let FunctionKind::Method(ty)
| FunctionKind::Static(ty)
| FunctionKind::Constructor(ty) = func.kind
Expand All @@ -754,33 +783,39 @@ impl<'a> TsInterface<'a> {
func.item_name().to_lower_camel_case()
};

let if_async = if is_async { "async " } else { "" };

if declaration {
match func.kind {
FunctionKind::Freestanding => {
if is_js_identifier(&out_name) {
iface.src.push_str(&format!("export function {out_name}"));
iface
.src
.push_str(&format!("export {if_async}function {out_name}"));
} else {
let (local_name, _) = iface.local_names.get_or_create(&out_name, &out_name);
iface
.src
.push_str(&format!("export {{ {local_name} as {out_name} }};\n"));
iface
.src
.push_str(&format!("declare function {local_name}"));
.push_str(&format!("declare {if_async}function {local_name}"));
};
}
FunctionKind::Method(_) => {
if is_js_identifier(&out_name) {
iface.src.push_str(&out_name);
iface.src.push_str(&format!("{if_async}{out_name}"));
} else {
iface.src.push_str(&format!("'{out_name}'"));
iface.src.push_str(&format!("{if_async}'{out_name}'"));
}
}
FunctionKind::Static(_) => {
if is_js_identifier(&out_name) {
iface.src.push_str(&format!("static {out_name}"))
iface.src.push_str(&format!("static {if_async}{out_name}"))
} else {
iface.src.push_str(&format!("static '{out_name}'"))
iface
.src
.push_str(&format!("static {if_async}'{out_name}'"))
}
}
FunctionKind::Constructor(_) => iface.src.push_str("constructor"),
Expand Down Expand Up @@ -825,6 +860,10 @@ impl<'a> TsInterface<'a> {
}
iface.src.push_str(": ");

if is_async {
iface.src.push_str("Promise<");
}

if let Some((ok_ty, _)) = func.results.throws(iface.resolve) {
iface.print_optional_ty(ok_ty);
} else {
Expand All @@ -843,6 +882,12 @@ impl<'a> TsInterface<'a> {
}
}
}

if is_async {
// closes `Promise<>`
iface.src.push_str(">");
}

iface.src.push_str(format!("{}\n", end_character).as_str());
}

Expand Down

0 comments on commit 7310483

Please sign in to comment.