Skip to content
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

JSON #131

Open
Daniel15 opened this issue May 31, 2024 · 2 comments
Open

JSON #131

Daniel15 opened this issue May 31, 2024 · 2 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@Daniel15
Copy link
Contributor

Is your feature request related to a problem? Please describe.

Thank you for working on this useful project! I was wondering whether you'd consider adding support for JSON files?

Describe the solution you'd like

Initially it could be something basic, like just a list of paths to ignore.

Round-tripping JSON shouldn't be too difficult, and a lexer + parser that retains trivia should let you retain the same formatting on output.

Describe alternatives you've considered

N/A

Additional context

@Daniel15 Daniel15 added the enhancement New feature or request label May 31, 2024
@VorpalBlade
Copy link
Owner

While I have not thought about json specifically, I did consider xml at one point. Json should be simpler than XML.

One thing that would be needed would be a format-preserving Json parser and serialiser (e.g. not change newlines, indentation, no reformatting numbers, etc). For INI files I wrote my own code for this, but I'd rather not for Json as it is a more complex format.

I also don't have a personal need for this, and this is a hobby project. So, contributions are welcome. If anyone is interested I'm willing to discuss the design (the first new format to support will be the hardest design-wise, as we need to make the code generic over the file format).

@VorpalBlade VorpalBlade added the help wanted Extra attention is needed label May 31, 2024
@VorpalBlade
Copy link
Owner

VorpalBlade commented Jun 2, 2024

So I had a think about what would be needed:

JSON

  • Find or write a library for round trip parsing of JSON. Preferably JSON5 (superset of JSON with support for comments and trailing commas) as that would be more general. I have not found any for Rust at least. Nor really for any other language. A stream SAX style parser would be preferable for the algorithms needed. There is no need to build a full DOM for the system state (and we can use the stream from the SAX parser to build a DOM ourselves for the source state).
    • Things to keep in mind is that number formatting can vary and we want to treat scalar values as opaque strings as far as possible (otherwise we might reformat 0.10 to 0.1 for example, along with various nasty issues around floating point precision etc).
    • If we have to write our own parser it would be preferable to use the winnow parsing library, as that is already in use for parsing the configuration script. Keeps the number of dependencies down (which help with compile time and binary size)
  • Figure out a way to describe matches over the data structure:
    • JSONpath seems like the obvious choice, but most Rust implementations seem tied to a specific library for parsing the JSON data. There is one library to parse jsonpath syntax (rsonpath) but the associated engine for evaluating that seems not reusable for our purposes.
    • Perhaps a simplified version of JSONpath might be suitable instead.
  • The current merge and filter algorithms are tightly coupled to how INI files are represented. I believe the general approach should work, but there are too many INI-specific quirks for a general implementation to be possible (for example, handling keys before the first section in INI files). That said, I do believe that JSON and some other potential future formats like YAML could share an implementation.
    • It isn't clear how to handle arrays, as the items don't have unique keys. Some thought is required here. Sometimes it might represent an unsorted collection, other times it is a sorted list, otherwise it might be conceptually keyed on a field in the objects stored in the array.
  • Finally there would need to be a language directive in the chezmoi_modify_manager config that selected the processing pipeline to use, along with some tweaks to which directives are valid for which file formats.
    • ignore, remove, add:remove seems fairly obvious how to support for JSON
    • set and the currently existing transforms is fairly straight forward for scalars in JSON
    • Trying to set or add:hide an array or object in JSON would require some thought, can be skipped initially, but lets avoid painting ourself into a corner with the design at least.

Other formats

Side note about about XML (since I also considered this case): XML would be more complicated: you may not have unique keys, you can have text as siblings to nodes, you have attributes on nodes (not just contents) etc.

Side note about toml: toml_edit exists as a Rust library, but this is a DOM style library as far as I know. Not ideal since the merge and filter algorithms is written for a streaming approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants