#![doc(html_root_url = "https://docs.rs/pdmt/")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![forbid(unsafe_code)]
#![warn(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_qualifications
)]
pub mod error;
pub mod models;
pub mod template;
pub mod validators;
#[cfg(feature = "quality-proxy")]
#[cfg_attr(docsrs, doc(cfg(feature = "quality-proxy")))]
pub mod quality;
#[cfg(feature = "mcp-tools")]
#[cfg_attr(docsrs, doc(cfg(feature = "mcp-tools")))]
pub mod mcp;
pub use crate::error::{Error, Result};
pub use crate::models::content::GeneratedContent;
pub use crate::template::definition::TemplateDefinition;
pub use crate::template::engine::TemplateEngine;
#[cfg(feature = "todo-validation")]
pub use crate::validators::todo::TodoValidator;
#[cfg(feature = "mcp-tools")]
pub use crate::mcp::tools::create_template_tool;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const DEFAULT_TEMPLATE_DIR: &str = "templates";
pub const MAX_TEMPLATE_SIZE: usize = 10 * 1024 * 1024;
#[cfg(feature = "quality-proxy")]
pub const DEFAULT_QUALITY_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30);
pub mod builtin {
pub const TODO_LIST: &str = "todo_list";
pub const PROJECT_SCAFFOLD: &str = "project_scaffold";
pub const BASE: &str = "base";
}
pub mod utils {
use crate::error::{Error, Result};
pub fn validate_template_id(id: &str) -> Result<()> {
if id.is_empty() {
return Err(Error::InvalidInput("Template ID cannot be empty".into()));
}
if id.len() > 64 {
return Err(Error::InvalidInput(
"Template ID too long (max 64 chars)".into(),
));
}
if !id.chars().all(|c| c.is_alphanumeric() || c == '_') {
return Err(Error::InvalidInput(
"Template ID contains invalid characters".into(),
));
}
Ok(())
}
#[cfg(feature = "todo-validation")]
pub fn generate_content_id() -> String {
uuid::Uuid::new_v4().to_string()
}
#[cfg(feature = "todo-validation")]
pub fn current_timestamp() -> chrono::DateTime<chrono::Utc> {
chrono::Utc::now()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[allow(clippy::const_is_empty)]
fn test_version_defined() {
assert!(!VERSION.is_empty());
}
#[test]
fn test_validate_template_id() {
assert!(utils::validate_template_id("todo_list").is_ok());
assert!(utils::validate_template_id("test123").is_ok());
assert!(utils::validate_template_id("a").is_ok());
assert!(utils::validate_template_id("").is_err());
assert!(utils::validate_template_id("invalid-id").is_err());
assert!(utils::validate_template_id("invalid!id").is_err());
assert!(utils::validate_template_id(&"x".repeat(65)).is_err());
}
#[cfg(feature = "todo-validation")]
#[test]
fn test_content_id_generation() {
let id1 = utils::generate_content_id();
let id2 = utils::generate_content_id();
assert_ne!(id1, id2);
assert!(!id1.is_empty());
}
}