eemeli / yaml

YAML parser and stringifier for JavaScript
https://eemeli.org/yaml
ISC License
1.31k stars 115 forks source link

Loosing quotes around a property value in yaml after converting it to json and back to yaml. #533

Closed vanessadnguyen closed 8 months ago

vanessadnguyen commented 8 months ago

Describe the bug Loosing quotes around a property value in yaml after converting it to json and back to yaml.

To Reproduce Steps to reproduce the behaviour.

Original yaml entered by users:

formatVersion: 1
inputs: {}
resources:
  Cloud_Machine_1:
    type: Cloud.Machine
      properties:
        image: "hnguyenImage"
        flavor: "hnguyenFlavor"
        xxxxx: "yes"
        xxxx1: "no"
        yyyyy: "true"
        yyyy1: "false"

We convert it to json using:

parse(this.yamlContent ?? '', { prettyErrors: false, strict: false })

We convert the json back to yaml using:

stringify(json, { indent: 2, lineWidth: 10000 });

The new yaml is losing quotes around property values except "true/false" values. For example, "yes/no" values no longer have double quotes surrounding them.

formatVersion: 1
inputs: {}
resources:
  Cloud_Machine_1:
    type: Cloud.Machine
    properties:
      image: hnguyenImage
      flavor: hnguyenFlavor
      xxxxx: yes
      xxxx1: no
      yyyyy: "true"
      yyyy1: "false"

Expected behaviour I expect quotes (single quotes or double quotes) to stay the way they were entered originally. Is there any way to configure the parse and stringify method to do this?

Versions (please complete the following information):

Additional context Add any other context about the problem here.

eemeli commented 8 months ago

To keep the original formatting, use parseDocument rather than parse to get a representation of the source that retains styling information.

vanessadnguyen commented 8 months ago

Hi Eemeli, Thanks for responding to my issue. parseDocument() method return Document object. However, our product relies on JS object or Json object to do some surgery on it (store it in our front-end data models) and then convert that JS object/Json object back to yaml using "stringify" method. Doing the entire surgery above using Document.contents is not something we can afford right now because that is a huge change of all foundation work we put in over the years. That might not even be possible due to our need of having data models as our source of truth.

However, using parseDocument().toJS() or parseDocument().toJSON() is pretty much the same with calling parse() method directly. And therefore, converting the JS/Json object back to yaml will cause losing quotes around property values again.

If you know any other work-around, please let me know. Thanks, Vanesssa

vanessadnguyen commented 8 months ago

Hi Eemeli, I wonder why yaml lib was able to maintain the original styling for "true/false" values, but not any other values? The quotes are still there for "true/false" values. This seems to be a bug in the library itself.

image: hnguyenImage
flavor: hnguyenFlavor
xxxxx: yes
xxxx1: no
yyyyy: "true"
yyyy1: "false"
eemeli commented 8 months ago

The true and false are quoted because they need to be to be later parsed as strings rather than booleans using the default YAML 1.2 schema. That's not a bug.

You seem to be asking for plain JS primitive values that somehow still have formatting metadata attached to them. Are you aware that this is not a reasonable request?

vanessadnguyen commented 8 months ago

If I don't provide single quotes nor double quotes for true/false values in original yaml, the "yaml to JS/Json to yaml" conversion process will produce the yaml with no quotes for true/false values.

If I provide single quotes or double quotes for true/false values in original yaml, the "yaml to JS/Json to yaml" conversion process will produce the final yaml with double quotes for true/false values. This is also not good since the original 'true'/'false' value in single quotes is replaced with "true"/"false" in double quotes.

What you said made sense, that true/false values are quoted for later parsed as string. Keeping exactly the original formatting does not seem to be reasonable.

The "keepSourceTokens" option does not help either. I looked at data returned by parseDocument method and I could find any information that would help me get back the original formatting metadata. Did you overlook something?

eemeli commented 8 months ago

If I don't provide single quotes nor double quotes for true/false values in original yaml, the "yaml to JS/Json to yaml" conversion process will produce the yaml with no quotes for true/false values.

Yes, that's because they get parsed as boolean values.

The "keepSourceTokens" option does not help either. I looked at data returned by parseDocument method and I could find any information that would help me get back the original formatting metadata. Did you overlook something?

Quoting the docs on this option:

Include a srcToken value on each parsed Node, containing the CST token that was composed into this node.

That is adding information to the document contents, and had no effect on the parsed JS output.

Closing, as the library is behaving as intended and there's nothing actionable here.

vanessadnguyen commented 6 months ago

FYI, I realized that if I do not want to lose quotes around yes/no values, I need to force YAML spec 1.1. The library is using YAML spec 1.2 by default. However, forcing 1.1 spec will cause yes/no without quotes to be converted to true/false after calling parse(), then stringify(). This is expected and it can be annoying.

I used to use js-yaml version 4.1.0 which is based on 1.2 spec also, but it has a different problem with its load() and dump() method. The library added quotes on a yes value that does not have quotes initially. https://github.com/nodeca/js-yaml/issues/657 After calling js-yaml's load() and dump() method, yes value without quotes will have quotes around it.

Our backend is using yaml spec 1.1. We will move to eemeli/yaml lib with spec 1.2 when our backend is ready to migrate to spec 1.2 also.