From 117928f0c085a1987e21408eb7885076030d0658 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 3 Jun 2019 13:18:11 -0700 Subject: [PATCH] Add doc comments to web-sys dictionaries/fields This commit ensures that web-sys generated dictionaries and fields all have comments like interfaces do, indicating a bare minimum of what's happening as well as the required features to enable the API. --- crates/backend/src/ast.rs | 3 +++ crates/backend/src/codegen.rs | 15 +++++++++++ crates/webidl/src/lib.rs | 51 ++++++++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 6 deletions(-) diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 0cef9011..574042bd 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -293,6 +293,8 @@ pub struct Dictionary { pub name: Ident, pub fields: Vec, pub ctor: bool, + pub doc_comment: Option, + pub ctor_doc_comment: Option, } #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] @@ -302,6 +304,7 @@ pub struct DictionaryField { pub js_name: String, pub required: bool, pub ty: syn::Type, + pub doc_comment: Option, } impl Export { diff --git a/crates/backend/src/codegen.rs b/crates/backend/src/codegen.rs index 09ff71a7..e1a78906 100644 --- a/crates/backend/src/codegen.rs +++ b/crates/backend/src/codegen.rs @@ -1281,9 +1281,18 @@ impl ToTokens for ast::Dictionary { .collect::>(); let required_names2 = required_names; let required_names3 = required_names; + let doc_comment = match &self.doc_comment { + None => "", + Some(doc_string) => doc_string, + }; let ctor = if self.ctor { + let doc_comment = match &self.ctor_doc_comment { + None => "", + Some(doc_string) => doc_string, + }; quote! { + #[doc = #doc_comment] pub fn new(#(#required_names: #required_types),*) -> #name { let mut _ret = #name { obj: ::js_sys::Object::new() }; #(_ret.#required_names2(#required_names3);)* @@ -1299,6 +1308,7 @@ impl ToTokens for ast::Dictionary { #[derive(Clone, Debug)] #[repr(transparent)] #[allow(clippy::all)] + #[doc = #doc_comment] pub struct #name { obj: ::js_sys::Object, } @@ -1414,8 +1424,13 @@ impl ToTokens for ast::DictionaryField { let rust_name = &self.rust_name; let js_name = &self.js_name; let ty = &self.ty; + let doc_comment = match &self.doc_comment { + None => "", + Some(doc_string) => doc_string, + }; (quote! { #[allow(clippy::all)] + #[doc = #doc_comment] pub fn #rust_name(&mut self, val: #ty) -> &mut Self { use wasm_bindgen::JsValue; let r = ::js_sys::Reflect::set( diff --git a/crates/webidl/src/lib.rs b/crates/webidl/src/lib.rs index 4dc04255..fd38c45c 100644 --- a/crates/webidl/src/lib.rs +++ b/crates/webidl/src/lib.rs @@ -26,6 +26,7 @@ use proc_macro2::{Ident, Span}; use quote::{quote, ToTokens}; use std::collections::{BTreeSet, HashSet}; use std::env; +use std::fmt::Display; use std::fs; use std::iter::FromIterator; use wasm_bindgen_backend::ast; @@ -313,12 +314,33 @@ impl<'src> FirstPassRecord<'src> { if !self.append_dictionary_members(def.identifier.0, &mut fields) { return; } + let name = rust_ident(&camel_case_ident(def.identifier.0)); + let extra_feature = name.to_string(); + for field in fields.iter_mut() { + let mut doc_comment = Some(format!( + "Configure the `{}` field of this object\n", + field.js_name, + )); + self.append_required_features_doc(&*field, &mut doc_comment, &[&extra_feature]); + field.doc_comment = doc_comment; + } - program.dictionaries.push(ast::Dictionary { - name: rust_ident(&camel_case_ident(def.identifier.0)), + let mut doc_comment = format!("The `{}` dictionary\n", def.identifier.0); + if let Some(s) = self.required_doc_string(vec![name.clone()]) { + doc_comment.push_str(&s); + } + let mut dict = ast::Dictionary { + name, fields, ctor: true, - }); + doc_comment: Some(doc_comment), + ctor_doc_comment: None, + }; + let mut ctor_doc_comment = Some(format!("Construct a new `{}`\n", def.identifier.0)); + self.append_required_features_doc(&dict, &mut ctor_doc_comment, &[&extra_feature]); + dict.ctor_doc_comment = ctor_doc_comment; + + program.dictionaries.push(dict); } fn append_dictionary_members( @@ -419,6 +441,7 @@ impl<'src> FirstPassRecord<'src> { rust_name: rust_ident(&snake_case_ident(field.identifier.0)), js_name: field.identifier.0.to_string(), ty, + doc_comment: None, }) } @@ -740,16 +763,29 @@ impl<'src> FirstPassRecord<'src> { if required.len() == 0 { return; } - let list = required + if let Some(extra) = self.required_doc_string(required) { + doc.push_str(&extra); + } + } + + fn required_doc_string( + &self, + features: impl IntoIterator, + ) -> Option { + let features = features.into_iter().collect::>(); + if features.len() == 0 { + return None; + } + let list = features .iter() .map(|ident| format!("`{}`", ident)) .collect::>() .join(", "); - doc.push_str(&format!( + Some(format!( "\n\n*This API requires the following crate features \ to be activated: {}*", list, - )); + )) } fn append_callback_interface( @@ -771,6 +807,7 @@ impl<'src> FirstPassRecord<'src> { rust_name: rust_ident(&snake_case_ident(identifier)), js_name: identifier.to_string(), ty: idl_type::IdlType::Callback.to_syn_type(pos).unwrap(), + doc_comment: None, }); } _ => { @@ -786,6 +823,8 @@ impl<'src> FirstPassRecord<'src> { name: rust_ident(&camel_case_ident(item.definition.identifier.0)), fields, ctor: true, + doc_comment: None, + ctor_doc_comment: None, }); } }