Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Upstream yewtil crate * cargo fmt * cargo clippy * cargo fmt
- Loading branch information
Showing
58 changed files
with
4,492 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[package] | ||
name = "yewtil-macro" | ||
version = "0.1.0" | ||
authors = ["Henry Zimmerman <zimhen7@gmail.com>"] | ||
edition = "2018" | ||
license = "MIT/Apache-2.0" | ||
description = "Macros to be re-exported from the yewtil crate" | ||
|
||
[lib] | ||
proc-macro = true | ||
|
||
[dependencies] | ||
proc-macro2 = "1.0.6" | ||
quote = "1.0.2" | ||
syn = { version = "1.0.11", features = ["full", "extra-traits"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
use proc_macro::TokenStream as TokenStream1; | ||
use proc_macro2::{Ident, Span, TokenStream}; | ||
use quote::quote; | ||
use syn::export::ToTokens; | ||
use syn::parse::{Parse, ParseBuffer}; | ||
use syn::parse_macro_input; | ||
use syn::punctuated::Punctuated; | ||
use syn::token; | ||
use syn::Token; | ||
use syn::{braced, parenthesized}; | ||
use syn::{Block, Error, Field, Stmt, Type, VisPublic, Visibility}; | ||
|
||
pub fn function_component_handler(attr: TokenStream, item: TokenStream1) -> TokenStream1 { | ||
let component_name = attr.to_string(); | ||
assert!( | ||
!component_name.is_empty(), | ||
"you must provide a component name. eg: function_component(MyComponent)" | ||
); | ||
let component_name = Ident::new(&component_name, Span::call_site()); | ||
let function = parse_macro_input!(item as Function); | ||
TokenStream1::from( | ||
FunctionComponentInfo { | ||
component_name, | ||
function, | ||
} | ||
.to_token_stream(), | ||
) | ||
} | ||
|
||
pub struct FunctionComponentInfo { | ||
component_name: Ident, | ||
function: Function, | ||
} | ||
|
||
// TODO, support type parameters | ||
|
||
pub struct Function { | ||
pub vis: Visibility, | ||
pub fn_token: Token![fn], | ||
pub name: Ident, | ||
pub paren_token: token::Paren, | ||
pub fields: Punctuated<Field, Token![,]>, | ||
pub returns_token: Token![->], | ||
pub return_ty: Ident, | ||
pub brace_token: token::Brace, | ||
pub body: Vec<Stmt>, | ||
} | ||
|
||
impl Parse for Function { | ||
fn parse(input: &ParseBuffer) -> Result<Self, Error> { | ||
let vis = input.parse()?; | ||
let fn_token = input.parse()?; | ||
let name = input.parse()?; | ||
let content; | ||
let paren_token = parenthesized!(content in input); | ||
let returns_token = input.parse()?; | ||
let return_ty = input.parse()?; | ||
let content2; | ||
let brace_token = braced!(content2 in input); | ||
Ok(Function { | ||
vis, | ||
fn_token, | ||
name, | ||
paren_token, | ||
fields: content.parse_terminated(Field::parse_named)?, | ||
returns_token, | ||
return_ty, | ||
brace_token, | ||
body: content2.call(Block::parse_within)?, | ||
}) | ||
} | ||
} | ||
|
||
impl ToTokens for Function { | ||
fn to_tokens(&self, tokens: &mut TokenStream) { | ||
let Function { | ||
vis, | ||
fn_token, | ||
name, | ||
fields, | ||
returns_token, | ||
return_ty, | ||
body, | ||
.. | ||
} = self; | ||
let fields = fields | ||
.iter() | ||
.map(|field: &Field| { | ||
let mut new_field: Field = field.clone(); | ||
new_field.attrs = vec![]; | ||
new_field | ||
}) | ||
.collect::<Punctuated<_, Token![,]>>(); | ||
|
||
tokens.extend(quote! { | ||
#vis #fn_token #name(#fields) #returns_token #return_ty { | ||
#(#body)* | ||
} | ||
}) | ||
} | ||
} | ||
|
||
impl ToTokens for FunctionComponentInfo { | ||
fn to_tokens(&self, tokens: &mut TokenStream) { | ||
let FunctionComponentInfo { | ||
component_name, | ||
function, | ||
} = self; | ||
// The function tokens must be re-generated in order to strip the attributes that are not allowed. | ||
let function_token_stream = function.to_token_stream(); | ||
let Function { | ||
vis, name, fields, .. | ||
} = function; | ||
|
||
let impl_name = format!("FuncComp{}", component_name.to_string()); | ||
let impl_name = Ident::new(&impl_name, Span::call_site()); | ||
|
||
let alias = quote! { | ||
#vis type #component_name = ::yewtil::Pure<#impl_name>; | ||
}; | ||
|
||
// Set the fields to be public and strips references as necessary. | ||
// This will preserve attributes like #[props(required)], which will appear in the generated struct below. | ||
let new_fields = fields | ||
.iter() | ||
.map(|field: &Field| { | ||
let mut new_field: Field = field.clone(); | ||
let visibility = Visibility::Public(VisPublic { | ||
pub_token: syn::token::Pub { | ||
span: Span::call_site(), | ||
}, | ||
}); | ||
// Strip references so the component can have a static lifetime. | ||
// TODO Handle 'static lifetimes gracefully here - allowing &'static strings instead of erroneously converting them to plain strs. | ||
let ty = match &field.ty { | ||
Type::Reference(x) => { | ||
let elem = x.elem.clone(); | ||
Type::Verbatim(quote! { | ||
#elem | ||
}) | ||
} | ||
x => x.clone(), | ||
}; | ||
new_field.vis = visibility; | ||
new_field.ty = ty; | ||
new_field | ||
}) | ||
.collect::<Punctuated<_, Token![,]>>(); | ||
|
||
let component_struct = quote! { | ||
#[derive(::std::clone::Clone, ::std::cmp::PartialEq, ::yew::Properties)] | ||
#vis struct #impl_name { | ||
#new_fields | ||
} | ||
}; | ||
|
||
let arguments = fields | ||
.iter() | ||
.zip(new_fields.iter()) | ||
.map(|(field, new_field): (&Field, &Field)| { | ||
let field_name = field.ident.as_ref().expect("Field must have name"); | ||
|
||
// If the fields differ, then a reference was removed from the function's field's type | ||
// to make it static. | ||
// Otherwise it is assumed that the type is not a reference on the function and it | ||
// implements clone, and that when calling the function, the type should be cloned again. | ||
if field.ty != new_field.ty { | ||
quote! { | ||
&self.#field_name | ||
} | ||
} else { | ||
quote! { | ||
self.#field_name.clone() | ||
} | ||
} | ||
}) | ||
.collect::<Punctuated<_, Token![,]>>(); | ||
|
||
let pure_component_impl = quote! { | ||
impl ::yewtil::PureComponent for #impl_name { | ||
fn render(&self) -> ::yew::Html { | ||
#name(#arguments) | ||
} | ||
} | ||
}; | ||
|
||
tokens.extend(quote! { | ||
#function_token_stream | ||
#alias | ||
#component_struct | ||
#pure_component_impl | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
extern crate proc_macro; | ||
use proc_macro::TokenStream; | ||
|
||
use crate::function_component::function_component_handler; | ||
|
||
mod function_component; | ||
#[proc_macro_attribute] | ||
pub fn function_component(attr: TokenStream, item: TokenStream) -> TokenStream { | ||
function_component_handler(attr.into(), item) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Changelog | ||
|
||
<!-- START TEMPLATE | ||
## ✨ **VERSION** *(DATE)* | ||
- #### ⚡️ Features | ||
- Sample | ||
- #### 🛠 Fixes | ||
- Sample | ||
- #### 🚨 Breaking changes | ||
- Sample | ||
END TEMPLATE--> | ||
|
||
## ✨ **v0.2.0** *11/18/19* | ||
- #### ⚡️ Features | ||
- Add new `FetchRequest` trait, `fetch_resource()` function, and `FetchState` enum | ||
to simplify making fetch requests using futures. | ||
- Add `Default` implementations to `Irc` and `Mrc`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
[package] | ||
name = "yewtil" | ||
version = "0.2.0" | ||
authors = ["Henry Zimmerman <zimhen7@gmail.com>"] | ||
edition = "2018" | ||
description = "Utility crate for Yew" | ||
license = "MIT/Apache-2.0" | ||
repository = "https://github.com/yewstack/yewtil" | ||
readme = "Readme.md" | ||
|
||
[features] | ||
default = ["stable"] # Only stable is included by default. | ||
all = ["stable", "experimental"] | ||
|
||
# Broad features | ||
## All features MUST be stable or experimental | ||
stable = ["neq", "pure", "history", "mrc_irc", "effect", "future"] | ||
experimental = ["dsl", "lrc", "with_callback", "fetch" ] | ||
|
||
# Some pointers are stable, some experimental. | ||
# This makes sure you get all the pointers | ||
ptr = ["lrc", "mrc_irc"] | ||
|
||
# Misc features | ||
neq = [] | ||
pure = ["neq", "yewtil-macro"] | ||
with_callback = [] | ||
history = [] | ||
dsl = [] | ||
effect = [] | ||
fetch = ["serde", "serde_json", "neq", "future"] | ||
future = ["wasm-bindgen-futures", "wasm-bindgen", "stdweb", "futures", "web-sys"] | ||
|
||
# Ptr features | ||
lrc = [] | ||
mrc_irc = [] | ||
|
||
[dependencies] | ||
futures = {version = "0.3.1", optional = true} | ||
log = "0.4.8" | ||
serde = {version= "1.0.102", optional = true} | ||
serde_json = { version = "1.0.41", optional = true } | ||
wasm-bindgen = {version = "0.2.51", features=["serde-serialize"], optional = true} | ||
wasm-bindgen-futures = {version = "0.4.3", optional = true} | ||
yew = { path = "../yew" } | ||
yewtil-macro = { path = "../yewtil-macro", optional = true } | ||
|
||
[dependencies.stdweb] | ||
version = "0.4.20" | ||
optional = true | ||
features = [ | ||
"futures-support", | ||
"experimental_features_which_may_break_on_minor_version_bumps", | ||
] | ||
|
||
[dependencies.web-sys] | ||
version = "0.3.31" | ||
optional = true | ||
features = [ | ||
'Headers', | ||
'Request', | ||
'RequestInit', | ||
'RequestMode', | ||
'Response', | ||
'Window', | ||
'Location', | ||
'Storage', | ||
] |
Oops, something went wrong.