1use crate::error::PRdocLibError;
9use regex::Regex;
10use serde_yaml::Value;
11use std::{
12 fs::{self, File},
13 path::{Path, PathBuf},
14};
15use valico::json_schema;
16
17pub const EXTENSION: &str = "prdoc";
19
20pub const PRDOC_DEFAULT_DIR: &str = "prdoc";
22
23#[derive(Debug, Clone)]
25pub struct Schema {
26 schema: PathBuf,
27}
28
29impl Schema {
30 pub fn new(schema: PathBuf) -> Self {
32 Self { schema }
33 }
34
35 pub fn get(s: String, strip_comments: bool) -> String {
38 if !strip_comments {
39 s
40 } else {
41 let re = Regex::new(r"(?m)^//(.*)$").unwrap();
42 let result = re.replace_all(&s, "");
43 result.to_string().trim().to_string()
44 }
45 }
46
47 pub fn check_file(&self, file: &PathBuf) -> bool {
49 self.load(file).is_ok()
50 }
51
52 pub fn load<P: AsRef<Path>>(&self, file: &P) -> crate::error::Result<Value> {
54 log::trace!("Loading schema file");
55 let content = fs::read_to_string(self.schema.clone())?.parse()?;
56 let schema_str = Self::get(content, true);
57
58 log::trace!("Parsing schema");
59 let json_schema: serde_json::Value = serde_json::from_str(&schema_str)?;
60
61 let reader = File::open(file)?;
62 let mut doc_as_yaml: serde_yaml::Value = serde_yaml::from_reader(reader)?;
63 doc_as_yaml.apply_merge()?;
64
65 let doc_as_json: serde_json::Value =
66 serde_yaml::from_value(serde_yaml::to_value(&doc_as_yaml)?)?;
67
68 let mut scope = json_schema::Scope::new();
69 let schema = scope.compile_and_return(json_schema, false)?;
70
71 log::trace!("Validate file with schema");
72 let validation = schema.validate(&doc_as_json);
73 let validation_result = validation.is_valid();
74 let validation_result_strict = validation.is_strictly_valid();
75
76 if !(validation_result && validation_result_strict) {
77 log::debug!("validation_result: {validation_result}");
78 log::debug!("validation_result_strict: {validation_result_strict}");
79 return Err(PRdocLibError::ValidationErrors(validation));
80 }
81
82 Ok(doc_as_yaml)
83 }
84}
85
86#[cfg(test)]
87mod test_schema_validation {
88 use super::*;
89 use std::path::PathBuf;
90
91 #[test]
92 fn test_load_valid_1234() {
93 let schema = Schema::new("./tests/data/sample_schema.json".into());
94 let file = PathBuf::from("./tests/data/some/pr_1234_some_test_minimal.prdoc");
95 assert!(schema.load(&file).is_ok());
96 }
97
98 #[test]
99 fn test_check_valid_1234() {
100 let schema = Schema::new("./tests/data/sample_schema.json".into());
101
102 let file = PathBuf::from("./tests/data/some/pr_1234_some_test_minimal.prdoc");
103 assert!(schema.check_file(&file));
104 }
105}