package yqlib import ( "container/list" "fmt" ) func deleteChildOperator(d *dataTreeNavigator, context Context, expressionNode *ExpressionNode) (Context, error) { nodesToDelete, err := d.GetMatchingNodes(context.ReadOnlyClone(), expressionNode.RHS) if err != nil { return Context{}, err } //need to iterate backwards to ensure correct indices when deleting multiple for el := nodesToDelete.MatchingNodes.Back(); el != nil; el = el.Prev() { candidate := el.Value.(*CandidateNode) if candidate.Parent == nil { // must be a top level thing, delete it return removeFromContext(context, candidate) } log.Debugf("processing deletion of candidate %v", NodeToString(candidate)) parentNode := candidate.Parent candidatePath := candidate.GetPath() childPath := candidatePath[len(candidatePath)-1] switch parentNode.Kind { case MappingNode: deleteFromMap(candidate.Parent, childPath) case SequenceNode: deleteFromArray(candidate.Parent, childPath) default: return Context{}, fmt.Errorf("cannot delete nodes from parent of tag %v", parentNode.Tag) } } return context, nil } func removeFromContext(context Context, candidate *CandidateNode) (Context, error) { newResults := list.New() for item := context.MatchingNodes.Front(); item != nil; item = item.Next() { nodeInContext := item.Value.(*CandidateNode) if nodeInContext != candidate { newResults.PushBack(nodeInContext) } else { log.Infof("Need to delete this %v", NodeToString(nodeInContext)) } } return context.ChildContext(newResults), nil } func deleteFromMap(node *CandidateNode, childPath interface{}) { log.Debug("deleteFromMap") contents := node.Content newContents := make([]*CandidateNode, 0) for index := 0; index < len(contents); index = index + 2 { key := contents[index] value := contents[index+1] shouldDelete := key.Value == childPath log.Debugf("shouldDelete %v? %v == %v = %v", NodeToString(value), key.Value, childPath, shouldDelete) if !shouldDelete { newContents = append(newContents, key, value) } } node.Content = newContents } func normaliseEmptySequenceMapKeyComment(node *CandidateNode) { if node.Kind != SequenceNode || len(node.Content) != 0 || node.LineComment != "" { return } key := node.Key if node.Parent != nil && node.Parent.Kind == MappingNode { for index := 0; index < len(node.Parent.Content)-1; index += 2 { if node.Parent.Content[index+1] == node { key = node.Parent.Content[index] break } } } if key == nil || key.LineComment == "" { return } node.LineComment = key.LineComment key.LineComment = "" node.Style = FlowStyle } func deleteFromArray(node *CandidateNode, childPath interface{}) { log.Debug("deleteFromArray") contents := node.Content newContents := make([]*CandidateNode, 0) for index := 0; index < len(contents); index = index + 1 { value := contents[index] shouldDelete := fmt.Sprintf("%v", index) == fmt.Sprintf("%v", childPath) if !shouldDelete { value.Key.Value = fmt.Sprintf("%v", len(newContents)) newContents = append(newContents, value) } } node.Content = newContents normaliseEmptySequenceMapKeyComment(node) }