-
Notifications
You must be signed in to change notification settings - Fork 243
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
Conversation
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.
I have some remarks. Also, the two commits could be squashed into one commit,... as well as further fixups of course!
Either way thanks for your contribution!
tests/file_jsonc.rs
Outdated
@@ -52,7 +52,7 @@ fn test_file() { | |||
assert_eq!(s.place.telephone, None); | |||
assert_eq!(s.elements.len(), 10); | |||
assert_eq!(s.elements[3], "4".to_string()); | |||
if cfg!(feature = "preserve_order") { | |||
if cfg!(feature = "TODO: preserve_order") { |
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.
Why this?
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.
well, that's because jsonc-parser doesn't support preserve_order. need time to contribute that
#[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"]); |
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.
Do I understand correctly that the jsonc
parser also parses json
even if that feature is disabled?
I think that's counter-intuitive and we should only parse jsonc
with the jsonc
parser.
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.
well, there are 2 reasons i added that.
- the file extension for jsonc is actually
.json
, not.jsonc
, so the real question is that when i enable the featurejsonc
it's about the format or the file extension? - for the common usage, people would choose only one of them, not both. and I believe the jsonc format is more common for config files than the json format.
Pull Request Test Coverage Report for Build 16902150946Details
💛 - Coveralls |
Well, I merged the upstream and fixed the test cases. I’m certain that when I submitted the pull request back then, all test cases passed. This behavior should follow one clear approach, rather than just forcing lowercase:
|
The feedback was back in 2023. You later pushed some commits in Feb 2024 and the PR was silent until recently. It's not a surprise that tests could fail given a new major zero ver release was made which permits breaking changes.
Regarding feedback with the I have seen crates like #[cfg(all(feature = "json", feature = "jsonc"))]
panic!("Both `json` and `jsonc` features are active, only one feature for parsing `.json` files is permitted"); Regarding use std::error::Error;
use crate::format;
use crate::map::Map;
use crate::value::Value;
pub fn parse(
uri: Option<&String>,
text: &str,
) -> Result<Map<String, Value>, Box<dyn Error + Send + Sync>> {
// Parse a JSON/JSONC input from the provided text
let value = format::from_parsed_value(uri, jsonc_parser::parse_to_serde_value(text)?);
format::extract_root_table(uri, value)
}
Lines 27 to 46 in 07f13ff
So that should already simplify your The following should work for now at least: - let value = format::from_parsed_value(uri, jsonc_parser::parse_to_serde_value(text)?);
+ let value = from_jsonc_value(uri, jsonc_parser::parse_to_value(text, &Default::default())?);
format::extract_root_table(uri, value) Should #472 get merged, then EDIT: Oh just noticed that the return type of the result is the value wrapped in an option, which unlike - let value = format::from_parsed_value(uri, jsonc_parser::parse_to_serde_value(text)?);
+ let parsed = jsonc_parser::parse_to_value(text, &Default::default())?;
+ let value = from_jsonc_value(uri, parsed.unwrap_or(ValueKind::Nil));
format::extract_root_table(uri, value) I'll apply that as a review suggestion 😅 |
Please rework your commits as meaningful, atomic commits to be merged. |
@epage, @polarathene all green now :D. The .json vs .jsonc issue comes down to the project’s philosophy: should it aim to be flexible or strict? If goes for flexible, the current behavior makes sense, because in practice, almost no one actually uses the .jsonc extension. People generally just want .json files that can contain comments. For example, from the earlier point about case insensitive handling and forcing lowercase mapping, these are closely tied to the overall design philosophy. Under a strict approach, case insensitive handling should be an optional feature rather than the default, and forcing lowercase mapping should be avoided - upper should map to upper, and lower should be lower. |
From https://jsonc.org/
imo comments inside of json is no longer json. We should be properly validating the json we parse. |
@@ -126,8 +126,9 @@ json = ["serde_json"] | |||
yaml = ["yaml-rust2"] | |||
ini = ["rust-ini"] | |||
json5 = ["json5_rs", "serde/derive"] | |||
jsonc = ["jsonc-parser"] |
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.
jsonc = ["jsonc-parser"] | |
jsonc = ["dep:jsonc-parser"] |
#676 is tracking fixing the rest.
|
||
#[test] | ||
fn test_nothing() { | ||
let res = Config::builder() | ||
.add_source(File::from_str("", FileFormat::Ini)) | ||
.build(); | ||
assert!(res.is_ok()); | ||
let c = res.unwrap(); | ||
assert_data_eq!( | ||
format!("{:?}", c), | ||
str!("Config { defaults: {}, overrides: {}, sources: [], cache: Value { origin: None, kind: Table({}) } }") | ||
); | ||
} |
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.
Why are these test_nothing
s added? if they are indirectly related (you wanted a test_nothing
for jsonc), then please add these in their own commit before this one
assert!(res.is_ok()); | ||
let c = res.unwrap(); | ||
assert_data_eq!( | ||
format!("{:?}", c), |
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.
c.to_debug()
assert!(res.is_err()); | ||
let err = res.unwrap_err().to_string(); | ||
let expected_prefix = | ||
"Expected colon after the string or word in object property on line 4 column 1 in "; | ||
assert!( | ||
err.starts_with(expected_prefix), | ||
"Error message does not start with expected prefix. Got: {}", | ||
err | ||
); |
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.
Can we switch this to snapshot testing (assert_data_eq!
) like our other formats?
I did a new commit, see #452