use crate::Package;
use chrono::Utc;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PackageFormat {
Yaml,
Json,
Python,
YamlCompressed,
JsonCompressed,
Binary,
Toml,
Xml,
}
#[derive(Debug, Clone)]
pub struct SerializationOptions {
pub pretty_print: bool,
pub include_metadata: bool,
pub include_timestamps: bool,
pub compression_level: u32,
pub field_filters: Vec<String>,
pub include_only: Option<Vec<String>>,
pub exclude_fields: Option<Vec<String>>,
pub custom_rules: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PackageMetadata {
pub serialized_at: String,
pub format: String,
pub serializer_version: String,
pub original_path: Option<String>,
pub checksum: Option<String>,
pub custom: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PackageContainer {
pub package: Package,
pub metadata: PackageMetadata,
pub schema_version: String,
}
impl PackageFormat {
pub fn from_extension(path: &Path) -> Option<Self> {
let path_str = path.to_string_lossy();
if path_str.ends_with(".yaml.gz") || path_str.ends_with(".yml.gz") {
return Some(Self::YamlCompressed);
}
if path_str.ends_with(".json.gz") {
return Some(Self::JsonCompressed);
}
match path.extension()?.to_str()? {
"yaml" | "yml" => Some(Self::Yaml),
"json" => Some(Self::Json),
"py" => Some(Self::Python),
"bin" => Some(Self::Binary),
"toml" => Some(Self::Toml),
"xml" => Some(Self::Xml),
_ => None,
}
}
pub fn default_filename(&self) -> &'static str {
match self {
Self::Yaml => "package.yaml",
Self::Json => "package.json",
Self::Python => "package.py",
Self::YamlCompressed => "package.yaml.gz",
Self::JsonCompressed => "package.json.gz",
Self::Binary => "package.bin",
Self::Toml => "package.toml",
Self::Xml => "package.xml",
}
}
pub fn supports_compression(&self) -> bool {
matches!(self, Self::YamlCompressed | Self::JsonCompressed)
}
pub fn is_text_format(&self) -> bool {
!matches!(self, Self::Binary)
}
pub fn mime_type(&self) -> &'static str {
match self {
Self::Yaml | Self::YamlCompressed => "application/x-yaml",
Self::Json | Self::JsonCompressed => "application/json",
Self::Python => "text/x-python",
Self::Binary => "application/octet-stream",
Self::Toml => "application/toml",
Self::Xml => "application/xml",
}
}
}
impl SerializationOptions {
pub fn new() -> Self {
Self {
pretty_print: true,
include_metadata: true,
include_timestamps: true,
compression_level: 6,
field_filters: Vec::new(),
include_only: None,
exclude_fields: None,
custom_rules: HashMap::new(),
}
}
pub fn minimal() -> Self {
Self {
pretty_print: false,
include_metadata: false,
include_timestamps: false,
compression_level: 1,
field_filters: Vec::new(),
include_only: None,
exclude_fields: None,
custom_rules: HashMap::new(),
}
}
pub fn compact() -> Self {
Self {
pretty_print: false,
include_metadata: true,
include_timestamps: false,
compression_level: 9,
field_filters: Vec::new(),
include_only: None,
exclude_fields: Some(vec!["description".to_string(), "help".to_string()]),
custom_rules: HashMap::new(),
}
}
pub fn add_field_filter(&mut self, filter: String) {
self.field_filters.push(filter);
}
pub fn set_include_only(&mut self, fields: Vec<String>) {
self.include_only = Some(fields);
}
pub fn set_exclude_fields(&mut self, fields: Vec<String>) {
self.exclude_fields = Some(fields);
}
pub fn add_custom_rule(&mut self, field: String, rule: String) {
self.custom_rules.insert(field, rule);
}
}
impl Default for SerializationOptions {
fn default() -> Self {
Self::new()
}
}
impl PackageMetadata {
pub fn new(format: String) -> Self {
Self {
serialized_at: Utc::now().to_rfc3339(),
format,
serializer_version: env!("CARGO_PKG_VERSION").to_string(),
original_path: None,
checksum: None,
custom: HashMap::new(),
}
}
pub fn set_original_path(&mut self, path: String) {
self.original_path = Some(path);
}
pub fn set_checksum(&mut self, checksum: String) {
self.checksum = Some(checksum);
}
pub fn add_custom(&mut self, key: String, value: String) {
self.custom.insert(key, value);
}
}
impl PackageContainer {
pub fn new(package: Package, format: String) -> Self {
Self {
package,
metadata: PackageMetadata::new(format),
schema_version: "1.0".to_string(),
}
}
pub fn with_metadata(package: Package, metadata: PackageMetadata) -> Self {
Self {
package,
metadata,
schema_version: "1.0".to_string(),
}
}
}