Coder Social home page Coder Social logo

Comments (3)

EdwardCooke avatar EdwardCooke commented on June 12, 2024 1

Ok, spent some time on this, you can use a custom INodeDeserializer to convert it into an array. I set the value to the Key property on the object. Here's the code.

Note, it does not deserialize to the same yaml, if you need that, let me know and I could try and put something together for that.

using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;

var yaml = @"name: ""Build""
on:
  workflow_dispatch:
    inputs:
      reason:
        description: The reason for the manual run
        required: true
        type: string
      something_else:
        description: Some other input
        required: false
        type: boolean
";
var deserializer = new DeserializerBuilder().WithNodeDeserializer(new InputObjectNodeDeserializer(), (syntax) => syntax.OnTop()).Build();

var action = deserializer.Deserialize<Actions>(yaml);
foreach (var input in action.On.WorkflowDispatch.Inputs)
{
    Console.WriteLine("{0} - {1}", input.Key, input.Description);
}

public class Actions
{
    [YamlMember(Alias = "name")]
    public string Name { get; set; }

    [YamlMember(Alias = "on")]
    public Dispatch On { get; set; }

}

public class Dispatch
{
    [YamlMember(Alias = "workflow_dispatch")]
    public WorkflowDispatch WorkflowDispatch { get; set; }
}

public class WorkflowDispatch
{
    [YamlMember(Alias = "inputs")]
    public Input[] Inputs { get; set; }
}

public class Input
{
    [YamlMember(Alias = "key")]
    public string Key { get; set; }

    [YamlMember(Alias = "description")]
    public string Description { get; set; }

    [YamlMember(Alias = "required")]
    public bool Required { get; set; }

    [YamlMember(Alias = "type")]
    public string Type { get; set; }
}

public class InputObjectNodeDeserializer : INodeDeserializer
{
    public bool Deserialize(IParser reader, Type expectedType, Func<IParser, Type, object?> nestedObjectDeserializer, out object? value)
    {
        if (expectedType != typeof(Input[]))
        {
            value = null;
            return false;
        }

        if (!reader.Accept<MappingStart>())
        {
            value = null;
            return false;
        }

        reader.Consume<MappingStart>();
        var result = new List<Input>();
        while (!reader.TryConsume<MappingEnd>(out var _))
        {
            var keyScalar = reader.Consume<Scalar>();
            var input = nestedObjectDeserializer(reader, typeof(Input)) as Input;
            if (input != null)
            {
                input.Key = keyScalar.Value;
            }
            result.Add(input);
        }

        value = result.ToArray();
        return true;
    }
}

The output

reason - The reason for the manual run
something_else - Some other input

I'm going to close this issue since this is an example of doing what you want, re-open if you need serialization too.

from yamldotnet.

EdwardCooke avatar EdwardCooke commented on June 12, 2024

The reasons it’s not coming in as an array is because it isn’t an array. It’s a mapping. Which means it will be properties or key/value pairs. You could probably create your own node deserializer or type converter to handle that part of your yaml differently.

You can see here what the different parts of your yaml are with this cool tool. It’s what we use to determine the validity of yaml and one of the tools we use to make sure we’re parsing things correctly.

http://ben-kiki.org/ypaste/data/78777/index.html

from yamldotnet.

tymokvo avatar tymokvo commented on June 12, 2024

I think the short answer to your question is "no" since arrays don't have string keys (like reason) but you could make a type/named tuple that can hold the key and value from the mapping in one value.

It seems a lot easier to deserialize the way the library intends and then just implement a method on your type that returns the array-ified (key, value) pairs. I made a quick version with F#, but the C# version should be broadly similar. Except more verbose 😉.

Some gross F# code
#r "nuget: YamlDotNet"

open YamlDotNet.Serialization
open System.IO

type Input() =
    member val description = "" with get, set
    member val required = false with get, set

    [<YamlMember(Alias = "type")>]
    member val kind = "" with get, set

    member z.toRecord =
        {| description = z.description
           required = z.required
           kind = z.kind |}

type WorkflowDispatch() =
    member val inputs: System.Collections.Generic.Dictionary<string, Input> =
        System.Collections.Generic.Dictionary() with get, set

    member z.inputsArray =
        z.inputs.Keys
        |> Seq.map (fun k ->
            {| name = k
               value = z.inputs[k].toRecord |})
        |> Seq.toArray

type On() =
    member val workflowDispatch = WorkflowDispatch() with get, set

type GHAction() =
    member val name = "" with get, set
    member val on = On() with get, set

    member z.inputsArray = z.on.workflowDispatch.inputsArray

/// Create a deserializer for a YAML file
let deserializer _ =
    DeserializerBuilder()
        .WithNamingConvention(NamingConventions.UnderscoredNamingConvention.Instance)
        .Build()

let deserialize<'t> (content: string) =
    content |> (() |> deserializer).Deserialize<'t>

File.ReadAllText("ghaction.yml")
|> deserialize<GHAction>
|> (fun gha -> gha.inputsArray)
|> printfn "%A"

result:

[| { name = "reason"
     value =
       { description = "The reason for the manual run"
         kind = "string"
         required = true } }
   { name = "something_else"
     value =
       { description = "Some other input"
         kind = "boolean"
         required = false } } |]

from yamldotnet.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.