version bumped to 0.5.1
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
//! This module defines the unified data model used by `mould` to represent
|
||||
//! configuration data across all supported file formats.
|
||||
//!
|
||||
//! By normalizing heterogeneous structures (like nested YAML or flat .env)
|
||||
//! into a standard tree-like representation, the TUI logic remains
|
||||
//! independent of the underlying file format.
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
pub mod env;
|
||||
@@ -5,24 +12,39 @@ pub mod hierarchical;
|
||||
pub mod ini;
|
||||
pub mod properties;
|
||||
|
||||
/// Represents the status of a configuration item relative to a template.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ItemStatus {
|
||||
/// Item exists in the active configuration and matches the template (or no template exists).
|
||||
Present,
|
||||
/// Item exists in the template but is missing from the active configuration.
|
||||
MissingFromActive,
|
||||
/// Item has been changed by the user during the current session.
|
||||
Modified,
|
||||
}
|
||||
|
||||
/// Hints about the original data type to ensure correct serialization during writes.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ValueType {
|
||||
/// Standard text.
|
||||
String,
|
||||
/// Numeric values (integers or floats).
|
||||
Number,
|
||||
/// True/False values.
|
||||
Bool,
|
||||
/// Representing an explicit null or empty value.
|
||||
Null,
|
||||
}
|
||||
|
||||
/// A single segment in a hierarchical configuration path.
|
||||
///
|
||||
/// For example, `services[0].image` would be represented as:
|
||||
/// `[Key("services"), Index(0), Key("image")]`
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum PathSegment {
|
||||
/// A named key in an object/map.
|
||||
Key(String),
|
||||
/// A numeric index in an array/list.
|
||||
Index(usize),
|
||||
}
|
||||
|
||||
@@ -35,20 +57,35 @@ impl std::fmt::Display for PathSegment {
|
||||
}
|
||||
}
|
||||
|
||||
/// The unified representation of a single configuration entry.
|
||||
///
|
||||
/// This model is used for UI rendering and internal manipulation.
|
||||
/// Format-specific handlers are responsible for translating their native
|
||||
/// data into this structure.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ConfigItem {
|
||||
/// The short display name of the key (e.g., `port`).
|
||||
pub key: String,
|
||||
/// The full hierarchical path defining this item's location in the config tree.
|
||||
pub path: Vec<PathSegment>,
|
||||
/// The active value of the configuration entry.
|
||||
pub value: Option<String>,
|
||||
/// The value found in the template file (if any).
|
||||
pub template_value: Option<String>,
|
||||
/// A fallback value to use if the item is missing.
|
||||
pub default_value: Option<String>,
|
||||
/// Visual depth in the tree (used for indentation in the TUI).
|
||||
pub depth: usize,
|
||||
/// True if this item represents a structural node (object or array) rather than a leaf value.
|
||||
pub is_group: bool,
|
||||
/// Comparison status relative to the template.
|
||||
pub status: ItemStatus,
|
||||
/// Metadata about the original data type.
|
||||
pub value_type: ValueType,
|
||||
}
|
||||
|
||||
impl ConfigItem {
|
||||
/// Returns a human-readable string representation of the full path (e.g., `server.port`).
|
||||
pub fn path_string(&self) -> String {
|
||||
let mut s = String::new();
|
||||
for (i, segment) in self.path.iter().enumerate() {
|
||||
@@ -67,6 +104,8 @@ impl ConfigItem {
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
/// Supported configuration file formats.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum FormatType {
|
||||
Env,
|
||||
@@ -78,8 +117,16 @@ pub enum FormatType {
|
||||
Properties,
|
||||
}
|
||||
|
||||
/// Defines the interface for parsing, merging, and writing configuration files.
|
||||
///
|
||||
/// Implementing this trait allows `mould` to support new file formats.
|
||||
pub trait FormatHandler {
|
||||
/// Parses a file into the unified `Vec<ConfigItem>` representation.
|
||||
fn parse(&self, path: &Path) -> anyhow::Result<Vec<ConfigItem>>;
|
||||
|
||||
/// Merges an active configuration with a template file.
|
||||
///
|
||||
/// This identifies missing keys, marks modifications, and syncs default values.
|
||||
fn merge(&self, path: &Path, vars: &mut Vec<ConfigItem>) -> anyhow::Result<()> {
|
||||
if !path.exists() {
|
||||
return Ok(());
|
||||
@@ -115,9 +162,12 @@ pub trait FormatHandler {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes the unified representation back to the original file format.
|
||||
fn write(&self, path: &Path, vars: &[ConfigItem]) -> anyhow::Result<()>;
|
||||
}
|
||||
|
||||
/// Automatically detects the configuration format based on file extension or an explicit override.
|
||||
pub fn detect_format(path: &Path, override_format: Option<String>) -> FormatType {
|
||||
if let Some(fmt) = override_format {
|
||||
match fmt.to_lowercase().as_str() {
|
||||
@@ -144,6 +194,7 @@ pub fn detect_format(path: &Path, override_format: Option<String>) -> FormatType
|
||||
}
|
||||
}
|
||||
|
||||
/// Factory function to return the appropriate handler implementation for a given format.
|
||||
pub fn get_handler(format: FormatType) -> Box<dyn FormatHandler> {
|
||||
match format {
|
||||
FormatType::Env => Box::new(env::EnvHandler),
|
||||
|
||||
Reference in New Issue
Block a user