Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/analysis/event_consumer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,14 +228,15 @@ impl<'i> RecipeCollector<'i, '_> {
Err(err) => {
// ! This message (can) contains line and column number, but line numbers
// ! are off by one thanks to the starting `---`
let mut diag = error!(err.to_string());
let mut diag = warning!(format!("Invalid YAML frontmatter syntax: {}", err));
let err_span = err
.location()
.map(|loc| Span::pos(yaml_text.span().start() + loc.index()));
if let Some(loc) = err_span {
diag = diag.label(label!(loc));
}
self.ctx.error(diag);
diag.add_hint("The frontmatter will be ignored. Fix the YAML syntax to use metadata.");
self.ctx.warn(diag);
return;
}
};
Expand Down
140 changes: 140 additions & 0 deletions tests/frontmatter_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use cooklang;
use indoc::indoc;

#[test]
fn test_invalid_yaml_frontmatter_becomes_warning() {
let input = indoc! {r#"
---
title: Test Recipe
tags: [test
invalid yaml here
---

This is a test recipe with invalid YAML frontmatter.

@eggs{2} and @butter{1%tbsp}
"#};

let result = cooklang::parse(input);

// Should not fail to parse
assert!(result.output().is_some(), "Recipe should parse successfully despite invalid YAML");

let recipe = result.output().unwrap();
let warnings = result.report();

// Should have warnings about invalid YAML
assert!(!warnings.is_empty(), "Should have warnings about invalid YAML");

// The frontmatter should be ignored, so metadata should be empty
assert!(recipe.metadata.map.is_empty(), "Metadata should be empty when YAML is invalid");

// Should still parse the recipe content
assert_eq!(recipe.ingredients.len(), 2, "Should still parse ingredients");
assert_eq!(recipe.ingredients[0].name, "eggs");
assert_eq!(recipe.ingredients[1].name, "butter");
}

#[test]
fn test_valid_yaml_frontmatter_still_works() {
let input = indoc! {r#"
---
title: Test Recipe
tags: [test, recipe]
prep_time: 10 min
---

This is a test recipe with valid YAML frontmatter.

@eggs{2} and @butter{1%tbsp}
"#};

let result = cooklang::parse(input);

// Should parse successfully
assert!(result.output().is_some(), "Recipe should parse successfully");

let recipe = result.output().unwrap();

// Metadata should be parsed
assert!(!recipe.metadata.map.is_empty(), "Metadata should not be empty");
assert_eq!(
recipe.metadata.map.get("title").and_then(|v| v.as_str()),
Some("Test Recipe"),
"Title should be parsed correctly"
);

// Should still parse the recipe content
assert_eq!(recipe.ingredients.len(), 2, "Should parse ingredients");
assert_eq!(recipe.ingredients[0].name, "eggs");
assert_eq!(recipe.ingredients[1].name, "butter");
}

#[test]
fn test_invalid_yaml_with_colon_in_value() {
let input = indoc! {r#"
---
title: Recipe: with colon
description: This has: many: colons
tags: [unclosed
---

@flour{2%cups}
"#};

let result = cooklang::parse(input);

// Should not fail to parse
assert!(result.output().is_some(), "Recipe should parse successfully despite invalid YAML");

let recipe = result.output().unwrap();
let warnings = result.report();

// Should have warnings
assert!(!warnings.is_empty(), "Should have warnings about invalid YAML");

// Metadata should be empty due to invalid YAML
assert!(recipe.metadata.map.is_empty(), "Metadata should be empty when YAML is invalid");

// Should still parse ingredients
assert_eq!(recipe.ingredients.len(), 1);
assert_eq!(recipe.ingredients[0].name, "flour");
}

#[test]
fn test_completely_malformed_yaml() {
let input = indoc! {r#"
---
{ this is not valid yaml at all }}}
: : : :
---

Simple recipe with @salt and @pepper
"#};

let result = cooklang::parse(input);

// Should not fail to parse
assert!(result.output().is_some(), "Recipe should parse successfully despite malformed YAML");

let recipe = result.output().unwrap();
let warnings = result.report();

// Should have warnings
assert!(!warnings.is_empty(), "Should have warnings about invalid YAML");

// Should contain information about invalid YAML in warning
let warning_str = format!("{:?}", warnings);
assert!(
warning_str.contains("Invalid YAML") || warning_str.contains("invalid YAML"),
"Warning should mention invalid YAML"
);

// Metadata should be empty
assert!(recipe.metadata.map.is_empty(), "Metadata should be empty when YAML is invalid");

// Should still parse the recipe
assert_eq!(recipe.ingredients.len(), 2);
assert_eq!(recipe.ingredients[0].name, "salt");
assert_eq!(recipe.ingredients[1].name, "pepper");
}