Skip to content

Commit 732d7d2

Browse files
feat: json5 source support
1 parent ad2a63c commit 732d7d2

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

confik/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- Minimum supported Rust version (MSRV) is now 1.67 due to `toml_edit` dependency.
6+
- Add `Json5` source support under `Json5Source`
67

78
## 0.11.7
89

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

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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 super::*;
49+
use crate::Configuration;
50+
51+
#[test]
52+
fn defaults() {
53+
let source = Json5Source::new("{}");
54+
assert!(!source.allows_secrets());
55+
}
56+
57+
#[test]
58+
fn clone() {
59+
let source = Json5Source::new("{}").allow_secrets();
60+
assert!(source.allows_secrets());
61+
assert!(source.clone().allow_secrets);
62+
}
63+
64+
#[test]
65+
fn json5() {
66+
#[derive(Configuration, Debug, PartialEq)]
67+
struct Config {
68+
message: String,
69+
n: i32,
70+
}
71+
72+
let config = "
73+
{
74+
// A traditional message.
75+
message: 'hello world',
76+
77+
// A number for some reason.
78+
n: 42,
79+
}
80+
";
81+
82+
assert_eq!(
83+
Config::builder()
84+
.override_with(Json5Source::new(config))
85+
.try_build()
86+
.expect("Failed to build config"),
87+
Config {
88+
message: "hello world".to_string(),
89+
n: 42,
90+
},
91+
);
92+
}
93+
}

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)