Skip to content

Commit f90e561

Browse files
committed
derive: escape strings at compile-time when possible
1 parent 34340cd commit f90e561

File tree

2 files changed

+42
-18
lines changed

2 files changed

+42
-18
lines changed

rinja_derive/src/generator.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use quote::quote;
1414

1515
use crate::config::WhitespaceHandling;
1616
use crate::heritage::{Context, Heritage};
17+
use crate::html::write_escaped_str;
1718
use crate::input::{Source, TemplateInput};
1819
use crate::{CompileError, MsgValidEscapers, CRATE};
1920

@@ -1161,8 +1162,43 @@ impl<'a> Generator<'a> {
11611162
}
11621163

11631164
fn write_expr(&mut self, ws: Ws, s: &'a WithSpan<'a, Expr<'a>>) {
1165+
let mut writable = Writable::Expr(s);
1166+
(|| {
1167+
let &Expr::StrLit(input) = &**s else {
1168+
return;
1169+
};
1170+
1171+
let Some(escaper) = self.input.escaper.strip_prefix(CRATE) else {
1172+
return;
1173+
};
1174+
let is_html = match escaper {
1175+
"::filters::Html" => true,
1176+
"::filters::Text" => false,
1177+
_ => return,
1178+
};
1179+
1180+
// TODO: implement parsing properly
1181+
let input = format!(r#""{input}""#);
1182+
let Ok(input) = input.parse::<proc_macro2::TokenStream>() else {
1183+
return;
1184+
};
1185+
let Ok(input) = syn::parse2::<syn::LitStr>(input) else {
1186+
return;
1187+
};
1188+
let input = input.value();
1189+
1190+
if is_html {
1191+
let mut escaped = String::with_capacity(input.len() + 20);
1192+
if write_escaped_str(&mut escaped, &input).is_ok() {
1193+
writable = Writable::Lit(Cow::Owned(escaped));
1194+
}
1195+
} else {
1196+
writable = Writable::Lit(Cow::Owned(input));
1197+
}
1198+
})();
1199+
11641200
self.handle_ws(ws);
1165-
self.buf_writable.push(Writable::Expr(s));
1201+
self.buf_writable.push(writable);
11661202
}
11671203

11681204
// Write expression buffer and empty

rinja_derive/src/tests.rs

+5-17
Original file line numberDiff line numberDiff line change
@@ -346,25 +346,13 @@ writer.write_str("12")?;
346346
r#"writer.write_str("The card is")?;
347347
match &self.suit {
348348
Suit::Clubs | Suit::Spades => {
349-
match (
350-
&((&&::rinja::filters::AutoEscaper::new(&(" black"), ::rinja::filters::Text)).rinja_auto_escape()?),
351-
) {
352-
(expr0,) => {
353-
(&&::rinja::filters::Writable(expr0)).rinja_write(writer)?;
354-
}
355-
}
356-
}
357-
Suit::Diamonds | Suit::Hearts => {
358-
match (
359-
&((&&::rinja::filters::AutoEscaper::new(&(" red"), ::rinja::filters::Text)).rinja_auto_escape()?),
360-
) {
361-
(expr0,) => {
362-
(&&::rinja::filters::Writable(expr0)).rinja_write(writer)?;
363-
}
364-
}
349+
writer.write_str(" black")?;
350+
}
351+
Suit::Diamonds | Suit::Hearts => {
352+
writer.write_str(" red")?;
365353
}
366354
}"#,
367355
&[("suit", "Suit")],
368-
14,
356+
16,
369357
);
370358
}

0 commit comments

Comments
 (0)