// Copyright (c) The OpenTofu Authors // SPDX-License-Identifier: MPL-2.0 // Copyright (c) 2023 HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package structured import ( "github.com/opentofu/opentofu/internal/command/jsonformat/structured/attribute_path" ) // ChangeSlice is a Change that represents a Tuple, Set, or List type, and has // converted the relevant interfaces into slices for easier access. type ChangeSlice struct { // Before contains the value before the proposed change. Before []interface{} // After contains the value after the proposed change. After []interface{} // Unknown contains the unknown status of any elements of this list/set. Unknown []interface{} // BeforeSensitive contains the before sensitive status of any elements of //this list/set. BeforeSensitive []interface{} // AfterSensitive contains the after sensitive status of any elements of //this list/set. AfterSensitive []interface{} // ReplacePaths matches the same attributes in Change exactly. ReplacePaths attribute_path.Matcher // RelevantAttributes matches the same attributes in Change exactly. RelevantAttributes attribute_path.Matcher } // AsSlice converts the Change into a slice representation by converting the // internal Before, After, Unknown, BeforeSensitive, and AfterSensitive data // structures into generic slices. func (change Change) AsSlice() ChangeSlice { return ChangeSlice{ Before: genericToSlice(change.Before), After: genericToSlice(change.After), Unknown: genericToSlice(change.Unknown), BeforeSensitive: genericToSlice(change.BeforeSensitive), AfterSensitive: genericToSlice(change.AfterSensitive), ReplacePaths: change.ReplacePaths, RelevantAttributes: change.RelevantAttributes, } } // GetChild safely packages up a Change object for the given child, handling // all the cases where the data might be null or a static boolean. func (s ChangeSlice) GetChild(beforeIx, afterIx int) Change { before, beforeExplicit := getFromGenericSlice(s.Before, beforeIx) after, afterExplicit := getFromGenericSlice(s.After, afterIx) unknown, _ := getFromGenericSlice(s.Unknown, afterIx) beforeSensitive, _ := getFromGenericSlice(s.BeforeSensitive, beforeIx) afterSensitive, _ := getFromGenericSlice(s.AfterSensitive, afterIx) mostRelevantIx := beforeIx if beforeIx < 0 || beforeIx >= len(s.Before) { mostRelevantIx = afterIx } return Change{ BeforeExplicit: beforeExplicit, AfterExplicit: afterExplicit, Before: before, After: after, Unknown: unknown, BeforeSensitive: beforeSensitive, AfterSensitive: afterSensitive, ReplacePaths: s.ReplacePaths.GetChildWithIndex(mostRelevantIx), RelevantAttributes: s.RelevantAttributes.GetChildWithIndex(mostRelevantIx), } } func getFromGenericSlice(generic []interface{}, ix int) (interface{}, bool) { if generic == nil { return nil, false } if ix < 0 || ix >= len(generic) { return nil, false } return generic[ix], true } func genericToSlice(generic interface{}) []interface{} { if concrete, ok := generic.([]interface{}); ok { return concrete } return nil }