aldrin_parser/
parser.rs

1use crate::error::DuplicateServiceUuid;
2use crate::issues::Issues;
3use crate::validate::Validate;
4use crate::{Error, Schema, Warning};
5use std::collections::hash_map::{Entry, HashMap};
6use std::path::{Path, PathBuf};
7
8#[derive(Debug)]
9pub struct Parser {
10    schema_paths: Vec<PathBuf>,
11}
12
13impl Parser {
14    pub fn new() -> Self {
15        Self {
16            schema_paths: Vec::new(),
17        }
18    }
19
20    pub fn add_schema_path<P>(&mut self, path: P)
21    where
22        P: Into<PathBuf>,
23    {
24        self.schema_paths.push(path.into());
25    }
26
27    pub fn parse<P>(&self, schema_path: P) -> Parsed
28    where
29        P: AsRef<Path>,
30    {
31        let mut issues = Issues::default();
32        let main_schema = Schema::parse(schema_path, &mut issues);
33
34        let mut parsed = Parsed {
35            main_schema: main_schema.name().to_owned(),
36            schemas: HashMap::new(),
37            issues,
38        };
39        parsed
40            .schemas
41            .insert(main_schema.name().to_owned(), main_schema);
42
43        let mut imports = parsed
44            .main_schema()
45            .imports()
46            .iter()
47            .map(|i| i.schema_name().value().to_owned())
48            .collect::<Vec<_>>();
49        while let Some(import) = imports.pop() {
50            let entry = match parsed.schemas.entry(import) {
51                Entry::Occupied(_) => continue,
52                Entry::Vacant(entry) => entry,
53            };
54
55            let schema_path = match self.find_schema(entry.key()) {
56                Some(schema_path) => schema_path,
57                None => continue,
58            };
59
60            let schema = Schema::parse(schema_path, &mut parsed.issues);
61            imports.extend(
62                schema
63                    .imports()
64                    .iter()
65                    .map(|i| i.schema_name().value().to_owned()),
66            );
67            entry.insert(schema);
68        }
69
70        parsed.validate(&self.schema_paths);
71        parsed
72    }
73
74    fn find_schema(&self, schema_name: &str) -> Option<PathBuf> {
75        for mut path in self.schema_paths.iter().rev().cloned() {
76            path.push(schema_name);
77            path.set_extension("aldrin");
78
79            if path.is_file() {
80                return Some(path);
81            }
82        }
83
84        None
85    }
86}
87
88impl Default for Parser {
89    fn default() -> Self {
90        Self::new()
91    }
92}
93
94#[derive(Debug)]
95pub struct Parsed {
96    main_schema: String,
97    schemas: HashMap<String, Schema>,
98    issues: Issues,
99}
100
101impl Parsed {
102    fn validate(&mut self, schema_paths: &[PathBuf]) {
103        DuplicateServiceUuid::validate(self.schemas.values(), &mut self.issues);
104
105        for (schema_name, schema) in &self.schemas {
106            let is_main_schema = *schema_name == self.main_schema;
107            let mut validate = Validate::new(
108                schema_name,
109                &mut self.issues,
110                &self.schemas,
111                is_main_schema,
112                schema_paths,
113            );
114            schema.validate(&mut validate);
115        }
116    }
117
118    pub fn main_schema(&self) -> &Schema {
119        self.get_schema(&self.main_schema).unwrap()
120    }
121
122    pub fn get_schema(&self, schema_name: &str) -> Option<&Schema> {
123        self.schemas.get(schema_name)
124    }
125
126    pub fn errors(&self) -> &[Error] {
127        self.issues.errors()
128    }
129
130    pub fn warnings(&self) -> &[Warning] {
131        self.issues.warnings()
132    }
133
134    pub fn other_warnings(&self) -> &[Warning] {
135        self.issues.other_warnings()
136    }
137}