Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

html! macro support hyphens in attributes #199

Merged
merged 1 commit into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 45 additions & 39 deletions crates/html-macro-test/src/tests/all_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use html_macro::html;
use std::collections::HashMap;
use virtual_node::{IterableNodes, VElement, VText, View, VirtualNode};
use virtual_node::{AttributeValue, IterableNodes, VElement, VText, View, VirtualNode};

#[must_use]
pub(crate) struct HtmlMacroTest {
Expand All @@ -28,7 +28,7 @@ fn empty_div() {
generated: html! { <div></div> },
expected: VirtualNode::element("div"),
}
.test();
.test();
}

#[test]
Expand All @@ -43,7 +43,7 @@ fn one_attr() {
generated: html! { <div id="hello-world"></div> },
expected: expected.into(),
}
.test();
.test();
}

#[test]
Expand All @@ -55,7 +55,7 @@ fn child_node() {
generated: html! { <div><span></span></div> },
expected: expected.into(),
}
.test();
.test();
}

#[test]
Expand All @@ -67,7 +67,7 @@ fn sibling_child_nodes() {
generated: html! { <div><span></span><b></b></div> },
expected: expected.into(),
}
.test();
.test();
}

/// Nested 3 nodes deep
Expand All @@ -83,16 +83,15 @@ fn three_nodes_deep() {
generated: html! { <div><span><b></b></span></div> },
expected: expected.into(),
}
.test()
.test()
}


// TODO: Requires proc macro APIs that are currently unstable - https://github.com/rust-lang/rust/issues/54725
// #[test]
// fn sibling_text_nodes() {
// let mut expected = VElement::new("div");
// expected.children = vec![VirtualNode::text("This is a text node")];
//
//
// HtmlMacroTest {
// generated: html! { <div>This is a text node</div> },
// expected: expected.into(),
Expand All @@ -116,7 +115,7 @@ fn nested_macro() {
},
expected: expected.into(),
}
.test();
.test();
}

/// If the first thing we see is a block then we grab whatever is inside it.
Expand All @@ -132,21 +131,21 @@ fn block_root() {
},
expected,
}
.test();
.test();
}

// TODO: Requires proc macro APIs that are currently unstable - https://github.com/rust-lang/rust/issues/54725
// /// Text followed by a block
// #[test]
// fn text_next_to_block() {
// let child = html! { <ul></ul> };
//
//
// let mut expected = VElement::new("div");
// expected.children = vec![
// VirtualNode::text(" A bit of text "),
// VirtualNode::element("ul"),
// ];
//
//
// HtmlMacroTest {
// generated: html! {
// <div>
Expand All @@ -165,7 +164,7 @@ fn block_root() {
// #[test]
// fn punctuation_token() {
// let text = "Hello, World";
//
//
// HtmlMacroTest {
// generated: html! { Hello, World },
// expected: VirtualNode::text(text),
Expand All @@ -184,22 +183,29 @@ fn vec_of_nodes() {
generated: html! { <div> { children } </div> },
expected: expected.into(),
}
.test();
.test();
}

/// Just make sure that this compiles since as, async, for, loop, and type are keywords
#[test]
fn keyword_attribute() {
html! { <link rel="prefetch" href="/style.css" as="style" /> }
;
html! { <script src="/app.js" async="async" /> }
;
html! { <label for="username">Username:</label> }
;
html! { <audio loop="loop"><source src="/beep.mp3" type="audio/mpeg" /></audio> }
;
html! { <link rel="stylesheet" type="text/css" href="/app.css" /> }
;
html! { <link rel="prefetch" href="/style.css" as="style" /> };
html! { <script src="/app.js" async="async" /> };
html! { <label for="username">Username:</label> };
html! { <audio loop="loop"><source src="/beep.mp3" type="audio/mpeg" /></audio> };
html! { <link rel="stylesheet" type="text/css" href="/app.css" /> };
}

/// Verify that we can use an attribute name that contains a hyphen.
#[test]
fn hyphenated_attribute() {
let element: VirtualNode = html! {
<meta http-equiv="refresh"/>
};
assert_eq!(
element.as_velement_ref().unwrap().attrs.get("http-equiv"),
Some(&AttributeValue::String("refresh".to_string()))
);
}

/// For unquoted text apostrophes should be parsed correctly
Expand All @@ -217,9 +223,9 @@ fn self_closing_tag_without_backslash() {
"area", "base", "br", "col", "hr", "img", "input", "link", "meta", "param", "command",
"keygen", "source",
]
.into_iter()
.map(|tag| VirtualNode::element(tag))
.collect();
.into_iter()
.map(|tag| VirtualNode::element(tag))
.collect();
expected.children = children;

HtmlMacroTest {
Expand All @@ -231,7 +237,7 @@ fn self_closing_tag_without_backslash() {
},
expected: expected.into(),
}
.test();
.test();
}

/// Verify that our self closing tags work with backslashes
Expand All @@ -243,7 +249,7 @@ fn self_closing_tag_with_backslace() {
},
expected: VirtualNode::element("br"),
}
.test();
.test();
}

#[test]
Expand All @@ -262,7 +268,7 @@ fn if_true_block() {
},
expected: expected.into(),
}
.test();
.test();
}

#[test]
Expand All @@ -285,7 +291,7 @@ fn if_false_block() {
},
expected: expected.into(),
}
.test();
.test();
}

#[test]
Expand All @@ -301,7 +307,7 @@ fn single_branch_if_true_block() {
},
expected: expected.into(),
}
.test();
.test();
}

#[test]
Expand All @@ -317,7 +323,7 @@ fn single_branch_if_false_block() {
},
expected: expected.into(),
}
.test();
.test();
}

#[test]
Expand Down Expand Up @@ -345,7 +351,7 @@ fn custom_component_props() {
},
expected: expected.into(),
}
.test();
.test();
}

#[test]
Expand Down Expand Up @@ -373,7 +379,7 @@ fn custom_component_children() {
},
expected: expected.into(),
}
.test();
.test();
}

/// Verify that we can properly render an empty list of virtual nodes that has a space after it.
Expand All @@ -387,7 +393,7 @@ fn space_before_and_after_empty_list() {
generated: html! {<div> {elements} </div>},
expected: html! {<div> </div>},
}
.test()
.test()
}

/// Verify that an Option::None virtual node gets ignored.
Expand All @@ -399,7 +405,7 @@ fn option_none() {
generated: html! {<div> {element} </div>},
expected: html! {<div> </div>},
}
.test()
.test()
}

/// Verify that an Some(VirtualNode) gets rendered.
Expand All @@ -411,7 +417,7 @@ fn option_some() {
generated: html! {<div> {element} </div>},
expected: html! {<div> <em></em> </div>},
}
.test()
.test()
}

/// Verify that our macro to generate IterableNodes implementations for numbers works.
Expand All @@ -424,5 +430,5 @@ fn numbers() {
generated: html! {<div> {num} {ref_num} </div>},
expected: html! {<div> {"3"} {"4"} </div>},
}
.test()
.test()
}
12 changes: 6 additions & 6 deletions crates/html-macro/src/parser/open_tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,12 @@ fn create_valid_node(
// html! { <div key = "..." ></div>
let key_attr = attrs
.iter()
.find(|attr| attr.key.to_string() == "key")
.map(|attr| &attr.value);
.find(|attr| attr.key_string() == "key")
.map(|attr| attr.value());

for attr in attrs.iter() {
let key = format!("{}", attr.key);
let value = &attr.value;
let key = attr.key_string();
let value = attr.value();

match value {
Expr::Closure(closure) => {
Expand Down Expand Up @@ -151,8 +151,8 @@ fn component_node(
let component_props: Vec<proc_macro2::TokenStream> = attrs
.into_iter()
.map(|attr| {
let key = Ident::new(format!("{}", attr.key).as_str(), name.span());
let value = &attr.value;
let key = Ident::new(attr.key_string().as_str(), name.span());
let value = attr.value();

quote! {
#key: #value,
Expand Down
4 changes: 2 additions & 2 deletions crates/html-macro/src/parser/open_tag/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pub(super) fn insert_closure_tokens(
key_attr_value: Option<&Expr>,
) -> TokenStream {
let arg_count = closure.inputs.len();
let event_name = event_attribute.key.to_string();
let event_name = event_attribute.key_string();

let attr_key_span = &event_attribute.key.span();
let attr_key_span = &event_attribute.key_span();

// TODO: Refactor duplicate code between these blocks.
if event_name == "on_create_element" {
Expand Down
Loading
Loading