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

Incrementally building YAML #1024

Open
matkoch opened this issue Dec 16, 2024 · 2 comments
Open

Incrementally building YAML #1024

matkoch opened this issue Dec 16, 2024 · 2 comments

Comments

@matkoch
Copy link

matkoch commented Dec 16, 2024

Hi there! I'm seeking wisdom :)

I want to build an API that allows to incrementally build a YAML file using classes/strings/anonymous types. Imagine the following:

new SomeWrapper()
    .Set(new TypedYamlFragment())
    .Set(new { a = new { b = "c" } })
    .Set("name: foobar")
    .AddList("key", _ => _
        .Set("""
            - item1
            - item2
            """));

This should translate to:

this-is:
  the-typed: 'part'
a:
  b: 'c'
name: 'foobar'
key:
  - 'item1'
  - 'item2'

My endeavor so far:

  • I started using nested Dictionary<string, object> in my initial draft. This works well, except I don't know how to quote only strings. Everything I tried (including IEventEmitter) also quotes dictionary keys (e.g., 'name': 'foobar').
  • In my second attempt, I looked into using YamlStream directly. But there, I'm missing some capabilities that I know from SerializerBuilder, such as setting the naming convention and default value handling.

Obligatory question: which approach would you think gives the most benefits/freedom, and how can I overcome these issues? Preferably, I'd also like to apply a partial ordering. For instance, name should be the first item in the YAML, even if it's set last.

Thanks in advance! ❤️

@EdwardCooke
Copy link
Collaborator

Ordering can be achieved with the yamlmember attribute, but that's on a property or a field on a type.

However, if you're trying to avoid using the serializerbuilder/deserializerbuilder you could use the emitter and manually send in the scalar's/mappings/etc. There's no "this is a key" property when setting the scalar, because even a mapping can be a key. When you pass in the scalar you can specify what type of quotes to use or not use. This is the most flexible, but also the most complex.

Maybe a simpler option you could do is something with an ordered dictionary for the backing of your API so it keeps track of the order the items are added to it. If you do a regular dictionary the ordering is not preserved. You could then use a custom yaml converter to generate/read the yaml.

Most of what you want would require reflection work in order to get names of properties. Especially when setting using an object like your second set command. Getting values from a yaml string is easy since you can just deserialize the yaml into a Dictionary<object, object> (Use OrderedDictionary to keep element orders) using the default deserializer and iterate over the key value pairs that are returned.

@matkoch
Copy link
Author

matkoch commented Dec 17, 2024

However, if you're trying to avoid using the serializerbuilder/deserializerbuilder you could use the emitter and manually send in the scalar's/mappings/etc.

I'm not trying to avoid it, it's rather that there are limitations. What exactly do you mean with "manually send in scalars/mappings" ? Also, so far it's not exactly clear to me when to use IEmitter or IEventEmitter – what's the difference?

Maybe a simpler option you could do is something with an ordered dictionary for the backing of your API so it keeps track of the order the items are added to it.

I considered that, but then I'm still facing the issue about quoting. What exactly do you mean with "custom converter" ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants