use std::{
collections::HashMap,
path::{Path, PathBuf},
};
use crate::{
Config,
error::{ConfigError, WorkspaceError},
view::Diagnostic,
};
mod diff;
mod edit;
mod id_index;
mod path_helpers;
mod save;
mod snapshot;
mod validate;
#[cfg(test)]
mod tests;
use id_index::{IdIndex, NodeAddress};
use path_helpers::resolve_root;
pub struct Workspace {
pub(super) root_path: PathBuf,
pub(super) config: Config,
pub(super) ids: IdIndex,
pub(super) diagnostics: Vec<Diagnostic>,
pub(super) baseline_files: HashMap<PathBuf, String>,
}
impl Workspace {
pub fn load(root: PathBuf) -> Result<Self, WorkspaceError> {
let resolved = resolve_root(&root)?;
let config_path_string = resolved.to_string_lossy().into_owned();
let config = Config::new(Some(&config_path_string), None).map_err(WorkspaceError::from)?;
let mut baseline_files: HashMap<PathBuf, String> = HashMap::new();
baseline_files.insert(
resolved.clone(),
crate::toml_writer::render_apimock_toml(&config),
);
for rule_set in config.service.rule_sets.iter() {
let path = PathBuf::from(rule_set.file_path.as_str());
baseline_files.insert(
path,
crate::toml_writer::render_rule_set_toml(rule_set),
);
}
let mut workspace = Self {
root_path: resolved,
config,
ids: IdIndex::default(),
diagnostics: Vec::new(),
baseline_files,
};
workspace.seed_ids();
Ok(workspace)
}
fn seed_ids(&mut self) {
self.ids.insert(NodeAddress::Root);
self.ids.insert(NodeAddress::FallbackRespondDir);
for (rs_idx, rule_set) in self.config.service.rule_sets.iter().enumerate() {
self.ids.insert(NodeAddress::RuleSet { rule_set: rs_idx });
for (rule_idx, _rule) in rule_set.rules.iter().enumerate() {
self.ids.insert(NodeAddress::Rule {
rule_set: rs_idx,
rule: rule_idx,
});
self.ids.insert(NodeAddress::Respond {
rule_set: rs_idx,
rule: rule_idx,
});
}
}
if let Some(paths) = self.config.service.middlewares_file_paths.as_ref() {
for mw_idx in 0..paths.len() {
self.ids
.insert(NodeAddress::Middleware { middleware: mw_idx });
}
}
}
pub(super) fn config_relative_dir(&self) -> Result<String, ConfigError> {
self.config.current_dir_to_parent_dir_relative_path()
}
pub(super) fn resolve_relative(&self, rel: &str) -> PathBuf {
match self.config.current_dir_to_parent_dir_relative_path() {
Ok(dir) => Path::new(&dir).join(rel),
Err(_) => PathBuf::from(rel),
}
}
pub fn config(&self) -> &Config {
&self.config
}
pub fn root_path(&self) -> &Path {
&self.root_path
}
pub fn list_directory(&self, path: &Path) -> Vec<apimock_routing::view::FileNodeView> {
let filter = self
.config
.file_tree_view
.as_ref()
.map(|c| c.to_filter())
.unwrap_or_default();
apimock_routing::view::build::list_directory_with(path, &filter)
}
}