use super::detector::ProjectDetector;
use super::types::ProjectDescriptor;
use super::validator::ProjectValidator;
use crate::config::StandardConfig;
use crate::error::{Error, Result};
use crate::filesystem::{AsyncFileSystem, FileSystemManager};
use std::path::{Path, PathBuf};
#[derive(Debug)]
pub struct ProjectManager<F: AsyncFileSystem = FileSystemManager> {
detector: ProjectDetector<F>,
validator: ProjectValidator<F>,
}
impl ProjectManager<FileSystemManager> {
#[must_use]
pub fn new() -> Self {
let detector = ProjectDetector::new();
let validator = ProjectValidator::new();
Self { detector, validator }
}
}
impl<F: AsyncFileSystem + Clone + 'static> ProjectManager<F> {
#[must_use]
pub fn with_filesystem(fs: F) -> Self {
let detector = ProjectDetector::with_filesystem(fs.clone());
let validator = ProjectValidator::with_filesystem(fs);
Self { detector, validator }
}
pub async fn create_project(
&self,
path: impl AsRef<Path>,
config: Option<&StandardConfig>,
) -> Result<ProjectDescriptor> {
let path = path.as_ref();
let mut project = self.detector.detect(path, config).await?;
self.validator.validate_project(&mut project).await?;
Ok(project)
}
pub async fn validate_project(&self, project: &mut ProjectDescriptor) -> Result<()> {
self.validator.validate_project(project).await
}
#[must_use]
pub async fn is_valid_project(&self, path: impl AsRef<Path>) -> bool {
self.detector.is_valid_project(path).await
}
#[must_use]
pub async fn find_project_root(&self, start_path: impl AsRef<Path>) -> Option<PathBuf> {
let start_path = start_path.as_ref();
let mut current = Some(start_path);
while let Some(path) = current {
if self.detector.is_valid_project(path).await {
return Some(path.to_path_buf());
}
current = path.parent();
}
None
}
pub async fn create_project_from_root(
&self,
root: impl AsRef<Path>,
config: Option<&StandardConfig>,
) -> Result<ProjectDescriptor> {
let root = root.as_ref();
if !self.detector.is_valid_project(root).await {
return Err(Error::operation(format!(
"Path is not a valid Node.js project: {}",
root.display()
)));
}
self.create_project(root, config).await
}
#[must_use]
pub fn detector(&self) -> &ProjectDetector<F> {
&self.detector
}
#[must_use]
pub fn validator(&self) -> &ProjectValidator<F> {
&self.validator
}
}
impl<F: AsyncFileSystem + Clone> Default for ProjectManager<F>
where
F: Default,
{
fn default() -> Self {
let detector = ProjectDetector::default();
let validator = ProjectValidator::default();
Self { detector, validator }
}
}