Skip to content

Commit dfa6659

Browse files
feat: json5 source support
1 parent ad2a63c commit dfa6659

File tree

4 files changed

+101
-0
lines changed

4 files changed

+101
-0
lines changed

confik/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ default = ["env", "toml"]
2626
# Source types
2727
env = ["dep:envious"]
2828
json = ["dep:serde_json"]
29+
json5 = ["dep:json5"]
2930
toml = ["dep:toml"]
3031

3132
# Destination types
@@ -48,6 +49,7 @@ serde = { version = "1", default-features = false, features = ["std", "derive"]
4849
thiserror = "1"
4950

5051
envious = { version = "0.2", optional = true }
52+
json5 = { version = "0.4", optional = true }
5153
serde_json = { version = "1", optional = true }
5254
toml = { version = "0.8", optional = true, default-features = false, features = ["parse"] }
5355

confik/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ mod third_party;
3636

3737
#[cfg(feature = "env")]
3838
pub use self::sources::env_source::EnvSource;
39+
#[cfg(feature = "json5")]
40+
pub use self::sources::json5_source::Json5Source;
3941
#[cfg(feature = "json")]
4042
pub use self::sources::json_source::JsonSource;
4143
#[cfg(feature = "toml")]

confik/src/sources/json5_source.rs

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use std::{borrow::Cow, error::Error, fmt};
2+
3+
use crate::{ConfigurationBuilder, Source};
4+
5+
/// A [`Source`] containing raw JSON data.
6+
#[derive(Clone)]
7+
pub struct Json5Source<'a> {
8+
contents: Cow<'a, str>,
9+
allow_secrets: bool,
10+
}
11+
12+
impl<'a> Json5Source<'a> {
13+
/// Creates a [`Source`] containing raw JSON data.
14+
pub fn new(contents: impl Into<Cow<'a, str>>) -> Self {
15+
Self {
16+
contents: contents.into(),
17+
allow_secrets: false,
18+
}
19+
}
20+
21+
/// Allows this source to contain secrets.
22+
pub fn allow_secrets(mut self) -> Self {
23+
self.allow_secrets = true;
24+
self
25+
}
26+
}
27+
28+
impl<'a> Source for Json5Source<'a> {
29+
fn allows_secrets(&self) -> bool {
30+
self.allow_secrets
31+
}
32+
33+
fn provide<T: ConfigurationBuilder>(&self) -> Result<T, Box<dyn Error + Sync + Send>> {
34+
Ok(json5::from_str(&self.contents)?)
35+
}
36+
}
37+
38+
impl<'a> fmt::Debug for Json5Source<'a> {
39+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40+
f.debug_struct("Json5Source")
41+
.field("allow_secrets", &self.allow_secrets)
42+
.finish_non_exhaustive()
43+
}
44+
}
45+
46+
#[cfg(test)]
47+
mod tests {
48+
use crate::Configuration;
49+
50+
use super::*;
51+
52+
#[test]
53+
fn defaults() {
54+
let source = Json5Source::new("{}");
55+
assert!(!source.allows_secrets());
56+
}
57+
58+
#[test]
59+
fn clone() {
60+
let source = Json5Source::new("{}").allow_secrets();
61+
assert!(source.allows_secrets());
62+
assert!(source.clone().allow_secrets);
63+
}
64+
65+
#[test]
66+
fn json5() {
67+
#[derive(Configuration, Debug, PartialEq)]
68+
struct Config {
69+
message: String,
70+
n: i32,
71+
}
72+
73+
let config = "
74+
{
75+
// A traditional message.
76+
message: 'hello world',
77+
78+
// A number for some reason.
79+
n: 42,
80+
}
81+
";
82+
83+
assert_eq!(
84+
Config::builder()
85+
.override_with(Json5Source::new(config))
86+
.try_build()
87+
.expect("Failed to build config"),
88+
Config {
89+
message: "hello world".to_string(),
90+
n: 42,
91+
},
92+
);
93+
}
94+
}

confik/src/sources/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub(crate) mod file_source;
5656
#[cfg(feature = "toml")]
5757
pub(crate) mod toml_source;
5858

59+
#[cfg(feature = "json5")]
60+
pub(crate) mod json5_source;
61+
5962
#[cfg(feature = "json")]
6063
pub(crate) mod json_source;
6164

0 commit comments

Comments
 (0)