Add support for raw (unescaped HTML) blocks
This commit is contained in:
parent
7171145aa5
commit
91ba94a38a
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -780,6 +780,7 @@ dependencies = [
|
|||||||
"hornbeam_grammar",
|
"hornbeam_grammar",
|
||||||
"hornbeam_ir",
|
"hornbeam_ir",
|
||||||
"html-escape",
|
"html-escape",
|
||||||
|
"insta",
|
||||||
"itertools",
|
"itertools",
|
||||||
"pollster",
|
"pollster",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@ -940,16 +941,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "insta"
|
name = "insta"
|
||||||
version = "1.28.0"
|
version = "1.38.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fea5b3894afe466b4bcf0388630fc15e11938a6074af0cd637c825ba2ec8a099"
|
checksum = "3eab73f58e59ca6526037208f0e98851159ec1633cf17b6cd2e1f2c3fd5d53cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console",
|
"console",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"linked-hash-map",
|
"linked-hash-map",
|
||||||
"serde",
|
"serde",
|
||||||
"similar",
|
"similar",
|
||||||
"yaml-rust",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2117,12 +2117,3 @@ checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yaml-rust"
|
|
||||||
version = "0.4.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
|
||||||
dependencies = [
|
|
||||||
"linked-hash-map",
|
|
||||||
]
|
|
||||||
|
@ -15,6 +15,7 @@ pub enum Block {
|
|||||||
ForBlock(ForBlock),
|
ForBlock(ForBlock),
|
||||||
MatchBlock(MatchBlock),
|
MatchBlock(MatchBlock),
|
||||||
Text(StringExpr),
|
Text(StringExpr),
|
||||||
|
RawUnescapedHtml(StringExpr),
|
||||||
DefineExpandSlot(DefineExpandSlot),
|
DefineExpandSlot(DefineExpandSlot),
|
||||||
DefineFragment(DefineFragment),
|
DefineFragment(DefineFragment),
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ BlockContent = _{
|
|||||||
Element |
|
Element |
|
||||||
IfBlock |
|
IfBlock |
|
||||||
Text |
|
Text |
|
||||||
|
RawUnescapedHtml |
|
||||||
DefineExpandSlot |
|
DefineExpandSlot |
|
||||||
ForBlock |
|
ForBlock |
|
||||||
MatchBlock |
|
MatchBlock |
|
||||||
@ -34,6 +35,10 @@ Text = {
|
|||||||
String ~ lineEnd
|
String ~ lineEnd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RawUnescapedHtml = {
|
||||||
|
"raw" ~ ws+ ~ String ~ lineEnd
|
||||||
|
}
|
||||||
|
|
||||||
IfBlock = {
|
IfBlock = {
|
||||||
"if" ~ ws+ ~ IfCondition ~ lineEnd ~ NewBlock ~
|
"if" ~ ws+ ~ IfCondition ~ lineEnd ~ NewBlock ~
|
||||||
ElseBlock?
|
ElseBlock?
|
||||||
|
@ -202,6 +202,12 @@ impl HornbeamParser {
|
|||||||
)?))
|
)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn RawUnescapedHtml(input: Node) -> PCResult<Block> {
|
||||||
|
Ok(Block::RawUnescapedHtml(HornbeamParser::String(
|
||||||
|
input.into_children().single()?,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
|
||||||
fn String(input: Node) -> PCResult<StringExpr> {
|
fn String(input: Node) -> PCResult<StringExpr> {
|
||||||
let mut pieces = Vec::new();
|
let mut pieces = Vec::new();
|
||||||
for node in input.into_children() {
|
for node in input.into_children() {
|
||||||
@ -491,6 +497,7 @@ impl HornbeamParser {
|
|||||||
Ok(match input.as_rule() {
|
Ok(match input.as_rule() {
|
||||||
Rule::Element => Some(HornbeamParser::Element(input)?),
|
Rule::Element => Some(HornbeamParser::Element(input)?),
|
||||||
Rule::Text => Some(HornbeamParser::Text(input)?),
|
Rule::Text => Some(HornbeamParser::Text(input)?),
|
||||||
|
Rule::RawUnescapedHtml => Some(HornbeamParser::RawUnescapedHtml(input)?),
|
||||||
Rule::IfBlock => Some(HornbeamParser::IfBlock(input)?),
|
Rule::IfBlock => Some(HornbeamParser::IfBlock(input)?),
|
||||||
Rule::ForBlock => Some(HornbeamParser::ForBlock(input)?),
|
Rule::ForBlock => Some(HornbeamParser::ForBlock(input)?),
|
||||||
Rule::MatchBlock => Some(HornbeamParser::MatchBlock(input)?),
|
Rule::MatchBlock => Some(HornbeamParser::MatchBlock(input)?),
|
||||||
@ -666,4 +673,17 @@ div
|
|||||||
)
|
)
|
||||||
.unwrap());
|
.unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn raw() {
|
||||||
|
assert_yaml_snapshot!(parse_template(
|
||||||
|
r#"
|
||||||
|
div
|
||||||
|
span
|
||||||
|
raw "<u>wow $x ${$x} @wowage{}</u>"
|
||||||
|
"#,
|
||||||
|
"inp"
|
||||||
|
)
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
source: hornbeam_grammar/src/parser.rs
|
||||||
|
expression: "parse_template(r#\"\ndiv\n span\n raw \"<u>wow $x ${$x} @wowage{}</u>\"\n \"#,\n \"inp\").unwrap()"
|
||||||
|
---
|
||||||
|
blocks:
|
||||||
|
- HtmlElement:
|
||||||
|
name: div
|
||||||
|
children:
|
||||||
|
- HtmlElement:
|
||||||
|
name: span
|
||||||
|
children:
|
||||||
|
- RawUnescapedHtml:
|
||||||
|
pieces:
|
||||||
|
- Literal: "<u>wow "
|
||||||
|
- Interpolation:
|
||||||
|
Variable:
|
||||||
|
name: x
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 21
|
||||||
|
- Literal: " "
|
||||||
|
- Interpolation:
|
||||||
|
Variable:
|
||||||
|
name: x
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 26
|
||||||
|
- Literal: " @wowage{}</u>"
|
||||||
|
classes: []
|
||||||
|
dom_id: ~
|
||||||
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
|
classes: []
|
||||||
|
dom_id: ~
|
||||||
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
@ -29,3 +29,6 @@ tracing = "0.1.37"
|
|||||||
[features]
|
[features]
|
||||||
default = ["fluent"]
|
default = ["fluent"]
|
||||||
fluent = ["fluent-templates"]
|
fluent = ["fluent-templates"]
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
insta = "1.38.0"
|
||||||
|
56
hornbeam_interpreter/tests/snapshots.rs
Normal file
56
hornbeam_interpreter/tests/snapshots.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use bevy_reflect::Reflect;
|
||||||
|
use hornbeam_interpreter::{localisation::NoLocalisation, LoadedTemplates, Params};
|
||||||
|
use insta::assert_snapshot;
|
||||||
|
|
||||||
|
#[derive(Reflect)]
|
||||||
|
struct SimpleTestStruct {
|
||||||
|
wombat: u64,
|
||||||
|
apple: u64,
|
||||||
|
banana: String,
|
||||||
|
carrot: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_test_struct() -> SimpleTestStruct {
|
||||||
|
SimpleTestStruct {
|
||||||
|
wombat: 42,
|
||||||
|
apple: 78,
|
||||||
|
banana: "banana!!!".to_owned(),
|
||||||
|
carrot: "mmm CARROT".to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn simple_render(template: &str) -> String {
|
||||||
|
let mut templates = LoadedTemplates::new(NoLocalisation);
|
||||||
|
templates
|
||||||
|
.load_template_from_str("main", template, "main.hnb")
|
||||||
|
.expect("failed to load template");
|
||||||
|
let params = Params::default()
|
||||||
|
.set("sts", simple_test_struct())
|
||||||
|
.set("five", 5);
|
||||||
|
let prepared = templates.prepare("main", None, params, "en".to_owned());
|
||||||
|
prepared.render_to_string().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn snapshot_001() {
|
||||||
|
assert_snapshot!(simple_render(
|
||||||
|
r#"
|
||||||
|
html
|
||||||
|
body
|
||||||
|
"this was a triumph :>"
|
||||||
|
br
|
||||||
|
raw "<u>making a note here, huge success</u>"
|
||||||
|
|
||||||
|
if $five == 5
|
||||||
|
"FIVE!!! $five"
|
||||||
|
br
|
||||||
|
|
||||||
|
if $five < 10
|
||||||
|
"five is less than ten!"
|
||||||
|
br
|
||||||
|
|
||||||
|
if $five > 5
|
||||||
|
"weird..."
|
||||||
|
"#
|
||||||
|
))
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
source: hornbeam_interpreter/tests/snapshots.rs
|
||||||
|
expression: "simple_render(r#\"\nhtml\n body\n \"this was a triumph :>\"\n br\n raw \"<u>making a note here, huge success</u>\"\n\n if $five == 5\n \"FIVE!!! $five\"\n br\n\n if $five < 10\n \"five is less than ten!\"\n br\n\n if $five > 5\n \"weird...\"\n \"#)"
|
||||||
|
---
|
||||||
|
<!DOCTYPE html><html><body>this was a triumph :><br><u>making a note here, huge success</u>FIVE!!! 5<br>five is less than ten!<br></body></html>
|
@ -132,7 +132,7 @@ fn pull_out_entrypoints_from_block<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Block::Text(_) | Block::DefineExpandSlot(_) => { /* nop */ }
|
Block::Text(_) | Block::RawUnescapedHtml(_) | Block::DefineExpandSlot(_) => { /* nop */ }
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -411,6 +411,41 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Block::RawUnescapedHtml(text) => {
|
||||||
|
for piece in &text.pieces {
|
||||||
|
match piece {
|
||||||
|
StringPiece::Literal(lit) => {
|
||||||
|
instructions.push(Step {
|
||||||
|
def: StepDef::WriteLiteral {
|
||||||
|
text: lit.clone(),
|
||||||
|
escape: false,
|
||||||
|
},
|
||||||
|
locator: Locator::empty(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
StringPiece::Interpolation(expr) => {
|
||||||
|
instructions.push(Step {
|
||||||
|
def: StepDef::WriteEval {
|
||||||
|
expr: expr.clone(),
|
||||||
|
escape: false,
|
||||||
|
},
|
||||||
|
locator: Locator::empty(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
piece @ StringPiece::Localise { .. } => {
|
||||||
|
instructions.push(Step {
|
||||||
|
def: StepDef::WriteEval {
|
||||||
|
expr: Expression::StringExpr(StringExpr {
|
||||||
|
pieces: vec![piece.clone()],
|
||||||
|
}),
|
||||||
|
escape: false,
|
||||||
|
},
|
||||||
|
locator: Locator::empty(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Block::DefineExpandSlot(slot) => {
|
Block::DefineExpandSlot(slot) => {
|
||||||
instructions.push(Step {
|
instructions.push(Step {
|
||||||
def: StepDef::CallSlotWithParentScope {
|
def: StepDef::CallSlotWithParentScope {
|
||||||
|
Loading…
Reference in New Issue
Block a user