mirror of
https://github.com/mikefarah/yq.git
synced 2026-07-07 14:25:38 +00:00
Support negative parent indices
This commit is contained in:
parent
66ec487792
commit
64516c639a
@ -79,6 +79,46 @@ will output
|
|||||||
c: cat
|
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
|
## N-th parent
|
||||||
You can optionally supply the number of levels to go up for the parent, the default being 1.
|
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) {
|
func extractNumberParameter(value string) (int, error) {
|
||||||
parameterParser := regexp.MustCompile(`.*\(([0-9]+)\)`)
|
parameterParser := regexp.MustCompile(`.*\((-?[0-9]+)\)`)
|
||||||
matches := parameterParser.FindStringSubmatch(value)
|
matches := parameterParser.FindStringSubmatch(value)
|
||||||
var indent, errParsingInt = parseInt(matches[1])
|
var indent, errParsingInt = parseInt(matches[1])
|
||||||
if errParsingInt != nil {
|
if errParsingInt != nil {
|
||||||
|
|||||||
@ -57,7 +57,7 @@ var participleYqRules = []*participleYqRule{
|
|||||||
simpleOp("sort_?keys", sortKeysOpType),
|
simpleOp("sort_?keys", sortKeysOpType),
|
||||||
|
|
||||||
{"ArrayToMap", "array_?to_?map", expressionOpToken(`(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i)`), 0},
|
{"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},
|
{"YamlEncodeWithIndent", `to_?yaml\([0-9]+\)`, encodeParseIndent(YamlFormat), 0},
|
||||||
{"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLFormat), 0},
|
{"XMLEncodeWithIndent", `to_?xml\([0-9]+\)`, encodeParseIndent(XMLFormat), 0},
|
||||||
{"JSONEncodeWithIndent", `to_?json\([0-9]+\)`, encodeParseIndent(JSONFormat), 0},
|
{"JSONEncodeWithIndent", `to_?json\([0-9]+\)`, encodeParseIndent(JSONFormat), 0},
|
||||||
@ -132,7 +132,7 @@ var participleYqRules = []*participleYqRule{
|
|||||||
simpleOp("split", splitStringOpType),
|
simpleOp("split", splitStringOpType),
|
||||||
|
|
||||||
simpleOp("parents", getParentsOpType),
|
simpleOp("parents", getParentsOpType),
|
||||||
{"ParentWithLevel", `parent\([0-9]+\)`, parentWithLevel(), 0},
|
{"ParentWithLevel", `parent\(-?[0-9]+\)`, parentWithLevel(), 0},
|
||||||
{"ParentWithDefaultLevel", `parent`, parentWithDefaultLevel(), 0},
|
{"ParentWithDefaultLevel", `parent`, parentWithDefaultLevel(), 0},
|
||||||
|
|
||||||
simpleOp("keys", keysOpType),
|
simpleOp("keys", keysOpType),
|
||||||
|
|||||||
@ -35,9 +35,28 @@ func getParentOperator(_ *dataTreeNavigator, context Context, expressionNode *Ex
|
|||||||
|
|
||||||
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
for el := context.MatchingNodes.Front(); el != nil; el = el.Next() {
|
||||||
candidate := el.Value.(*CandidateNode)
|
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
|
currentLevel := 0
|
||||||
for currentLevel < prefs.Level && candidate != nil {
|
for currentLevel < levelsToGoUp && candidate != nil {
|
||||||
log.Debugf("currentLevel: %v, desired: %v", currentLevel, prefs.Level)
|
log.Debugf("currentLevel: %v, desired: %v", currentLevel, levelsToGoUp)
|
||||||
log.Debugf("candidate: %v", NodeToString(candidate))
|
log.Debugf("candidate: %v", NodeToString(candidate))
|
||||||
candidate = candidate.Parent
|
candidate = candidate.Parent
|
||||||
currentLevel++
|
currentLevel++
|
||||||
|
|||||||
@ -38,6 +38,49 @@ var parentOperatorScenarios = []expressionScenario{
|
|||||||
"D0, P[], (!!seq)::- {c: cat}\n- {b: {c: cat}}\n- {a: {b: {c: cat}}}\n",
|
"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",
|
description: "N-th parent",
|
||||||
subdescription: "You can optionally supply the number of levels to go up for the parent, the default being 1.",
|
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