1use crate::error::DuplicateServiceUuid;
2use crate::issues::Issues;
3use crate::validate::Validate;
4use crate::{Error, Resolver, Schema, Warning};
5use std::collections::hash_map::{Entry, HashMap};
6use std::iter;
7
8#[derive(Debug)]
9pub struct Parser {
10 main_schema: String,
11 schemas: HashMap<String, Schema>,
12 issues: Issues,
13}
14
15impl Parser {
16 pub fn parse<T: Resolver>(mut resolver: T) -> Self {
17 let mut issues = Issues::default();
18 let main_schema = Schema::parse(&resolver.main_schema(), &mut issues);
19
20 let mut this = Self {
21 main_schema: main_schema.name().to_owned(),
22 schemas: HashMap::from_iter(iter::once((main_schema.name().to_owned(), main_schema))),
23 issues,
24 };
25
26 let mut imports = this
27 .main_schema()
28 .imports()
29 .iter()
30 .map(|i| i.schema_name().value().to_owned())
31 .collect::<Vec<_>>();
32
33 while let Some(import) = imports.pop() {
34 let Entry::Vacant(entry) = this.schemas.entry(import) else {
35 continue;
36 };
37
38 let Some(schema_file) = resolver.resolve(entry.key()) else {
39 continue;
40 };
41
42 let schema = Schema::parse(&schema_file, &mut this.issues);
43
44 imports.extend(
45 schema
46 .imports()
47 .iter()
48 .map(|i| i.schema_name().value().to_owned()),
49 );
50
51 entry.insert(schema);
52 }
53
54 this.validate();
55 this
56 }
57
58 fn validate(&mut self) {
59 DuplicateServiceUuid::validate(self.schemas.values(), &mut self.issues);
60
61 for (schema_name, schema) in &self.schemas {
62 let is_main_schema = *schema_name == self.main_schema;
63
64 let mut validate =
65 Validate::new(schema_name, &mut self.issues, &self.schemas, is_main_schema);
66
67 schema.validate(&mut validate);
68 }
69 }
70
71 pub fn main_schema(&self) -> &Schema {
72 self.get_schema(&self.main_schema).unwrap()
73 }
74
75 pub fn get_schema(&self, schema_name: &str) -> Option<&Schema> {
76 self.schemas.get(schema_name)
77 }
78
79 pub fn errors(&self) -> &[Error] {
80 self.issues.errors()
81 }
82
83 pub fn warnings(&self) -> &[Warning] {
84 self.issues.warnings()
85 }
86
87 pub fn other_warnings(&self) -> &[Warning] {
88 self.issues.other_warnings()
89 }
90
91 pub(crate) fn schemas(&self) -> &HashMap<String, Schema> {
92 &self.schemas
93 }
94}