diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index d336b6bf..4b491fd0 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -78,6 +78,7 @@ pub struct ImportFunction { pub structural: bool, pub kind: ImportFunctionKind, pub shim: Ident, + pub doc_comment: Option, } #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] @@ -123,6 +124,7 @@ pub struct ImportType { pub vis: syn::Visibility, pub name: Ident, pub attrs: Vec, + pub doc_comment: Option, } #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 4c12921d..5ece1108 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -492,9 +492,14 @@ impl ToTokens for ast::ImportType { let vis = &self.vis; let name = &self.name; let attrs = &self.attrs; + let doc_comment = match &self.doc_comment { + None => "", + Some(comment) => comment, + }; (quote! { #[allow(bad_style)] #(#attrs)* + #[doc = #doc_comment] #vis struct #name { obj: ::wasm_bindgen::JsValue, } @@ -780,6 +785,10 @@ impl ToTokens for ast::ImportFunction { let attrs = &self.function.rust_attrs; let arguments = &arguments; + let doc_comment = match &self.doc_comment { + None => "", + Some(doc_string) => doc_string, + }; let me = if is_method { quote! { &self, } } else { @@ -790,6 +799,7 @@ impl ToTokens for ast::ImportFunction { #(#attrs)* #[allow(bad_style)] #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] + #[doc = #doc_comment] #vis fn #rust_name(#me #(#arguments),*) #ret { // See definition of `link_mem_intrinsics` for what this is doing ::wasm_bindgen::__rt::link_mem_intrinsics(); @@ -812,6 +822,7 @@ impl ToTokens for ast::ImportFunction { #(#attrs)* #[allow(bad_style, unused_variables)] #[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))] + #[doc = #doc_comment] #vis fn #rust_name(#me #(#arguments),*) #ret { panic!("cannot call wasm-bindgen imported functions on \ non-wasm targets"); diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index cb65fd2a..254d2d57 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -469,6 +469,7 @@ impl ConvertToAst for syn::ForeignItemFn { structural: opts.structural(), rust_name: self.ident.clone(), shim: Ident::new(&shim, Span::call_site()), + doc_comment: None, }) } } @@ -481,6 +482,7 @@ impl ConvertToAst<()> for syn::ForeignItemType { vis: self.vis, name: self.ident, attrs: self.attrs, + doc_comment: None, }) } } diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index f733b986..ca013d93 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -40,7 +40,7 @@ use heck::{ShoutySnakeCase}; use quote::ToTokens; use first_pass::{FirstPass, FirstPassRecord}; -use util::{public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident}; +use util::{public, webidl_const_ty_to_syn_ty, webidl_const_v_to_backend_const_v, TypePosition, camel_case_ident, mdn_doc}; pub use error::{Error, ErrorKind, Result}; @@ -272,6 +272,8 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface { return Ok(()); } + let doc_comment = Some(format!("The `{}` object\n\n{}", &self.name, mdn_doc(&self.name, None))); + program.imports.push(backend::ast::Import { module: None, version: None, @@ -280,6 +282,7 @@ impl WebidlParse<()> for webidl::ast::NonPartialInterface { vis: public(), name: rust_ident(camel_case_ident(&self.name).as_str()), attrs: Vec::new(), + doc_comment, }), }); @@ -363,6 +366,7 @@ impl<'a> WebidlParse<&'a webidl::ast::NonPartialInterface> for webidl::ast::Exte kind, structural, throws, + None, ) .map(wrap_import_function) .map(|import| program.imports.push(import)); diff --git a/crates/webidl/src/util.rs b/crates/webidl/src/util.rs index 9558d0d4..2050cf55 100644 --- a/crates/webidl/src/util.rs +++ b/crates/webidl/src/util.rs @@ -25,6 +25,14 @@ pub fn camel_case_ident(identifier: &str) -> String { identifier.replace("HTML", "HTML_").to_camel_case() } +// Returns a link to MDN +pub fn mdn_doc(class: &str, method: Option<&str>) -> String { + let mut link = format!("https://developer.mozilla.org/en-US/docs/Web/API/{}", class); + if let Some(method) = method { + link.push_str(&format!("/{}", method)); + } + format!("[Documentation]({})", link).into() +} /// For a webidl const type node, get the corresponding syn type node. pub fn webidl_const_ty_to_syn_ty(ty: &webidl::ast::ConstType) -> syn::Type { @@ -317,6 +325,7 @@ impl<'a> FirstPassRecord<'a> { kind: backend::ast::ImportFunctionKind, structural: bool, catch: bool, + doc_comment: Option, ) -> Option where I: Iterator, @@ -355,6 +364,7 @@ impl<'a> FirstPassRecord<'a> { structural, kind, shim, + doc_comment, }) } @@ -397,6 +407,7 @@ impl<'a> FirstPassRecord<'a> { } } }; + let doc_comment = Some(format!("The `{}()` method\n\n{}", name, mdn_doc(self_name, Some(name)))); self.create_function( &name, @@ -407,6 +418,7 @@ impl<'a> FirstPassRecord<'a> { kind, false, catch, + doc_comment, ) } @@ -436,8 +448,9 @@ impl<'a> FirstPassRecord<'a> { kind: backend::ast::OperationKind::Getter(Some(raw_ident(name))), }), }; + let doc_comment = Some(format!("The `{}` getter\n\n{}", name, mdn_doc(self_name, Some(name)))); - self.create_function(name, iter::empty(), ret, kind, is_structural, catch) + self.create_function(name, iter::empty(), ret, kind, is_structural, catch, doc_comment) } /// Create a wasm-bindgen setter method, if possible. @@ -458,6 +471,7 @@ impl<'a> FirstPassRecord<'a> { kind: backend::ast::OperationKind::Setter(Some(raw_ident(name))), }), }; + let doc_comment = Some(format!("The `{}` setter\n\n{}", name, mdn_doc(self_name, Some(name)))); self.create_function( &format!("set_{}", name), @@ -466,6 +480,7 @@ impl<'a> FirstPassRecord<'a> { kind, is_structural, catch, + doc_comment, ) } }