Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions async-zero-cost-templating-proc-macro2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ syn = { default-features = false, version = "2.0", features = [
] }
tracing = "0.1"
tracing-subscriber = "0.3"
itertools = "0.13"
17 changes: 13 additions & 4 deletions async-zero-cost-templating-proc-macro2/src/intermediate.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use itertools::Itertools as _;
use proc_macro2::{Span, TokenStream};
use syn::{
spanned::Spanned,
token::{Brace, Paren},
};

use crate::parse::{
HtmlElement, HtmlForLoop, HtmlIf, HtmlInAttributeContext, HtmlInAttributeValueContext,
HtmlInElementContext, HtmlWhile,
DashOrColon, HtmlElement, HtmlForLoop, HtmlIf, HtmlInAttributeContext, HtmlInAttributeValueContext, HtmlInElementContext, HtmlWhile
};

pub enum Intermediate {
Expand All @@ -23,8 +23,17 @@ impl From<HtmlInAttributeContext> for Vec<Intermediate> {
match value {
HtmlInAttributeContext::Literal(key, value) => Vec::from_iter(
[Intermediate::Literal(
" ".to_owned() + &key.to_string(),
key.span(),
" ".to_owned() + &key.pairs()
.map(|p| {
p.value().to_string()
+ match p.punct() {
Some(DashOrColon::Colon(_)) => ":",
Some(DashOrColon::Dash(_)) => "-",
None => "",
}
})
.join(""),
key.first().unwrap().span(),
)]
.into_iter()
.chain(
Expand Down
60 changes: 52 additions & 8 deletions async-zero-cost-templating-proc-macro2/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,7 @@ use std::{
use proc_macro2::{Delimiter, TokenStream, TokenTree};
use proc_macro2_diagnostics::{Diagnostic, SpanDiagnosticExt};
use syn::{
braced, bracketed,
ext::IdentExt,
parenthesized,
parse::{Parse, ParseStream},
spanned::Spanned,
token::{Brace, Bracket, Else, For, If, In, Paren, While},
Ident, LitStr, Token,
braced, bracketed, ext::IdentExt, parenthesized, parse::{Parse, ParseStream}, punctuated::Punctuated, spanned::Spanned, token::{Brace, Bracket, Else, For, If, In, Paren, While}, Ident, LitStr, Token
};
use tracing::instrument;
use tracing::{error, level_filters::LevelFilter};
Expand Down Expand Up @@ -197,9 +191,16 @@ pub enum HtmlInAttributeValueContext {
For(HtmlForLoop<Vec<HtmlInAttributeValueContext>>),
}


#[derive(Debug)]
pub enum DashOrColon {
Dash(Token![-]),
Colon(Token![:]),
}

#[derive(Debug)]
pub enum HtmlInAttributeContext {
Literal(Ident, Option<(Token![=], Vec<HtmlInAttributeValueContext>)>),
Literal(Punctuated<Ident, DashOrColon>, Option<(Token![=], Vec<HtmlInAttributeValueContext>)>),
Computation((Brace, TokenStream)),
If(HtmlIf<Vec<HtmlInAttributeContext>>),
While(HtmlWhile<Vec<HtmlInAttributeContext>>),
Expand Down Expand Up @@ -422,6 +423,48 @@ impl MyParse<HtmlInAttributeValueContext> for ParseStream<'_> {
}
}

impl MyParse<DashOrColon> for ParseStream<'_> {
fn inner_my_parse(self) -> Result<(DashOrColon, Vec<Diagnostic>), Vec<Diagnostic>> {
let lookahead = self.lookahead1();
let dash_or_colon = if lookahead.peek(Token![-]) {
self.parse().map(DashOrColon::Dash).map_err(|err| Vec::from([Diagnostic::from(err)]))?
} else if lookahead.peek(Token![:]) {
self.parse().map(DashOrColon::Colon).map_err(|err| Vec::from([Diagnostic::from(err)]))?
} else {
return Err(Vec::from([Diagnostic::from(lookahead.error())]))
};
Ok((dash_or_colon, vec![]))
}
}

impl MyParse<Punctuated<Ident, DashOrColon>> for ParseStream<'_> {
fn inner_my_parse(self) -> Result<(Punctuated<Ident, DashOrColon>, Vec<Diagnostic>), Vec<Diagnostic>> {
let mut diagnostics = Vec::new();
let mut ident: Punctuated<Ident, DashOrColon> = Punctuated::new();
ident.push_value({
let value: Ident;
(value, diagnostics) =
MyParse::my_parse(self, identity, identity, diagnostics)?;
value
});
while self.peek(Token![-]) || self.peek(Token![:]) {
ident.push_punct({
let value: DashOrColon;
(value, diagnostics) =
MyParse::my_parse(self, identity, identity, diagnostics)?;
value
});
ident.push_value({
let value: Ident;
(value, diagnostics) =
MyParse::my_parse(self, identity, identity, diagnostics)?;
value
});
}
Ok((ident, diagnostics))
}
}

impl MyParse<HtmlInAttributeContext> for ParseStream<'_> {
#[instrument(err(Debug), ret, name = "Html<Inner>")]
fn inner_my_parse(self) -> Result<(HtmlInAttributeContext, Vec<Diagnostic>), Vec<Diagnostic>> {
Expand Down Expand Up @@ -452,6 +495,7 @@ impl MyParse<HtmlInAttributeContext> for ParseStream<'_> {
diagnostics,
)?)
} else if lookahead.peek(Ident::peek_any) {
// here
Ok((
HtmlInAttributeContext::Literal(
{
Expand Down
16 changes: 16 additions & 0 deletions async-zero-cost-templating/tests/attribute_with_dash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
extern crate alloc;

use async_zero_cost_templating::html;
use async_zero_cost_templating::TemplateToStream;
use core::pin::pin;
use futures_util::stream::StreamExt;

#[tokio::test]
async fn test() {
let stream = html! {
<a aria-current="true">
</a>
};
let result: String = stream.collect().await;
assert_eq!(result, r#"<a aria-current="true"></a>"#)
}