-
Notifications
You must be signed in to change notification settings - Fork 242
Support jsonc format #457
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Support jsonc format #457
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use std::error::Error; | ||
|
||
use crate::error::{ConfigError, Unexpected}; | ||
use crate::map::Map; | ||
use crate::value::{Value, ValueKind}; | ||
|
||
use jsonc_parser::JsonValue; | ||
|
||
pub fn parse( | ||
uri: Option<&String>, | ||
text: &str, | ||
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> { | ||
match jsonc_parser::parse_to_value(text, &Default::default())? { | ||
Some(r) => match r { | ||
JsonValue::String(ref value) => Err(Unexpected::Str(value.to_string())), | ||
JsonValue::Number(value) => Err(Unexpected::Float(value.parse::<f64>().unwrap())), | ||
JsonValue::Boolean(value) => Err(Unexpected::Bool(value)), | ||
JsonValue::Object(o) => match from_jsonc_value(uri, JsonValue::Object(o)).kind { | ||
ValueKind::Table(map) => Ok(map), | ||
_ => unreachable!(), | ||
}, | ||
JsonValue::Array(_) => Err(Unexpected::Seq), | ||
JsonValue::Null => Err(Unexpected::Unit), | ||
}, | ||
None => Err(Unexpected::Unit), | ||
} | ||
.map_err(|err| ConfigError::invalid_root(uri, err)) | ||
.map_err(|err| Box::new(err) as Box<dyn Error + Send + Sync>) | ||
} | ||
|
||
fn from_jsonc_value(uri: Option<&String>, value: JsonValue) -> Value { | ||
let vk = match value { | ||
JsonValue::Null => ValueKind::Nil, | ||
JsonValue::String(v) => ValueKind::String(v.to_string()), | ||
JsonValue::Number(number) => { | ||
if let Ok(v) = number.parse::<i64>() { | ||
ValueKind::I64(v) | ||
} else if let Ok(v) = number.parse::<f64>() { | ||
ValueKind::Float(v) | ||
} else { | ||
unreachable!(); | ||
} | ||
} | ||
JsonValue::Boolean(v) => ValueKind::Boolean(v), | ||
JsonValue::Object(table) => { | ||
let m = table | ||
.into_iter() | ||
.map(|(k, v)| (k, from_jsonc_value(uri, v))) | ||
.collect(); | ||
ValueKind::Table(m) | ||
} | ||
JsonValue::Array(array) => { | ||
let l = array | ||
.into_iter() | ||
.map(|v| from_jsonc_value(uri, v)) | ||
.collect(); | ||
ValueKind::Array(l) | ||
} | ||
}; | ||
Value::new(uri, vk) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,9 @@ mod ron; | |
#[cfg(feature = "json5")] | ||
mod json5; | ||
|
||
#[cfg(feature = "jsonc")] | ||
mod jsonc; | ||
|
||
/// File formats provided by the library. | ||
/// | ||
/// Although it is possible to define custom formats using [`Format`] trait it is recommended to use FileFormat if possible. | ||
|
@@ -55,6 +58,10 @@ pub enum FileFormat { | |
/// JSON5 (parsed with json5) | ||
#[cfg(feature = "json5")] | ||
Json5, | ||
|
||
/// JSONC (parsed with jsonc) | ||
#[cfg(feature = "jsonc")] | ||
Jsonc, | ||
} | ||
|
||
lazy_static! { | ||
|
@@ -81,6 +88,12 @@ lazy_static! { | |
#[cfg(feature = "json5")] | ||
formats.insert(FileFormat::Json5, vec!["json5"]); | ||
|
||
#[cfg(all(feature = "jsonc", feature = "json"))] | ||
formats.insert(FileFormat::Jsonc, vec!["jsonc"]); | ||
|
||
#[cfg(all(feature = "jsonc", not(feature = "json")))] | ||
formats.insert(FileFormat::Jsonc, vec!["jsonc", "json"]); | ||
Comment on lines
+91
to
+95
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do I understand correctly that the I think that's counter-intuitive and we should only parse There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well, there are 2 reasons i added that.
|
||
|
||
formats | ||
}; | ||
} | ||
|
@@ -117,13 +130,17 @@ impl FileFormat { | |
#[cfg(feature = "json5")] | ||
FileFormat::Json5 => json5::parse(uri, text), | ||
|
||
#[cfg(feature = "jsonc")] | ||
FileFormat::Jsonc => jsonc::parse(uri, text), | ||
|
||
#[cfg(all( | ||
not(feature = "toml"), | ||
not(feature = "json"), | ||
not(feature = "yaml"), | ||
not(feature = "ini"), | ||
not(feature = "ron"), | ||
not(feature = "json5"), | ||
not(feature = "jsonc"), | ||
))] | ||
_ => unreachable!("No features are enabled, this library won't work without features"), | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
// foo | ||
"bar": "bar is a lowercase param", | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"ok": true, | ||
"error" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
// c | ||
/* c */ | ||
"debug": true, | ||
"debug_json": true, | ||
"production": false, | ||
"arr": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], | ||
"place": { | ||
"name": "Torre di Pisa", | ||
"longitude": 43.7224985, | ||
"latitude": 10.3970522, | ||
"favorite": false, | ||
"reviews": 3866, | ||
"rating": 4.5, | ||
"creator": { | ||
"name": "John Smith", | ||
"username": "jsmith", | ||
"email": "jsmith@localhost" | ||
}, | ||
}, | ||
"FOO": "FOO should be overridden", | ||
"bar": "I am bar", | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note about adding a new format: traditionally, we've enabled all of them by default but #621 would have us re-evaluate that assumption.