فهرست منبع

Merge pull request #132 from DioxusLabs/jk/partialexpansion

feat: split out rsx into its own crate
Jonathan Kelley 3 سال پیش
والد
کامیت
93b4f745af

+ 3 - 0
.github/workflows/main.yml

@@ -33,6 +33,7 @@ jobs:
           command: check
 
   test:
+    if: github.event.pull_request.draft == false
     name: Test Suite
     runs-on: ubuntu-latest
     steps:
@@ -54,6 +55,7 @@ jobs:
           args: tests
 
   fmt:
+    if: github.event.pull_request.draft == false
     name: Rustfmt
     runs-on: ubuntu-latest
     steps:
@@ -71,6 +73,7 @@ jobs:
           args: --all -- --check
 
   clippy:
+    if: github.event.pull_request.draft == false
     name: Clippy
     runs-on: ubuntu-latest
     steps:

+ 3 - 1
Cargo.toml

@@ -16,6 +16,7 @@ dioxus-core = { path = "./packages/core", version = "^0.1.9" }
 dioxus-html = { path = "./packages/html", version = "^0.1.6", optional = true }
 dioxus-core-macro = { path = "./packages/core-macro", version = "^0.1.7", optional = true }
 dioxus-hooks = { path = "./packages/hooks", version = "^0.1.7", optional = true }
+dioxus-rsx = { path = "./packages/rsx", optional = true }
 fermi = { path = "./packages/fermi", version = "^0.1.0", optional = true }
 
 dioxus-web = { path = "./packages/web", version = "^0.0.5", optional = true }
@@ -30,7 +31,7 @@ dioxus-interpreter-js = { path = "./packages/interpreter", version = "^0.0.0", o
 [features]
 default = ["macro", "hooks", "html"]
 
-macro = ["dioxus-core-macro"]
+macro = ["dioxus-core-macro", "dioxus-rsx"]
 hooks = ["dioxus-hooks"]
 html = ["dioxus-html"]
 ssr = ["dioxus-ssr"]
@@ -42,6 +43,7 @@ router = ["dioxus-router"]
 members = [
     "packages/core",
     "packages/core-macro",
+    "packages/rsx",
     "packages/html",
     "packages/hooks",
     "packages/web",

+ 1 - 0
packages/core-macro/Cargo.toml

@@ -15,6 +15,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"]
 proc-macro = true
 
 [dependencies]
+dioxus-rsx = { path = "../rsx" }
 proc-macro-error = "1.0.4"
 proc-macro2 = { version = "1.0.6" }
 quote = "1.0"

+ 0 - 443
packages/core-macro/src/htm.rs

@@ -1,443 +0,0 @@
-//!
-//! TODO:
-//! - [ ] Support for VComponents
-//! - [ ] Support for inline format in text
-//! - [ ] Support for expressions in attribute positions
-//! - [ ] Support for iterators
-//! - [ ] support for inline html!
-//!
-//!
-//!
-//!
-//!
-//!
-//!
-
-use {
-    proc_macro2::TokenStream as TokenStream2,
-    quote::{quote, ToTokens, TokenStreamExt},
-    syn::{
-        ext::IdentExt,
-        parse::{Parse, ParseStream},
-        token, Error, Expr, ExprClosure, Ident, LitStr, Result, Token,
-    },
-};
-
-// ==============================================
-// Parse any stream coming from the html! macro
-// ==============================================
-pub struct HtmlRender {
-    kind: NodeOrList,
-}
-
-impl Parse for HtmlRender {
-    fn parse(input: ParseStream) -> Result<Self> {
-        if input.peek(LitStr) {
-            return input.parse::<LitStr>()?.parse::<HtmlRender>();
-        }
-
-        // let __cx: Ident = s.parse()?;
-        // s.parse::<Token![,]>()?;
-        // if elements are in an array, return a bumpalo::collections::Vec rather than a Node.
-        let kind = if input.peek(token::Bracket) {
-            let nodes_toks;
-            syn::bracketed!(nodes_toks in input);
-            let mut nodes: Vec<MaybeExpr<Node>> = vec![nodes_toks.parse()?];
-            while nodes_toks.peek(Token![,]) {
-                nodes_toks.parse::<Token![,]>()?;
-                nodes.push(nodes_toks.parse()?);
-            }
-            NodeOrList::List(NodeList(nodes))
-        } else {
-            NodeOrList::Node(input.parse()?)
-        };
-        Ok(HtmlRender { kind })
-    }
-}
-
-impl ToTokens for HtmlRender {
-    fn to_tokens(&self, out_tokens: &mut TokenStream2) {
-        let new_toks = ToToksCtx::new(&self.kind).to_token_stream();
-
-        // create a lazy tree that accepts a bump allocator
-        let final_tokens = quote! {
-            dioxus::prelude::LazyNodes::new(move |__cx| {
-                let bump = __cx.bump();
-
-                #new_toks
-            })
-        };
-
-        final_tokens.to_tokens(out_tokens);
-    }
-}
-
-/// =============================================
-/// Parse any child as a node or list of nodes
-/// =============================================
-/// - [ ] Allow iterators
-///
-///
-enum NodeOrList {
-    Node(Node),
-    List(NodeList),
-}
-
-impl ToTokens for ToToksCtx<&NodeOrList> {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        match self.inner {
-            NodeOrList::Node(node) => self.recurse(node).to_tokens(tokens),
-            NodeOrList::List(list) => self.recurse(list).to_tokens(tokens),
-        }
-    }
-}
-
-struct NodeList(Vec<MaybeExpr<Node>>);
-
-impl ToTokens for ToToksCtx<&NodeList> {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        let nodes = self.inner.0.iter().map(|node| self.recurse(node));
-        tokens.append_all(quote! {
-            dioxus::bumpalo::vec![in bump;
-                #(#nodes),*
-            ]
-        });
-    }
-}
-
-enum Node {
-    Element(Element),
-    Text(TextNode),
-}
-
-impl ToTokens for ToToksCtx<&Node> {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        match &self.inner {
-            Node::Element(el) => self.recurse(el).to_tokens(tokens),
-            Node::Text(txt) => self.recurse(txt).to_tokens(tokens),
-        }
-    }
-}
-
-impl Node {
-    fn _peek(s: ParseStream) -> bool {
-        (s.peek(Token![<]) && !s.peek2(Token![/])) || s.peek(token::Brace) || s.peek(LitStr)
-    }
-}
-
-impl Parse for Node {
-    fn parse(s: ParseStream) -> Result<Self> {
-        Ok(if s.peek(Token![<]) {
-            Node::Element(s.parse()?)
-        } else {
-            Node::Text(s.parse()?)
-        })
-    }
-}
-
-/// =======================================
-/// Parse the VNode::Element type
-/// =======================================
-/// - [ ] Allow VComponent
-///
-///
-struct Element {
-    name: Ident,
-    attrs: Vec<Attr>,
-    children: MaybeExpr<Vec<Node>>,
-}
-
-impl ToTokens for ToToksCtx<&Element> {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        // let __cx = self.__cx;
-        let name = &self.inner.name;
-        // let name = &self.inner.name.to_string();
-        tokens.append_all(quote! {
-            __cx.element(dioxus_elements::#name)
-            // dioxus::builder::ElementBuilder::new( #name)
-        });
-        for attr in self.inner.attrs.iter() {
-            self.recurse(attr).to_tokens(tokens);
-        }
-
-        // if is_valid_svg_tag(&name.to_string()) {
-        //     tokens.append_all(quote! {
-        //         .namespace(Some("http://www.w3.org/2000/svg"))
-        //     });
-        // }
-
-        match &self.inner.children {
-            MaybeExpr::Expr(expr) => tokens.append_all(quote! {
-                .children(#expr)
-            }),
-            MaybeExpr::Literal(nodes) => {
-                let mut children = nodes.iter();
-                if let Some(child) = children.next() {
-                    let mut inner_toks = TokenStream2::new();
-                    self.recurse(child).to_tokens(&mut inner_toks);
-                    for child in children {
-                        quote!(,).to_tokens(&mut inner_toks);
-                        self.recurse(child).to_tokens(&mut inner_toks);
-                    }
-                    tokens.append_all(quote! {
-                        .children([#inner_toks])
-                    });
-                }
-            }
-        }
-        tokens.append_all(quote! {
-            .finish()
-        });
-    }
-}
-
-impl Parse for Element {
-    fn parse(s: ParseStream) -> Result<Self> {
-        s.parse::<Token![<]>()?;
-        let name = Ident::parse_any(s)?;
-        let mut attrs = vec![];
-        let _children: Vec<Node> = vec![];
-
-        // keep looking for attributes
-        while !s.peek(Token![>]) {
-            // self-closing
-            if s.peek(Token![/]) {
-                s.parse::<Token![/]>()?;
-                s.parse::<Token![>]>()?;
-                return Ok(Self {
-                    name,
-                    attrs,
-                    children: MaybeExpr::Literal(vec![]),
-                });
-            }
-            attrs.push(s.parse()?);
-        }
-        s.parse::<Token![>]>()?;
-
-        // Contents of an element can either be a brace (in which case we just copy verbatim), or a
-        // sequence of nodes.
-        let children = if s.peek(token::Brace) {
-            // expr
-            let content;
-            syn::braced!(content in s);
-            MaybeExpr::Expr(content.parse()?)
-        } else {
-            // nodes
-            let mut children = vec![];
-            while !(s.peek(Token![<]) && s.peek2(Token![/])) {
-                children.push(s.parse()?);
-            }
-            MaybeExpr::Literal(children)
-        };
-
-        // closing element
-        s.parse::<Token![<]>()?;
-        s.parse::<Token![/]>()?;
-        let close = Ident::parse_any(s)?;
-        if close != name {
-            return Err(Error::new_spanned(
-                close,
-                "closing element does not match opening",
-            ));
-        }
-        s.parse::<Token![>]>()?;
-
-        Ok(Self {
-            name,
-            attrs,
-            children,
-        })
-    }
-}
-
-/// =======================================
-/// Parse a VElement's Attributes
-/// =======================================
-/// - [ ] Allow expressions as attribute
-///
-///
-struct Attr {
-    name: Ident,
-    ty: AttrType,
-}
-
-impl Parse for Attr {
-    fn parse(s: ParseStream) -> Result<Self> {
-        let mut name = Ident::parse_any(s)?;
-        let name_str = name.to_string();
-        s.parse::<Token![=]>()?;
-
-        // Check if this is an event handler
-        // If so, parse into literal tokens
-        let ty = if name_str.starts_with("on") {
-            // remove the "on" bit
-            name = Ident::new(name_str.trim_start_matches("on"), name.span());
-            let content;
-            syn::braced!(content in s);
-            // AttrType::Value(content.parse()?)
-            AttrType::Event(content.parse()?)
-        // AttrType::Event(content.parse()?)
-        } else {
-            let lit_str = if name_str == "style" && s.peek(token::Brace) {
-                // special-case to deal with literal styles.
-                let outer;
-                syn::braced!(outer in s);
-                // double brace for inline style.
-                // todo!("Style support not ready yet");
-
-                // if outer.peek(token::Brace) {
-                //     let inner;
-                //     syn::braced!(inner in outer);
-                //     let styles: Styles = inner.parse()?;
-                //     MaybeExpr::Literal(LitStr::new(&styles.to_string(), Span::call_site()))
-                // } else {
-                // just parse as an expression
-                MaybeExpr::Expr(outer.parse()?)
-            // }
-            } else {
-                s.parse()?
-            };
-            AttrType::Value(lit_str)
-        };
-        Ok(Attr { name, ty })
-    }
-}
-
-impl ToTokens for ToToksCtx<&Attr> {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        let name = self.inner.name.to_string();
-        let _attr_stream = TokenStream2::new();
-        match &self.inner.ty {
-            AttrType::Value(value) => {
-                let value = self.recurse(value);
-                if name == "xmlns" {
-                    tokens.append_all(quote! {
-                        .namespace(Some(#value))
-                    });
-                } else {
-                    tokens.append_all(quote! {
-                        .attr(#name, format_args_f!(#value))
-                    });
-                }
-            }
-            AttrType::Event(event) => {
-                tokens.append_all(quote! {
-                    .on(#name, #event)
-                });
-            }
-        }
-    }
-}
-
-enum AttrType {
-    Value(MaybeExpr<LitStr>),
-    Event(ExprClosure),
-    // todo Bool(MaybeExpr<LitBool>)
-}
-
-/// =======================================
-/// Parse just plain text
-/// =======================================
-/// - [ ] Perform formatting automatically
-///
-///
-struct TextNode(MaybeExpr<LitStr>);
-
-impl Parse for TextNode {
-    fn parse(s: ParseStream) -> Result<Self> {
-        Ok(Self(s.parse()?))
-    }
-}
-
-impl ToTokens for ToToksCtx<&TextNode> {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        let mut token_stream = TokenStream2::new();
-        self.recurse(&self.inner.0).to_tokens(&mut token_stream);
-        tokens.append_all(quote! {
-            __cx.text(format_args_f!(#token_stream))
-        });
-    }
-}
-
-#[allow(clippy::large_enum_variant)]
-enum MaybeExpr<T> {
-    Literal(T),
-    Expr(Expr),
-}
-
-impl<T: Parse> Parse for MaybeExpr<T> {
-    fn parse(s: ParseStream) -> Result<Self> {
-        if s.peek(token::Brace) {
-            let content;
-            syn::braced!(content in s);
-            Ok(MaybeExpr::Expr(content.parse()?))
-        } else {
-            Ok(MaybeExpr::Literal(s.parse()?))
-        }
-    }
-}
-
-impl<'a, T> ToTokens for ToToksCtx<&'a MaybeExpr<T>>
-where
-    T: 'a,
-    ToToksCtx<&'a T>: ToTokens,
-{
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        match &self.inner {
-            MaybeExpr::Literal(v) => self.recurse(v).to_tokens(tokens),
-            MaybeExpr::Expr(expr) => expr.to_tokens(tokens),
-        }
-    }
-}
-
-/// ToTokens context
-struct ToToksCtx<T> {
-    inner: T,
-}
-
-impl<'a, T> ToToksCtx<T> {
-    fn new(inner: T) -> Self {
-        ToToksCtx { inner }
-    }
-
-    fn recurse<U>(&self, inner: U) -> ToToksCtx<U> {
-        ToToksCtx { inner }
-    }
-}
-
-impl ToTokens for ToToksCtx<&LitStr> {
-    fn to_tokens(&self, tokens: &mut TokenStream2) {
-        self.inner.to_tokens(tokens)
-    }
-}
-
-#[cfg(test)]
-mod test {
-    fn parse(input: &str) -> super::Result<super::HtmlRender> {
-        syn::parse_str(input)
-    }
-
-    #[test]
-    fn div() {
-        parse("bump, <div class=\"test\"/>").unwrap();
-    }
-
-    #[test]
-    fn nested() {
-        parse("bump, <div class=\"test\"><div />\"text\"</div>").unwrap();
-    }
-
-    #[test]
-    fn complex() {
-        parse(
-            "bump,
-            <section style={{
-                display: flex;
-                flex-direction: column;
-                max-width: 95%;
-            }} class=\"map-panel\">{contact_details}</section>
-        ",
-        )
-        .unwrap();
-    }
-}

+ 4 - 36
packages/core-macro/src/lib.rs

@@ -2,11 +2,9 @@ use proc_macro::TokenStream;
 use quote::ToTokens;
 use syn::parse_macro_input;
 
-pub(crate) mod ifmt;
-pub(crate) mod inlineprops;
-pub(crate) mod props;
-pub(crate) mod router;
-pub(crate) mod rsx;
+mod ifmt;
+mod inlineprops;
+mod props;
 
 #[proc_macro]
 pub fn format_args_f(input: TokenStream) -> TokenStream {
@@ -180,42 +178,12 @@ pub fn derive_typed_builder(input: proc_macro::TokenStream) -> proc_macro::Token
 #[proc_macro_error::proc_macro_error]
 #[proc_macro]
 pub fn rsx(s: TokenStream) -> TokenStream {
-    match syn::parse::<rsx::CallBody>(s) {
+    match syn::parse::<dioxus_rsx::CallBody>(s) {
         Err(err) => err.to_compile_error().into(),
         Ok(stream) => stream.to_token_stream().into(),
     }
 }
 
-/// Derive macro used to mark an enum as Routable.
-///
-/// This macro can only be used on enums. Every varient of the macro needs to be marked
-/// with the `at` attribute to specify the URL of the route. It generates an implementation of
-///  `yew_router::Routable` trait and `const`s for the routes passed which are used with `Route`
-/// component.
-///
-/// # Example
-///
-/// ```
-/// # use yew_router::Routable;
-/// #[derive(Debug, Clone, Copy, PartialEq, Routable)]
-/// enum Routes {
-///     #[at("/")]
-///     Home,
-///     #[at("/secure")]
-///     Secure,
-///     #[at("/profile/{id}")]
-///     Profile(u32),
-///     #[at("/404")]
-///     NotFound,
-/// }
-/// ```
-#[proc_macro_derive(Routable, attributes(at, not_found))]
-pub fn routable_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
-    use router::{routable_derive_impl, Routable};
-    let input = parse_macro_input!(input as Routable);
-    routable_derive_impl(input).into()
-}
-
 /// Derive props for a component within the component definition.
 ///
 /// This macro provides a simple transformation from `Scope<{}>` to `Scope<P>`,

+ 0 - 214
packages/core-macro/src/router.rs

@@ -1,214 +0,0 @@
-#![allow(dead_code)]
-
-use proc_macro2::TokenStream;
-use quote::quote;
-use syn::parse::{Parse, ParseStream};
-use syn::punctuated::Punctuated;
-use syn::spanned::Spanned;
-use syn::{Data, DeriveInput, Fields, Ident, LitStr, Variant};
-
-const AT_ATTR_IDENT: &str = "at";
-const NOT_FOUND_ATTR_IDENT: &str = "not_found";
-
-pub struct Routable {
-    ident: Ident,
-    ats: Vec<LitStr>,
-    variants: Punctuated<Variant, syn::token::Comma>,
-    not_found_route: Option<Ident>,
-}
-
-impl Parse for Routable {
-    fn parse(input: ParseStream) -> syn::Result<Self> {
-        let DeriveInput { ident, data, .. } = input.parse()?;
-
-        let data = match data {
-            Data::Enum(data) => data,
-            Data::Struct(s) => {
-                return Err(syn::Error::new(
-                    s.struct_token.span(),
-                    "expected enum, found struct",
-                ))
-            }
-            Data::Union(u) => {
-                return Err(syn::Error::new(
-                    u.union_token.span(),
-                    "expected enum, found union",
-                ))
-            }
-        };
-
-        let (not_found_route, ats) = parse_variants_attributes(&data.variants)?;
-
-        Ok(Self {
-            ident,
-            variants: data.variants,
-            ats,
-            not_found_route,
-        })
-    }
-}
-
-fn parse_variants_attributes(
-    variants: &Punctuated<Variant, syn::token::Comma>,
-) -> syn::Result<(Option<Ident>, Vec<LitStr>)> {
-    let mut not_founds = vec![];
-    let mut ats: Vec<LitStr> = vec![];
-
-    let mut not_found_attrs = vec![];
-
-    for variant in variants.iter() {
-        if let Fields::Unnamed(ref field) = variant.fields {
-            return Err(syn::Error::new(
-                field.span(),
-                "only named fields are supported",
-            ));
-        }
-
-        let attrs = &variant.attrs;
-        let at_attrs = attrs
-            .iter()
-            .filter(|attr| attr.path.is_ident(AT_ATTR_IDENT))
-            .collect::<Vec<_>>();
-
-        let attr = match at_attrs.len() {
-            1 => *at_attrs.first().unwrap(),
-            0 => {
-                return Err(syn::Error::new(
-                    variant.span(),
-                    format!(
-                        "{} attribute must be present on every variant",
-                        AT_ATTR_IDENT
-                    ),
-                ))
-            }
-            _ => {
-                return Err(syn::Error::new_spanned(
-                    quote! { #(#at_attrs)* },
-                    format!("only one {} attribute must be present", AT_ATTR_IDENT),
-                ))
-            }
-        };
-
-        let lit = attr.parse_args::<LitStr>()?;
-        ats.push(lit);
-
-        for attr in attrs.iter() {
-            if attr.path.is_ident(NOT_FOUND_ATTR_IDENT) {
-                not_found_attrs.push(attr);
-                not_founds.push(variant.ident.clone())
-            }
-        }
-    }
-
-    if not_founds.len() > 1 {
-        return Err(syn::Error::new_spanned(
-            quote! { #(#not_found_attrs)* },
-            format!("there can only be one {}", NOT_FOUND_ATTR_IDENT),
-        ));
-    }
-
-    Ok((not_founds.into_iter().next(), ats))
-}
-
-impl Routable {
-    // fn build_from_path(&self) -> TokenStream {
-    //     let from_path_matches = self.variants.iter().enumerate().map(|(i, variant)| {
-    //         let ident = &variant.ident;
-    //         let right = match &variant.fields {
-    //             Fields::Unit => quote! { Self::#ident },
-    //             Fields::Named(field) => {
-    //                 let fields = field.named.iter().map(|it| {
-    //                     //named fields have idents
-    //                     it.ident.as_ref().unwrap()
-    //                 });
-    //                 quote! { Self::#ident { #(#fields: params.get(stringify!(#fields))?.parse().ok()?,)* } }
-    //             }
-    //             Fields::Unnamed(_) => unreachable!(), // already checked
-    //         };
-
-    //         let left = self.ats.get(i).unwrap();
-    //         quote! {
-    //             #left => ::std::option::Option::Some(#right)
-    //         }
-    //     });
-
-    //     quote! {
-    //         fn from_path(path: &str, params: &::std::collections::HashMap<&str, &str>) -> ::std::option::Option<Self> {
-    //             match path {
-    //                 #(#from_path_matches),*,
-    //                 _ => ::std::option::Option::None,
-    //             }
-    //         }
-    //     }
-    // }
-
-    // fn build_to_path(&self) -> TokenStream {
-    //     let to_path_matches = self.variants.iter().enumerate().map(|(i, variant)| {
-    //         let ident = &variant.ident;
-    //         let mut right = self.ats.get(i).unwrap().value();
-
-    //         match &variant.fields {
-    //             Fields::Unit => quote! { Self::#ident => ::std::string::ToString::to_string(#right) },
-    //             Fields::Named(field) => {
-    //                 let fields = field
-    //                     .named
-    //                     .iter()
-    //                     .map(|it| it.ident.as_ref().unwrap())
-    //                     .collect::<Vec<_>>();
-
-    //                 for field in fields.iter() {
-    //                     // :param -> {param}
-    //                     // so we can pass it to `format!("...", param)`
-    //                     right = right.replace(&format!(":{}", field), &format!("{{{}}}", field))
-    //                 }
-
-    //                 quote! {
-    //                     Self::#ident { #(#fields),* } => ::std::format!(#right, #(#fields = #fields),*)
-    //                 }
-    //             }
-    //             Fields::Unnamed(_) => unreachable!(), // already checked
-    //         }
-    //     });
-
-    //     quote! {
-    //         fn to_path(&self) -> ::std::string::String {
-    //             match self {
-    //                 #(#to_path_matches),*,
-    //             }
-    //         }
-    //     }
-    // }
-}
-
-pub fn routable_derive_impl(input: Routable) -> TokenStream {
-    let Routable {
-        // ats,
-        // not_found_route,
-        // ident,
-        ..
-    } = &input;
-
-    // let from_path = input.build_from_path();
-    // let to_path = input.build_to_path();
-
-    quote! {
-        // #[automatically_derived]
-        // impl ::dioxus::router::Routable for #ident {
-
-        //     fn recognize(pathname: &str) -> ::std::option::Option<Self> {
-        //         todo!()
-        //         // ::std::thread_local! {
-        //         //     static ROUTER: ::dioxus::router::__macro::Router = ::dioxus::router::__macro::build_router::<#ident>();
-        //         // }
-        //         // let route = ROUTER.with(|router| ::dioxus::router::__macro::recognize_with_router(router, pathname));
-        //         // {
-        //         //     let route = ::std::clone::Clone::clone(&route);
-        //         //     #cache_thread_local_ident.with(move |val| {
-        //         //         *val.borrow_mut() = route;
-        //         //     });
-        //         // }
-        //         // route
-        //     }
-        // }
-    }
-}

+ 0 - 84
packages/core-macro/src/rsxtemplate.rs

@@ -1,84 +0,0 @@
-use crate::{rsx::RsxBody, util::is_valid_svg_tag};
-
-use {
-    proc_macro::TokenStream,
-    proc_macro2::{Span, TokenStream as TokenStream2},
-    quote::{quote, ToTokens, TokenStreamExt},
-    syn::{
-        ext::IdentExt,
-        parse::{Parse, ParseStream},
-        token, Error, Expr, ExprClosure, Ident, LitBool, LitStr, Path, Result, Token,
-    },
-};
-
-// ==============================================
-// Parse any stream coming from the html! macro
-// ==============================================
-pub struct RsxTemplate {
-    inner: RsxBody,
-}
-
-impl Parse for RsxTemplate {
-    fn parse(s: ParseStream) -> Result<Self> {
-        if s.peek(LitStr) {
-            use std::str::FromStr;
-
-            let lit = s.parse::<LitStr>()?;
-            let g = lit.span();
-            let mut value = lit.value();
-            if value.ends_with('\n') {
-                value.pop();
-                if value.ends_with('\r') {
-                    value.pop();
-                }
-            }
-            let lit = LitStr::new(&value, lit.span());
-
-            // panic!("{:#?}", lit);
-            match lit.parse::<crate::rsx::RsxBody>() {
-                Ok(r) => Ok(Self { inner: r }),
-                Err(e) => Err(e),
-            }
-        } else {
-            panic!("Not a str lit")
-        }
-        // let t = s.parse::<LitStr>()?;
-
-        // let new_stream = TokenStream::from(t.to_s)
-
-        // let cx: Ident = s.parse()?;
-        // s.parse::<Token![,]>()?;
-        // if elements are in an array, return a bumpalo::collections::Vec rather than a Node.
-        // let kind = if s.peek(token::Bracket) {
-        //     let nodes_toks;
-        //     syn::bracketed!(nodes_toks in s);
-        //     let mut nodes: Vec<MaybeExpr<Node>> = vec![nodes_toks.parse()?];
-        //     while nodes_toks.peek(Token![,]) {
-        //         nodes_toks.parse::<Token![,]>()?;
-        //         nodes.push(nodes_toks.parse()?);
-        //     }
-        //     NodeOrList::List(NodeList(nodes))
-        // } else {
-        //     NodeOrList::Node(s.parse()?)
-        // };
-        // Ok(HtmlRender { kind })
-    }
-}
-
-impl ToTokens for RsxTemplate {
-    fn to_tokens(&self, out_tokens: &mut TokenStream2) {
-        self.inner.to_tokens(out_tokens);
-        // let new_toks = ToToksCtx::new(&self.kind).to_token_stream();
-
-        // // create a lazy tree that accepts a bump allocator
-        // let final_tokens = quote! {
-        //     dioxus::prelude::LazyNodes::new(move |cx| {
-        //         let bump = &cx.bump();
-
-        //         #new_toks
-        //     })
-        // };
-
-        // final_tokens.to_tokens(out_tokens);
-    }
-}

+ 13 - 0
packages/rsx/Cargo.toml

@@ -0,0 +1,13 @@
+[package]
+name = "dioxus-rsx"
+version = "0.0.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+once_cell = "1.8"
+proc-macro-error = "1.0.4"
+proc-macro2 = { version = "1.0.6" }
+quote = "1.0"
+syn = { version = "1.0.11", features = ["full", "extra-traits"] }

+ 4 - 4
packages/core-macro/src/rsx/component.rs → packages/rsx/src/component.rs

@@ -23,10 +23,10 @@ use syn::{
 };
 
 pub struct Component {
-    name: syn::Path,
-    body: Vec<ComponentField>,
-    children: Vec<BodyNode>,
-    manual_props: Option<Expr>,
+    pub name: syn::Path,
+    pub body: Vec<ComponentField>,
+    pub children: Vec<BodyNode>,
+    pub manual_props: Option<Expr>,
 }
 
 impl Parse for Component {

+ 27 - 23
packages/core-macro/src/rsx/element.rs → packages/rsx/src/element.rs

@@ -11,12 +11,11 @@ use syn::{
 // Parse the VNode::Element type
 // =======================================
 pub struct Element {
-    name: Ident,
-    key: Option<LitStr>,
-    attributes: Vec<ElementAttrNamed>,
-    listeners: Vec<ElementAttrNamed>,
-    children: Vec<BodyNode>,
-    _is_static: bool,
+    pub name: Ident,
+    pub key: Option<LitStr>,
+    pub attributes: Vec<ElementAttrNamed>,
+    pub children: Vec<BodyNode>,
+    pub _is_static: bool,
 }
 
 impl Parse for Element {
@@ -28,7 +27,6 @@ impl Parse for Element {
         syn::braced!(content in stream);
 
         let mut attributes: Vec<ElementAttrNamed> = vec![];
-        let mut listeners: Vec<ElementAttrNamed> = vec![];
         let mut children: Vec<BodyNode> = vec![];
         let mut key = None;
         let mut _el_ref = None;
@@ -54,6 +52,7 @@ impl Parse for Element {
                     });
                 } else {
                     let value = content.parse::<Expr>()?;
+
                     attributes.push(ElementAttrNamed {
                         el_name: el_name.clone(),
                         attr: ElementAttr::CustomAttrExpression { name, value },
@@ -82,7 +81,7 @@ impl Parse for Element {
                 content.parse::<Token![:]>()?;
 
                 if name_str.starts_with("on") {
-                    listeners.push(ElementAttrNamed {
+                    attributes.push(ElementAttrNamed {
                         el_name: el_name.clone(),
                         attr: ElementAttr::EventTokens {
                             name,
@@ -182,7 +181,6 @@ impl Parse for Element {
             name: el_name,
             attributes,
             children,
-            listeners,
             _is_static: false,
         })
     }
@@ -193,14 +191,21 @@ impl ToTokens for Element {
         let name = &self.name;
         let children = &self.children;
 
-        let listeners = &self.listeners;
-        let attr = &self.attributes;
-
         let key = match &self.key {
             Some(ty) => quote! { Some(format_args_f!(#ty)) },
             None => quote! { None },
         };
 
+        let listeners = self
+            .attributes
+            .iter()
+            .filter(|f| matches!(f.attr, ElementAttr::EventTokens { .. }));
+
+        let attr = self
+            .attributes
+            .iter()
+            .filter(|f| !matches!(f.attr, ElementAttr::EventTokens { .. }));
+
         tokens.append_all(quote! {
             __cx.element(
                 dioxus_elements::#name,
@@ -213,29 +218,28 @@ impl ToTokens for Element {
     }
 }
 
-enum ElementAttr {
-    // attribute: "valuee {}"
+pub enum ElementAttr {
+    /// attribute: "valuee {}"
     AttrText { name: Ident, value: LitStr },
 
-    // attribute: true,
+    /// attribute: true,
     AttrExpression { name: Ident, value: Expr },
 
-    // "attribute": "value {}"
+    /// "attribute": "value {}"
     CustomAttrText { name: LitStr, value: LitStr },
 
-    // "attribute": true,
+    /// "attribute": true,
     CustomAttrExpression { name: LitStr, value: Expr },
 
-    // // onclick: move |_| {}
+    // /// onclick: move |_| {}
     // EventClosure { name: Ident, closure: ExprClosure },
-
-    // onclick: {}
+    /// onclick: {}
     EventTokens { name: Ident, tokens: Expr },
 }
 
-struct ElementAttrNamed {
-    el_name: Ident,
-    attr: ElementAttr,
+pub struct ElementAttrNamed {
+    pub el_name: Ident,
+    pub attr: ElementAttr,
 }
 
 impl ToTokens for ElementAttrNamed {

+ 4 - 2
packages/core-macro/src/rsx/mod.rs → packages/rsx/src/lib.rs

@@ -15,6 +15,8 @@ mod component;
 mod element;
 mod node;
 
+pub mod pretty;
+
 // Re-export the namespaces into each other
 pub use component::*;
 pub use element::*;
@@ -29,8 +31,8 @@ use syn::{
 };
 
 pub struct CallBody {
-    custom_context: Option<Ident>,
-    roots: Vec<BodyNode>,
+    pub custom_context: Option<Ident>,
+    pub roots: Vec<BodyNode>,
 }
 
 impl Parse for CallBody {

+ 3 - 1
packages/core-macro/src/rsx/node.rs → packages/rsx/src/node.rs

@@ -4,7 +4,7 @@ use proc_macro2::TokenStream as TokenStream2;
 use quote::{quote, ToTokens, TokenStreamExt};
 use syn::{
     parse::{Parse, ParseStream},
-    token, Expr, LitStr, Result, Token,
+    token, Attribute, Expr, LitStr, Result, Token,
 };
 
 /*
@@ -20,6 +20,7 @@ pub enum BodyNode {
     Component(Component),
     Text(LitStr),
     RawExpr(Expr),
+    Meta(Attribute),
 }
 
 impl Parse for BodyNode {
@@ -79,6 +80,7 @@ impl ToTokens for BodyNode {
             BodyNode::RawExpr(exp) => tokens.append_all(quote! {
                  __cx.fragment_from_iter(#exp)
             }),
+            BodyNode::Meta(_) => {}
         }
     }
 }

+ 1 - 0
packages/rsx/src/pretty.rs

@@ -0,0 +1 @@
+//! pretty printer for rsx!

+ 1 - 1
src/lib.rs

@@ -353,7 +353,7 @@ pub mod events {
 
 pub mod prelude {
     pub use dioxus_core::prelude::*;
-    pub use dioxus_core_macro::{format_args_f, inline_props, rsx, Props, Routable};
+    pub use dioxus_core_macro::{format_args_f, inline_props, rsx, Props};
     pub use dioxus_elements::{GlobalAttributes, SvgAttributes};
     pub use dioxus_hooks::*;
     pub use dioxus_html as dioxus_elements;