mirror of
https://github.com/Orange-OpenSource/hurl.git
synced 2024-12-23 02:52:34 +03:00
Add Date value/filters
This commit is contained in:
parent
8d470a51b6
commit
550c517149
@ -415,18 +415,22 @@ variable-name: [A-Za-z] [A-Za-z_-0-9]*
|
||||
|
||||
filter:
|
||||
count-filter
|
||||
| format-filter
|
||||
| html-escape-filter
|
||||
| html-unescape-filter
|
||||
| nth-filter
|
||||
| regex-filter
|
||||
| replace-filter
|
||||
| split-filter
|
||||
| to-date-filter
|
||||
| to-int-filter
|
||||
| url-decode-filter
|
||||
| url-encode-filter
|
||||
|
||||
count-filter: "count"
|
||||
|
||||
format-filter: "format"
|
||||
|
||||
html-escape-filter: "htmlEscape"
|
||||
|
||||
html-unescape-filter: "htmlUnescape"
|
||||
@ -439,6 +443,8 @@ replace-filter: "replace" sp (quoted-string | regex) sp quoted-string
|
||||
|
||||
split-filter: "split" sp quoted-string
|
||||
|
||||
to-date-filter: "toDate"
|
||||
|
||||
to-int-filter: "toInt"
|
||||
|
||||
url-decode-filter: "urlDecode"
|
||||
|
@ -24,4 +24,12 @@ error: Filter Error
|
||||
|
|
||||
7 | jsonpath "$.list" nth 5 == 3
|
||||
| ^^^^^ invalid filter input: Out of bound - size is 3
|
||||
|
|
||||
|
|
||||
|
||||
error: Filter Error
|
||||
--> tests_failed/filter.hurl:8:17
|
||||
|
|
||||
8 | jsonpath "$.id" toDate "%a, %d %b %Y %H:%M:%S GMT" == "unused"
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid filter input: string <123x>
|
||||
|
|
||||
|
||||
|
@ -5,3 +5,4 @@ jsonpath "$.id" toInt == 123
|
||||
jsonpath "$.status" toInt == 0
|
||||
jsonpath "$.unknown" toInt == 1
|
||||
jsonpath "$.list" nth 5 == 3
|
||||
jsonpath "$.id" toDate "%a, %d %b %Y %H:%M:%S GMT" == "unused"
|
@ -9,6 +9,8 @@
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Content-Type"</span> <span class="predicate-type">exists</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Header1"</span> <span class="predicate-type">==</span> <span class="string">"value1"</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"ETag"</span> <span class="predicate-type">==</span> <span class="string">"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Expires"</span> <span class="predicate-type">==</span> <span class="string">"Wed, 21 Oct 2015 07:28:00 GMT"</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Expires"</span> <span class="filter-type">toDate</span> <span class="string">"%a, %d %b %Y %H:%M:%S GMT"</span> <span class="filter-type">format</span> <span class="string">"%Y"</span> <span class="predicate-type">==</span> <span class="string">"2015"</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Set-Cookie"</span> <span class="predicate-type">exists</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Set-Cookie"</span> <span class="filter-type">count</span> <span class="predicate-type">==</span> <span class="number">3</span></span>
|
||||
<span class="line"><span class="query-type">header</span> <span class="string">"Set-Cookie"</span> <span class="predicate-type">includes</span> <span class="string">"cookie1=value1; Path=/"</span></span>
|
||||
|
@ -9,6 +9,8 @@ header "Custom" not exists
|
||||
header "Content-Type" exists
|
||||
header "Header1" == "value1"
|
||||
header "ETag" == "\"33a64df551425fcc55e4d42a148795d9f25f89d4\""
|
||||
header "Expires" == "Wed, 21 Oct 2015 07:28:00 GMT"
|
||||
header "Expires" toDate "%a, %d %b %Y %H:%M:%S GMT" format "%Y" == "2015"
|
||||
header "Set-Cookie" exists
|
||||
header "Set-Cookie" count == 3
|
||||
header "Set-Cookie" includes "cookie1=value1; Path=/"
|
||||
|
@ -1 +1 @@
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/assert-header"},"response":{"status":200,"headers":[{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"}],"asserts":[{"query":{"type":"header","name":"Custom"},"predicate":{"not":true,"type":"exist"}},{"query":{"type":"header","name":"Content-Type"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Header1"},"predicate":{"type":"equal","value":"value1"}},{"query":{"type":"header","name":"ETag"},"predicate":{"type":"equal","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Set-Cookie"},"filters":[{"type":"count"}],"predicate":{"type":"equal","value":3}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"include","value":"cookie1=value1; Path=/"}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"not":true,"type":"include","value":"cookie4=value4; Path=/"}}]}}]}
|
||||
{"entries":[{"request":{"method":"GET","url":"http://localhost:8000/assert-header"},"response":{"status":200,"headers":[{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"}],"asserts":[{"query":{"type":"header","name":"Custom"},"predicate":{"not":true,"type":"exist"}},{"query":{"type":"header","name":"Content-Type"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Header1"},"predicate":{"type":"equal","value":"value1"}},{"query":{"type":"header","name":"ETag"},"predicate":{"type":"equal","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""}},{"query":{"type":"header","name":"Expires"},"predicate":{"type":"equal","value":"Wed, 21 Oct 2015 07:28:00 GMT"}},{"query":{"type":"header","name":"Expires"},"filters":[{"type":"toDate","fmt":"%a, %d %b %Y %H:%M:%S GMT"},{"type":"format","fmt":"%Y"}],"predicate":{"type":"equal","value":"2015"}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"exist"}},{"query":{"type":"header","name":"Set-Cookie"},"filters":[{"type":"count"}],"predicate":{"type":"equal","value":3}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"type":"include","value":"cookie1=value1; Path=/"}},{"query":{"type":"header","name":"Set-Cookie"},"predicate":{"not":true,"type":"include","value":"cookie4=value4; Path=/"}}]}}]}
|
||||
|
@ -1 +1 @@
|
||||
{"cookies":[{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie1","path":"/","value":"value1"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie2","path":"/","value":"value2"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie3","path":"/","value":"value3"}],"entries":[{"asserts":[{"line":3,"success":true},{"line":3,"success":true},{"line":4,"success":true},{"line":5,"success":true},{"line":6,"success":true},{"line":8,"success":true},{"line":9,"success":true},{"line":10,"success":true},{"line":11,"success":true},{"line":12,"success":true},{"line":13,"success":true},{"line":14,"success":true},{"line":15,"success":true}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/~~~"}],"method":"GET","queryString":[],"url":"http://localhost:8000/assert-header"},"response":{"cookies":[{"name":"cookie1","path":"/","value":"value1"},{"name":"cookie2","path":"/","value":"value2"},{"name":"cookie3","path":"/","value":"value3"}],"headers":[{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Header1","value":"value1"},{"name":"ETag","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"},{"name":"Set-Cookie","value":"cookie3=value3; Path=/"},{"name":"Server","value":"Flask Server"},{"name":"Content-Length","value":"0"},{"name":"Date","value":"~~~"}],"httpVersion":"HTTP/1.0","status":200}}],"captures":[],"index":1,"time":~~~}],"filename":"tests_ok/assert_header.hurl","success":true,"time":~~~}
|
||||
{"cookies":[{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie1","path":"/","value":"value1"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie2","path":"/","value":"value2"},{"domain":"localhost","expires":"0","https":"FALSE","include_subdomain":"FALSE","name":"cookie3","path":"/","value":"value3"}],"entries":[{"asserts":[{"line":3,"success":true},{"line":3,"success":true},{"line":4,"success":true},{"line":5,"success":true},{"line":6,"success":true},{"line":8,"success":true},{"line":9,"success":true},{"line":10,"success":true},{"line":11,"success":true},{"line":12,"success":true},{"line":13,"success":true},{"line":14,"success":true},{"line":15,"success":true},{"line":16,"success":true},{"line":17,"success":true}],"calls":[{"request":{"cookies":[],"headers":[{"name":"Host","value":"localhost:8000"},{"name":"Accept","value":"*/*"},{"name":"User-Agent","value":"hurl/2.1.0-SNAPSHOT"}],"method":"GET","queryString":[],"url":"http://localhost:8000/assert-header"},"response":{"cookies":[{"name":"cookie1","path":"/","value":"value1"},{"name":"cookie2","path":"/","value":"value2"},{"name":"cookie3","path":"/","value":"value3"}],"headers":[{"name":"Content-Type","value":"text/html; charset=utf-8"},{"name":"Header1","value":"value1"},{"name":"ETag","value":"\"33a64df551425fcc55e4d42a148795d9f25f89d4\""},{"name":"Expires","value":"Wed, 21 Oct 2015 07:28:00 GMT"},{"name":"Set-Cookie","value":"cookie1=value1; Path=/"},{"name":"Set-Cookie","value":"cookie2=value2; Path=/"},{"name":"Set-Cookie","value":"cookie3=value3; Path=/"},{"name":"Server","value":"Flask Server"},{"name":"Content-Length","value":"0"},{"name":"Date","value":"~~~"}],"httpVersion":"HTTP/1.0","status":200}}],"captures":[],"index":1,"time":~~~}],"filename":"tests_ok/assert_header.hurl","success":true,"time":~~~}
|
||||
|
@ -7,6 +7,7 @@ def assert_header():
|
||||
resp = make_response()
|
||||
resp.headers["Header1"] = "value1"
|
||||
resp.headers["ETag"] = '"33a64df551425fcc55e4d42a148795d9f25f89d4"'
|
||||
resp.headers["Expires"] = "Wed, 21 Oct 2015 07:28:00 GMT"
|
||||
resp.set_cookie("cookie1", "value1")
|
||||
resp.set_cookie("cookie2", "value2")
|
||||
resp.set_cookie("cookie3", "value3")
|
||||
|
@ -24,6 +24,7 @@ impl Value {
|
||||
pub fn to_json(&self) -> serde_json::Value {
|
||||
match self {
|
||||
Value::Bool(v) => serde_json::Value::Bool(*v),
|
||||
Value::Date(v) => serde_json::Value::String(v.to_string()),
|
||||
Value::Integer(v) => serde_json::Value::Number(serde_json::Number::from(*v)),
|
||||
Value::Float(f) => serde_json::Value::Number(serde_json::Number::from_f64(*f).unwrap()),
|
||||
Value::String(s) => serde_json::Value::String(s.clone()),
|
||||
|
@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
use chrono::NaiveDateTime;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use percent_encoding::AsciiSet;
|
||||
@ -49,6 +50,9 @@ fn eval_filter(
|
||||
) -> Result<Value, Error> {
|
||||
match &filter.value {
|
||||
FilterValue::Count => eval_count(value, &filter.source_info, in_assert),
|
||||
FilterValue::Format { fmt, .. } => {
|
||||
eval_format(value, fmt, variables, &filter.source_info, in_assert)
|
||||
}
|
||||
FilterValue::HtmlEscape => eval_html_escape(value, &filter.source_info, in_assert),
|
||||
FilterValue::HtmlUnescape => eval_html_unescape(value, &filter.source_info, in_assert),
|
||||
FilterValue::Regex {
|
||||
@ -76,6 +80,9 @@ fn eval_filter(
|
||||
FilterValue::Split { sep, .. } => {
|
||||
eval_split(value, variables, &filter.source_info, in_assert, sep)
|
||||
}
|
||||
FilterValue::ToDate { fmt, .. } => {
|
||||
eval_to_date(value, fmt, variables, &filter.source_info, in_assert)
|
||||
}
|
||||
FilterValue::ToInt => eval_to_int(value, &filter.source_info, in_assert),
|
||||
FilterValue::UrlDecode => eval_url_decode(value, &filter.source_info, in_assert),
|
||||
FilterValue::UrlEncode => eval_url_encode(value, &filter.source_info, in_assert),
|
||||
@ -127,6 +134,28 @@ fn eval_count(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<V
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_format(
|
||||
value: &Value,
|
||||
fmt: &Template,
|
||||
variables: &HashMap<String, Value>,
|
||||
source_info: &SourceInfo,
|
||||
assert: bool,
|
||||
) -> Result<Value, Error> {
|
||||
let fmt = eval_template(fmt, variables)?;
|
||||
|
||||
match value {
|
||||
Value::Date(value) => {
|
||||
let formatted = format!("{}", value.format(fmt.as_str()));
|
||||
Ok(Value::String(formatted))
|
||||
}
|
||||
v => Err(Error {
|
||||
source_info: source_info.clone(),
|
||||
inner: RunnerError::FilterInvalidInput(v._type()),
|
||||
assert,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
// does not encode "/"
|
||||
// like Jinja template (https://jinja.palletsprojects.com/en/3.1.x/templates/#jinja-filters.urlencode)
|
||||
fn eval_url_encode(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<Value, Error> {
|
||||
@ -269,6 +298,32 @@ fn eval_split(
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_to_date(
|
||||
value: &Value,
|
||||
fmt: &Template,
|
||||
variables: &HashMap<String, Value>,
|
||||
source_info: &SourceInfo,
|
||||
assert: bool,
|
||||
) -> Result<Value, Error> {
|
||||
let fmt = eval_template(fmt, variables)?;
|
||||
|
||||
match value {
|
||||
Value::String(v) => match NaiveDateTime::parse_from_str(v, fmt.as_str()) {
|
||||
Ok(v) => Ok(Value::Date(v.and_local_timezone(chrono::Utc).unwrap())),
|
||||
Err(_) => Err(Error {
|
||||
source_info: source_info.clone(),
|
||||
inner: RunnerError::FilterInvalidInput(value.display()),
|
||||
assert,
|
||||
}),
|
||||
},
|
||||
v => Err(Error {
|
||||
source_info: source_info.clone(),
|
||||
inner: RunnerError::FilterInvalidInput(v.display()),
|
||||
assert,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_to_int(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<Value, Error> {
|
||||
match value {
|
||||
Value::Integer(v) => Ok(Value::Integer(*v)),
|
||||
@ -291,9 +346,10 @@ fn eval_to_int(value: &Value, source_info: &SourceInfo, assert: bool) -> Result<
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use hurl_core::ast::{FilterValue, SourceInfo, Template, TemplateElement, Whitespace};
|
||||
|
||||
use super::*;
|
||||
use chrono::offset::Utc;
|
||||
use chrono::prelude::*;
|
||||
use hurl_core::ast::{FilterValue, SourceInfo, Template, TemplateElement, Whitespace};
|
||||
|
||||
pub fn filter_count() -> Filter {
|
||||
Filter {
|
||||
@ -351,6 +407,42 @@ pub mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn eval_filter_format() {
|
||||
// let naivedatetime_utc = NaiveDate::from_ymd_opt(2000, 1, 12).unwrap().and_hms_opt(2, 0, 0).unwrap();
|
||||
//let datetime_utc = DateTime::<Utc>::from_utc(naivedatetime_utc, Utc);
|
||||
|
||||
let variables = HashMap::new();
|
||||
let whitespace = Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
};
|
||||
let filter = Filter {
|
||||
source_info: SourceInfo::new(1, 1, 1, 20),
|
||||
value: FilterValue::Format {
|
||||
space0: whitespace,
|
||||
fmt: Template {
|
||||
delimiter: None,
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "%d/%m/%Y %H:%M".to_string(),
|
||||
encoded: "%d/%m/%Y %H:%M".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(1, 7, 1, 20),
|
||||
},
|
||||
},
|
||||
};
|
||||
assert_eq!(
|
||||
eval_filter(
|
||||
&filter,
|
||||
&Value::Date(Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap()),
|
||||
&variables,
|
||||
false,
|
||||
)
|
||||
.unwrap(),
|
||||
Value::String("02/04/2017 12:50".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eval_filter_regex() {
|
||||
// regex "Hello (.*)!"
|
||||
@ -711,4 +803,77 @@ pub mod tests {
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn eval_filter_to_date() {
|
||||
let variables = HashMap::new();
|
||||
|
||||
let filter = Filter {
|
||||
source_info: SourceInfo::new(1, 1, 1, 1),
|
||||
value: FilterValue::ToDate {
|
||||
fmt: Template {
|
||||
delimiter: Some('"'),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "%Y %b %d %H:%M:%S%.3f %z".to_string(),
|
||||
encoded: "%Y %b %d %H:%M:%S%.3f %z".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
space0: Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let naivedatetime_utc = NaiveDate::from_ymd_opt(1983, 4, 13)
|
||||
.unwrap()
|
||||
.and_hms_micro_opt(12, 9, 14, 274000)
|
||||
.unwrap();
|
||||
let datetime_utc = DateTime::<Utc>::from_utc(naivedatetime_utc, Utc);
|
||||
assert_eq!(
|
||||
eval_filter(
|
||||
&filter,
|
||||
&Value::String("1983 Apr 13 12:09:14.274 +0000".to_string()),
|
||||
&variables,
|
||||
false
|
||||
)
|
||||
.unwrap(),
|
||||
Value::Date(datetime_utc)
|
||||
);
|
||||
|
||||
let filter = Filter {
|
||||
source_info: SourceInfo::new(1, 1, 1, 1),
|
||||
value: FilterValue::ToDate {
|
||||
fmt: Template {
|
||||
delimiter: Some('"'),
|
||||
elements: vec![TemplateElement::String {
|
||||
value: "%a, %d %b %Y %H:%M:%S GMT".to_string(),
|
||||
encoded: "%a, %d %b %Y %H:%M:%S GMT".to_string(),
|
||||
}],
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
space0: Whitespace {
|
||||
value: String::from(""),
|
||||
source_info: SourceInfo::new(0, 0, 0, 0),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
let naivedatetime_utc = NaiveDate::from_ymd_opt(2015, 10, 21)
|
||||
.unwrap()
|
||||
.and_hms_opt(7, 28, 0)
|
||||
.unwrap();
|
||||
let datetime_utc = DateTime::<Utc>::from_utc(naivedatetime_utc, Utc);
|
||||
assert_eq!(
|
||||
eval_filter(
|
||||
&filter,
|
||||
&Value::String("Wed, 21 Oct 2015 07:28:00 GMT".to_string()),
|
||||
&variables,
|
||||
false
|
||||
)
|
||||
.unwrap(),
|
||||
Value::Date(datetime_utc)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -94,6 +94,7 @@ impl Value {
|
||||
pub fn display(&self) -> String {
|
||||
match self {
|
||||
Value::Bool(v) => format!("bool <{v}>"),
|
||||
Value::Date(v) => format!("date <{v}>"),
|
||||
Value::Integer(v) => format!("int <{v}>"),
|
||||
Value::String(v) => format!("string <{v}>"),
|
||||
Value::Float(f) => format!("float <{}>", format_float(*f)),
|
||||
@ -139,6 +140,7 @@ impl Value {
|
||||
match self {
|
||||
Value::Bool(value) => format!("bool <{value}>"),
|
||||
Value::Bytes(values) => format!("list of size {}", values.len()),
|
||||
Value::Date(value) => format!("date <{value}>"),
|
||||
Value::Float(f) => format!("float <{}>", format_float(*f)),
|
||||
Value::Integer(value) => format!("integer <{value}>"),
|
||||
Value::List(value) => format!("list of size {}", value.len()),
|
||||
|
@ -25,6 +25,7 @@ use std::fmt;
|
||||
pub enum Value {
|
||||
Bool(bool),
|
||||
Bytes(Vec<u8>),
|
||||
Date(chrono::DateTime<chrono::Utc>),
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
List(Vec<Value>),
|
||||
@ -50,6 +51,7 @@ impl PartialEq for Value {
|
||||
(Value::Object(v1), Value::Object(v2)) => v1 == v2,
|
||||
(Value::String(v1), Value::String(v2)) => v1 == v2,
|
||||
(Value::Unit, Value::Unit) => true,
|
||||
(Value::Date(v1), Value::Date(v2)) => v1 == v2,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -62,6 +64,7 @@ impl fmt::Display for Value {
|
||||
let value = match self {
|
||||
Value::Integer(x) => x.to_string(),
|
||||
Value::Bool(x) => x.to_string(),
|
||||
Value::Date(v) => v.to_string(),
|
||||
Value::Float(f) => format_float(*f),
|
||||
Value::String(x) => x.clone(),
|
||||
Value::List(values) => {
|
||||
@ -95,6 +98,7 @@ impl Value {
|
||||
match self {
|
||||
Value::Integer(_) => "integer".to_string(),
|
||||
Value::Bool(_) => "boolean".to_string(),
|
||||
Value::Date(_) => "date".to_string(),
|
||||
Value::Float(_) => "float".to_string(),
|
||||
Value::String(_) => "string".to_string(),
|
||||
Value::List(_) => "list".to_string(),
|
||||
|
@ -873,6 +873,10 @@ pub struct Filter {
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum FilterValue {
|
||||
Count,
|
||||
Format {
|
||||
space0: Whitespace,
|
||||
fmt: Template,
|
||||
},
|
||||
HtmlEscape,
|
||||
HtmlUnescape,
|
||||
Nth {
|
||||
@ -893,6 +897,10 @@ pub enum FilterValue {
|
||||
space0: Whitespace,
|
||||
sep: Template,
|
||||
},
|
||||
ToDate {
|
||||
space0: Whitespace,
|
||||
fmt: Template,
|
||||
},
|
||||
ToInt,
|
||||
UrlDecode,
|
||||
UrlEncode,
|
||||
|
@ -1121,6 +1121,12 @@ impl Htmlable for FilterValue {
|
||||
fn to_html(&self) -> String {
|
||||
match self {
|
||||
FilterValue::Count => "<span class=\"filter-type\">count</span>".to_string(),
|
||||
FilterValue::Format { space0, fmt } => {
|
||||
let mut buffer = "<span class=\"filter-type\">format</span>".to_string();
|
||||
buffer.push_str(space0.to_html().as_str());
|
||||
buffer.push_str(fmt.to_html().as_str());
|
||||
buffer
|
||||
}
|
||||
FilterValue::HtmlEscape => "<span class=\"filter-type\">htmlEscape</span>".to_string(),
|
||||
FilterValue::HtmlUnescape => {
|
||||
"<span class=\"filter-type\">htmlUnescape</span>".to_string()
|
||||
@ -1157,6 +1163,13 @@ impl Htmlable for FilterValue {
|
||||
buffer.push_str(sep.to_html().as_str());
|
||||
buffer
|
||||
}
|
||||
FilterValue::ToDate { space0, fmt } => {
|
||||
let mut buffer = "".to_string();
|
||||
buffer.push_str("<span class=\"filter-type\">toDate</span>");
|
||||
buffer.push_str(space0.to_html().as_str());
|
||||
buffer.push_str(fmt.to_html().as_str());
|
||||
buffer
|
||||
}
|
||||
FilterValue::ToInt => "<span class=\"filter-type\">toInt</span>".to_string(),
|
||||
FilterValue::UrlDecode => "<span class=\"filter-type\">urlDecode</span>".to_string(),
|
||||
FilterValue::UrlEncode => "<span class=\"filter-type\">urlEncode</span>".to_string(),
|
||||
|
@ -52,6 +52,7 @@ pub fn filter(reader: &mut Reader) -> ParseResult<'static, Filter> {
|
||||
let value = choice(
|
||||
&[
|
||||
count_filter,
|
||||
format_filter,
|
||||
html_decode_filter,
|
||||
html_encode_filter,
|
||||
nth_filter,
|
||||
@ -59,6 +60,7 @@ pub fn filter(reader: &mut Reader) -> ParseResult<'static, Filter> {
|
||||
replace_filter,
|
||||
split_filter,
|
||||
to_int_filter,
|
||||
to_date_filter,
|
||||
url_decode_filter,
|
||||
url_encode_filter,
|
||||
],
|
||||
@ -87,6 +89,13 @@ fn count_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
Ok(FilterValue::Count)
|
||||
}
|
||||
|
||||
fn format_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
try_literal("format", reader)?;
|
||||
let space0 = one_or_more_spaces(reader)?;
|
||||
let fmt = quoted_template(reader)?;
|
||||
Ok(FilterValue::Format { space0, fmt })
|
||||
}
|
||||
|
||||
fn html_encode_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
try_literal("htmlEscape", reader)?;
|
||||
Ok(FilterValue::HtmlEscape)
|
||||
@ -132,6 +141,13 @@ fn split_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
Ok(FilterValue::Split { space0, sep })
|
||||
}
|
||||
|
||||
fn to_date_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
try_literal("toDate", reader)?;
|
||||
let space0 = one_or_more_spaces(reader)?;
|
||||
let fmt = quoted_template(reader)?;
|
||||
Ok(FilterValue::ToDate { space0, fmt })
|
||||
}
|
||||
|
||||
fn to_int_filter(reader: &mut Reader) -> ParseResult<'static, FilterValue> {
|
||||
try_literal("toInt", reader)?;
|
||||
Ok(FilterValue::ToInt)
|
||||
|
@ -529,6 +529,10 @@ impl ToJson for FilterValue {
|
||||
FilterValue::Count => {
|
||||
attributes.push(("type".to_string(), JValue::String("count".to_string())));
|
||||
}
|
||||
FilterValue::Format { fmt, .. } => {
|
||||
attributes.push(("type".to_string(), JValue::String("format".to_string())));
|
||||
attributes.push(("fmt".to_string(), JValue::String(fmt.to_string())));
|
||||
}
|
||||
FilterValue::Nth { n, .. } => {
|
||||
attributes.push(("type".to_string(), JValue::String("nth".to_string())));
|
||||
attributes.push(("n".to_string(), JValue::Number(n.to_string())));
|
||||
@ -568,6 +572,10 @@ impl ToJson for FilterValue {
|
||||
attributes.push(("type".to_string(), JValue::String("split".to_string())));
|
||||
attributes.push(("sep".to_string(), JValue::String(sep.to_string())));
|
||||
}
|
||||
FilterValue::ToDate { fmt, .. } => {
|
||||
attributes.push(("type".to_string(), JValue::String("toDate".to_string())));
|
||||
attributes.push(("fmt".to_string(), JValue::String(fmt.to_string())));
|
||||
}
|
||||
FilterValue::ToInt => {
|
||||
attributes.push(("type".to_string(), JValue::String("toInt".to_string())));
|
||||
}
|
||||
|
@ -1144,6 +1144,12 @@ impl Tokenizable for Filter {
|
||||
fn tokenize(&self) -> Vec<Token> {
|
||||
match self.value.clone() {
|
||||
FilterValue::Count => vec![Token::FilterType(String::from("count"))],
|
||||
FilterValue::Format { space0, fmt } => {
|
||||
let mut tokens: Vec<Token> = vec![Token::FilterType(String::from("format"))];
|
||||
tokens.append(&mut space0.tokenize());
|
||||
tokens.append(&mut fmt.tokenize());
|
||||
tokens
|
||||
}
|
||||
FilterValue::HtmlEscape => vec![Token::FilterType(String::from("htmlEscape"))],
|
||||
FilterValue::HtmlUnescape => {
|
||||
vec![Token::FilterType(String::from("htmlUnescape"))]
|
||||
@ -1181,6 +1187,12 @@ impl Tokenizable for Filter {
|
||||
tokens.append(&mut sep.tokenize());
|
||||
tokens
|
||||
}
|
||||
FilterValue::ToDate { space0, fmt } => {
|
||||
let mut tokens: Vec<Token> = vec![Token::FilterType(String::from("toDate"))];
|
||||
tokens.append(&mut space0.tokenize());
|
||||
tokens.append(&mut fmt.tokenize());
|
||||
tokens
|
||||
}
|
||||
FilterValue::ToInt => vec![Token::FilterType(String::from("toInt"))],
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user