1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Allow large error types - detailed config errors are expected
//! Premortem: A configuration library that performs a premortem on your app's config.
//!
//! Premortem validates your configuration before your application runs, finding all
//! the ways it could die from bad config upfront. It uses stillwater's functional
//! patterns for error accumulation and composable validation.
//!
//! # Core Concepts
//!
//! - **Error Accumulation**: Find ALL configuration errors, not just the first one
//! - **Source Layering**: Merge config from files and environment variables
//! - **Required Variables**: Declarative validation of required environment variables
//! - **Testable I/O**: Dependency injection via `ConfigEnv` trait
//! - **Type Safety**: Deserialize into your types with full validation
//!
//! # Quick Start
//!
//! ```ignore
//! use premortem::prelude::*;
//! use serde::Deserialize;
//!
//! #[derive(Debug, Deserialize)]
//! struct AppConfig {
//! host: String,
//! port: u16,
//! }
//!
//! impl Validate for AppConfig {
//! fn validate(&self) -> ConfigValidation<()> {
//! if self.port > 0 {
//! Validation::Success(())
//! } else {
//! Validation::fail_with(ConfigError::ValidationError {
//! path: "port".to_string(),
//! source_location: None,
//! value: Some(self.port.to_string()),
//! message: "port must be positive".to_string(),
//! })
//! }
//! }
//! }
//!
//! fn main() -> Result<(), ConfigErrors> {
//! let config = Config::<AppConfig>::builder()
//! .source(Toml::file("config.toml"))
//! .source(Env::new().prefix("APP"))
//! .build()?;
//!
//! println!("Running on {}:{}", config.host, config.port);
//! Ok(())
//! }
//! ```
//!
//! # Import Patterns
//!
//! ## Quick Start (Recommended)
//!
//! For most users, import the prelude:
//!
//! ```ignore
//! use premortem::prelude::*;
//! ```
//!
//! ## Selective Imports
//!
//! Import only what you need:
//!
//! ```ignore
//! use premortem::{Config, Validate};
//! use premortem::error::ConfigErrors;
//! ```
//!
//! ## Advanced: Direct Stillwater Access
//!
//! For custom sources or advanced patterns:
//!
//! ```ignore
//! use premortem::prelude::*;
//! use stillwater::Effect; // Direct stillwater access
//! ```
//!
//! # Required Environment Variables
//!
//! Mark environment variables as required at the source level with error accumulation:
//!
//! ```ignore
//! use premortem::prelude::*;
//!
//! let config = Config::<AppConfig>::builder()
//! .source(
//! Env::prefix("APP_")
//! .require_all(&["JWT_SECRET", "DATABASE_URL", "API_KEY"])
//! )
//! .build()?;
//! ```
//!
//! All missing required variables are reported together:
//!
//! ```text
//! Configuration errors (3):
//! [env:APP_JWT_SECRET] Missing required field: jwt.secret
//! [env:APP_DATABASE_URL] Missing required field: database.url
//! [env:APP_API_KEY] Missing required field: api.key
//! ```
//!
//! This separates **presence validation** (does the variable exist?) from
//! **value validation** (does it meet constraints?).
//!
//! # Architecture
//!
//! Premortem follows the "pure core, imperative shell" pattern:
//!
//! - **Pure Core**: Value merging, deserialization, and validation are pure functions
//! - **Imperative Shell**: I/O operations use the `ConfigEnv` trait for dependency injection
//!
//! This architecture enables:
//! - Easy unit testing with `MockEnv`
//! - Composable validation with error accumulation
//! - Clear separation of concerns
//!
//! # Module Structure
//!
//! - [`prelude`]: Convenient re-exports for common usage
//! - [`config`]: `Config` and `ConfigBuilder` for loading configuration
//! - [`error`]: Error types (`ConfigError`, `ConfigErrors`, `ConfigValidation`)
//! - [`value`]: `Value` enum for intermediate representation
//! - [`source`]: `Source` trait and `ConfigValues` container
//! - [`mod@env`]: `ConfigEnv` trait and `MockEnv` for testing
//! - [`validate`]: `Validate` trait for custom validation
//!
//! # Stillwater Integration
//!
//! Premortem uses these stillwater types:
//!
//! | Type | Usage |
//! |------|-------|
//! | `Validation<T, E>` | Error accumulation for config errors |
//! | `NonEmptyVec<T>` | Guaranteed non-empty error lists |
//! | `Semigroup` | Combining errors from multiple sources |
//!
//! These are re-exported from the prelude for convenience.
// Re-exports for convenience
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
pub use validators;
pub use ;
pub use ;
// Re-export sources
pub use Env;
pub use Json;
pub use Toml;
pub use Yaml;
pub use ;
// Re-export watch types
pub use ;
// Re-export stillwater types that are commonly used
pub use ;
// Re-export stillwater predicate module and types (0.13.0+)
pub use ;
// Re-export derive macro when the feature is enabled
pub use Validate as DeriveValidate;