-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
mod.rs
157 lines (143 loc) · 4.49 KB
/
mod.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
pub mod html_block;
pub mod html_component;
pub mod html_dashed_name;
pub mod html_iterable;
pub mod html_list;
pub mod html_node;
pub mod html_prop;
pub mod html_tag;
use crate::PeekValue;
use html_block::HtmlBlock;
use html_component::HtmlComponent;
use html_dashed_name::HtmlDashedName;
use html_iterable::HtmlIterable;
use html_list::HtmlList;
use html_node::HtmlNode;
use html_prop::HtmlProp;
use html_prop::HtmlPropSuffix;
use html_tag::HtmlTag;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use syn::buffer::Cursor;
use syn::parse::{Parse, ParseStream, Result};
pub enum HtmlType {
Block,
Component,
List,
Tag,
Empty,
}
pub enum HtmlTree {
Block(Box<HtmlBlock>),
Component(Box<HtmlComponent>),
Iterable(Box<HtmlIterable>),
List(Box<HtmlList>),
Tag(Box<HtmlTag>),
Node(Box<HtmlNode>),
Empty,
}
pub struct HtmlRoot(HtmlTree);
impl Parse for HtmlRoot {
fn parse(input: ParseStream) -> Result<Self> {
let html_root = if HtmlTree::peek(input.cursor()).is_some() {
HtmlRoot(input.parse()?)
} else if HtmlIterable::peek(input.cursor()).is_some() {
HtmlRoot(HtmlTree::Iterable(Box::new(input.parse()?)))
} else {
HtmlRoot(HtmlTree::Node(Box::new(input.parse()?)))
};
if !input.is_empty() {
let stream: TokenStream = input.parse()?;
Err(syn::Error::new_spanned(
stream,
"only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)",
))
} else {
Ok(html_root)
}
}
}
impl ToTokens for HtmlRoot {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let HtmlRoot(html_tree) = self;
html_tree.to_tokens(tokens);
}
}
impl Parse for HtmlTree {
fn parse(input: ParseStream) -> Result<Self> {
let html_type = HtmlTree::peek(input.cursor())
.ok_or_else(|| input.error("expected a valid html element"))?;
let html_tree = match html_type {
HtmlType::Empty => HtmlTree::Empty,
HtmlType::Component => HtmlTree::Component(Box::new(input.parse()?)),
HtmlType::Tag => HtmlTree::Tag(Box::new(input.parse()?)),
HtmlType::Block => HtmlTree::Block(Box::new(input.parse()?)),
HtmlType::List => HtmlTree::List(Box::new(input.parse()?)),
};
Ok(html_tree)
}
}
impl PeekValue<HtmlType> for HtmlTree {
fn peek(cursor: Cursor) -> Option<HtmlType> {
if cursor.eof() {
Some(HtmlType::Empty)
} else if HtmlComponent::peek(cursor).is_some() {
Some(HtmlType::Component)
} else if HtmlTag::peek(cursor).is_some() {
Some(HtmlType::Tag)
} else if HtmlBlock::peek(cursor).is_some() {
Some(HtmlType::Block)
} else if HtmlList::peek(cursor).is_some() {
Some(HtmlType::List)
} else {
None
}
}
}
impl ToTokens for HtmlTree {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let node = self.token_stream();
tokens.extend(quote! {
::yew::virtual_dom::VNode::from(#node)
});
}
}
impl HtmlTree {
fn token_stream(&self) -> proc_macro2::TokenStream {
match self {
HtmlTree::Empty => HtmlList {
children: Vec::new(),
key: None,
}
.into_token_stream(),
HtmlTree::Component(comp) => comp.into_token_stream(),
HtmlTree::Tag(tag) => tag.into_token_stream(),
HtmlTree::List(list) => list.into_token_stream(),
HtmlTree::Node(node) => node.into_token_stream(),
HtmlTree::Iterable(iterable) => iterable.into_token_stream(),
HtmlTree::Block(block) => block.into_token_stream(),
}
}
}
pub struct HtmlRootNested(HtmlTreeNested);
impl Parse for HtmlRootNested {
fn parse(input: ParseStream) -> Result<Self> {
Ok(HtmlRootNested(HtmlTreeNested::parse(input)?))
}
}
impl ToTokens for HtmlRootNested {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
self.0.to_tokens(tokens);
}
}
pub struct HtmlTreeNested(HtmlTree);
impl Parse for HtmlTreeNested {
fn parse(input: ParseStream) -> Result<Self> {
Ok(HtmlTreeNested(HtmlTree::parse(input)?))
}
}
impl ToTokens for HtmlTreeNested {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
tokens.extend(self.0.token_stream());
}
}