Skip to content

Commit

Permalink
feat!: Replace Colon and Dash with a merged variant (#34)
Browse files Browse the repository at this point in the history
  • Loading branch information
gbj committed Nov 6, 2022
1 parent 98cc893 commit 0516f8f
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 33 deletions.
63 changes: 37 additions & 26 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

use std::{convert::TryFrom, fmt, ops::Deref};

use proc_macro2::TokenStream;
use proc_macro2::{Punct, TokenStream};
use quote::ToTokens;
use syn::{punctuated::Punctuated, token::Colon, Expr, ExprBlock, ExprLit, ExprPath, Ident, Lit};
use syn::{
punctuated::{Pair, Punctuated},
Expr, ExprBlock, ExprLit, ExprPath, Ident, Lit,
};

use crate::{punctuation::Dash, Error};
use crate::Error;

/// Node types.
#[derive(Debug, PartialEq, Eq)]
Expand Down Expand Up @@ -226,11 +229,9 @@ pub enum NodeName {
/// be separated by double colons, e.g. `<foo::bar />`.
Path(ExprPath),

/// Name separated by dashes, e.g. `<div data-foo="bar" />`.
Dash(Punctuated<Ident, Dash>),

/// Name separated by colons, e.g. `<div on:click={foo} />`.
Colon(Punctuated<Ident, Colon>),
/// Name separated by punctuation, e.g. `<div data-foo="bar" />` or `<div
/// data:foo="bar" />`.
Punctuated(Punctuated<Ident, Punct>),

/// Arbitrary rust code in braced `{}` blocks.
Block(Expr),
Expand All @@ -256,12 +257,23 @@ impl PartialEq for NodeName {
Self::Path(other) => this == other,
_ => false,
},
Self::Dash(this) => match other {
Self::Dash(other) => this == other,
_ => false,
},
Self::Colon(this) => match other {
Self::Colon(other) => this == other,
// can't be derived automatically because `Punct` doesn't impl `PartialEq`
Self::Punctuated(this) => match other {
Self::Punctuated(other) => {
this.pairs()
.zip(other.pairs())
.all(|(this, other)| match (this, other) {
(
Pair::Punctuated(this_ident, this_punct),
Pair::Punctuated(other_ident, other_punct),
) => {
this_ident == other_ident
&& this_punct.as_char() == other_punct.as_char()
}
(Pair::End(this), Pair::End(other)) => this == other,
_ => false,
})
}
_ => false,
},
Self::Block(this) => match other {
Expand All @@ -276,8 +288,7 @@ impl ToTokens for NodeName {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
NodeName::Path(name) => name.to_tokens(tokens),
NodeName::Dash(name) => name.to_tokens(tokens),
NodeName::Colon(name) => name.to_tokens(tokens),
NodeName::Punctuated(name) => name.to_tokens(tokens),
NodeName::Block(name) => name.to_tokens(tokens),
}
}
Expand All @@ -290,16 +301,16 @@ impl fmt::Display for NodeName {
"{}",
match self {
NodeName::Path(expr) => path_to_string(expr),
NodeName::Dash(name) => name
.iter()
.map(|ident| ident.to_string())
.collect::<Vec<String>>()
.join("-"),
NodeName::Colon(name) => name
.iter()
.map(|ident| ident.to_string())
.collect::<Vec<String>>()
.join(":"),
NodeName::Punctuated(name) => {
name.pairs()
.flat_map(|pair| match pair {
Pair::Punctuated(ident, punct) => {
[ident.to_string(), punct.to_string()]
}
Pair::End(ident) => [ident.to_string(), "".to_string()],
})
.collect::<String>()
}
NodeName::Block(_) => String::from("{}"),
}
)
Expand Down
43 changes: 36 additions & 7 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use std::vec;

use proc_macro2::{Span, TokenStream, TokenTree};
use proc_macro2::{Punct, Span, TokenStream, TokenTree};
use syn::{
braced,
ext::IdentExt,
Expand Down Expand Up @@ -424,12 +424,11 @@ impl Parser {
},
})
})
} else if input.peek2(Colon) {
self.node_name_punctuated_ident::<Colon, fn(_) -> Colon, Ident>(input, Colon)
.map(NodeName::Colon)
} else if input.peek2(Dash) {
self.node_name_punctuated_ident::<Dash, fn(_) -> Dash, Ident>(input, Dash)
.map(NodeName::Dash)
} else if input.peek2(Colon) || input.peek2(Dash) {
self.node_name_punctuated_ident_with_alternate::<Punct, fn(_) -> Colon, fn(_) -> Dash, Ident>(
input, Colon, Dash,
)
.map(NodeName::Punctuated)
} else if input.peek(Brace) {
let fork = &input.fork();
let value = self.block_expr(fork)?;
Expand Down Expand Up @@ -485,4 +484,34 @@ impl Parser {
Err(fork.error("expected punctuated node name"))
}
}

/// Parse the stream as punctuated idents, with two possible punctuations
/// available
fn node_name_punctuated_ident_with_alternate<T: Parse, F: Peek, G: Peek, X: From<Ident>>(
&self,
input: ParseStream,
punct: F,
alternate_punct: G,
) -> Result<Punctuated<X, T>> {
let fork = &input.fork();
let mut segments = Punctuated::<X, T>::new();

while !fork.is_empty() && fork.peek(Ident::peek_any) {
let ident = Ident::parse_any(fork)?;
segments.push_value(ident.clone().into());

if fork.peek(punct) || fork.peek(alternate_punct) {
segments.push_punct(fork.parse()?);
} else {
break;
}
}

if segments.len() > 1 {
input.advance_to(fork);
Ok(segments)
} else {
Err(fork.error("expected punctuated node name"))
}
}
}
14 changes: 14 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,20 @@ fn test_coloned_attribute_name() -> Result<()> {
Ok(())
}

#[test]
fn test_mixed_colon_and_dash_attribute_name() -> Result<()> {
let tokens = quote! {
<div on:ce-click={foo} />
};

let nodes = parse2(tokens)?;
let attribute = get_element_attribute(&nodes, 0, 0);

assert_eq!(attribute.key.to_string(), "on:ce-click");

Ok(())
}

#[test]
fn test_block_as_attribute() -> Result<()> {
let tokens = quote! {
Expand Down

0 comments on commit 0516f8f

Please sign in to comment.