a6199b76
—
Gal Schlezinger 6 years ago
escape strings
- Cargo.lock +7 -0
- render/Cargo.toml +1 -0
- render/src/lib.rs +11 -10
- render/src/text_element.rs +47 -6
- render_tests/src/lib.rs +12 -0
Cargo.lock
CHANGED
|
@@ -22,6 +22,11 @@ name = "difference"
|
|
|
22
22
|
version = "2.0.0"
|
|
23
23
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
24
24
|
|
|
25
|
+
[[package]]
|
|
26
|
+
name = "htmlescape"
|
|
27
|
+
version = "0.3.1"
|
|
28
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
29
|
+
|
|
25
30
|
[[package]]
|
|
26
31
|
name = "output_vt100"
|
|
27
32
|
version = "0.1.2"
|
|
@@ -61,6 +66,7 @@ dependencies = [
|
|
|
61
66
|
name = "render"
|
|
62
67
|
version = "0.1.0"
|
|
63
68
|
dependencies = [
|
|
69
|
+
"htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
64
70
|
"pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
65
71
|
"render_macros 0.1.0",
|
|
66
72
|
]
|
|
@@ -120,6 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
|
120
126
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
|
121
127
|
"checksum ctor 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3e061727ebef83bbccac7c27b9a5ff9fd83094d34cb20f4005440a9562a27de7"
|
|
122
128
|
"checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
|
|
129
|
+
"checksum htmlescape 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163"
|
|
123
130
|
"checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
|
|
124
131
|
"checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
|
|
125
132
|
"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
|
render/Cargo.toml
CHANGED
|
@@ -14,6 +14,7 @@ license = "MIT"
|
|
|
14
14
|
|
|
15
15
|
[dependencies]
|
|
16
16
|
render_macros = { path = "../render_macros", version = "0.1" }
|
|
17
|
+
htmlescape = "0.3"
|
|
17
18
|
|
|
18
19
|
[dev-dependencies]
|
|
19
20
|
pretty_assertions = "0.6"
|
render/src/lib.rs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
//! > 🔏 A safe and simple template engine with the ergonomics of JSX
|
|
2
|
-
//!
|
|
2
|
+
//!
|
|
3
3
|
//! The `Renderable` trait contains a simple function that returns `String`. This is very handy for type-safe HTML templates, but can also work for writing tree-like terminal coloring mechanism like ReasonML's [Pastel](https://reason-native.com/docs/pastel/).
|
|
4
|
-
//!
|
|
4
|
+
//!
|
|
5
5
|
//! ## Why this is different from `typed-html`?
|
|
6
|
-
//!
|
|
6
|
+
//!
|
|
7
7
|
//! `typed-html` is a wonderful library. Unfortunately, it focused its power in strictness of the HTML spec itself, and doesn't allow arbitrary compositions of custom elements.
|
|
8
|
-
//!
|
|
8
|
+
//!
|
|
9
9
|
//! `render` takes a different approach. For now, HTML is not typed at all. It can get any key and get any string value. The main focus is custom components, so you can create a composable and declarative template with no runtime errors.
|
|
10
|
-
//!
|
|
10
|
+
//!
|
|
11
11
|
//! ## Usage
|
|
12
|
-
//!
|
|
12
|
+
//!
|
|
13
13
|
//! ```rust
|
|
14
14
|
//! #![feature(proc_macro_hygiene)]
|
|
15
|
-
//!
|
|
15
|
+
//!
|
|
16
16
|
//! // A simple HTML 5 doctype declaration
|
|
17
17
|
//! use render::html::HTML5Doctype;
|
|
18
18
|
//! use render::{
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
//! // A trait for custom components
|
|
24
24
|
//! Renderable,
|
|
25
25
|
//! };
|
|
26
|
-
//!
|
|
26
|
+
//!
|
|
27
27
|
//! // This can be any layout we want
|
|
28
28
|
//! #[derive(Debug)]
|
|
29
29
|
//! struct Page<'a, T: Renderable> {
|
|
30
30
|
//! title: &'a str,
|
|
31
31
|
//! children: T,
|
|
32
32
|
//! }
|
|
33
|
-
//!
|
|
33
|
+
//!
|
|
34
34
|
//! // Implementing `Renderable` gives the ability to compose
|
|
35
35
|
//! // components
|
|
36
36
|
//! impl<'a, T: Renderable> Renderable for Page<'a, T> {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
//! }
|
|
49
49
|
//! }
|
|
50
50
|
//! }
|
|
51
|
-
//!
|
|
51
|
+
//!
|
|
52
52
|
//! // This can be a route in Rocket, the web framework,
|
|
53
53
|
//! // for instance.
|
|
54
54
|
//! pub fn some_page(user_name: &str) -> String {
|
|
@@ -83,3 +83,4 @@ pub use fragment::Fragment;
|
|
|
83
83
|
pub use render_macros::{html, rsx};
|
|
84
84
|
pub use renderable::Renderable;
|
|
85
85
|
pub use simple_element::SimpleElement;
|
|
86
|
+
pub use text_element::Raw;
|
render/src/text_element.rs
CHANGED
|
@@ -1,17 +1,58 @@
|
|
|
1
1
|
use crate::Renderable;
|
|
2
|
+
use htmlescape::encode_minimal;
|
|
2
3
|
|
|
3
|
-
/// Renders
|
|
4
|
+
/// Renders an escaped-html string
|
|
4
|
-
/// > TODO: this should escape HTML!
|
|
5
5
|
impl Renderable for String {
|
|
6
6
|
fn render(self) -> String {
|
|
7
|
-
self
|
|
7
|
+
encode_minimal(&self)
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
/// Renders
|
|
11
|
+
/// Renders an escaped-html string
|
|
12
|
-
/// > TODO: this should escape HTML!
|
|
13
12
|
impl Renderable for &str {
|
|
14
13
|
fn render(self) -> String {
|
|
15
|
-
|
|
14
|
+
encode_minimal(self)
|
|
16
15
|
}
|
|
17
16
|
}
|
|
17
|
+
|
|
18
|
+
/// A raw (unencoded) html string
|
|
19
|
+
#[derive(Debug)]
|
|
20
|
+
pub struct Raw<'s>(&'s str);
|
|
21
|
+
|
|
22
|
+
impl<'s> From<&'s str> for Raw<'s> {
|
|
23
|
+
fn from(s: &'s str) -> Self {
|
|
24
|
+
Raw(s)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/// A raw (unencoded) html string
|
|
29
|
+
impl<'s> Renderable for Raw<'s> {
|
|
30
|
+
fn render(self) -> String {
|
|
31
|
+
self.0.to_string()
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[cfg(test)]
|
|
36
|
+
mod tests {
|
|
37
|
+
use super::*;
|
|
38
|
+
|
|
39
|
+
#[test]
|
|
40
|
+
fn decodes_html() {
|
|
41
|
+
let rendered = "<Hello />".render();
|
|
42
|
+
assert_eq!(rendered, "<Hello />");
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#[test]
|
|
46
|
+
fn allows_raw_text() {
|
|
47
|
+
let rendered = Raw::from("<Hello />").render();
|
|
48
|
+
assert_eq!(rendered, "<Hello />");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/// Creates a raw (unencoded) html string
|
|
53
|
+
#[macro_export]
|
|
54
|
+
macro_rules! raw {
|
|
55
|
+
($text:expr) => {
|
|
56
|
+
::render::Raw::from($text)
|
|
57
|
+
};
|
|
58
|
+
}
|
render_tests/src/lib.rs
CHANGED
|
@@ -44,3 +44,15 @@ pub fn it_works() -> String {
|
|
|
44
44
|
pub fn verify_works() {
|
|
45
45
|
println!("{}", it_works());
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
#[test]
|
|
49
|
+
pub fn works_with_raw() {
|
|
50
|
+
use pretty_assertions::assert_eq;
|
|
51
|
+
use render::raw;
|
|
52
|
+
|
|
53
|
+
let actual = html! {
|
|
54
|
+
<div>{raw!("<Hello />")}</div>
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
assert_eq!(actual, "<div><Hello /></div>");
|
|
58
|
+
}
|