schemaorg_rs/profiles/google/
recipe.rs1use crate::types::SchemaNode;
7use crate::validation::ValidationDiagnostic as VD;
8
9use super::common::{recommend_property, require_property, validate_nested};
10use crate::profiles::{NodeProfileResult, Profile, TypeEligibility};
11
12pub struct GoogleRecipeProfile;
14
15impl Profile for GoogleRecipeProfile {
16 fn name(&self) -> &'static str {
17 "google"
18 }
19
20 fn version(&self) -> &'static str {
21 "2026-04-01"
22 }
23
24 fn source_url(&self) -> &'static str {
25 "https://developers.google.com/search/docs/appearance/structured-data/recipe"
26 }
27
28 fn supported_types(&self) -> &[&str] {
29 &["Recipe"]
30 }
31
32 fn evaluate_node(&self, node: &SchemaNode, _vocab_diagnostics: &[VD]) -> NodeProfileResult {
33 let path = "Recipe";
34 let mut diagnostics = Vec::new();
35 let mut required_missing = Vec::new();
36 let mut recommended_missing = Vec::new();
37
38 for prop in &["name", "image"] {
40 if let Some(d) = require_property(node, prop, path) {
41 required_missing.push((*prop).to_string());
42 diagnostics.push(d);
43 }
44 }
45
46 for prop in &[
48 "author",
49 "datePublished",
50 "description",
51 "recipeCuisine",
52 "prepTime",
53 "cookTime",
54 "totalTime",
55 "recipeYield",
56 "recipeCategory",
57 "recipeIngredient",
58 "recipeInstructions",
59 "nutrition",
60 "video",
61 ] {
62 if let Some(d) = recommend_property(node, prop, path) {
63 recommended_missing.push((*prop).to_string());
64 diagnostics.push(d);
65 }
66 }
67
68 let step_diags = validate_nested(
70 node,
71 "recipeInstructions",
72 "HowToStep",
73 &["text"],
74 &[],
75 path,
76 );
77 diagnostics.extend(step_diags);
78
79 let eligible = required_missing.is_empty();
80
81 NodeProfileResult {
82 type_eligibility: TypeEligibility {
83 schema_type: "Recipe".to_string(),
84 eligible,
85 required_missing,
86 recommended_missing,
87 field_diagnostics: diagnostics,
88 },
89 }
90 }
91}