eemeli / yaml

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

Document created using parseDocument does not store undefined values, instead stores null #584

Closed saravmajestic closed 3 hours ago

saravmajestic commented 4 hours ago

Describe the bug First of all, thank you for this library. Really helpful for us. When updating a document created using parseDocument with undefined values, the value is set as null, so stringify returns null value

To Reproduce

const yaml = require("yaml");

const obj = { a: "A", b: undefined, c: "C" };
const doc = yaml.parseDocument(yaml.stringify(obj, {}));
console.log(yaml.stringify(doc));
console.log("====================================");
doc.set("b", undefined);
console.log(yaml.stringify(doc));

First console log shows output without b, which is good. Second console log show null for b, which seems to be inconsistent

Ouput:

a: A
c: C

====================================
a: A
c: C
b: null

Expected behaviour undefined should be preserved

Versions (please complete the following information):

Additional context This seems to be caused while initializing Pair object which default to null value: https://github.com/eemeli/yaml/blob/main/src/nodes/Pair.ts#L32

eemeli commented 3 hours ago

This is not a bug, and is working as intended.

With

doc.set("b", undefined);

you're explicitly asking for an entry to exist in the doc with a key b and an empty value. As YAML only has one empty value (canonically null, also represented by an empty plain string), that's used for it.

Such a key-value pair with an empty value can also be represented in YAML as

? b

where b is an explicit key and the value is completely missing.

If you'd like to remove the value from the doc, you should use

dec.delete('b')

In pure JS, an undefined value often has the same behaviour as a value that is, literally, undefined. To not provide that affordance and have such values work the same way as you're seeing the document interface working, you can use keepUndefined: false when constructing the document from a JS object: https://eemeli.org/yaml/#createnode-options

saravmajestic commented 3 hours ago

Thank you for the quick reply. Your explanation makes sense. I will use the delete Or keepUndefined flag