From 330e1e54d757cdcf6d0785ed5551b315935f877e Mon Sep 17 00:00:00 2001 From: natasha41575 Date: Thu, 8 Sep 2022 14:24:04 -0500 Subject: [PATCH] make sequence style configurable --- goyaml.v3/emitterc.go | 22 +++++- goyaml.v3/patch.go | 33 +++++++++ goyaml.v3/patch_test.go | 146 ++++++++++++++++++++++++++++++++++++++++ goyaml.v3/yamlh.go | 2 + 4 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 goyaml.v3/patch.go create mode 100644 goyaml.v3/patch_test.go diff --git a/goyaml.v3/emitterc.go b/goyaml.v3/emitterc.go index 0f47c9c..430591a 100644 --- a/goyaml.v3/emitterc.go +++ b/goyaml.v3/emitterc.go @@ -226,7 +226,7 @@ func yaml_emitter_append_tag_directive(emitter *yaml_emitter_t, value *yaml_tag_ } // Increase the indentation level. -func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { +func yaml_emitter_increase_indent_compact(emitter *yaml_emitter_t, flow, indentless bool, compact_seq bool) bool { emitter.indents = append(emitter.indents, emitter.indent) if emitter.indent < 0 { if flow { @@ -241,7 +241,14 @@ func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool emitter.indent += 2 } else { // Everything else aligns to the chosen indentation. - emitter.indent = emitter.best_indent*((emitter.indent+emitter.best_indent)/emitter.best_indent) + emitter.indent = emitter.best_indent * ((emitter.indent + emitter.best_indent) / emitter.best_indent) + if compact_seq { + // The value compact_seq passed in is almost always set to `false` when this function is called, + // except when we are dealing with sequence nodes. So this gets triggered to subtract 2 only when we + // are increasing the indent to account for sequence nodes, which will be correct because we need to + // subtract 2 to account for the - at the beginning of the sequence node. + emitter.indent = emitter.indent - 2 + } } } return true @@ -728,7 +735,16 @@ func yaml_emitter_emit_flow_mapping_value(emitter *yaml_emitter_t, event *yaml_e // Expect a block item node. func yaml_emitter_emit_block_sequence_item(emitter *yaml_emitter_t, event *yaml_event_t, first bool) bool { if first { - if !yaml_emitter_increase_indent(emitter, false, false) { + // emitter.mapping context tells us if we are currently in a mapping context. + // emiiter.column tells us which column we are in in the yaml output. 0 is the first char of the column. + // emitter.indentation tells us if the last character was an indentation character. + // emitter.compact_sequence_indent tells us if '- ' is considered part of the indentation for sequence elements. + // So, `seq` means that we are in a mapping context, and we are either at the first char of the column or + // the last character was not an indentation character, and we consider '- ' part of the indentation + // for sequence elements. + seq := emitter.mapping_context && (emitter.column == 0 || !emitter.indention) && + emitter.compact_sequence_indent + if !yaml_emitter_increase_indent_compact(emitter, false, false, seq) { return false } } diff --git a/goyaml.v3/patch.go b/goyaml.v3/patch.go new file mode 100644 index 0000000..208d8dd --- /dev/null +++ b/goyaml.v3/patch.go @@ -0,0 +1,33 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package yaml + +// yaml_emitter_increase_indent preserves the original signature and delegates to +// yaml_emitter_increase_indent_compact without compact-sequence indentation +func yaml_emitter_increase_indent(emitter *yaml_emitter_t, flow, indentless bool) bool { + return yaml_emitter_increase_indent_compact(emitter, flow, indentless, false) +} + +// CompactSeqIndent makes it so that '- ' is considered part of the indentation. +func (e *Encoder) CompactSeqIndent() { + e.encoder.emitter.compact_sequence_indent = true +} + +// DefaultSeqIndent makes it so that '- ' is not considered part of the indentation. +func (e *Encoder) DefaultSeqIndent() { + e.encoder.emitter.compact_sequence_indent = false +} diff --git a/goyaml.v3/patch_test.go b/goyaml.v3/patch_test.go new file mode 100644 index 0000000..08707dd --- /dev/null +++ b/goyaml.v3/patch_test.go @@ -0,0 +1,146 @@ +/* +Copyright 2023 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package yaml_test + +import ( + "bytes" + + . "gopkg.in/check.v1" + yaml "sigs.k8s.io/yaml/goyaml.v3" +) + +func (s *S) TestCompactSeqIndentDefault(c *C) { + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) + enc.CompactSeqIndent() + err := enc.Encode(map[string]interface{}{"a": []string{"b", "c"}}) + c.Assert(err, Equals, nil) + err = enc.Close() + c.Assert(err, Equals, nil) + // The default indent is 4, so these sequence elements get 2 indents as before + c.Assert(buf.String(), Equals, `a: + - b + - c +`) +} + +func (s *S) TestCompactSequenceWithSetIndent(c *C) { + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) + enc.CompactSeqIndent() + enc.SetIndent(2) + err := enc.Encode(map[string]interface{}{"a": []string{"b", "c"}}) + c.Assert(err, Equals, nil) + err = enc.Close() + c.Assert(err, Equals, nil) + // The sequence indent is 2, so these sequence elements don't get indented at all + c.Assert(buf.String(), Equals, `a: +- b +- c +`) +} + +type normal string +type compact string + +// newlinePlusNormalToNewlinePlusCompact maps the normal encoding (prefixed with a newline) +// to the compact encoding (prefixed with a newline), for test cases in marshalTests +var newlinePlusNormalToNewlinePlusCompact = map[normal]compact{ + normal(` +v: + - A + - B +`): compact(` +v: + - A + - B +`), + + normal(` +v: + - A + - |- + B + C +`): compact(` +v: + - A + - |- + B + C +`), + + normal(` +v: + - A + - 1 + - B: + - 2 + - 3 +`): compact(` +v: + - A + - 1 + - B: + - 2 + - 3 +`), + + normal(` +a: + - 1 + - 2 +`): compact(` +a: + - 1 + - 2 +`), + + normal(` +a: + b: + - c: 1 + d: 2 +`): compact(` +a: + b: + - c: 1 + d: 2 +`), +} + +func (s *S) TestEncoderCompactIndents(c *C) { + for i, item := range marshalTests { + c.Logf("test %d. %q", i, item.data) + var buf bytes.Buffer + enc := yaml.NewEncoder(&buf) + enc.CompactSeqIndent() + err := enc.Encode(item.value) + c.Assert(err, Equals, nil) + err = enc.Close() + c.Assert(err, Equals, nil) + + // Default to expecting the item data + expected := item.data + // If there's a different compact representation, use that + if c, ok := newlinePlusNormalToNewlinePlusCompact[normal("\n"+item.data)]; ok { + expected = string(c[1:]) + } + + c.Assert(buf.String(), Equals, expected) + } +} diff --git a/goyaml.v3/yamlh.go b/goyaml.v3/yamlh.go index 7c6d007..40c74de 100644 --- a/goyaml.v3/yamlh.go +++ b/goyaml.v3/yamlh.go @@ -742,6 +742,8 @@ type yaml_emitter_t struct { indent int // The current indentation level. + compact_sequence_indent bool // Is '- ' is considered part of the indentation for sequence elements? + flow_level int // The current flow level. root_context bool // Is it the document root context?