blob: 9284f89f44dcaa6fd4ebe558a82ea70f669f782b [file] [edit]
// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package jsonconfig
import (
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/configs/configschema"
"github.com/opentofu/opentofu/internal/tofu"
)
// MarshalSingleModule is a variant of [Marshal] that describes only a single
// module, without any references to its child modules or associated provider
// schemas.
//
// This uses only a subset of the typical configuration representation, due to
// schema and child module information being unavailable:
// - Module calls omit the "module" property that would normally describe the
// content of the child module.
// - Resource descriptions omit the "schema_version" property because no
// schema-based information is included.
// - Expression-related properties are omitted in all cases. Technically only
// expressions passed to providers _need_ to be omitted, but for now we
// just consistently omit all of them because that's an easier rule to
// explain and avoids exposing what is and is not provider-based so that
// we could potentially change those details in future.
func MarshalSingleModule(m *configs.Module) ([]byte, error) {
// Our shared codepaths are built to work with a full config tree rather
// than a single module, so we'll construct a synthetic [configs.Config]
// that only has a root module and then downstream shared functions will
// use the nil-ness of the schemas argument to handle the special
// treatments required in single-module mode.
cfg := &configs.Config{
Module: m,
// Everything else intentionally not populated because single module
// mode should not attempt to access anything else.
}
return marshal(cfg, nil)
}
// inSingleModuleMode returns true if the given schema value indicates that
// we should be rendering in "single module" mode, meaning that we're producing
// a result for [MarshalSingleModule] rather than [Marshal].
//
// Currently the rule is only that a nil schemas represents single-module mode;
// this simple rule is factored out into this helper function only so we can
// centralize it underneath this doc comment explaining the special convention.
//
// (This rather odd design is a consequence of how this code evolved; we
// retrofitted the single-module mode later while using this strange treatment
// to minimize the risk to the existing working codepaths. Maybe we'll change
// the appoach to this in future; this is only an implementation detail
// within this package so we'll be able to those changes without affecting
// callers.)
func inSingleModuleMode[S schemaObject](schema S) bool {
return schema == nil
}
// mapSchema is a helper that uses the given function to transform the given
// schema object only if it isn't nil, or immediately returns nil otherwise.
//
// This is part of our strategy to retrofit the single-module mode without
// a risky refactor of the already-working code, intended to be used in
// conjunction with [inSingleModuleMode] to smuggle the flag for whether we're
// in that mode through the nil-ness of the schema objects.
func mapSchema[In, Out schemaObject](schema In, f func(In) Out) Out {
if schema == nil {
return nil
}
return f(schema)
}
// schemaObject is a helper interface to allow [inSingleModuleMode] to be
// generic over the different nilable schema types used by different parts
// of the implementation in this package.
type schemaObject interface {
*tofu.Schemas | *configschema.Block
}