Repository: opentofu/opentofu
File: internal/command/jsonplan/values.go (Go)

Code before:
	resources, err := marshalPlanResources(changeMap, moduleResourceMap[""], schemas)
	if err != nil {
		return ret, err
	}
	ret.Resources = resources

	childModules, err := marshalPlanModules(changeMap, schemas, moduleMap[""], moduleMap, moduleResourceMap)
	if err != nil {
		return ret, err
	}
	sort.Slice(childModules, func(i, j int) bool {
		return childModules[i].Address < childModules[j].Address
	})

	ret.ChildModules = childModules

	return ret, nil
}

// marshalPlanResources
func marshalPlanResources(changeMap map[string]*plans.ResourceInstanceChangeSrc, ris []addrs.AbsResourceInstance, schemas *tofu.Schemas) ([]Resource, error) {
	var ret []Resource

	for _, ri := range ris {
		r, ok := changeMap[ri.String()]
		if !ok || r.Action == plans.Delete {
			continue
		}

		resource := Resource{
			Address:      r.Addr.String(),
			Type:         r.Addr.Resource.Resource.Type,
			Name:         r.Addr.Resource.Resource.Name,
			ProviderName: r.ProviderAddr.Provider.String(),
			Index:        r.Addr.Resource.Key,
		}

		switch r.Addr.Resource.Resource.Mode {
		case addrs.ManagedResourceMode:
			resource.Mode = "managed"
		case addrs.DataResourceMode:
			resource.Mode = "data"
		default:
			return nil, fmt.Errorf("resource %s has an unsupported mode %s",
				r.Addr.String(),
				r.Addr.Resource.Resource.Mode.String(),
			)
		}

		schema, schemaVer := schemas.ResourceTypeConfig(
			r.ProviderAddr.Provider,

Review comment (suggestion):
nit: `changes.ResourceInstance` returns nil if there is nothing found. Then, it would panic on `r.Action == plans.Delete` check. In the current implementation, we would skip the resource if it is not found, assuming this is a `plans.Delete` action. However, it might silence some critical dev error (because panic is hidden). I would prefer to keep the original behavior here.

Code after:
			// only need to report the "parent" module for each child module
			// once.
			if !seenModules[childStr] {
				moduleMap[aStr] = append(moduleMap[aStr], ancestors[i+1])
				seenModules[childStr] = true
			}
		}
	}

	// start with the root module
	resources, err := marshalPlanResources(changeMap, moduleResourceMap[""], schemas)
	if err != nil {
		return ret, err
	}
	ret.Resources = resources

	childModules, err := marshalPlanModules(changeMap, schemas, moduleMap[""], moduleMap, moduleResourceMap)
	if err != nil {
		return ret, err
	}
	sort.Slice(childModules, func(i, j int) bool {
		return childModules[i].Address < childModules[j].Address
	})

	ret.ChildModules = childModules

	return ret, nil
}

// marshalPlanResources
func marshalPlanResources(changeMap map[string]*plans.ResourceInstanceChangeSrc, ris []addrs.AbsResourceInstance, schemas *tofu.Schemas) ([]Resource, error) {
	var ret []Resource

	for _, ri := range ris {
		// This is equivalent to calling plans.Changes.ResourceInstance(ri),
		// but uses the precomputed changeMap to avoid quadratic complexity.
		r := changeMap[ri.String()]
		if r.Action == plans.Delete {
			continue
		}

		resource := Resource{
			Address:      r.Addr.String(),
			Type:         r.Addr.Resource.Resource.Type,
			Name:         r.Addr.Resource.Resource.Name,
			ProviderName: r.ProviderAddr.Provider.String(),
			Index:        r.Addr.Resource.Key,
		}

		switch r.Addr.Resource.Resource.Mode {
		case addrs.ManagedResourceMode: