mirror of
https://github.com/mikefarah/yq.git
synced 2026-07-04 11:25:37 +00:00
Support negative parent indices
This commit is contained in:
parent
ea40e14fb1
commit
c6ecad1546
@ -79,6 +79,46 @@ will output
|
||||
c: cat
|
||||
```
|
||||
|
||||
## Get the top (root) parent
|
||||
Use negative numbers to get the top parents
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a.b.c | parent(-1)' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
|
||||
## Root
|
||||
Alias for parent(-1), returns the top level parent. This is usually the document node.
|
||||
|
||||
Given a sample.yml file of:
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
then
|
||||
```bash
|
||||
yq '.a.b.c | root' sample.yml
|
||||
```
|
||||
will output
|
||||
```yaml
|
||||
a:
|
||||
b:
|
||||
c: cat
|
||||
```
|
||||
|
||||
## N-th parent
|
||||
You can optionally supply the number of levels to go up for the parent, the default being 1.
|
||||
|
||||
|
||||
@ -61,7 +61,7 @@ func unwrap(value string) string {
|
||||
}
|
||||
|
||||
func extractNumberParameter(value string) (int, error) {
|
||||
parameterParser := regexp.MustCompile(`.*\(([0-9]+)\)`)
|
||||
parameterParser := regexp.MustCompile(`.*\((-?[0-9]+)\)`)
|
||||
matches := parameterParser.FindStringSubmatch(value)
|
||||
var indent, errParsingInt = parseInt(matches[1])
|
||||
if errParsingInt != nil {
|
||||
|
||||
@ -57,7 +57,7 @@ var participleYqRules = []*participleYqRule{
|
||||
simpleOp("sort_?keys", sortKeysOpType),
|
||||
|
||||
{"ArrayToMap", "array_?to_?map", expressionOpToken(`(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)`), 0},
|
||||
|
||||
{"Root", "root", expressionOpToken(`parent(-1)`), 0},
|
||||
{"YamlEncodeWithIndent", `to_?yaml\([0-9]+\)`, encodeParseIndent(YamlFormat), 0},
|
||||
{"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLFormat), 0},
|
||||
{"JSONEncodeWithIndent", `to_?json\([0-9]+\)`, encodeParseIndent(JSONFormat), 0},
|
||||
@ -132,7 +132,7 @@ var participleYqRules = []*participleYqRule{
|
||||
simpleOp("split", splitStringOpType),
|
||||
|
||||
simpleOp("parents", getParentsOpType),
|
||||
{"ParentWithLevel", `parent\([0-9]+\)`, parentWithLevel(), 0},
|
||||
{"ParentWithLevel", `parent\(-?[0-9]+\)`, parentWithLevel(), 0},
|
||||
{"ParentWithDefaultLevel", `parent`, parentWithDefaultLevel(), 0},
|
||||
|
||||
simpleOp("keys", keysOpType),
|
||||
|
||||
@ -35,9 +35,28 @@ func getParentOperator(_ *dataTreeNavigator, context Context, expressionNode *Ex
|
||||
|
||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||
candidate := el.Value.(*CandidateNode)
|
||||
|
||||
// Handle negative levels: count total parents first
|
||||
levelsToGoUp := prefs.Level
|
||||
if prefs.Level < 0 {
|
||||
// Count all parents
|
||||
totalParents := 0
|
||||
temp := candidate.Parent
|
||||
for temp != nil {
|
||||
totalParents++
|
||||
temp = temp.Parent
|
||||
}
|
||||
// Convert negative index to positive
|
||||
// -1 means last parent (root), -2 means second to last, etc.
|
||||
levelsToGoUp = totalParents + prefs.Level + 1
|
||||
if levelsToGoUp < 0 {
|
||||
levelsToGoUp = 0
|
||||
}
|
||||
}
|
||||
|
||||
currentLevel := 0
|
||||
for currentLevel < prefs.Level && candidate != nil {
|
||||
log.Debugf("currentLevel: %v, desired: %v", currentLevel, prefs.Level)
|
||||
for currentLevel < levelsToGoUp && candidate != nil {
|
||||
log.Debugf("currentLevel: %v, desired: %v", currentLevel, levelsToGoUp)
|
||||
log.Debugf("candidate: %v", NodeToString(candidate))
|
||||
candidate = candidate.Parent
|
||||
currentLevel++
|
||||
|
||||
@ -38,6 +38,49 @@ var parentOperatorScenarios = []expressionScenario{
|
||||
"D0, P[], (!!seq)::- {c: cat}\n- {b: {c: cat}}\n- {a: {b: {c: cat}}}\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Get the top (root) parent",
|
||||
subdescription: "Use negative numbers to get the top parents",
|
||||
document: "a:\n b:\n c: cat\n",
|
||||
expression: `.a.b.c | parent(-1)`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::a:\n b:\n c: cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Root",
|
||||
subdescription: "Alias for parent(-1), returns the top level parent. This is usually the document node.",
|
||||
document: "a:\n b:\n c: cat\n",
|
||||
expression: `.a.b.c | root`,
|
||||
expected: []string{
|
||||
"D0, P[], (!!map)::a:\n b:\n c: cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "N-th negative",
|
||||
skipDoc: true,
|
||||
document: "a:\n b:\n c: cat\n",
|
||||
expression: `.a.b.c | parent(-2)`,
|
||||
expected: []string{
|
||||
"D0, P[a], (!!map)::b:\n c: cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "large negative",
|
||||
skipDoc: true,
|
||||
document: "a:\n b:\n c: cat\n",
|
||||
expression: `.a.b.c | parent(-10)`,
|
||||
expected: []string{
|
||||
"D0, P[a b c], (!!str)::cat\n",
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "large positive",
|
||||
skipDoc: true,
|
||||
document: "a:\n b:\n c: cat\n",
|
||||
expression: `.a.b.c | parent(10)`,
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
description: "N-th parent",
|
||||
subdescription: "You can optionally supply the number of levels to go up for the parent, the default being 1.",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user