mirror of
https://github.com/mikefarah/yq.git
synced 2026-07-07 14:25:38 +00:00
Fixing TOML ArrayTable parsing issues #1758
This commit is contained in:
parent
f00852bc6c
commit
306dc931a5
@ -1,8 +1,3 @@
|
|||||||
# 001
|
[[fruits]]
|
||||||
---
|
[[fruits.varieties]] # nested array of tables
|
||||||
abc: # 001
|
name = "red delicious
|
||||||
- 1 # one
|
|
||||||
- 2 # two
|
|
||||||
|
|
||||||
---
|
|
||||||
def # 002
|
|
||||||
@ -1,26 +1,6 @@
|
|||||||
|
[[fruits]]
|
||||||
|
|
||||||
|
[animals]
|
||||||
|
|
||||||
# This is a TOML document
|
[[fruits.varieties]] # nested array of tables
|
||||||
|
name = "red delicious"
|
||||||
title = "TOML Example"
|
|
||||||
|
|
||||||
[owner]
|
|
||||||
name = "Tom Preston-Werner"
|
|
||||||
dob = 1979-05-27T07:32:00-08:00
|
|
||||||
|
|
||||||
[database]
|
|
||||||
enabled = true
|
|
||||||
ports = [ 8000, 8001, 8002 ]
|
|
||||||
data = [ ["delta", "phi"], [3.14] ]
|
|
||||||
temp_targets = { cpu = 79.5, case = 72.0 }
|
|
||||||
|
|
||||||
[servers]
|
|
||||||
|
|
||||||
[servers.alpha]
|
|
||||||
ip = "10.0.0.1"
|
|
||||||
role = "frontend"
|
|
||||||
|
|
||||||
[servers.beta]
|
|
||||||
ip = "10.0.0.2"
|
|
||||||
role = "backend"
|
|
||||||
|
|
||||||
@ -324,32 +324,58 @@ func (dec *tomlDecoder) arrayAppend(context Context, path []interface{}, rhsNode
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error) {
|
func (dec *tomlDecoder) processArrayTable(currentNode *toml.Node) (bool, error) {
|
||||||
log.Debug("Entering processArrayTable")
|
log.Debug("c")
|
||||||
fullPath := dec.getFullPath(currentNode.Child())
|
fullPath := dec.getFullPath(currentNode.Child())
|
||||||
log.Debug("Fullpath: %v", fullPath)
|
log.Debug("Fullpath: %v", fullPath)
|
||||||
|
|
||||||
|
c := Context{}
|
||||||
|
c = c.SingleChildContext(dec.rootMap)
|
||||||
|
|
||||||
|
pathToCheck := fullPath
|
||||||
|
if len(fullPath) >= 1 {
|
||||||
|
pathToCheck = fullPath[:len(fullPath)-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// if fullPath points to an array of maps rather than a map
|
||||||
|
// then it should set this element into the _last_ element of that array.
|
||||||
|
// Because TOML. So we'll inject the last index into the path.
|
||||||
|
readOp := createTraversalTree(pathToCheck, traversePreferences{DontAutoCreate: true}, false)
|
||||||
|
|
||||||
|
resultContext, err := dec.d.GetMatchingNodes(c, readOp)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if resultContext.MatchingNodes.Len() >= 1 {
|
||||||
|
match := resultContext.MatchingNodes.Front().Value.(*CandidateNode)
|
||||||
|
// path refers to an array, we need to add this to the last element in the array
|
||||||
|
if match.Kind == SequenceNode {
|
||||||
|
fullPath = append(pathToCheck, len(match.Content)-1, fullPath[len(fullPath)-1])
|
||||||
|
log.Debugf("Adding to end of %v array, using path: %v", pathToCheck, fullPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// need to use the array append exp to add another entry to
|
// need to use the array append exp to add another entry to
|
||||||
// this array: fullpath += [ thing ]
|
// this array: fullpath += [ thing ]
|
||||||
|
|
||||||
hasValue := dec.parser.NextExpression()
|
hasValue := dec.parser.NextExpression()
|
||||||
if !hasValue {
|
|
||||||
return false, fmt.Errorf("error retrieving table %v value: %w", fullPath, dec.parser.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
tableNodeValue := &CandidateNode{
|
tableNodeValue := &CandidateNode{
|
||||||
Kind: MappingNode,
|
Kind: MappingNode,
|
||||||
Tag: "!!map",
|
Tag: "!!map",
|
||||||
}
|
}
|
||||||
|
runAgainstCurrentExp := false
|
||||||
|
// if the next value is a ArrayTable or Table, then its not part of this declaration (not a key value pair)
|
||||||
|
// so lets leave that expression for the next round of parsing
|
||||||
|
if hasValue && (dec.parser.Expression().Kind == toml.ArrayTable || dec.parser.Expression().Kind == toml.Table) {
|
||||||
|
runAgainstCurrentExp = true
|
||||||
|
} else if hasValue {
|
||||||
|
// otherwise, if there is a value, it must be some key value pairs of the
|
||||||
|
// first object in the array!
|
||||||
tableValue := dec.parser.Expression()
|
tableValue := dec.parser.Expression()
|
||||||
runAgainstCurrentExp, err := dec.decodeKeyValuesIntoMap(tableNodeValue, tableValue)
|
runAgainstCurrentExp, err = dec.decodeKeyValuesIntoMap(tableNodeValue, tableValue)
|
||||||
log.Debugf("table node err: %w", err)
|
|
||||||
if err != nil && !errors.Is(err, io.EOF) {
|
if err != nil && !errors.Is(err, io.EOF) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
c := Context{}
|
}
|
||||||
|
|
||||||
c = c.SingleChildContext(dec.rootMap)
|
|
||||||
|
|
||||||
// += function
|
// += function
|
||||||
err = dec.arrayAppend(c, fullPath, tableNodeValue)
|
err = dec.arrayAppend(c, fullPath, tableNodeValue)
|
||||||
|
|||||||
@ -104,6 +104,27 @@ owner:
|
|||||||
suburb: nice
|
suburb: nice
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Parse: Array of Array Table
|
||||||
|
Given a sample.toml file of:
|
||||||
|
```toml
|
||||||
|
|
||||||
|
[[fruits]]
|
||||||
|
name = "apple"
|
||||||
|
[[fruits.varieties]] # nested array of tables
|
||||||
|
name = "red delicious"
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq -oy '.' sample.toml
|
||||||
|
```
|
||||||
|
will output
|
||||||
|
```yaml
|
||||||
|
fruits:
|
||||||
|
- name: apple
|
||||||
|
varieties:
|
||||||
|
- name: red delicious
|
||||||
|
```
|
||||||
|
|
||||||
## Parse: Empty Table
|
## Parse: Empty Table
|
||||||
Given a sample.toml file of:
|
Given a sample.toml file of:
|
||||||
```toml
|
```toml
|
||||||
|
|||||||
@ -37,6 +37,64 @@ owner:
|
|||||||
age: 36
|
age: 36
|
||||||
`
|
`
|
||||||
|
|
||||||
|
var doubleArrayTable = `
|
||||||
|
[[fruits]]
|
||||||
|
name = "apple"
|
||||||
|
[[fruits.varieties]] # nested array of tables
|
||||||
|
name = "red delicious"`
|
||||||
|
|
||||||
|
var doubleArrayTableExpected = `fruits:
|
||||||
|
- name: apple
|
||||||
|
varieties:
|
||||||
|
- name: red delicious
|
||||||
|
`
|
||||||
|
|
||||||
|
var doubleArrayTableMultipleEntries = `
|
||||||
|
[[fruits]]
|
||||||
|
name = "banana"
|
||||||
|
[[fruits]]
|
||||||
|
name = "apple"
|
||||||
|
[[fruits.varieties]] # nested array of tables
|
||||||
|
name = "red delicious"`
|
||||||
|
|
||||||
|
var doubleArrayTableMultipleEntriesExpected = `fruits:
|
||||||
|
- name: banana
|
||||||
|
- name: apple
|
||||||
|
varieties:
|
||||||
|
- name: red delicious
|
||||||
|
`
|
||||||
|
|
||||||
|
var doubleArrayTableNothingAbove = `
|
||||||
|
[[fruits.varieties]] # nested array of tables
|
||||||
|
name = "red delicious"`
|
||||||
|
|
||||||
|
var doubleArrayTableNothingAboveExpected = `fruits:
|
||||||
|
varieties:
|
||||||
|
- name: red delicious
|
||||||
|
`
|
||||||
|
|
||||||
|
var doubleArrayTableEmptyAbove = `
|
||||||
|
[[fruits]]
|
||||||
|
[[fruits.varieties]] # nested array of tables
|
||||||
|
name = "red delicious"`
|
||||||
|
|
||||||
|
var doubleArrayTableEmptyAboveExpected = `fruits:
|
||||||
|
- varieties:
|
||||||
|
- name: red delicious
|
||||||
|
`
|
||||||
|
|
||||||
|
var emptyArrayTableThenTable = `
|
||||||
|
[[fruits]]
|
||||||
|
[animals]
|
||||||
|
[[fruits.varieties]] # nested array of tables
|
||||||
|
name = "red delicious"`
|
||||||
|
|
||||||
|
var emptyArrayTableThenTableExpected = `fruits:
|
||||||
|
- varieties:
|
||||||
|
- name: red delicious
|
||||||
|
animals: {}
|
||||||
|
`
|
||||||
|
|
||||||
var sampleArrayTable = `
|
var sampleArrayTable = `
|
||||||
[owner.contact]
|
[owner.contact]
|
||||||
name = "Tom Preston-Werner"
|
name = "Tom Preston-Werner"
|
||||||
@ -249,6 +307,40 @@ var tomlScenarios = []formatScenario{
|
|||||||
expected: sampleArrayTableExpected,
|
expected: sampleArrayTableExpected,
|
||||||
scenarioType: "decode",
|
scenarioType: "decode",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
description: "Parse: Array of Array Table",
|
||||||
|
input: doubleArrayTable,
|
||||||
|
expected: doubleArrayTableExpected,
|
||||||
|
scenarioType: "decode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Parse: Array of Array Table; nothing above",
|
||||||
|
input: doubleArrayTableNothingAbove,
|
||||||
|
expected: doubleArrayTableNothingAboveExpected,
|
||||||
|
scenarioType: "decode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Parse: Array of Array Table; empty above",
|
||||||
|
input: doubleArrayTableEmptyAbove,
|
||||||
|
expected: doubleArrayTableEmptyAboveExpected,
|
||||||
|
scenarioType: "decode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Parse: Array of Array Table; multiple entries",
|
||||||
|
input: doubleArrayTableMultipleEntries,
|
||||||
|
expected: doubleArrayTableMultipleEntriesExpected,
|
||||||
|
scenarioType: "decode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
skipDoc: true,
|
||||||
|
description: "Parse: Array of Array Table; then table; then array table",
|
||||||
|
input: emptyArrayTableThenTable,
|
||||||
|
expected: emptyArrayTableThenTableExpected,
|
||||||
|
scenarioType: "decode",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
description: "Parse: Empty Table",
|
description: "Parse: Empty Table",
|
||||||
input: emptyTable,
|
input: emptyTable,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user