Merge pull request #132 from DioxusLabs/jk/partialexpansion
feat: split out rsx into its own crate
This commit is contained in:
14 files changed
+64
-809
No files matched your search
@@ -33,6 +33,7 @@ jobs:
|
|||||||
command: check
|
command: check
|
||||||
|
|
||||||
test:
|
test:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
name: Test Suite
|
name: Test Suite
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -54,6 +55,7 @@ jobs:
|
|||||||
args: tests
|
args: tests
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
name: Rustfmt
|
name: Rustfmt
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
@@ -71,6 +73,7 @@ jobs:
|
|||||||
args: --all -- --check
|
args: --all -- --check
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
|
if: github.event.pull_request.draft == false
|
||||||
name: Clippy
|
name: Clippy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
+3
-1
@@ -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-html = { path = "./packages/html", version = "^0.1.6", optional = true }
|
||||||
dioxus-core-macro = { path = "./packages/core-macro", version = "^0.1.7", 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-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 }
|
fermi = { path = "./packages/fermi", version = "^0.1.0", optional = true }
|
||||||
|
|
||||||
dioxus-web = { path = "./packages/web", version = "^0.0.5", 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]
|
[features]
|
||||||
default = ["macro", "hooks", "html"]
|
default = ["macro", "hooks", "html"]
|
||||||
|
|
||||||
macro = ["dioxus-core-macro"]
|
macro = ["dioxus-core-macro", "dioxus-rsx"]
|
||||||
hooks = ["dioxus-hooks"]
|
hooks = ["dioxus-hooks"]
|
||||||
html = ["dioxus-html"]
|
html = ["dioxus-html"]
|
||||||
ssr = ["dioxus-ssr"]
|
ssr = ["dioxus-ssr"]
|
||||||
@@ -42,6 +43,7 @@ router = ["dioxus-router"]
|
|||||||
members = [
|
members = [
|
||||||
"packages/core",
|
"packages/core",
|
||||||
"packages/core-macro",
|
"packages/core-macro",
|
||||||
|
"packages/rsx",
|
||||||
"packages/html",
|
"packages/html",
|
||||||
"packages/hooks",
|
"packages/hooks",
|
||||||
"packages/web",
|
"packages/web",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ keywords = ["dom", "ui", "gui", "react", "wasm"]
|
|||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
dioxus-rsx = { path = "../rsx" }
|
||||||
proc-macro-error = "1.0.4"
|
proc-macro-error = "1.0.4"
|
||||||
proc-macro2 = { version = "1.0.6" }
|
proc-macro2 = { version = "1.0.6" }
|
||||||
quote = "1.0"
|
quote = "1.0"
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,11 +2,9 @@ use proc_macro::TokenStream;
|
|||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::parse_macro_input;
|
use syn::parse_macro_input;
|
||||||
|
|
||||||
pub(crate) mod ifmt;
|
mod ifmt;
|
||||||
pub(crate) mod inlineprops;
|
mod inlineprops;
|
||||||
pub(crate) mod props;
|
mod props;
|
||||||
pub(crate) mod router;
|
|
||||||
pub(crate) mod rsx;
|
|
||||||
|
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn format_args_f(input: TokenStream) -> TokenStream {
|
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_error::proc_macro_error]
|
||||||
#[proc_macro]
|
#[proc_macro]
|
||||||
pub fn rsx(s: TokenStream) -> TokenStream {
|
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(),
|
Err(err) => err.to_compile_error().into(),
|
||||||
Ok(stream) => stream.to_token_stream().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.
|
/// Derive props for a component within the component definition.
|
||||||
///
|
///
|
||||||
/// This macro provides a simple transformation from `Scope<{}>` to `Scope<P>`,
|
/// This macro provides a simple transformation from `Scope<{}>` to `Scope<P>`,
|
||||||
|
|||||||
@@ -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
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"] }
|
||||||
@@ -23,10 +23,10 @@ use syn::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub struct Component {
|
pub struct Component {
|
||||||
name: syn::Path,
|
pub name: syn::Path,
|
||||||
body: Vec<ComponentField>,
|
pub body: Vec<ComponentField>,
|
||||||
children: Vec<BodyNode>,
|
pub children: Vec<BodyNode>,
|
||||||
manual_props: Option<Expr>,
|
pub manual_props: Option<Expr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Component {
|
impl Parse for Component {
|
||||||
@@ -11,12 +11,11 @@ use syn::{
|
|||||||
// Parse the VNode::Element type
|
// Parse the VNode::Element type
|
||||||
// =======================================
|
// =======================================
|
||||||
pub struct Element {
|
pub struct Element {
|
||||||
name: Ident,
|
pub name: Ident,
|
||||||
key: Option<LitStr>,
|
pub key: Option<LitStr>,
|
||||||
attributes: Vec<ElementAttrNamed>,
|
pub attributes: Vec<ElementAttrNamed>,
|
||||||
listeners: Vec<ElementAttrNamed>,
|
pub children: Vec<BodyNode>,
|
||||||
children: Vec<BodyNode>,
|
pub _is_static: bool,
|
||||||
_is_static: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Element {
|
impl Parse for Element {
|
||||||
@@ -28,7 +27,6 @@ impl Parse for Element {
|
|||||||
syn::braced!(content in stream);
|
syn::braced!(content in stream);
|
||||||
|
|
||||||
let mut attributes: Vec<ElementAttrNamed> = vec![];
|
let mut attributes: Vec<ElementAttrNamed> = vec![];
|
||||||
let mut listeners: Vec<ElementAttrNamed> = vec![];
|
|
||||||
let mut children: Vec<BodyNode> = vec![];
|
let mut children: Vec<BodyNode> = vec![];
|
||||||
let mut key = None;
|
let mut key = None;
|
||||||
let mut _el_ref = None;
|
let mut _el_ref = None;
|
||||||
@@ -54,6 +52,7 @@ impl Parse for Element {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let value = content.parse::<Expr>()?;
|
let value = content.parse::<Expr>()?;
|
||||||
|
|
||||||
attributes.push(ElementAttrNamed {
|
attributes.push(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr::CustomAttrExpression { name, value },
|
attr: ElementAttr::CustomAttrExpression { name, value },
|
||||||
@@ -82,7 +81,7 @@ impl Parse for Element {
|
|||||||
content.parse::<Token![:]>()?;
|
content.parse::<Token![:]>()?;
|
||||||
|
|
||||||
if name_str.starts_with("on") {
|
if name_str.starts_with("on") {
|
||||||
listeners.push(ElementAttrNamed {
|
attributes.push(ElementAttrNamed {
|
||||||
el_name: el_name.clone(),
|
el_name: el_name.clone(),
|
||||||
attr: ElementAttr::EventTokens {
|
attr: ElementAttr::EventTokens {
|
||||||
name,
|
name,
|
||||||
@@ -182,7 +181,6 @@ impl Parse for Element {
|
|||||||
name: el_name,
|
name: el_name,
|
||||||
attributes,
|
attributes,
|
||||||
children,
|
children,
|
||||||
listeners,
|
|
||||||
_is_static: false,
|
_is_static: false,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -193,14 +191,21 @@ impl ToTokens for Element {
|
|||||||
let name = &self.name;
|
let name = &self.name;
|
||||||
let children = &self.children;
|
let children = &self.children;
|
||||||
|
|
||||||
let listeners = &self.listeners;
|
|
||||||
let attr = &self.attributes;
|
|
||||||
|
|
||||||
let key = match &self.key {
|
let key = match &self.key {
|
||||||
Some(ty) => quote! { Some(format_args_f!(#ty)) },
|
Some(ty) => quote! { Some(format_args_f!(#ty)) },
|
||||||
None => quote! { None },
|
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! {
|
tokens.append_all(quote! {
|
||||||
__cx.element(
|
__cx.element(
|
||||||
dioxus_elements::#name,
|
dioxus_elements::#name,
|
||||||
@@ -213,29 +218,28 @@ impl ToTokens for Element {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ElementAttr {
|
pub enum ElementAttr {
|
||||||
// attribute: "valuee {}"
|
/// attribute: "valuee {}"
|
||||||
AttrText { name: Ident, value: LitStr },
|
AttrText { name: Ident, value: LitStr },
|
||||||
|
|
||||||
// attribute: true,
|
/// attribute: true,
|
||||||
AttrExpression { name: Ident, value: Expr },
|
AttrExpression { name: Ident, value: Expr },
|
||||||
|
|
||||||
// "attribute": "value {}"
|
/// "attribute": "value {}"
|
||||||
CustomAttrText { name: LitStr, value: LitStr },
|
CustomAttrText { name: LitStr, value: LitStr },
|
||||||
|
|
||||||
// "attribute": true,
|
/// "attribute": true,
|
||||||
CustomAttrExpression { name: LitStr, value: Expr },
|
CustomAttrExpression { name: LitStr, value: Expr },
|
||||||
|
|
||||||
// // onclick: move |_| {}
|
// /// onclick: move |_| {}
|
||||||
// EventClosure { name: Ident, closure: ExprClosure },
|
// EventClosure { name: Ident, closure: ExprClosure },
|
||||||
|
/// onclick: {}
|
||||||
// onclick: {}
|
|
||||||
EventTokens { name: Ident, tokens: Expr },
|
EventTokens { name: Ident, tokens: Expr },
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ElementAttrNamed {
|
pub struct ElementAttrNamed {
|
||||||
el_name: Ident,
|
pub el_name: Ident,
|
||||||
attr: ElementAttr,
|
pub attr: ElementAttr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for ElementAttrNamed {
|
impl ToTokens for ElementAttrNamed {
|
||||||
@@ -15,6 +15,8 @@ mod component;
|
|||||||
mod element;
|
mod element;
|
||||||
mod node;
|
mod node;
|
||||||
|
|
||||||
|
pub mod pretty;
|
||||||
|
|
||||||
// Re-export the namespaces into each other
|
// Re-export the namespaces into each other
|
||||||
pub use component::*;
|
pub use component::*;
|
||||||
pub use element::*;
|
pub use element::*;
|
||||||
@@ -29,8 +31,8 @@ use syn::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub struct CallBody {
|
pub struct CallBody {
|
||||||
custom_context: Option<Ident>,
|
pub custom_context: Option<Ident>,
|
||||||
roots: Vec<BodyNode>,
|
pub roots: Vec<BodyNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for CallBody {
|
impl Parse for CallBody {
|
||||||
@@ -4,7 +4,7 @@ use proc_macro2::TokenStream as TokenStream2;
|
|||||||
use quote::{quote, ToTokens, TokenStreamExt};
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
use syn::{
|
use syn::{
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
token, Expr, LitStr, Result, Token,
|
token, Attribute, Expr, LitStr, Result, Token,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -20,6 +20,7 @@ pub enum BodyNode {
|
|||||||
Component(Component),
|
Component(Component),
|
||||||
Text(LitStr),
|
Text(LitStr),
|
||||||
RawExpr(Expr),
|
RawExpr(Expr),
|
||||||
|
Meta(Attribute),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for BodyNode {
|
impl Parse for BodyNode {
|
||||||
@@ -79,6 +80,7 @@ impl ToTokens for BodyNode {
|
|||||||
BodyNode::RawExpr(exp) => tokens.append_all(quote! {
|
BodyNode::RawExpr(exp) => tokens.append_all(quote! {
|
||||||
__cx.fragment_from_iter(#exp)
|
__cx.fragment_from_iter(#exp)
|
||||||
}),
|
}),
|
||||||
|
BodyNode::Meta(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
//! pretty printer for rsx!
|
||||||
+1
-1
@@ -353,7 +353,7 @@ pub mod events {
|
|||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use dioxus_core::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_elements::{GlobalAttributes, SvgAttributes};
|
||||||
pub use dioxus_hooks::*;
|
pub use dioxus_hooks::*;
|
||||||
pub use dioxus_html as dioxus_elements;
|
pub use dioxus_html as dioxus_elements;
|
||||||
|
|||||||
Reference in new issue
Block a user