Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

78 cannot replace variables with values of type map from another class sometimes #79

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion data.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,16 @@ func (d Data) GetPath(path ...interface{}) (tree interface{}, err error) {
return nil, fmt.Errorf("key not found: %v", el)
}

case map[string]interface{}:
key, ok := el.(string)
if !ok {
return nil, fmt.Errorf("unexpected string key in map[string]interface '%T' at index %d", el, i)
}
tree, ok = node[key]
if !ok {
return nil, fmt.Errorf("key not found: %v", el)
}

case map[interface{}]interface{}:
var ok bool
tree, ok = node[el]
Expand Down Expand Up @@ -154,6 +164,13 @@ func (d *Data) SetPath(value interface{}, path ...interface{}) (err error) {
}
node[key] = value

case map[string]interface{}:
key, ok := element.(string)
if !ok {
return fmt.Errorf("unexpected string key in map[string]interface '%T' at index %d", element, i)
}
node[key] = value

case []interface{}:
index, ok := element.(int)
if !ok {
Expand Down Expand Up @@ -228,7 +245,6 @@ func (d Data) FindValues(valueFunc FindValueFunc, target *[]interface{}) (err er

var walk func(reflect.Value, []interface{}) error
walk = func(v reflect.Value, path []interface{}) error {

// fix indirects through pointers and interfaces
for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
v = v.Elem()
Expand Down
82 changes: 1 addition & 81 deletions variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,7 @@ func ReplaceVariables(data Data, classFiles []*Class, predefinedVariables map[st
}

// replace variable in Data
data.SetPath(sourceValue, variable.Identifier...)

return nil
return data.SetPath(sourceValue, variable.Identifier...)
}

// Replace variables in an undefined amount of iterations.
Expand Down Expand Up @@ -226,84 +224,6 @@ func ReplaceVariables(data Data, classFiles []*Class, predefinedVariables map[st
return nil
}

func replaceVariable(data Data, variable Variable, classFiles []*Class, predefinedVariables map[string]interface{}) (err error) {
isPredefinedVariable := func(variable Variable) bool {
for name := range predefinedVariables {
if strings.EqualFold(variable.Name, name) {
return true
}
}
return false
}

var targetValue interface{}
if isPredefinedVariable(variable) {
targetValue = predefinedVariables[variable.Name]
return nil
} else {
// targetValue is the value on which the variable points to.
// This is the value we need to replace the variable with
targetValue, err = data.GetPath(variable.NameAsIdentifier()...)
if err != nil {

// for any other error than a 'key not found' there is nothing we can do
if !strings.Contains(err.Error(), "key not found") {
return fmt.Errorf("reference to invalid variable '%s': %w", variable.FullName(), err)
}

// Local variable handling
//
// at this point we have failed to resolve the variable using 'absolute' paths
// but the variable may be only locally defined which means we need to change the lookup path.
// We iterate over all classes and attempt to resolve the variable within that limited scope.
for i, class := range classFiles {

// if the value to which the variable points is valid inside the class scope, we just need to add the class identifier
// if the combination works this means we have found ourselves a local variable and we can set the targetValue
fullPath := []interface{}{}
fullPath = append(fullPath, class.NameAsIdentifier()...)

// edge case: the class root key is 'foo', and the variable used references it like ${foo:bar:baz}
// this would result in the full path being 'foo foo bar baz', hence we need to strip the class name from the variable reference.
if strings.EqualFold(class.RootKey(), variable.NameAsIdentifier()[0].(string)) {
fullPath = append(fullPath, variable.NameAsIdentifier()[1:]...)
} else {
// default case: the class root key is not used in the variable, we can add the full variable identifier
fullPath = append(fullPath, variable.NameAsIdentifier()...)
}

targetValue, err = data.GetPath(fullPath...)

// as long as not all classes have been checked, we cannot be sure that the variable is undefined (aka. key not found error)
if targetValue == nil &&
i < len(classFiles) &&
strings.Contains(err.Error(), "key not found") {
continue
}

// the local variable is really not defined at this point
if err != nil {
return fmt.Errorf("reference to invalid variable '%s': %w", variable.FullName(), err)
}

break
}
}
}

// sourceValue is the value where the variable is located. It needs to be replaced with the 'targetValue'
sourceValue, err := data.GetPath(variable.Identifier...)
if err != nil {
return err
}

// Replace the full variable name (${variable}) with the targetValue
sourceValue = strings.ReplaceAll(fmt.Sprint(sourceValue), variable.FullName(), fmt.Sprint(targetValue))
data.SetPath(sourceValue, variable.Identifier...)

return nil
}

// variableFindValueFunc implements the [FindValueFunc] and searches for variables inside [Data].
// Variables are extracted by matching the values to the [variableRegex].
// All found variables are initialized and added to the output.
Expand Down
Loading