Skip to content

Commit ec1b945

Browse files
Allow web-sys to emit correct typescript declarations from webidl (#1998)
* Update to emit typescript names * Update to use NamedAnyref * Update incoming / outgoing * Remove added space * Remove comment * Add basic typescript tests for web-sys
1 parent 9d55978 commit ec1b945

File tree

14 files changed

+140
-6
lines changed

14 files changed

+140
-6
lines changed

crates/backend/src/ast.rs

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ pub struct ImportType {
181181
pub rust_name: Ident,
182182
pub js_name: String,
183183
pub attrs: Vec<syn::Attribute>,
184+
pub typescript_name: Option<String>,
184185
pub doc_comment: Option<String>,
185186
pub instanceof_shim: String,
186187
pub is_type_of: Option<syn::Expr>,

crates/backend/src/codegen.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,21 @@ impl ToTokens for ast::ImportType {
579579
}
580580
};
581581

582+
let description = if let Some(typescript_name) = &self.typescript_name {
583+
let typescript_name_len = typescript_name.len() as u32;
584+
let typescript_name_chars = typescript_name.chars().map(|c| c as u32);
585+
quote! {
586+
use wasm_bindgen::describe::*;
587+
inform(NAMED_ANYREF);
588+
inform(#typescript_name_len);
589+
#(inform(#typescript_name_chars);)*
590+
}
591+
} else {
592+
quote! {
593+
JsValue::describe()
594+
}
595+
};
596+
582597
let is_type_of = self.is_type_of.as_ref().map(|is_type_of| {
583598
quote! {
584599
#[inline]
@@ -611,7 +626,7 @@ impl ToTokens for ast::ImportType {
611626

612627
impl WasmDescribe for #rust_name {
613628
fn describe() {
614-
JsValue::describe();
629+
#description
615630
}
616631
}
617632

crates/cli-support/src/descriptor.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ tys! {
3131
SLICE
3232
VECTOR
3333
ANYREF
34+
NAMED_ANYREF
3435
ENUM
3536
RUST_STRUCT
3637
CHAR
@@ -62,6 +63,7 @@ pub enum Descriptor {
6263
CachedString,
6364
String,
6465
Anyref,
66+
NamedAnyref(String),
6567
Enum { hole: u32 },
6668
RustStruct(String),
6769
Char,
@@ -134,11 +136,13 @@ impl Descriptor {
134136
ANYREF => Descriptor::Anyref,
135137
ENUM => Descriptor::Enum { hole: get(data) },
136138
RUST_STRUCT => {
137-
let name = (0..get(data))
138-
.map(|_| char::from_u32(get(data)).unwrap())
139-
.collect();
139+
let name = get_string(data);
140140
Descriptor::RustStruct(name)
141141
}
142+
NAMED_ANYREF => {
143+
let name = get_string(data);
144+
Descriptor::NamedAnyref(name)
145+
}
142146
CHAR => Descriptor::Char,
143147
UNIT => Descriptor::Unit,
144148
CLAMPED => Descriptor::_decode(data, true),
@@ -200,6 +204,12 @@ fn get(a: &mut &[u32]) -> u32 {
200204
ret
201205
}
202206

207+
fn get_string(data: &mut &[u32]) -> String {
208+
(0..get(data))
209+
.map(|_| char::from_u32(get(data)).unwrap())
210+
.collect()
211+
}
212+
203213
impl Closure {
204214
fn decode(data: &mut &[u32]) -> Closure {
205215
let shim_idx = get(data);

crates/cli-support/src/js/binding.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,7 @@ fn adapter2ts(ty: &AdapterType, dst: &mut String) {
12381238
adapter2ts(ty, dst);
12391239
dst.push_str(" | undefined");
12401240
}
1241+
AdapterType::NamedAnyref(name) => dst.push_str(name),
12411242
AdapterType::Struct(name) => dst.push_str(name),
12421243
AdapterType::Function => dst.push_str("any"),
12431244
}

crates/cli-support/src/wit/incoming.rs

+23
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ impl InstructionBuilder<'_, '_> {
6767
&[AdapterType::I32],
6868
);
6969
}
70+
Descriptor::NamedAnyref(name) => {
71+
self.instruction(
72+
&[AdapterType::NamedAnyref(name.clone())],
73+
Instruction::I32FromAnyrefOwned,
74+
&[AdapterType::I32]
75+
)
76+
}
7077
Descriptor::RustStruct(class) => {
7178
self.instruction(
7279
&[AdapterType::Struct(class.clone())],
@@ -161,6 +168,13 @@ impl InstructionBuilder<'_, '_> {
161168
&[AdapterType::I32],
162169
);
163170
}
171+
Descriptor::NamedAnyref(name) => {
172+
self.instruction(
173+
&[AdapterType::NamedAnyref(name.clone())],
174+
Instruction::I32FromAnyrefBorrow,
175+
&[AdapterType::I32],
176+
);
177+
}
164178
Descriptor::String | Descriptor::CachedString => {
165179
// This allocation is cleaned up once it's received in Rust.
166180
self.instruction(
@@ -224,6 +238,15 @@ impl InstructionBuilder<'_, '_> {
224238
&[AdapterType::I32],
225239
);
226240
}
241+
Descriptor::NamedAnyref(name) => {
242+
self.instruction(
243+
&[AdapterType::NamedAnyref(name.clone()).option()],
244+
Instruction::I32FromOptionAnyref {
245+
table_and_alloc: None,
246+
},
247+
&[AdapterType::I32],
248+
);
249+
}
227250
Descriptor::I8 => self.in_option_sentinel(AdapterType::S8),
228251
Descriptor::U8 => self.in_option_sentinel(AdapterType::U8),
229252
Descriptor::I16 => self.in_option_sentinel(AdapterType::S16),

crates/cli-support/src/wit/outgoing.rs

+28
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ impl InstructionBuilder<'_, '_> {
3939
&[AdapterType::Anyref],
4040
);
4141
}
42+
Descriptor::NamedAnyref(name) => {
43+
self.instruction(
44+
&[AdapterType::I32],
45+
Instruction::AnyrefLoadOwned,
46+
&[AdapterType::NamedAnyref(name.clone())],
47+
);
48+
}
4249
Descriptor::I8 => self.outgoing_i32(AdapterType::S8),
4350
Descriptor::U8 => self.outgoing_i32(AdapterType::U8),
4451
Descriptor::I16 => self.outgoing_i32(AdapterType::S16),
@@ -162,6 +169,13 @@ impl InstructionBuilder<'_, '_> {
162169
&[AdapterType::Anyref],
163170
);
164171
}
172+
Descriptor::NamedAnyref(name) => {
173+
self.instruction(
174+
&[AdapterType::I32],
175+
Instruction::TableGet,
176+
&[AdapterType::NamedAnyref(name.clone())],
177+
);
178+
}
165179
Descriptor::CachedString => self.cached_string(false, false)?,
166180

167181
Descriptor::String => {
@@ -227,6 +241,13 @@ impl InstructionBuilder<'_, '_> {
227241
&[AdapterType::Anyref.option()],
228242
);
229243
}
244+
Descriptor::NamedAnyref(name) => {
245+
self.instruction(
246+
&[AdapterType::I32],
247+
Instruction::AnyrefLoadOwned,
248+
&[AdapterType::NamedAnyref(name.clone()).option()],
249+
);
250+
}
230251
Descriptor::I8 => self.out_option_sentinel(AdapterType::S8),
231252
Descriptor::U8 => self.out_option_sentinel(AdapterType::U8),
232253
Descriptor::I16 => self.out_option_sentinel(AdapterType::S16),
@@ -316,6 +337,13 @@ impl InstructionBuilder<'_, '_> {
316337
&[AdapterType::Anyref.option()],
317338
);
318339
}
340+
Descriptor::NamedAnyref(name) => {
341+
self.instruction(
342+
&[AdapterType::I32],
343+
Instruction::TableGet,
344+
&[AdapterType::NamedAnyref(name.clone()).option()],
345+
);
346+
}
319347
Descriptor::CachedString => self.cached_string(true, false)?,
320348
Descriptor::String | Descriptor::Slice(_) => {
321349
let kind = arg.vector_kind().ok_or_else(|| {

crates/cli-support/src/wit/standard.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ pub enum AdapterType {
8484
Vector(VectorKind),
8585
Option(Box<AdapterType>),
8686
Struct(String),
87+
NamedAnyref(String),
8788
Function,
8889
}
8990

@@ -322,7 +323,7 @@ impl AdapterType {
322323
AdapterType::I64 => walrus::ValType::I64,
323324
AdapterType::F32 => walrus::ValType::F32,
324325
AdapterType::F64 => walrus::ValType::F64,
325-
AdapterType::Anyref => walrus::ValType::Anyref,
326+
AdapterType::Anyref | AdapterType::NamedAnyref(_) => walrus::ValType::Anyref,
326327
_ => return None,
327328
})
328329
}
@@ -340,7 +341,7 @@ impl AdapterType {
340341
AdapterType::F32 => wit_walrus::ValType::F32,
341342
AdapterType::F64 => wit_walrus::ValType::F64,
342343
AdapterType::String => wit_walrus::ValType::String,
343-
AdapterType::Anyref => wit_walrus::ValType::Anyref,
344+
AdapterType::Anyref | AdapterType::NamedAnyref(_) => wit_walrus::ValType::Anyref,
344345

345346
AdapterType::I32 => wit_walrus::ValType::I32,
346347
AdapterType::I64 => wit_walrus::ValType::I64,

crates/macro-support/src/parser.rs

+1
Original file line numberDiff line numberDiff line change
@@ -554,6 +554,7 @@ impl ConvertToAst<BindgenAttrs> for syn::ForeignItemType {
554554
instanceof_shim: shim,
555555
is_type_of,
556556
rust_name: self.ident,
557+
typescript_name: None,
557558
js_name,
558559
extends,
559560
vendor_prefixes,

crates/typescript-tests/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2018"
66

77
[dependencies]
88
wasm-bindgen = { path = '../..' }
9+
web-sys = { path = '../web-sys', features = [ 'HtmlElement', 'Node', 'Document' ] }
910

1011
[lib]
1112
crate-type = ['cdylib']

crates/typescript-tests/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ pub mod opt_args_and_ret;
44
pub mod optional_fields;
55
pub mod simple_fn;
66
pub mod simple_struct;
7+
pub mod web_sys;
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use wasm_bindgen::prelude::*;
2+
use web_sys::*;
3+
4+
#[wasm_bindgen]
5+
pub struct DocStruct {
6+
doc: Document,
7+
}
8+
9+
#[wasm_bindgen]
10+
impl DocStruct {
11+
pub fn new(doc: Document) -> Self {
12+
Self { doc }
13+
}
14+
15+
pub fn get_doc(&self) -> Document {
16+
self.doc.clone()
17+
}
18+
19+
pub fn append_element(&self, element: &HtmlElement) {
20+
self.doc.body().unwrap().append_child(element).unwrap();
21+
}
22+
23+
pub fn append_many(&self, _: &HtmlElement, _: &HtmlElement, _: &HtmlElement) {}
24+
}
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as wbg from "../pkg/typescript_tests";
2+
3+
const doc: Document = document;
4+
5+
const docStruct = wbg.DocStruct.new(doc);
6+
7+
const el: HTMLElement = document.createElement("a");
8+
9+
docStruct.append_element(el);
10+
docStruct.append_many(el, el, el);
11+
12+
const newDoc = docStruct.get_doc();
13+
14+
// This test ensures that the correct Typescript types are
15+
// used. If "newDoc" is "any", then "event" will cause the
16+
// compilation to fail because of noImplicitAny.
17+
newDoc.addEventListener("load", event => {
18+
console.log(event);
19+
});
20+
21+
// Same as above, but testing that the param is a document.
22+
const listener: Parameters<
23+
Parameters<typeof wbg["DocStruct"]["new"]>[0]["addEventListener"]
24+
>[1] = event => console.log(event);
25+
26+
newDoc.addEventListener("load", listener);

crates/webidl/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ impl<'src> FirstPassRecord<'src> {
568568
} else {
569569
Some(syn::parse_quote! { |_| false })
570570
},
571+
typescript_name: Some(name.to_string()),
571572
extends: Vec::new(),
572573
vendor_prefixes: Vec::new(),
573574
};

src/describe.rs

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ tys! {
3737
SLICE
3838
VECTOR
3939
ANYREF
40+
NAMED_ANYREF
4041
ENUM
4142
RUST_STRUCT
4243
CHAR

0 commit comments

Comments
 (0)