From b6a80d56a100dec387e6842bd7c3cd0d25653e83 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Thu, 6 Oct 2022 22:13:18 -0400 Subject: [PATCH] Derive the class_name if missing --- derive/Cargo.toml | 1 + derive/src/lib.rs | 14 +++-- web-component/src/lib.rs | 114 +++++++++++++++++++++------------------ 3 files changed, 73 insertions(+), 56 deletions(-) diff --git a/derive/Cargo.toml b/derive/Cargo.toml index 3d016a5..543a3d6 100644 --- a/derive/Cargo.toml +++ b/derive/Cargo.toml @@ -12,6 +12,7 @@ proc-macro = true quote = "1.0" proc-macro2 = "1.0" proc-macro-crate = "1.2.1" +str_inflector = "0.12.0" [dependencies.syn] version = "1.0.101" diff --git a/derive/src/lib.rs b/derive/src/lib.rs index a3b42a4..4178f1a 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use inflector::Inflector; use proc_macro::TokenStream; use proc_macro2::{Literal, Span}; use proc_macro_crate::{crate_name, FoundCrate}; @@ -54,13 +55,20 @@ fn get_class_and_element_names(args: Vec) -> (Literal, Literal, Lite } } } + // TODO(jwall): it should be a compile error if this is missing. let class_name = class_name .map(|n| n.token()) .unwrap_or_else(|| LitStr::new("", Span::call_site()).token()); - let element_name = element_name - .map(|n| n.token()) - .unwrap_or_else(|| LitStr::new("", Span::call_site()).token()); + // TODO(jwall): if Missing we should derive this from the class name. + let element_name = match element_name.map(|n| n.token()) { + Some(n) => n, + None => { + let class_kebab = class_name.to_string().to_kebab_case(); + LitStr::new(&class_kebab, Span::call_site()).token() + } + }; + let observed_attributes = observed_attributes .map(|n| n.token()) .unwrap_or_else(|| LitStr::new("[]", Span::call_site()).token()); diff --git a/web-component/src/lib.rs b/web-component/src/lib.rs index 621e87d..48533f4 100644 --- a/web-component/src/lib.rs +++ b/web-component/src/lib.rs @@ -67,59 +67,6 @@ mod tests { wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); - #[web_component( - class_name = "MyElement", - element_name = "my-element", - observed_attrs = "['class']" - )] - pub struct MyElementImpl {} - - impl WebComponentBinding for MyElementImpl { - fn connected(&self, element: &HtmlElement) { - log("Firing connected call back".to_owned()); - let node = Text::new().unwrap(); - node.set_text_content(Some("Added a text node on connect".into())); - element.append_child(&node).unwrap(); - log(format!( - "element contents: {}", - &element.text_content().unwrap() - )); - } - - fn disconnected(&self, element: &HtmlElement) { - log("Firing discconnected call back".to_owned()); - let node = element.first_child().unwrap(); - element.remove_child(&node).unwrap(); - } - - fn adopted(&self, element: &HtmlElement) { - log("Firing adopted call back".to_owned()); - let node = Text::new().unwrap(); - node.set_text_content(Some("Added a text node on adopt".into())); - element.append_child(&node).unwrap(); - log_with_val("element: ".to_owned(), element); - } - - fn attribute_changed( - &self, - element: &HtmlElement, - name: JsValue, - old_value: JsValue, - new_value: JsValue, - ) { - log("Firing attribute changed callback".to_owned()); - let node = element.first_child().unwrap(); - node.set_text_content(Some(&format!( - "Setting {} from {} to {}", - name.as_string().unwrap_or("None".to_owned()), - old_value.as_string().unwrap_or("None".to_owned()), - new_value.as_string().unwrap_or("None".to_owned()), - ))); - element.append_child(&node).unwrap(); - log_with_val("element: ".to_owned(), element); - } - } - #[wasm_bindgen] extern "C" { #[wasm_bindgen(js_namespace = console, js_name = log)] @@ -132,6 +79,58 @@ mod tests { // to the handle we run this all in one single function. #[wasm_bindgen_test] fn test_component() { + #[web_component( + class_name = "MyElement", + element_name = "my-element", + observed_attrs = "['class']" + )] + pub struct MyElementImpl {} + + impl WebComponentBinding for MyElementImpl { + fn connected(&self, element: &HtmlElement) { + log("Firing connected call back".to_owned()); + let node = Text::new().unwrap(); + node.set_text_content(Some("Added a text node on connect".into())); + element.append_child(&node).unwrap(); + log(format!( + "element contents: {}", + &element.text_content().unwrap() + )); + } + + fn disconnected(&self, element: &HtmlElement) { + log("Firing discconnected call back".to_owned()); + let node = element.first_child().unwrap(); + element.remove_child(&node).unwrap(); + } + + fn adopted(&self, element: &HtmlElement) { + log("Firing adopted call back".to_owned()); + let node = Text::new().unwrap(); + node.set_text_content(Some("Added a text node on adopt".into())); + element.append_child(&node).unwrap(); + log_with_val("element: ".to_owned(), element); + } + + fn attribute_changed( + &self, + element: &HtmlElement, + name: JsValue, + old_value: JsValue, + new_value: JsValue, + ) { + log("Firing attribute changed callback".to_owned()); + let node = element.first_child().unwrap(); + node.set_text_content(Some(&format!( + "Setting {} from {} to {}", + name.as_string().unwrap_or("None".to_owned()), + old_value.as_string().unwrap_or("None".to_owned()), + new_value.as_string().unwrap_or("None".to_owned()), + ))); + element.append_child(&node).unwrap(); + log_with_val("element: ".to_owned(), element); + } + } let obj = MyElementImpl::define().expect("Failed to define web component"); let fun = obj.element_constructor.dyn_ref::().unwrap(); assert_eq!(fun.name(), MyElementImpl::class_name()); @@ -171,4 +170,13 @@ mod tests { "Added a text node on adopt" ); } + + #[wasm_bindgen_test] + fn test_component_no_element_name() { + #[web_component(class_name = "AnElement")] + pub struct AnElement {} + impl WebComponentBinding for AnElement {} + + assert_eq!(AnElement::element_name(), "an-element"); + } }