Skip to content

Commit

Permalink
Merge pull request #12 from blorbb/0.3.0
Browse files Browse the repository at this point in the history
0.3.0
  • Loading branch information
blorbb authored Feb 22, 2024
2 parents 82fe059 + c049960 commit c43e25b
Show file tree
Hide file tree
Showing 25 changed files with 415 additions and 159 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "leptos-mview"
version = "0.2.3"
version = "0.3.0"
edition = "2021"
license = "MIT OR Apache-2.0"
keywords = ["macro", "leptos", "view"]
Expand All @@ -11,7 +11,7 @@ readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
leptos-mview-macro = { path = "leptos-mview-macro", version = "0.2.3" }
leptos-mview-macro = { path = "leptos-mview-macro", version = "0.3.0" }

[dev-dependencies]
trybuild = "1"
Expand Down
17 changes: 11 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,19 @@ The `view!` macros in Leptos is often the largest part of a component, and can g

## Performance note

Currently, the macro expands to the [builder syntax](https://github.com/leptos-rs/leptos/blob/main/docs/book/src/view/builder.md) (ish), but it has some [performance downsides](https://github.com/leptos-rs/leptos/issues/1492#issuecomment-1664675672) in SSR mode. This is expected to be fixed with the new renderer in leptos `0.7`, so I'm not going to make this implementation.
Currently, the macro expands to the [builder syntax](https://github.com/leptos-rs/leptos/blob/main/docs/book/src/view/builder.md) (ish), but it has some [performance downsides](https://github.com/leptos-rs/leptos/issues/1492#issuecomment-1664675672) in SSR mode. This is expected to be fixed with the new renderer in Leptos `0.7`, so I'm not going to make this implementation.

## Compatibility

This macro will be compatible with the latest stable release of Leptos.
This macro will be compatible with the latest stable release of Leptos. The macro references Leptos items using `::leptos::...`, no items are re-exported from this crate. Therefore, this crate will likely work with any Leptos version if no view-related items are changed.

The below are the versions with which I have tested it to be working. It is likely that the macro works with more versions of Leptos.

| `leptos_mview` version | Compatible `leptos` version |
| ---------------------- | --------------------------- |
| `0.1` | `0.5.0`-`0.5.1` |
| `0.2` | `0.5.2`+, `0.6` |
| `0.1` | `0.5` |
| `0.2` | `0.5`, `0.6` |
| `0.3` | `0.6` |

## Syntax details

Expand All @@ -143,7 +146,7 @@ mview! {
}
```

Adding generics is the same as in leptos: add it directly after the component name, with or without the turbofish.
Adding generics is the same as in Leptos: add it directly after the component name, with or without the turbofish.
```rust
#[component]
pub fn GenericComponent<S>(ty: PhantomData<S>) -> impl IntoView {
Expand Down Expand Up @@ -338,6 +341,8 @@ mview! {
}
```

Note that the `use:` directive automatically calls `.into()` on its argument, consistent with behaviour from Leptos.

#### Special Attributes

There are a few special attributes you can put on your component to emulate some features only available on HTML elements.
Expand All @@ -347,7 +352,7 @@ If a component has a `class` attribute, the classes using the selector syntax `.
```rust
#[component]
// the `class` parameter should have these attributes and type to work properly
fn TakesClasses(#[prop(into, default="".into())] class: TextProp) -> impl IntoView {
fn TakesClasses(#[prop(optional, into)] class: TextProp) -> impl IntoView {
mview! {
// "my-component" will always be present, extra classes passed in will also be added
div.my-component class=[class.get()] { "..." }
Expand Down
2 changes: 1 addition & 1 deletion leptos-mview-core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "leptos-mview-core"
version = "0.2.3"
version = "0.3.0"
edition = "2021"
license = "MIT OR Apache-2.0"
description = "Main implementation of leptos-mview"
Expand Down
14 changes: 2 additions & 12 deletions leptos-mview-core/src/ast/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use syn::{
};

use self::{directive::Directive, kv::KvAttr, spread_attrs::SpreadAttr};
use crate::{error_ext::ResultExt, recover::rollback_err};
use crate::{error_ext::ResultExt, parse::rollback_err};

#[derive(Clone)]
pub enum Attr {
Expand All @@ -19,16 +19,6 @@ pub enum Attr {
Spread(SpreadAttr),
}

// impl Attr {
// pub fn span(&self) -> Span {
// match self {
// Self::Kv(kv) => kv.span(),
// Self::Directive(dir) => dir.span(),
// Self::Spread(s) => s.span(),
// }
// }
// }

impl Parse for Attr {
fn parse(input: ParseStream) -> syn::Result<Self> {
// ident then colon must be directive
Expand All @@ -40,7 +30,7 @@ impl Parse for Attr {
Ok(Self::Directive(dir))
} else if input.peek(syn::Ident) {
// definitely a k-v attribute
let kv = input.parse::<KvAttr>()?;
let kv = KvAttr::parse(input)?;
Ok(Self::Kv(kv))
} else if let Some(kv) = rollback_err(input, KvAttr::parse) {
// k-v attributes don't necessarily start with ident, try the rest
Expand Down
5 changes: 2 additions & 3 deletions leptos-mview-core/src/ast/attribute/directive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use syn::{

use crate::{
ast::{BracedKebabIdent, KebabIdentOrStr, Value},
recover::rollback_err,
parse::rollback_err,
};

/// A special attribute like `on:click={...}`.
Expand Down Expand Up @@ -63,8 +63,7 @@ impl Parse for Directive {
key = KebabIdentOrStr::parse(input)?;
modifier = try_parse_modifier(input)?;
value = rollback_err(input, <Token![=]>::parse)
.is_some()
.then(|| Value::parse_or_emit_err(input));
.map(|eq| Value::parse_or_emit_err(input, eq.span));
};

Ok(Self {
Expand Down
9 changes: 5 additions & 4 deletions leptos-mview-core/src/ast/attribute/kv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use syn::{parse::Parse, parse_quote, Token};

use crate::{
ast::{BracedKebabIdent, KebabIdent, Value},
recover::rollback_err,
parse::rollback_err,
span,
};

Expand Down Expand Up @@ -41,17 +41,18 @@ impl KvAttr {
impl Parse for KvAttr {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let (ident, value) = if input.peek(syn::token::Brace) {
let braced_ident = input.parse::<BracedKebabIdent>()?;
let braced_ident = BracedKebabIdent::parse(input)?;
(
braced_ident.ident().clone(),
braced_ident.into_block_value(),
)
} else {
let ident = KebabIdent::parse(input)?;
if rollback_err(input, <Token![=]>::parse).is_some() {
let value = Value::parse_or_emit_err(input);
if let Some(eq) = rollback_err(input, <Token![=]>::parse) {
let value = Value::parse_or_emit_err(input, eq.span);
(ident, value)
} else {
// don't span the attribute name to the `true` or it becomes bool-colored
let value = Value::Lit(parse_quote!(true));
(ident, value)
}
Expand Down
6 changes: 3 additions & 3 deletions leptos-mview-core/src/ast/attribute/selector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use syn::{
Token,
};

use crate::{ast::KebabIdent, recover::rollback_err};
use crate::{ast::KebabIdent, parse::rollback_err};

/// A shorthand for adding class or ids to an element.
///
Expand Down Expand Up @@ -57,13 +57,13 @@ impl SelectorShorthand {
impl Parse for SelectorShorthand {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
if let Some(dot) = rollback_err(input, <Token![.]>::parse) {
let class = input.parse::<KebabIdent>()?;
let class = KebabIdent::parse(input)?;
Ok(Self::Class {
dot_symbol: dot,
class,
})
} else if let Some(pound) = rollback_err(input, <Token![#]>::parse) {
let id = input.parse::<KebabIdent>()?;
let id = KebabIdent::parse(input)?;
Ok(Self::Id {
pound_symbol: pound,
id,
Expand Down
2 changes: 1 addition & 1 deletion leptos-mview-core/src/ast/attribute/spread_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use syn::{
Token,
};

use crate::{parse::extract_braced, recover::rollback_err};
use crate::parse::{extract_braced, rollback_err};

/// A spread attribute like `{..attrs}`.
///
Expand Down
33 changes: 20 additions & 13 deletions leptos-mview-core/src/ast/children.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use proc_macro2::{Span, TokenStream};
use proc_macro2::Span;
use proc_macro_error::emit_error;
use quote::ToTokens;
use syn::{
Expand All @@ -8,7 +8,12 @@ use syn::{
};

use super::Element;
use crate::{ast::Value, error_ext::SynErrorExt, kw, recover::rollback_err};
use crate::{
ast::Value,
error_ext::SynErrorExt,
kw,
parse::{self, rollback_err},
};

/// A child that is an actual HTML value (i.e. not a slot).
///
Expand Down Expand Up @@ -43,10 +48,6 @@ impl NodeChild {
///
/// Children can either be a [`NodeChild`] (i.e. an actual element), or a slot.
/// Slots are distinguished by prefixing the child with `slot:`.
///
/// # Parsing
/// Mostly **aborts** if parsing fails. An [`Err`] is only returned if there are
/// no tokens remaining.
pub enum Child {
Node(NodeChild),
Slot(kw::slot, Element),
Expand Down Expand Up @@ -85,9 +86,6 @@ impl Parse for Child {
///
/// Parsing does not include the surrounding braces.
/// If no children are present, an empty vector will be stored.
///
/// There are two ways of passing children, so no `ToTokens` implementation
/// is provided. Use `to_child_methods` or `to_fragment` instead.
pub struct Children(Vec<Child>);

impl std::ops::Deref for Children {
Expand All @@ -106,10 +104,19 @@ impl Parse for Children {
match Child::parse(input) {
Ok(child) => vec.push(child),
Err(e) => {
e.emit_as_error();
// skip the rest of the tokens
// need to consume all tokens otherwise an error is made on drop
input.parse::<TokenStream>().unwrap();
if input.peek(Token![;]) {
// an extra semi-colon: just skip it and keep parsing
emit_error!(
e.span(), "extra semi-colon found";
help="remove this semi-colon"
);
<Token![;]>::parse(input).unwrap();
} else {
e.emit_as_error();
// skip the rest of the tokens
// need to consume all tokens otherwise an error is made on drop
parse::take_rest(input);
}
}
};
}
Expand Down
14 changes: 4 additions & 10 deletions leptos-mview-core/src/ast/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ use syn::{
use super::{attribute::selector::SelectorShorthands, Attrs, Children, Tag};
use crate::{
expand::{component_to_tokens, xml_to_tokens},
parse,
recover::rollback_err,
parse::{self, rollback_err},
span,
};

Expand Down Expand Up @@ -43,11 +42,6 @@ use crate::{
///
/// Whether the element is a slot or not is distinguished by
/// [`Child`](crate::ast::Child).
///
/// # Parsing
/// Parsing will return an [`Err`] if parsing the [`Tag`] fails (i.e. the next
/// token is not an ident; however, will abort if a component is found +
/// generics fail). If anything else fails, parsing will **abort**.
pub struct Element {
tag: Tag,
selectors: SelectorShorthands,
Expand Down Expand Up @@ -162,17 +156,17 @@ impl Element {
/// so no other `|` characters are allowed within a pattern that is outside of a
/// nested group.
fn parse_closure_args(input: ParseStream) -> syn::Result<TokenStream> {
let first_pipe = input.parse::<Token![|]>()?;
let first_pipe = <Token![|]>::parse(input)?;

let mut tokens = TokenStream::new();
first_pipe.to_tokens(&mut tokens);

loop {
// parse until second `|` is found
if let Ok(pipe) = input.parse::<Token![|]>() {
if let Some(pipe) = rollback_err(input, <Token![|]>::parse) {
pipe.to_tokens(&mut tokens);
break Ok(tokens);
} else if let Ok(tt) = input.parse::<TokenTree>() {
} else if let Some(tt) = rollback_err(input, TokenTree::parse) {
tokens.append(tt);
} else {
break Err(syn::Error::new_spanned(
Expand Down
Loading

0 comments on commit c43e25b

Please sign in to comment.