github.com/MontFerret/ferret@v0.18.0/pkg/stdlib/objects/merge_recursive.go (about)

     1  package objects
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/MontFerret/ferret/pkg/runtime/core"
     7  	"github.com/MontFerret/ferret/pkg/runtime/values"
     8  	"github.com/MontFerret/ferret/pkg/runtime/values/types"
     9  )
    10  
    11  // MERGE_RECURSIVE recursively merge the given objects into a single object.
    12  // @param {Objects, repeated} objects - Objects to merge.
    13  // @return {Object} - Object created by merging.
    14  func MergeRecursive(_ context.Context, args ...core.Value) (core.Value, error) {
    15  	err := core.ValidateArgs(args, 1, core.MaxArgs)
    16  	if err != nil {
    17  		return values.None, err
    18  	}
    19  
    20  	for _, arg := range args {
    21  		if err = core.ValidateType(arg, types.Object); err != nil {
    22  			return values.None, err
    23  		}
    24  	}
    25  
    26  	merged := values.NewObject()
    27  
    28  	for _, arg := range args {
    29  		merged = merge(merged, arg).(*values.Object)
    30  	}
    31  
    32  	return merged.Clone(), nil
    33  }
    34  
    35  func merge(src, dst core.Value) core.Value {
    36  	if src.Type() != dst.Type() {
    37  		return dst
    38  	}
    39  
    40  	if src.Type() != types.Object {
    41  		return dst
    42  	}
    43  
    44  	srcObj := src.(*values.Object)
    45  	dstObj := dst.(*values.Object)
    46  
    47  	if dstObj.Length() == 0 {
    48  		return src
    49  	}
    50  
    51  	keyObj := values.NewString("")
    52  	exists := values.NewBoolean(false)
    53  	var srcVal core.Value
    54  
    55  	dstObj.ForEach(func(val core.Value, key string) bool {
    56  		keyObj = values.NewString(key)
    57  
    58  		if srcVal, exists = srcObj.Get(keyObj); exists {
    59  			val = merge(srcVal, val)
    60  		}
    61  
    62  		srcObj.Set(keyObj, val)
    63  		return true
    64  	})
    65  
    66  	return src
    67  }