Skip to main content

presolve_compiler/
compilation_unit.rs

1use std::path::Path;
2
3use presolve_parser::{parse_file, ParsedFile};
4
5/// The parsed source files that participate in one compiler invocation.
6///
7/// Files are stored in path order so every frontend consumer observes a
8/// deterministic application input before module resolution is introduced.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct CompilationUnit {
11    files: Vec<ParsedFile>,
12}
13
14impl CompilationUnit {
15    #[must_use]
16    pub fn from_parsed_files(mut files: Vec<ParsedFile>) -> Self {
17        files.sort_by(|left, right| left.path.cmp(&right.path));
18        Self { files }
19    }
20
21    #[must_use]
22    pub fn parse_sources<I, P, S>(sources: I) -> Self
23    where
24        I: IntoIterator<Item = (P, S)>,
25        P: AsRef<Path>,
26        S: AsRef<str>,
27    {
28        let files = sources
29            .into_iter()
30            .map(|(path, source)| parse_file(path, source.as_ref()))
31            .collect();
32
33        Self::from_parsed_files(files)
34    }
35
36    #[must_use]
37    pub fn files(&self) -> &[ParsedFile] {
38        &self.files
39    }
40
41    #[must_use]
42    pub fn is_empty(&self) -> bool {
43        self.files.is_empty()
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use super::CompilationUnit;
50
51    #[test]
52    fn sorts_parsed_sources_by_path() {
53        let unit = CompilationUnit::parse_sources([
54            ("src/Zeta.tsx", "class Zeta {}"),
55            ("src/Alpha.tsx", "class Alpha {}"),
56        ]);
57
58        let paths = unit
59            .files()
60            .iter()
61            .map(|file| file.path.to_string_lossy().into_owned())
62            .collect::<Vec<_>>();
63
64        assert_eq!(paths, vec!["src/Alpha.tsx", "src/Zeta.tsx"]);
65    }
66}