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}