|
| 1 | +// lovingly named by japi (July 24, 2025) |
| 2 | + |
| 3 | +use crate::parser; |
| 4 | +use std::{error::Error, fs, path::PathBuf}; |
| 5 | + |
| 6 | +pub mod printer; |
| 7 | + |
| 8 | +pub struct Blossom {} |
| 9 | + |
| 10 | +impl Blossom { |
| 11 | + pub fn build(path: String) -> Result<(), Box<dyn Error>> { |
| 12 | + let path_buf = PathBuf::from(path); |
| 13 | + let file_tree = collect_files(path_buf)?; |
| 14 | + let lovely_files = file_tree |
| 15 | + .filter(&|name, _| name.ends_with(".lv")) |
| 16 | + .expect("Expected a directory"); |
| 17 | + let parsed_lovely_files = |
| 18 | + lovely_files.try_map(&|s| parser::Parser::new(s).parse().map_err(|e| e.into()))?; |
| 19 | + |
| 20 | + println!("Building your project..."); |
| 21 | + |
| 22 | + Ok(()) |
| 23 | + } |
| 24 | +} |
| 25 | + |
| 26 | +fn collect_files(path: PathBuf) -> Result<FileTreeNode<String>, Box<dyn Error>> { |
| 27 | + if !path.is_dir() { |
| 28 | + printer::error("That's not a directory you silly!"); |
| 29 | + return Err("Not a directory".into()); |
| 30 | + } |
| 31 | + let Ok(dir) = path.read_dir() else { |
| 32 | + printer::error("Uh for some reason we couldn't read the directory. Not really sure why."); |
| 33 | + return Err("Failed to read directory".into()); |
| 34 | + }; |
| 35 | + let Ok(dir) = dir.collect::<Result<Vec<_>, _>>() else { |
| 36 | + printer::error( |
| 37 | + "You know, today just really isn't your day is it. Something awful happened, and I have no idea what it was.", |
| 38 | + ); |
| 39 | + return Err("Failed to read directory".into()); |
| 40 | + }; |
| 41 | + |
| 42 | + let mut children = vec![]; |
| 43 | + |
| 44 | + for dir_entry in dir { |
| 45 | + if dir_entry.path().is_dir() { |
| 46 | + children.push(collect_files(dir_entry.path())?); |
| 47 | + } else { |
| 48 | + let contents = fs::read_to_string(dir_entry.path())?; |
| 49 | + let name = dir_entry.path().to_str().unwrap().to_string(); |
| 50 | + children.push(FileTreeNode::File { name, contents }) |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + Ok(FileTreeNode::Directory { |
| 55 | + children, |
| 56 | + name: path |
| 57 | + .to_str() |
| 58 | + .expect("Weird file name, it made me uncomfortable.") |
| 59 | + .into(), |
| 60 | + }) |
| 61 | +} |
| 62 | + |
| 63 | +enum FileTreeNode<T> { |
| 64 | + Directory { |
| 65 | + name: String, |
| 66 | + children: Vec<FileTreeNode<T>>, |
| 67 | + }, |
| 68 | + File { |
| 69 | + name: String, |
| 70 | + contents: T, |
| 71 | + }, |
| 72 | +} |
| 73 | + |
| 74 | +impl<T> FileTreeNode<T> { |
| 75 | + fn filter<F>(&self, f: &F) -> Option<FileTreeNode<T>> |
| 76 | + where |
| 77 | + F: Fn(&String, &T) -> bool, |
| 78 | + T: Clone, |
| 79 | + { |
| 80 | + match self { |
| 81 | + FileTreeNode::Directory { children, name } => Some(FileTreeNode::Directory { |
| 82 | + name: name.clone(), |
| 83 | + children: children.iter().filter_map(|c| c.filter(f)).collect(), |
| 84 | + }), |
| 85 | + FileTreeNode::File { name, contents } => { |
| 86 | + if f(name, contents) { |
| 87 | + Some(FileTreeNode::File { |
| 88 | + name: name.clone(), |
| 89 | + contents: contents.clone(), |
| 90 | + }) |
| 91 | + } else { |
| 92 | + None |
| 93 | + } |
| 94 | + } |
| 95 | + } |
| 96 | + } |
| 97 | + |
| 98 | + fn map<U>(&self, f: &impl Fn(&T) -> U) -> FileTreeNode<U> { |
| 99 | + match self { |
| 100 | + Self::Directory { name, children } => FileTreeNode::Directory { |
| 101 | + name: name.clone(), |
| 102 | + children: children.iter().map(|c| FileTreeNode::map(c, f)).collect(), |
| 103 | + }, |
| 104 | + Self::File { name, contents } => FileTreeNode::File { |
| 105 | + name: name.clone(), |
| 106 | + contents: f(contents), |
| 107 | + }, |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + fn try_map<U>( |
| 112 | + &self, |
| 113 | + f: &impl Fn(&T) -> Result<U, Box<dyn Error>>, |
| 114 | + ) -> Result<FileTreeNode<U>, Box<dyn Error>> { |
| 115 | + match self { |
| 116 | + Self::Directory { name, children } => Ok(FileTreeNode::Directory { |
| 117 | + name: name.clone(), |
| 118 | + children: children |
| 119 | + .iter() |
| 120 | + .map(|c| c.try_map(f)) |
| 121 | + .collect::<Result<Vec<_>, _>>()?, |
| 122 | + }), |
| 123 | + Self::File { name, contents } => Ok(FileTreeNode::File { |
| 124 | + name: name.clone(), |
| 125 | + contents: f(contents)?, |
| 126 | + }), |
| 127 | + } |
| 128 | + } |
| 129 | +} |
0 commit comments