Skip to main content

cooklang/analysis/
mod.rs

1//! Analysis pass of the parser
2//!
3//! This is just if for some reason you want to split the parsing from the
4//! analysis.
5
6use crate::{
7    error::{CowStr, PassResult, SourceDiag},
8    Recipe,
9};
10
11mod event_consumer;
12
13pub use event_consumer::parse_events;
14
15pub type AnalysisResult = PassResult<Recipe>;
16
17#[derive(PartialEq, Eq, Debug, Clone, Copy)]
18pub(crate) enum DefineMode {
19    All,
20    Components,
21    Steps,
22    Text,
23}
24
25#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26pub(crate) enum DuplicateMode {
27    New,
28    Reference,
29}
30
31/// Extra configuration for the analysis of events
32#[derive(Default)]
33pub struct ParseOptions<'a> {
34    /// Check recipe references for existence
35    pub recipe_ref_check: Option<RecipeRefCheck<'a>>,
36    /// Check metadata entries for validity
37    ///
38    /// Some checks are performed by default, but you can add your own here.
39    /// The function receives the key, value and an [`CheckOptions`] where you
40    /// can customize what happens to the key, including not running the default
41    /// checks.
42    pub metadata_validator: Option<MetadataValidator<'a>>,
43}
44
45/// Return type for check functions in [`ParseOptions`]
46///
47/// `Error` and `Warning` contain hints to the user with why it
48/// failed and/or how to solve it. They should be ordered from most to least
49/// important.
50#[derive(Debug, Clone, PartialEq, Eq)]
51pub enum CheckResult {
52    Ok,
53    Warning(Vec<CowStr>),
54    Error(Vec<CowStr>),
55}
56
57impl CheckResult {
58    pub(crate) fn into_source_diag<F, O>(self, message: F) -> Option<SourceDiag>
59    where
60        F: FnOnce() -> O,
61        O: Into<CowStr>,
62    {
63        let (severity, hints) = match self {
64            CheckResult::Ok => return None,
65            CheckResult::Warning(hints) => (crate::error::Severity::Warning, hints),
66            CheckResult::Error(hints) => (crate::error::Severity::Error, hints),
67        };
68        let mut diag = SourceDiag::unlabeled(message(), severity, crate::error::Stage::Analysis);
69        for hint in hints {
70            diag.add_hint(hint);
71        }
72        Some(diag)
73    }
74}
75
76/// Customize how a metadata entry should be treated
77///
78/// By default the entry is included and the [`StdKey`](crate::metadata::StdKey)
79/// checks run.
80pub struct CheckOptions {
81    include: bool,
82    run_std_checks: bool,
83}
84
85impl Default for CheckOptions {
86    fn default() -> Self {
87        Self {
88            include: true,
89            run_std_checks: true,
90        }
91    }
92}
93
94impl CheckOptions {
95    /// To include or not the metadata entry in the recipe
96    ///
97    /// If this is `false`, the entry will not be in the recipe. This will avoid
98    /// keeping invalid values.
99    pub fn include(&mut self, do_include: bool) {
100        self.include = do_include;
101    }
102
103    /// To run or not the checks for [`StdKey`](crate::metadata::StdKey)
104    ///
105    /// Disable these checks if you want to change the semantics or structure of a
106    /// [`StdKey`](crate::metadata::StdKey) and don't want the parser to issue
107    /// warnings about it.
108    ///
109    /// If the key is **not** an [`StdKey`](crate::metadata::StdKey) this has no effect.
110    pub fn run_std_checks(&mut self, do_check: bool) {
111        self.run_std_checks = do_check;
112    }
113}
114
115pub type RecipeRefCheck<'a> = Box<dyn FnMut(&str) -> CheckResult + 'a>;
116pub type MetadataValidator<'a> =
117    Box<dyn FnMut(&serde_yaml::Value, &serde_yaml::Value, &mut CheckOptions) -> CheckResult + 'a>;