use crate::constants::MISSING_JSON_OBJECT;
use crate::mustache::{Context, Template, Value};
#[derive(Debug, Clone)]
pub struct JavaScriptResource {
obj_name: String,
json_object: String,
session_id: String,
sequence: i32,
supports_promises: bool,
supports_fetch: bool,
url: String,
parameters: String,
enable_cookies: bool,
update_enabled: bool,
has_delayed_properties: bool,
}
impl JavaScriptResource {
#[allow(clippy::too_many_arguments)]
pub fn new(
obj_name: impl Into<String>,
json_object: impl Into<String>,
session_id: impl Into<String>,
sequence: i32,
supports_promises: bool,
supports_fetch: bool,
url: impl Into<String>,
parameters: impl Into<String>,
enable_cookies: bool,
update_enabled: bool,
has_delayed_properties: bool,
) -> Self {
let json_object = json_object.into();
let json_object = if json_object.trim().is_empty() {
MISSING_JSON_OBJECT.to_owned()
} else {
json_object
};
JavaScriptResource {
obj_name: obj_name.into(),
json_object,
session_id: session_id.into(),
sequence,
supports_promises,
supports_fetch,
url: url.into(),
parameters: parameters.into(),
enable_cookies,
update_enabled,
has_delayed_properties,
}
}
pub fn render(&self, template: &Template) -> String {
template.render(self)
}
}
impl Context for JavaScriptResource {
fn value(&self, name: &str) -> Option<Value<'_>> {
match name {
"_objName" => Some(Value::Str(&self.obj_name)),
"_jsonObject" => Some(Value::Str(&self.json_object)),
"_sessionId" => Some(Value::Str(&self.session_id)),
"_sequence" => Some(Value::Int(self.sequence as i64)),
"_url" => Some(Value::Str(&self.url)),
"_parameters" => Some(Value::Str(&self.parameters)),
"_supportsPromises" => Some(Value::Str(bool_str(self.supports_promises))),
"_supportsFetch" => Some(Value::Str(bool_str(self.supports_fetch))),
"_enableCookies" => Some(Value::Str(bool_str(self.enable_cookies))),
"_updateEnabled" => Some(Value::Str(bool_str(self.update_enabled))),
"_hasDelayedProperties" => Some(Value::Str(bool_str(self.has_delayed_properties))),
_ => None,
}
}
fn flag(&self, name: &str) -> Option<bool> {
match name {
"_supportsPromises" => Some(self.supports_promises),
"_supportsFetch" => Some(self.supports_fetch),
"_enableCookies" => Some(self.enable_cookies),
"_updateEnabled" => Some(self.update_enabled),
"_hasDelayedProperties" => Some(self.has_delayed_properties),
_ => None,
}
}
}
fn bool_str(value: bool) -> &'static str {
if value {
"true"
} else {
"false"
}
}
#[cfg(test)]
mod tests {
use super::*;
fn resource(json: &str) -> JavaScriptResource {
JavaScriptResource::new(
"fod",
json,
"sid",
1,
false,
false,
"https://h/json",
"{}",
true,
true,
false,
)
}
#[test]
fn missing_json_falls_back_to_placeholder() {
let resource = resource(" ");
assert_eq!(resource.json_object, MISSING_JSON_OBJECT);
}
#[test]
fn fields_are_not_html_escaped() {
let source = "var json = {{&_jsonObject}}; var name = \"{{_objName}}\";";
let template = Template::parse(source).unwrap();
let resource = JavaScriptResource::new(
"ob<j>",
"{\"a\":\"<b>&\\\"\"}",
"sid",
1,
false,
false,
"",
"{}",
true,
false,
false,
);
let rendered = resource.render(&template);
assert!(!rendered.contains("<"));
assert!(!rendered.contains(">"));
assert!(!rendered.contains("&"));
assert!(!rendered.contains("""));
assert!(rendered.contains("ob<j>"));
assert!(rendered.contains("{\"a\":\"<b>&\\\"\"}"));
}
#[test]
fn boolean_sections_render_their_body() {
let source =
"{{#_enableCookies}}YES{{/_enableCookies}}{{^_enableCookies}}NO{{/_enableCookies}}";
let template = Template::parse(source).unwrap();
let cookies_on = JavaScriptResource::new(
"fod", "{}", "", 1, false, false, "", "{}", true, false, false,
);
assert_eq!(cookies_on.render(&template), "YES");
let cookies_off = JavaScriptResource::new(
"fod", "{}", "", 1, false, false, "", "{}", false, false, false,
);
assert_eq!(cookies_off.render(&template), "NO");
}
#[test]
fn sequence_renders_as_bare_integer() {
let source = "var sequence = {{&_sequence}};";
let template = Template::parse(source).unwrap();
let resource = JavaScriptResource::new(
"fod", "{}", "", 7, false, false, "", "{}", true, false, false,
);
assert_eq!(resource.render(&template), "var sequence = 7;");
}
}