Skip to content

Commit

Permalink
don't allow naming objects with reserved fields
Browse files Browse the repository at this point in the history
  • Loading branch information
jesseditson committed Feb 15, 2024
1 parent d69324f commit 23d2d6a
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 27 deletions.
6 changes: 4 additions & 2 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ impl Object {

#[cfg(test)]
mod tests {
use crate::{field_value::DateTime, object_definition::tests::artist_and_page_definition_str};
use crate::{
field_value::DateTime, object_definition::tests::artist_and_example_definition_str,
};

use super::*;

Expand All @@ -166,7 +168,7 @@ mod tests {
#[test]
fn object_parsing() -> Result<(), Box<dyn Error>> {
let defs =
ObjectDefinition::from_table(&toml::from_str(artist_and_page_definition_str())?)?;
ObjectDefinition::from_table(&toml::from_str(artist_and_example_definition_str())?)?;
let table: Table = toml::from_str(artist_object_str())?;
let obj = Object::from_table(defs.get("artist").unwrap(), "tormenta-rey", &table)?;
assert_eq!(obj.order, 1);
Expand Down
27 changes: 16 additions & 11 deletions src/object_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub enum InvalidFieldError {
},
#[error("not an array: {key:?} ({value:?})")]
NotAnArray { key: String, value: String },
#[error("cannot define an object with reserved name {0}")]
ReservedObjectNameError(String),
}

#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
Expand Down Expand Up @@ -99,6 +101,9 @@ pub struct ObjectDefinition {

impl ObjectDefinition {
pub fn new(name: &str, definition: &Table) -> Result<ObjectDefinition, Box<dyn Error>> {
if is_reserved_field(name) {
return Err(InvalidFieldError::ReservedObjectNameError(name.to_string()).into());
}
let mut obj_def = ObjectDefinition {
name: name.to_string(),
fields: HashMap::new(),
Expand Down Expand Up @@ -144,7 +149,7 @@ pub mod tests {

use super::*;

pub fn artist_and_page_definition_str() -> &'static str {
pub fn artist_and_example_definition_str() -> &'static str {
"[artist]
name = \"string\"
template = \"artist\"
Expand All @@ -154,22 +159,22 @@ pub mod tests {
[artist.numbers]
number = \"number\"
[page]
[example]
content = \"markdown\"
[page.links]
[example.links]
url = \"string\""
}

#[test]
fn parsing() -> Result<(), Box<dyn Error>> {
let table: Table = toml::from_str(artist_and_page_definition_str())?;
let table: Table = toml::from_str(artist_and_example_definition_str())?;
let defs = ObjectDefinition::from_table(&table)?;

println!("{:?}", defs);

assert_eq!(defs.keys().len(), 2);
assert!(defs.get("artist").is_some());
assert!(defs.get("page").is_some());
assert!(defs.get("example").is_some());
let artist = defs.get("artist").unwrap();
assert_eq!(artist.field_order.len(), 4);
assert_eq!(artist.field_order[0], "name".to_string());
Expand Down Expand Up @@ -199,12 +204,12 @@ pub mod tests {
assert!(numbers.fields.get("number").is_some());
assert_eq!(numbers.fields.get("number").unwrap(), &FieldType::Number);

let page = defs.get("page").unwrap();
assert!(page.fields.get("content").is_some());
assert_eq!(page.fields.get("content").unwrap(), &FieldType::Markdown);
assert_eq!(page.children.len(), 1);
assert!(page.children.get("links").is_some());
let links = page.children.get("links").unwrap();
let example = defs.get("example").unwrap();
assert!(example.fields.get("content").is_some());
assert_eq!(example.fields.get("content").unwrap(), &FieldType::Markdown);
assert_eq!(example.children.len(), 1);
assert!(example.children.get("links").is_some());
let links = example.children.get("links").unwrap();
assert!(links.fields.get("url").is_some());
assert_eq!(links.fields.get("url").unwrap(), &FieldType::String);

Expand Down
25 changes: 13 additions & 12 deletions src/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ impl<'a> Page<'a> {
parser: &liquid::Parser,
objects_map: &HashMap<String, Vec<Object>>,
) -> Result<String, Box<dyn Error>> {
tracing::debug!("rendering {}", self.name);
let mut objects: HashMap<String, Vec<liquid::model::Value>> = HashMap::new();
for (name, objs) in objects_map {
let values = objs.iter().map(|o| o.liquid_object()).collect();
Expand All @@ -67,11 +68,11 @@ impl<'a> Page<'a> {
"path": template_info.object.path,
template_info.definition.name.to_owned(): template_info.object.values.to_value()
});
tracing::debug!("=== context (template): \n{}", toml::to_string(&context)?);
context.extend(globals);
// tracing::debug!("=== context: \n{}", toml::to_string(&context)?);
return Ok(template.render(&context)?);
} else if let Some(content) = &self.content {
// tracing::debug!("=== context: \n{}", toml::to_string(&globals)?);
tracing::debug!("=== context (page): \n{}", toml::to_string(&globals)?);
let template = parser.parse(content)?;
return Ok(template.render(&globals)?);
}
Expand Down Expand Up @@ -128,7 +129,7 @@ mod tests {
"url".to_string(),
FieldValue::String("foo.com".to_string()),
)])];
let page_values = HashMap::from([
let c_values = HashMap::from([
(
"content".to_string(),
FieldValue::Markdown("# hello".to_string()),
Expand All @@ -137,17 +138,17 @@ mod tests {
("links".to_string(), FieldValue::Objects(links_objects)),
]);

let page = Object {
let c = Object {
filename: "home".to_string(),
object_name: "page".to_string(),
object_name: "c".to_string(),
path: "home".to_string(),
order: -1,
values: page_values,
values: c_values,
};

HashMap::from([
("artist".to_string(), vec![artist]),
("page".to_string(), vec![page]),
("c".to_string(), vec![c]),
])
}

Expand Down Expand Up @@ -194,11 +195,11 @@ mod tests {
}

fn page_content() -> &'static str {
"{% assign page = objects.page | where: \"name\", \"home\" | first %}
name: {{page.name}}
content: {{page.content}}
page_path: {{page.path}}
{% for link in page.links %}
"{% assign c = objects.c | where: \"name\", \"home\" | first %}
name: {{c.name}}
content: {{c.content}}
page_path: {{c.path}}
{% for link in c.links %}
link: {{link.url}}
{% endfor %}
{% for artist in objects.artist %}
Expand Down
12 changes: 10 additions & 2 deletions src/reserved_fields.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::{error::Error, fmt};

// These fields may not be used as keys in object definitions.
// These fields may not be used as keys in object definitions or as the names of
// objects.
pub const TEMPLATE: &str = "template";
pub const ORDER: &str = "order";
pub const OBJECTS: &str = "objects";
pub const OBJECT_NAME: &str = "object_name";
pub const PAGE: &str = "page";
pub const PAGE_NAME: &str = "page_name";

#[derive(Debug, Clone)]
Expand All @@ -23,10 +26,15 @@ pub fn reserved_field_from_str(field: &str) -> &'static str {
ORDER => ORDER,
PAGE_NAME => PAGE_NAME,
TEMPLATE => TEMPLATE,
OBJECTS => OBJECTS,
PAGE => PAGE,
_ => panic!("{} is not a reserved field", field),
}
}

pub fn is_reserved_field(field: &str) -> bool {
matches!(field, OBJECT_NAME | ORDER | PAGE_NAME | TEMPLATE)
matches!(
field,
OBJECT_NAME | ORDER | OBJECTS | PAGE_NAME | PAGE | TEMPLATE
)
}

0 comments on commit 23d2d6a

Please sign in to comment.