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

Add a flag to output a single line in ConvertTo-YAML. #147

Closed
RokeJulianLockhart opened this issue Oct 22, 2024 · 13 comments · Fixed by #148
Closed

Add a flag to output a single line in ConvertTo-YAML. #147

RokeJulianLockhart opened this issue Oct 22, 2024 · 13 comments · Fixed by #148

Comments

@RokeJulianLockhart
Copy link

RokeJulianLockhart commented Oct 22, 2024

Suggestion

Sometimes, I want the YAML to be a single line, because some input forms solely permit that.

Cuurent Status

The current documentation doesn't indicate a way to accomplish this:

  1. (Get-Help -Name 'ConvertTo-YAML').syntax.syntaxItem.parameter | Format-List
  2. name             : Data
    required         : false
    pipelineInput    : true (ByValue)
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    parameterValue   : Object
    type             : @{name=Object}
    position         : 0
    aliases          : None
    
    name             : OutFile
    required         : false
    pipelineInput    : false
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    parameterValue   : string
    type             : @{name=string}
    position         : Named
    aliases          : None
    
    name             : JsonCompatible
    required         : false
    pipelineInput    : false
    isDynamic        : false
    globbing         : false
    parameterSetName : NoOptions
    type             : @{name=switch}
    position         : Named
    aliases          : None
    
    name             : KeepArray
    required         : false
    pipelineInput    : false
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    type             : @{name=switch}
    position         : Named
    aliases          : None
    
    name             : Force
    required         : false
    pipelineInput    : false
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    type             : @{name=switch}
    position         : Named
    aliases          : None
    
    name             : Data
    required         : false
    pipelineInput    : true (ByValue)
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    parameterValue   : Object
    type             : @{name=Object}
    position         : 0
    aliases          : None
    
    name             : OutFile
    required         : false
    pipelineInput    : false
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    parameterValue   : string
    type             : @{name=string}
    position         : Named
    aliases          : None
    
    name                : Options
    required            : false
    pipelineInput       : false
    isDynamic           : false
    globbing            : false
    parameterSetName    : Options
    parameterValue      : SerializationOptions
    type                : @{name=SerializationOptions}
    position            : Named
    aliases             : None
    parameterValueGroup : @{parameterValue=System.Object[]}
    
    name             : KeepArray
    required         : false
    pipelineInput    : false
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    type             : @{name=switch}
    position         : Named
    aliases          : None
    
    name             : Force
    required         : false
    pipelineInput    : false
    isDynamic        : false
    globbing         : false
    parameterSetName : (All)
    type             : @{name=switch}
    position         : Named
    aliases          : None
@gabriel-samfira
Copy link
Member

Could you give an example of what you mean by having the output as a single line?

@RokeJulianLockhart
Copy link
Author

RokeJulianLockhart commented Oct 22, 2024

#147 (comment)

@gabriel-samfira, https://stackoverflow.com/revisions/67645180/2#:~:text=networkMapping:%20%7B'test_net_1':%20%7B'external':%20true%7D%2C%20'test_net_2':%20%7B'external':%20true%7D%2C%20'test_net_3':%20%7B'external':%20true%7D%7D provides an example:

networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'external': true}, 'test_net_3': {'external': true}}

...which, surprisingly, doesn't appear to be supported whatsoever by this library:

PS /home/RokeJulianLockhart> networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'external': true}, 'test_net_3': {'external': true}} | ConvertFrom-YAML
ParserError: 
Line |
   1 |  networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'ex …
     |                               ~
     | Unexpected token ':' in expression or statement.
PS /home/RokeJulianLockhart> Get-Error

Type        : System.Management.Automation.ParseException
Errors      : 
    Extent  : :
    ErrorId : UnexpectedToken
    Message : Unexpected token ':' in expression or statement.

    Extent  : :
    ErrorId : UnexpectedToken
    Message : Unexpected token ':' in expression or statement.

    Extent  : :
    ErrorId : UnexpectedToken
    Message : Unexpected token ':' in expression or statement.

    Extent  : :
    ErrorId : UnexpectedToken
    Message : Unexpected token ':' in expression or statement.
Message     : At line:1 char:30
              + networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'ex …
              +                              ~
              Unexpected token ':' in expression or statement.
              
              At line:1 char:43
              + networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'ex …
              +                                           ~
              Unexpected token ':' in expression or statement.
              
              At line:1 char:77
              + … {'test_net_1': {'external': true}, 'test_net_2': {'external': true},  …
              +                                                               ~
              Unexpected token ':' in expression or statement.
              
              At line:1 char:111
              + …  'test_net_2': {'external': true}, 'test_net_3': {'external': true}}  …
              +                                                               ~
              Unexpected token ':' in expression or statement.
ErrorRecord : 
    Exception             : 
        Type    : System.Management.Automation.ParentContainsErrorRecordException
        Message : At line:1 char:30
                  + networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'ex …
                  +                              ~
                  Unexpected token ':' in expression or statement.
                  
                  At line:1 char:43
                  + networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'ex …
                  +                                           ~
                  Unexpected token ':' in expression or statement.
                  
                  At line:1 char:77
                  + … {'test_net_1': {'external': true}, 'test_net_2': {'external': true},  …
                  +                                                               ~
                  Unexpected token ':' in expression or statement.
                  
                  At line:1 char:111
                  + …  'test_net_2': {'external': true}, 'test_net_3': {'external': true}}  …
                  +                                                               ~
                  Unexpected token ':' in expression or statement.
        HResult : -2146233087
    CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    FullyQualifiedErrorId : UnexpectedToken
    InvocationInfo        : 
        ScriptLineNumber : 1
        OffsetInLine     : 30
        HistoryId        : 2
        Line             : networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'external': true}, 'test_net_3': {'external': true}} | ConvertFrom-YAML
        Statement        : :
        PositionMessage  : At line:1 char:30
                           + networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'ex …
                           +                              ~
        CommandOrigin    : Internal
TargetSite  : 
    Name          : Invoke
    DeclaringType : [System.Management.Automation.Runspaces.PipelineBase]
    MemberType    : Method
    Module        : System.Management.Automation.dll
Source      : System.Management.Automation
HResult     : -2146233087
StackTrace  : 
   at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input)
   at Microsoft.PowerShell.Executor.ExecuteCommandHelper(Pipeline tempPipeline, Exception& exceptionThrown, ExecutionOptions options)

@skycommand
Copy link

@RokeJulianLockhart That's because your PowerShell command is not well-formed.

The correct command is this:

$TestYaml = "networkMapping: {'test_net_1': {'external': true}, 'test_net_2': {'external': true}, 'test_net_3': {'external': true}}" | ConvertFrom-Yaml

Now you can inspect the resulting object:

$TestYaml
Name                           Value
----                           -----
networkMapping                 {[test_net_3, System.Collections.Hashtable], [test_net_2, System.Collections.Hashtable], [test_net_1, System.Collections.Hashtable]}
$TestYaml.networkMapping
Name                           Value
----                           -----
test_net_3                     {[external, True]}
test_net_2                     {[external, True]}
test_net_1                     {[external, True]}

@RokeJulianLockhart

This comment was marked as off-topic.

@gabriel-samfira
Copy link
Member

That's okay @RokeJulianLockhart ! Happened to me more than once. Glad things got sorted out. Closing this bug.

@RokeJulianLockhart
Copy link
Author

RokeJulianLockhart commented Oct 23, 2024

#147 (comment)

@gabriel-samfira, the issue hasn't been solved! That was an aside. This issue requests the ability to output a single line. Instructing ConvertTo-YAML to do so still isn't possible.

@RokeJulianLockhart RokeJulianLockhart changed the title Add a flag to output a single line. Add a flag to output a single line in ConvertTo-YAML. Oct 23, 2024
@gabriel-samfira
Copy link
Member

Have you tried the -JsonCompatible flag? It will output json in one line. Jdon being a subset of yaml, you should then be able to parse it with any other library.

@RokeJulianLockhart
Copy link
Author

RokeJulianLockhart commented Oct 23, 2024

#147 (comment)

@gabriel-samfira, thanks. However, having it in one line merely because it's JSON-compatible, instead of prettified like usual, doesn't seem to make much sense.

Irrespective, I want to use YAML because it's more readable, even on a single line. Outputting JSON-compatible YAML rather nullifies that.

@gabriel-samfira
Copy link
Member

gabriel-samfira commented Oct 23, 2024

So, this example:

$TestYaml = 'networkMapping: {"test_net_1": {"external": true}, "test_net_2": {"external": true}, "test_net_3": {"external": true}}'

is equivalent to:

$TestYaml = '{"networkMapping": {"test_net_1": {"external": true}, "test_net_2": {"external": true}, "test_net_3": {"external": true}}}'

In your example, you essentially have a JSON assigned to networkMapping. The only thing I added was an opening and closing bracket. And quotes around networkMapping. The rest is identical.

There is no flow style in yaml that gives you a one liner from a data structure that has nested data structures like arrays, maps, etc. Not unless you use json which allows you to have one line. YAML depends on newlines and indents if you want actual yaml. The only places where it doesn't is where you use JSON (which is a subset of yaml).

As an example, here is how python does it. First, with default_flow_style=False. This will output YAML:

# With default_flow_style=False
>>> import yaml
>>> data = {"a": [1, 2, 3], "b": {"c": 7}}
>>> print(yaml.dump(data, default_flow_style=False))
a:
- 1
- 2
- 3
b:
  c: 7

Now let's try with default_flow_style=True:

>>> import yaml
>>> data = {"a": [1, 2, 3], "b": {"c": 7}}
>>> print(yaml.dump(data,default_flow_style=True))
{a: [1, 2, 3], b: {c: 7}}

>>> 

We essentially got a JSON. The only thing missing from that YAML output are the quotes around the keys. But it looks just as unfriendly as any other JSON.

@gabriel-samfira
Copy link
Member

gabriel-samfira commented Oct 23, 2024

Don't get me wrong, I am willing to add a flag to enable the Flow style instead of the Block style, but I am not sure it adds much value. Let me know if you really need it and I can add it in the next round of updates.

@gabriel-samfira
Copy link
Member

See if #148 suits your needs. It's still a WiP because I also need to write tests, but it should do what you need.

@RokeJulianLockhart
Copy link
Author

#147 (comment)

Many thanks, @gabriel-samfira. I'm no expert at YAML, so I'll acquiesce - your explanation at #147 (comment) is fairly comprehensive.

@gabriel-samfira
Copy link
Member

No worries! I usually add features when they make sense. If nothing else, flow style is useful when used in sequences, as it makes the yaml more compact. If we add flow for sequences, it makes sense to add for mappings as well. So the mastet branch has both now.

I need to write some tests and release a new version on PowerShell gallery.

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

Successfully merging a pull request may close this issue.

3 participants