mirror of
https://github.com/mikefarah/yq.git
synced 2026-07-07 14:25:38 +00:00
Merge b78119772a into e2f1d5ccf7
This commit is contained in:
commit
9cf3f90788
@ -157,9 +157,25 @@ func (dec *tomlDecoder) createInlineTableMap(tomlNode *toml.Node) (*CandidateNod
|
||||
}, nil
|
||||
}
|
||||
|
||||
// commentIsOnNewLine reports whether comment begins on a line after the end of
|
||||
// prev, by scanning the raw input bytes between them for a newline. When the
|
||||
// range cannot be determined it returns true, preserving the historic behaviour
|
||||
// of treating in-array comments as head comments for the next element.
|
||||
func (dec *tomlDecoder) commentIsOnNewLine(prev, comment *toml.Node) bool {
|
||||
prevEnd := prev.Raw.Offset + prev.Raw.Length
|
||||
commentStart := comment.Raw.Offset
|
||||
if commentStart < prevEnd {
|
||||
return true
|
||||
}
|
||||
between := dec.parser.Raw(toml.Range{Offset: prevEnd, Length: commentStart - prevEnd})
|
||||
return bytes.IndexByte(between, '\n') >= 0
|
||||
}
|
||||
|
||||
func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*CandidateNode, error) {
|
||||
content := make([]*CandidateNode, 0)
|
||||
var pendingArrayComments []string
|
||||
var prevElem *toml.Node
|
||||
var prevYamlNode *CandidateNode
|
||||
|
||||
iterator := tomlNode.Children()
|
||||
for iterator.Next() {
|
||||
@ -167,8 +183,19 @@ func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*CandidateNode, error)
|
||||
|
||||
// Handle comments within arrays
|
||||
if child.Kind == toml.Comment {
|
||||
// Collect comments to attach to the next array element
|
||||
pendingArrayComments = append(pendingArrayComments, string(child.Data))
|
||||
// A comment on the same line as the preceding element is a trailing
|
||||
// (inline) comment on that element; a comment on its own line is a
|
||||
// head comment for the next element.
|
||||
if prevYamlNode != nil && !dec.commentIsOnNewLine(prevElem, child) {
|
||||
if prevYamlNode.LineComment == "" {
|
||||
prevYamlNode.LineComment = string(child.Data)
|
||||
} else {
|
||||
prevYamlNode.LineComment = prevYamlNode.LineComment + "\n" + string(child.Data)
|
||||
}
|
||||
} else {
|
||||
// Collect comments to attach to the next array element
|
||||
pendingArrayComments = append(pendingArrayComments, string(child.Data))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@ -184,6 +211,8 @@ func (dec *tomlDecoder) createArray(tomlNode *toml.Node) (*CandidateNode, error)
|
||||
}
|
||||
|
||||
content = append(content, yamlNode)
|
||||
prevElem = child
|
||||
prevYamlNode = yamlNode
|
||||
}
|
||||
|
||||
return &CandidateNode{
|
||||
|
||||
@ -188,6 +188,10 @@ func (te *tomlEncoder) encodeTopLevelEntry(w io.Writer, path []string, node *Can
|
||||
te.wroteRootAttr = false
|
||||
}
|
||||
for _, it := range node.Content {
|
||||
// Write head comment before the array-of-tables header
|
||||
if err := te.writeComment(w, it.HeadComment); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte("[[" + quotedKey + "]]\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -283,10 +287,10 @@ func (te *tomlEncoder) writeArrayAttribute(w io.Writer, key string, seq *Candida
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if any array elements have head comments - if so, use multiline format
|
||||
// Check if any array elements have head or line comments - if so, use multiline format
|
||||
hasElementComments := false
|
||||
for _, it := range seq.Content {
|
||||
if it.HeadComment != "" {
|
||||
if it.HeadComment != "" || it.LineComment != "" {
|
||||
hasElementComments = true
|
||||
break
|
||||
}
|
||||
@ -299,6 +303,13 @@ func (te *tomlEncoder) writeArrayAttribute(w io.Writer, key string, seq *Candida
|
||||
}
|
||||
|
||||
for i, it := range seq.Content {
|
||||
// Separate a head-commented element from the previous one with a blank line
|
||||
if i > 0 && it.HeadComment != "" {
|
||||
if _, err := w.Write([]byte("\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Write head comment for this element
|
||||
if it.HeadComment != "" {
|
||||
commentLines := strings.Split(it.HeadComment, "\n")
|
||||
@ -340,15 +351,17 @@ func (te *tomlEncoder) writeArrayAttribute(w io.Writer, key string, seq *Candida
|
||||
// Always add trailing comma in multiline arrays
|
||||
itemStr += ","
|
||||
|
||||
if _, err := w.Write([]byte(" " + itemStr + "\n")); err != nil {
|
||||
return err
|
||||
// Append trailing (inline) comment on the same line, if present
|
||||
if it.LineComment != "" {
|
||||
lineComment := strings.TrimSpace(it.LineComment)
|
||||
if !strings.HasPrefix(lineComment, "#") {
|
||||
lineComment = "# " + lineComment
|
||||
}
|
||||
itemStr += " " + lineComment
|
||||
}
|
||||
|
||||
// Add blank line between elements (except after the last one)
|
||||
if i < len(seq.Content)-1 {
|
||||
if _, err := w.Write([]byte("\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte(" " + itemStr + "\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@ -546,6 +559,10 @@ func (te *tomlEncoder) encodeSeparateMapping(w io.Writer, path []string, m *Cand
|
||||
te.wroteRootAttr = false
|
||||
}
|
||||
for _, it := range v.Content {
|
||||
// Write head comment before the array-of-tables header
|
||||
if err := te.writeComment(w, it.HeadComment); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte("[[" + key + "]]\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -603,6 +620,10 @@ func (te *tomlEncoder) encodeMappingBodyWithPath(w io.Writer, path []string, m *
|
||||
if isTomlArrayOfTables(v) {
|
||||
dotted := tomlDottedKey(append(append([]string{}, path...), k))
|
||||
for _, it := range v.Content {
|
||||
// Write head comment before the array-of-tables header
|
||||
if err := te.writeComment(w, it.HeadComment); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := w.Write([]byte("[[" + dotted + "]]\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -677,7 +698,7 @@ func (te *tomlEncoder) colorizeToml(input []byte) []byte {
|
||||
|
||||
// Table sections - [section] or [[array]]
|
||||
// Only treat '[' as a table section if it appears at the start of the line
|
||||
// (possibly after whitespace). This avoids incorrectly colouring inline arrays like
|
||||
// (possibly after whitespace). This avoids incorrectly colouring inline arrays like
|
||||
// "ports = [8000, 8001]" as table sections.
|
||||
if ch == '[' {
|
||||
isSectionHeader := true
|
||||
|
||||
@ -325,6 +325,33 @@ the_array = [
|
||||
]
|
||||
`
|
||||
|
||||
// Bug: a head comment directly above an [[array-of-tables]] header is dropped
|
||||
// on round-trip when other content precedes the array-of-tables.
|
||||
var rtArrayTableHeadComment = `[package]
|
||||
name = "x"
|
||||
|
||||
# the binary
|
||||
[[bin]]
|
||||
name = "y"
|
||||
`
|
||||
|
||||
// Same bug via a nested array-of-tables ([[a.b]]) under a table with attributes.
|
||||
var rtNestedArrayTableHeadComment = `[fruit]
|
||||
name = "apple"
|
||||
# a variety
|
||||
[[fruit.variety]]
|
||||
name = "red delicious"
|
||||
`
|
||||
|
||||
// Bug: an inline (trailing) comment on an array item detaches from its item and
|
||||
// floats onto its own line as a head comment on the next item, with a spurious
|
||||
// blank line.
|
||||
var rtArrayItemInlineComment = `default = [
|
||||
"a", # why a
|
||||
"b",
|
||||
]
|
||||
`
|
||||
|
||||
var expectedSubArrays = `array:
|
||||
- subarray:
|
||||
- subsubarray:
|
||||
@ -369,7 +396,7 @@ var tomlScenarios = []formatScenario{
|
||||
skipDoc: true,
|
||||
description: "blank",
|
||||
input: `A = "hello`,
|
||||
expectedError: `bad file 'sample.yml': basic string not terminated by "`,
|
||||
expectedError: `bad file 'sample.yml': unterminated basic string`,
|
||||
scenarioType: "decode-error",
|
||||
},
|
||||
{
|
||||
@ -700,6 +727,30 @@ var tomlScenarios = []formatScenario{
|
||||
expected: tomlTableWithComments,
|
||||
scenarioType: "roundtrip",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Roundtrip: head comment above array-of-tables",
|
||||
input: rtArrayTableHeadComment,
|
||||
expression: ".",
|
||||
expected: rtArrayTableHeadComment,
|
||||
scenarioType: "roundtrip",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Roundtrip: head comment above nested array-of-tables",
|
||||
input: rtNestedArrayTableHeadComment,
|
||||
expression: ".",
|
||||
expected: rtNestedArrayTableHeadComment,
|
||||
scenarioType: "roundtrip",
|
||||
},
|
||||
{
|
||||
skipDoc: true,
|
||||
description: "Roundtrip: inline comment on array item",
|
||||
input: rtArrayItemInlineComment,
|
||||
expression: ".",
|
||||
expected: rtArrayItemInlineComment,
|
||||
scenarioType: "roundtrip",
|
||||
},
|
||||
// Encode (YAML → TOML) scenarios - verify readable table sections are produced
|
||||
{
|
||||
description: "Encode: Simple mapping produces table section",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user