diff --git a/examples/small.properties b/examples/small.properties index c73af7a6..7a75a2e5 100644 --- a/examples/small.properties +++ b/examples/small.properties @@ -1,10 +1 @@ -# great huh - -# things and stuff -this.is = a properties file - - -this.cat.0 = free -# this one is important -# another thing -this.cat.1 = meow +this.is = a properties file \ No newline at end of file diff --git a/pkg/yqlib/decoder_properties.go b/pkg/yqlib/decoder_properties.go index 1ec9b069..f234f9c3 100644 --- a/pkg/yqlib/decoder_properties.go +++ b/pkg/yqlib/decoder_properties.go @@ -75,7 +75,6 @@ func (dec *propertiesDecoder) applyPropertyComments(context Context, path []inte return err } -// TODO: test comment on array func (dec *propertiesDecoder) applyProperty(context Context, properties *properties.Properties, key string) error { value, _ := properties.Get(key) path := parsePropKey(key) diff --git a/pkg/yqlib/doc/operators/load.md b/pkg/yqlib/doc/operators/load.md index ff76f442..79dc0149 100644 --- a/pkg/yqlib/doc/operators/load.md +++ b/pkg/yqlib/doc/operators/load.md @@ -154,9 +154,7 @@ will output cool: things more_stuff: this: - is: a properties file # great huh - # things and stuff - another: a properties file # another thing + is: a properties file ``` ## Merge from properties @@ -175,10 +173,8 @@ yq '. *= load_props("../../examples/small.properties")' sample.yml will output ```yaml this: - is: a properties file # great huh - # things and stuff + is: a properties file cool: ay - another: a properties file # another thing ``` ## Load from base64 encoded file diff --git a/pkg/yqlib/doc/usage/properties.md b/pkg/yqlib/doc/usage/properties.md index d9331aa8..4e21e08b 100644 --- a/pkg/yqlib/doc/usage/properties.md +++ b/pkg/yqlib/doc/usage/properties.md @@ -139,10 +139,12 @@ yq -p=props sample.properties will output ```yaml person: - name: Mike Wazowski # block comments come through + # block comments come through # comments on values appear + name: Mike Wazowski pets: - - cat # comments on array values appear + # comments on array values appear + - cat food: - pizza ``` diff --git a/pkg/yqlib/encoder_properties.go b/pkg/yqlib/encoder_properties.go index dc7c630a..e62b3f16 100644 --- a/pkg/yqlib/encoder_properties.go +++ b/pkg/yqlib/encoder_properties.go @@ -65,7 +65,7 @@ func (pe *propertiesEncoder) PrintLeadingContent(writer io.Writer, content strin func (pe *propertiesEncoder) Encode(writer io.Writer, node *yaml.Node) error { mapKeysToStrings(node) p := properties.NewProperties() - err := pe.doEncode(p, node, "") + err := pe.doEncode(p, node, "", nil) if err != nil { return err } @@ -74,10 +74,17 @@ func (pe *propertiesEncoder) Encode(writer io.Writer, node *yaml.Node) error { return err } -func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, path string) error { +func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, path string, keyNode *yaml.Node) error { - commentsWithSpaces := strings.ReplaceAll(headAndLineComment(node), "\n", "\n ") + comments := "" + if keyNode != nil { + // include the key node comments if present + comments = headAndLineComment(keyNode) + } + comments = comments + headAndLineComment(node) + commentsWithSpaces := strings.ReplaceAll(comments, "\n", "\n ") p.SetComments(path, strings.Split(commentsWithSpaces, "\n")) + switch node.Kind { case yaml.ScalarNode: var nodeValue string @@ -89,13 +96,13 @@ func (pe *propertiesEncoder) doEncode(p *properties.Properties, node *yaml.Node, _, _, err := p.Set(path, nodeValue) return err case yaml.DocumentNode: - return pe.doEncode(p, node.Content[0], path) + return pe.doEncode(p, node.Content[0], path, node) case yaml.SequenceNode: return pe.encodeArray(p, node.Content, path) case yaml.MappingNode: return pe.encodeMap(p, node.Content, path) case yaml.AliasNode: - return pe.doEncode(p, node.Alias, path) + return pe.doEncode(p, node.Alias, path, nil) default: return fmt.Errorf("Unsupported node %v", node.Tag) } @@ -110,7 +117,7 @@ func (pe *propertiesEncoder) appendPath(path string, key interface{}) string { func (pe *propertiesEncoder) encodeArray(p *properties.Properties, kids []*yaml.Node, path string) error { for index, child := range kids { - err := pe.doEncode(p, child, pe.appendPath(path, index)) + err := pe.doEncode(p, child, pe.appendPath(path, index), nil) if err != nil { return err } @@ -122,7 +129,7 @@ func (pe *propertiesEncoder) encodeMap(p *properties.Properties, kids []*yaml.No for index := 0; index < len(kids); index = index + 2 { key := kids[index] value := kids[index+1] - err := pe.doEncode(p, value, pe.appendPath(path, key.Value)) + err := pe.doEncode(p, value, pe.appendPath(path, key.Value), key) if err != nil { return err } diff --git a/pkg/yqlib/properties_test.go b/pkg/yqlib/properties_test.go index 1bdaa457..1d201f53 100644 --- a/pkg/yqlib/properties_test.go +++ b/pkg/yqlib/properties_test.go @@ -8,6 +8,48 @@ import ( "github.com/mikefarah/yq/v4/test" ) +const propertiesWithCommentsOnMap = `this.thing = hi hi +# important notes +# about this value +this.value = cool +` + +const expectedPropertiesWithCommentsOnMapProps = `this.thing = hi hi + +# important notes +# about this value +this.value = cool +` + +const expectedPropertiesWithCommentsOnMapYaml = `this: + thing: hi hi + # important notes + # about this value + value: cool +` + +const propertiesWithCommentInArray = ` +this.array.0 = cat +# important notes +# about dogs +this.array.1 = dog +` + +const expectedPropertiesWithCommentInArrayProps = `this.array.0 = cat + +# important notes +# about dogs +this.array.1 = dog +` + +const expectedPropertiesWithCommentInArrayYaml = `this: + array: + - cat + # important notes + # about dogs + - dog +` + const samplePropertiesYaml = `# block comments come through person: # neither do comments on maps name: Mike Wazowski # comments on values appear @@ -46,9 +88,12 @@ person.food.0 = pizza ` const expectedDecodedYaml = `person: - name: Mike Wazowski # comments on values appear + # block comments come through + # comments on values appear + name: Mike Wazowski pets: - - cat # comments on array values appear + # comments on array values appear + - cat food: - pizza ` @@ -116,6 +161,34 @@ var propertyScenarios = []formatScenario{ expected: expectedUpdatedProperties, scenarioType: "roundtrip", }, + { + skipDoc: true, + description: "comments on arrays roundtrip", + input: propertiesWithCommentInArray, + expected: expectedPropertiesWithCommentInArrayProps, + scenarioType: "roundtrip", + }, + { + skipDoc: true, + description: "comments on arrays decode", + input: propertiesWithCommentInArray, + expected: expectedPropertiesWithCommentInArrayYaml, + scenarioType: "decode", + }, + { + skipDoc: true, + description: "comments on map roundtrip", + input: propertiesWithCommentsOnMap, + expected: expectedPropertiesWithCommentsOnMapProps, + scenarioType: "roundtrip", + }, + { + skipDoc: true, + description: "comments on map decode", + input: propertiesWithCommentsOnMap, + expected: expectedPropertiesWithCommentsOnMapYaml, + scenarioType: "decode", + }, { description: "Empty doc", skipDoc: true, diff --git a/pkg/yqlib/string_evaluator.go b/pkg/yqlib/string_evaluator.go index 738b3066..59d451ca 100644 --- a/pkg/yqlib/string_evaluator.go +++ b/pkg/yqlib/string_evaluator.go @@ -1,11 +1,13 @@ package yqlib import ( + "bufio" "bytes" "container/list" "errors" "fmt" "io" + "strings" ) type StringEvaluator interface { @@ -35,10 +37,7 @@ func (s *stringEvaluator) Evaluate(expression string, input string, encoder Enco return "", err } - reader, err := readString(input) - if err != nil { - return "", err - } + reader := bufio.NewReader(strings.NewReader(input)) var currentIndex uint err = decoder.Init(reader) diff --git a/pkg/yqlib/utils.go b/pkg/yqlib/utils.go index 0d39046f..a1afff27 100644 --- a/pkg/yqlib/utils.go +++ b/pkg/yqlib/utils.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "os" - "strings" ) func readStream(filename string) (io.Reader, error) { @@ -27,10 +26,6 @@ func readStream(filename string) (io.Reader, error) { } -func readString(input string) (io.Reader, error) { - return bufio.NewReader(strings.NewReader(input)), nil -} - func writeString(writer io.Writer, txt string) error { _, errorWriting := writer.Write([]byte(txt)) return errorWriting