~repos /tide-jsx

#rust#proc-macro#jsx

git clone https://pyrossh.dev/repos/tide-jsx.git

Tide + JSX


7c790e33 Gal Schlezinger

6 years ago
Support empty brackets as Fragments (#5)
README.md CHANGED
@@ -32,8 +32,6 @@ use render::{
32
32
  component,
33
33
  // A macro to compose components in JSX fashion
34
34
  html,
35
- // A component that just render its children
36
- Fragment,
37
35
  // A trait for custom components
38
36
  Renderable,
39
37
  };
@@ -42,7 +40,7 @@ use render::{
42
40
  #[component]
43
41
  fn Page<'a, Children: Renderable>(title: &'a str, children: Children) -> String {
44
42
  html! {
45
- <Fragment>
43
+ <>
46
44
  <HTML5Doctype />
47
45
  <html>
48
46
  <head><title>{title}</title></head>
@@ -50,7 +48,7 @@ fn Page<'a, Children: Renderable>(title: &'a str, children: Children) -> String
50
48
  {children}
51
49
  </body>
52
50
  </html>
53
- </Fragment>
51
+ </>
54
52
  }
55
53
  }
56
54
 
render/src/fragment.rs CHANGED
@@ -10,12 +10,11 @@ use crate::Renderable;
10
10
  /// # use pretty_assertions::assert_eq;
11
11
  /// # use render::html::HTML5Doctype;
12
12
  /// # use render_macros::html;
13
- /// # use render::fragment::Fragment;
14
13
  /// let result = html! {
15
- /// <Fragment>
14
+ /// <>
16
15
  /// <a />
17
16
  /// <b />
18
- /// </Fragment>
17
+ /// </>
19
18
  /// };
20
19
  /// assert_eq!(result, "<a /><b />");
21
20
  /// ```
render/src/html.rs CHANGED
@@ -9,15 +9,14 @@ use crate::Renderable;
9
9
  /// # use pretty_assertions::assert_eq;
10
10
  /// # use render::html::HTML5Doctype;
11
11
  /// # use render::html;
12
- /// # use render::fragment::Fragment;
13
12
  /// # let result =
14
13
  /// html! {
15
- /// <Fragment>
14
+ /// <>
16
15
  /// <HTML5Doctype />
17
16
  /// <html>
18
17
  /// <body />
19
18
  /// </html>
20
- /// </Fragment>
19
+ /// </>
21
20
  /// };
22
21
  /// # assert_eq!(result, "<!DOCTYPE html><html><body /></html>");
23
22
  /// ```
render/src/lib.rs CHANGED
@@ -30,8 +30,6 @@
30
30
  //! component,
31
31
  //! // A macro to compose components in JSX fashion
32
32
  //! html,
33
- //! // A component that just render its children
34
- //! Fragment,
35
33
  //! // A trait for custom components
36
34
  //! Renderable,
37
35
  //! };
@@ -40,7 +38,7 @@
40
38
  //! #[component]
41
39
  //! fn Page<'a, Children: Renderable>(title: &'a str, children: Children) -> String {
42
40
  //! html! {
43
- //! <Fragment>
41
+ //! <>
44
42
  //! <HTML5Doctype />
45
43
  //! <html>
46
44
  //! <head><title>{title}</title></head>
@@ -48,7 +46,7 @@
48
46
  //! {children}
49
47
  //! </body>
50
48
  //! </html>
51
- //! </Fragment>
49
+ //! </>
52
50
  //! }
53
51
  //! }
54
52
  //!
render_macros/src/element.rs CHANGED
@@ -5,7 +5,7 @@ use quote::{quote, ToTokens};
5
5
  use syn::parse::{Parse, ParseStream, Result};
6
6
 
7
7
  pub struct Element {
8
- name: syn::Ident,
8
+ name: syn::Path,
9
9
  attributes: ElementAttributes,
10
10
  children: Children,
11
11
  }
@@ -33,9 +33,14 @@ impl Parse for Element {
33
33
 
34
34
  impl Element {
35
35
  pub fn is_custom_element(&self) -> bool {
36
+ match self.name.get_ident() {
37
+ None => true,
38
+ Some(ident) => {
36
- let name = self.name.to_string();
39
+ let name = ident.to_string();
37
- let first_letter = name.get(0..1).unwrap();
40
+ let first_letter = name.get(0..1).unwrap();
38
- first_letter.to_uppercase() == first_letter
41
+ first_letter.to_uppercase() == first_letter
42
+ }
43
+ }
39
44
  }
40
45
  }
41
46
 
render_macros/src/element_attribute.rs CHANGED
@@ -1,4 +1,5 @@
1
1
  use quote::quote;
2
+ use std::hash::{Hash, Hasher};
2
3
  use syn::parse::{Parse, ParseStream, Result};
3
4
 
4
5
  pub enum ElementAttribute {
@@ -29,9 +30,9 @@ impl PartialEq for ElementAttribute {
29
30
 
30
31
  impl Eq for ElementAttribute {}
31
32
 
32
- impl std::hash::Hash for ElementAttribute {
33
+ impl Hash for ElementAttribute {
33
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
34
+ fn hash<H: Hasher>(&self, state: &mut H) {
34
- std::hash::Hash::hash(self.ident(), state)
35
+ Hash::hash(self.ident(), state)
35
36
  }
36
37
  }
37
38
 
render_macros/src/tags.rs CHANGED
@@ -1,20 +1,30 @@
1
1
  use crate::element_attributes::ElementAttributes;
2
+ use quote::quote;
2
3
  use syn::parse::{Parse, ParseStream, Result};
4
+ use syn::spanned::Spanned;
3
5
 
4
6
  pub struct OpenTag {
5
- pub name: syn::Ident,
7
+ pub name: syn::Path,
6
8
  pub attributes: ElementAttributes,
7
9
  pub self_closing: bool,
8
10
  }
9
11
 
12
+ fn name_or_fragment(maybe_name: Result<syn::Path>) -> syn::Path {
13
+ maybe_name.unwrap_or_else(|_| {
14
+ syn::parse_str::<syn::Path>("::render::Fragment").unwrap()
15
+ })
16
+ }
17
+
10
18
  impl Parse for OpenTag {
11
19
  fn parse(input: ParseStream) -> Result<Self> {
12
- let _starts_a_tag = input.parse::<syn::Token![<]>().is_ok();
20
+ input.parse::<syn::Token![<]>()?;
13
- let name = input.parse()?;
21
+ let maybe_name = syn::Path::parse_mod_style(input);
14
22
  let attributes = input.parse::<ElementAttributes>()?;
15
23
  let self_closing = input.parse::<syn::Token![/]>().is_ok();
16
24
  input.parse::<syn::Token![>]>()?;
17
25
 
26
+ let name = name_or_fragment(maybe_name);
27
+
18
28
  Ok(Self {
19
29
  name,
20
30
  attributes,
@@ -24,13 +34,17 @@ impl Parse for OpenTag {
24
34
  }
25
35
 
26
36
  pub struct ClosingTag {
27
- name: syn::Ident,
37
+ name: syn::Path,
28
38
  }
29
39
 
30
40
  impl ClosingTag {
31
41
  pub fn validate(&self, open_tag: &OpenTag) {
42
+ let open_tag_path = &open_tag.name;
43
+ let open_tag_path_str = quote!(#open_tag_path).to_string();
44
+ let self_path = &self.name;
45
+ let self_path_str = quote!(#self_path).to_string();
32
- if self.name != open_tag.name {
46
+ if self_path_str != open_tag_path_str {
33
- let error_message = format!("Expected closing tag for: <{}>", &open_tag.name);
47
+ let error_message = format!("Expected closing tag for: <{}>", &open_tag_path_str);
34
48
  self.name.span().unwrap().error(error_message).emit();
35
49
  }
36
50
  }
@@ -40,8 +54,10 @@ impl Parse for ClosingTag {
40
54
  fn parse(input: ParseStream) -> Result<Self> {
41
55
  input.parse::<syn::Token![<]>()?;
42
56
  input.parse::<syn::Token![/]>()?;
43
- let name = input.parse::<syn::Ident>()?;
57
+ let maybe_name = input.parse::<syn::Path>();
44
58
  input.parse::<syn::Token![>]>()?;
45
- Ok(Self { name })
59
+ Ok(Self {
60
+ name: name_or_fragment(maybe_name),
61
+ })
46
62
  }
47
63
  }
render_tests/src/lib.rs CHANGED
@@ -1,7 +1,7 @@
1
1
  #![feature(proc_macro_hygiene)]
2
2
 
3
3
  use render::html::HTML5Doctype;
4
- use render::{component, html, rsx, Fragment, Renderable};
4
+ use render::{component, html, rsx, Renderable};
5
5
 
6
6
  #[derive(Debug)]
7
7
  struct Hello<'a, T: Renderable> {
@@ -29,13 +29,13 @@ pub fn it_works() -> String {
29
29
  <em>{format!("hello world?")}</em>
30
30
  };
31
31
  let value = html! {
32
- <Fragment>
32
+ <>
33
33
  <HTML5Doctype />
34
34
  <Hello world yes={1 + 1}>
35
35
  <div>{format!("HEY!")}</div>
36
36
  {other_value}
37
37
  </Hello>
38
- </Fragment>
38
+ </>
39
39
  };
40
40
  value
41
41
  }