// 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/computed" ) type ProcessUnknown func(current Change) computed.Diff type ProcessUnknownWithBefore func(current Change, before Change) computed.Diff func (change Change) IsUnknown() bool { if unknown, ok := change.Unknown.(bool); ok { return unknown } return false } // CheckForUnknown is a helper function that handles all common functionality // for processing an unknown value. // // It returns the computed unknown diff and true if this value was unknown and // needs to be rendered as such, otherwise it returns the second return value as // false and the first return value should be discarded. // // The actual processing of unknown values happens in the ProcessUnknown and // ProcessUnknownWithBefore functions. If a value is unknown and is being // created, the ProcessUnknown function is called and the caller should decide // how to create the unknown value. If a value is being updated the // ProcessUnknownWithBefore function is called and the function provides the // before value as if it is being deleted for the caller to handle. Note that // values being deleted will never be marked as unknown so this case isn't // handled. // // The childUnknown argument is meant to allow callers with extra information // about the type being processed to provide a list of known children that might // not be present in the before or after values. These values will be propagated // as the unknown values in the before value should it be needed. func (change Change) CheckForUnknown(childUnknown interface{}, process ProcessUnknown, processBefore ProcessUnknownWithBefore) (computed.Diff, bool) { unknown := change.IsUnknown() if !unknown { return computed.Diff{}, false } // No matter what we do here, we want to treat the after value as explicit. // This is because it is going to be null in the value, and we don't want // the functions in this package to assume this means it has been deleted. change.AfterExplicit = true if change.Before == nil { return process(change), true } // If we get here, then we have a before value. We're going to model a // delete operation and our renderer later can render the overall change // accurately. before := change.AsDelete() // We also let our callers override the unknown values in any before, this // is the renderers can display them as being computed instead of deleted. before.Unknown = childUnknown return processBefore(change, before), true }