mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-22 20:23:09 +00:00
Parse raw elements, attributes, and web components in rsx (#2655)
* parse raw elements and attributes in rsx --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
This commit is contained in:
parent
fa4e5dbf62
commit
3bb9a535d8
6 changed files with 42 additions and 9 deletions
|
@ -92,6 +92,10 @@ fn app() -> Element {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
use {}
|
||||||
|
link {
|
||||||
|
as: "asd"
|
||||||
|
}
|
||||||
|
|
||||||
// Expressions can be used in element position too:
|
// Expressions can be used in element position too:
|
||||||
{rsx!(p { "More templating!" })}
|
{rsx!(p { "More templating!" })}
|
||||||
|
|
|
@ -63,8 +63,8 @@ pub struct Attribute {
|
||||||
impl Parse for Attribute {
|
impl Parse for Attribute {
|
||||||
fn parse(content: ParseStream) -> syn::Result<Self> {
|
fn parse(content: ParseStream) -> syn::Result<Self> {
|
||||||
// if there's an ident not followed by a colon, it's a shorthand attribute
|
// if there's an ident not followed by a colon, it's a shorthand attribute
|
||||||
if content.peek(Ident) && !content.peek2(Token![:]) {
|
if content.peek(Ident::peek_any) && !content.peek2(Token![:]) {
|
||||||
let ident = Ident::parse(content)?;
|
let ident = parse_raw_ident(content)?;
|
||||||
let comma = content.parse().ok();
|
let comma = content.parse().ok();
|
||||||
|
|
||||||
return Ok(Attribute {
|
return Ok(Attribute {
|
||||||
|
@ -80,7 +80,7 @@ impl Parse for Attribute {
|
||||||
// Parse the name as either a known or custom attribute
|
// Parse the name as either a known or custom attribute
|
||||||
let name = match content.peek(LitStr) {
|
let name = match content.peek(LitStr) {
|
||||||
true => AttributeName::Custom(content.parse::<LitStr>()?),
|
true => AttributeName::Custom(content.parse::<LitStr>()?),
|
||||||
false => AttributeName::BuiltIn(Ident::parse_any(content)?),
|
false => AttributeName::BuiltIn(parse_raw_ident(content)?),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure there's a colon
|
// Ensure there's a colon
|
||||||
|
|
|
@ -358,7 +358,8 @@ impl ToTokens for ElementName {
|
||||||
|
|
||||||
impl Parse for ElementName {
|
impl Parse for ElementName {
|
||||||
fn parse(stream: ParseStream) -> Result<Self> {
|
fn parse(stream: ParseStream) -> Result<Self> {
|
||||||
let raw = Punctuated::<Ident, Token![-]>::parse_separated_nonempty(stream)?;
|
let raw =
|
||||||
|
Punctuated::<Ident, Token![-]>::parse_separated_nonempty_with(stream, parse_raw_ident)?;
|
||||||
if raw.len() == 1 {
|
if raw.len() == 1 {
|
||||||
Ok(ElementName::Ident(raw.into_iter().next().unwrap()))
|
Ok(ElementName::Ident(raw.into_iter().next().unwrap()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -607,3 +608,14 @@ fn diagnositcs() {
|
||||||
|
|
||||||
let _parsed: Element = syn::parse2(input).unwrap();
|
let _parsed: Element = syn::parse2(input).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parses_raw_elements() {
|
||||||
|
let input = quote::quote! {
|
||||||
|
use {
|
||||||
|
"hello"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let _parsed: Element = syn::parse2(input).unwrap();
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::innerlude::*;
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn::{
|
use syn::{
|
||||||
|
ext::IdentExt,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
spanned::Spanned,
|
spanned::Spanned,
|
||||||
token::{self},
|
token::{self},
|
||||||
|
@ -72,7 +73,7 @@ impl Parse for BodyNode {
|
||||||
|
|
||||||
// If there's an ident immediately followed by a dash, it's a web component
|
// If there's an ident immediately followed by a dash, it's a web component
|
||||||
// Web components support no namespacing, so just parse it as an element directly
|
// Web components support no namespacing, so just parse it as an element directly
|
||||||
if stream.peek(Ident) && stream.peek2(Token![-]) {
|
if stream.peek(Ident::peek_any) && stream.peek2(Token![-]) {
|
||||||
return Ok(BodyNode::Element(stream.parse::<Element>()?));
|
return Ok(BodyNode::Element(stream.parse::<Element>()?));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,8 +87,8 @@ impl Parse for BodyNode {
|
||||||
//
|
//
|
||||||
// example:
|
// example:
|
||||||
// div {}
|
// div {}
|
||||||
if stream.peek(Ident) && !stream.peek2(Token![::]) {
|
if stream.peek(Ident::peek_any) && !stream.peek2(Token![::]) {
|
||||||
let ident = stream.fork().parse::<Ident>().unwrap();
|
let ident = parse_raw_ident(&stream.fork()).unwrap();
|
||||||
let el_name = ident.to_string();
|
let el_name = ident.to_string();
|
||||||
let first_char = el_name.chars().next().unwrap();
|
let first_char = el_name.chars().next().unwrap();
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ impl RsxBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse unambiguous attributes - these can't be confused with anything
|
// Parse unambiguous attributes - these can't be confused with anything
|
||||||
if (content.peek(LitStr) || content.peek(Ident) || content.peek(Ident::peek_any))
|
if (content.peek(LitStr) || content.peek(Ident::peek_any))
|
||||||
&& content.peek2(Token![:])
|
&& content.peek2(Token![:])
|
||||||
&& !content.peek3(Token![:])
|
&& !content.peek3(Token![:])
|
||||||
{
|
{
|
||||||
|
@ -239,7 +239,7 @@ impl RsxBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peek_lowercase_ident(stream: &ParseStream) -> bool {
|
fn peek_lowercase_ident(stream: &ParseStream) -> bool {
|
||||||
let Ok(ident) = stream.fork().parse::<Ident>() else {
|
let Ok(ident) = stream.fork().call(Ident::parse_any) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,11 @@ use internment::Intern;
|
||||||
|
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use std::{fmt::Debug, hash::Hash};
|
use std::{fmt::Debug, hash::Hash};
|
||||||
|
use syn::{
|
||||||
|
ext::IdentExt,
|
||||||
|
parse::{Parse, ParseBuffer},
|
||||||
|
Ident,
|
||||||
|
};
|
||||||
|
|
||||||
/// interns a object into a static object, resusing the value if it already exists
|
/// interns a object into a static object, resusing the value if it already exists
|
||||||
#[cfg(feature = "hot_reload")]
|
#[cfg(feature = "hot_reload")]
|
||||||
|
@ -27,3 +32,14 @@ impl PrettyUnparse for TokenStream2 {
|
||||||
prettier_please::unparse_expr(&parsed)
|
prettier_please::unparse_expr(&parsed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a raw ident and return a new ident with the r# prefix added
|
||||||
|
pub fn parse_raw_ident(parse_buffer: &ParseBuffer) -> syn::Result<Ident> {
|
||||||
|
// First try to parse as a normal ident
|
||||||
|
if let Ok(ident) = Ident::parse(parse_buffer) {
|
||||||
|
return Ok(ident);
|
||||||
|
}
|
||||||
|
// If that fails, try to parse as a raw ident
|
||||||
|
let ident = Ident::parse_any(parse_buffer)?;
|
||||||
|
Ok(Ident::new_raw(&ident.to_string(), ident.span()))
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue