func (c *Config) ResolveAbsProviderAddr(addr addrs.ProviderConfig, inModule addrs.Module) addrs.AbsProviderConfig {
	switch addr := addr.(type) {
	case addrs.AbsProviderConfig:
		return addr
	case addrs.LocalProviderConfig:
		mc := c.Descendent(inModule)
		if mc == nil {
			panic(fmt.Sprintf("ResolveAbsProviderAddr with non-existent module %s", inModule.String()))
		}
		var provider addrs.Provider
		if providerReq, exists := c.Module.ProviderRequirements.RequiredProviders[addr.LocalName]; exists {
			provider = providerReq.Type
		} else {
			provider = addrs.ImpliedProviderForUnqualifiedType(addr.LocalName)
		}
		return addrs.AbsProviderConfig{
			Module:   inModule,
			Provider: provider,
			Alias:    addr.Alias,
		}
	default:
		panic(fmt.Sprintf("cannot ResolveAbsProviderAddr(%v, ...)", addr))
	}
}
ResolveAbsProviderAddr returns the AbsProviderConfig represented by the given
ProviderConfig address, which must not be nil or this method will panic.

If the given address is already an AbsProviderConfig then this method returns
it verbatim, and will always succeed. If it's a LocalProviderConfig then
it will consult the local-to-FQN mapping table for the given module
to find the absolute address corresponding to the given local one.

The module address to resolve local addresses in must be given in the second
argument, and must refer to a module that exists under the receiver or
else this method will panic.
package configs
import (
	"fmt"
	"sort"
	"github.com/camptocamp/terraboard/internal/terraform/addrs"
	"github.com/camptocamp/terraboard/internal/terraform/getproviders"
	version "github.com/hashicorp/go-version"
	"github.com/hashicorp/hcl/v2"
)
type Config struct {
	Root *Config
	Parent *Config
	Path addrs.Module
	Children map[string]*Config
	Module *Module
	CallRange hcl.Range
	SourceAddr string
	SourceAddrRange hcl.Range
	Version *version.Version
}
type ModuleRequirements struct {
	Name         string
	SourceAddr   string
	SourceDir    string
	Requirements getproviders.Requirements
	Children     map[string]*ModuleRequirements
}
func NewEmptyConfig() *Config {
	ret := &Config{}
	ret.Root = ret
	ret.Children = make(map[string]*Config)
	ret.Module = &Module{}
	return ret
}
func (c *Config) Depth() int {
	ret := 0
	this := c
	for this.Parent != nil {
		ret++
		this = this.Parent
	}
	return ret
}
func (c *Config) DeepEach(cb func(c *Config)) {
	cb(c)
	names := make([]string, 0, len(c.Children))
	for name := range c.Children {
		names = append(names, name)
	}
	for _, name := range names {
		c.Children[name].DeepEach(cb)
	}
}
func (c *Config) AllModules() []*Config {
	var ret []*Config
	c.DeepEach(func(c *Config) {
		ret = append(ret, c)
	})
	return ret
}
func (c *Config) Descendent(path addrs.Module) *Config {
	current := c
	for _, name := range path {
		current = current.Children[name]
		if current == nil {
			return nil
		}
	}
	return current
}
func (c *Config) DescendentForInstance(path addrs.ModuleInstance) *Config {
	current := c
	for _, step := range path {
		current = current.Children[step.Name]
		if current == nil {
			return nil
		}
	}
	return current
}
func (c *Config) ProviderRequirements() (getproviders.Requirements, hcl.Diagnostics) {
	reqs := make(getproviders.Requirements)
	diags := c.addProviderRequirements(reqs, true)
	return reqs, diags
}
func (c *Config) ProviderRequirementsShallow() (getproviders.Requirements, hcl.Diagnostics) {
	reqs := make(getproviders.Requirements)
	diags := c.addProviderRequirements(reqs, false)
	return reqs, diags
}
func (c *Config) ProviderRequirementsByModule() (*ModuleRequirements, hcl.Diagnostics) {
	reqs := make(getproviders.Requirements)
	diags := c.addProviderRequirements(reqs, false)
	children := make(map[string]*ModuleRequirements)
	for name, child := range c.Children {
		childReqs, childDiags := child.ProviderRequirementsByModule()
		childReqs.Name = name
		children[name] = childReqs
		diags = append(diags, childDiags...)
	}
	ret := &ModuleRequirements{
		SourceAddr:   c.SourceAddr,
		SourceDir:    c.Module.SourceDir,
		Requirements: reqs,
		Children:     children,
	}
	return ret, diags
}
func (c *Config) addProviderRequirements(reqs getproviders.Requirements, recurse bool) hcl.Diagnostics {
	var diags hcl.Diagnostics
	if c.Module.ProviderRequirements != nil {
		for _, providerReqs := range c.Module.ProviderRequirements.RequiredProviders {
			fqn := providerReqs.Type
			if _, ok := reqs[fqn]; !ok {
				reqs[fqn] = nil
			}
			constraints, err := getproviders.ParseVersionConstraints(providerReqs.Requirement.Required.String())
			if err != nil {
				diags = diags.Append(&hcl.Diagnostic{
					Severity: hcl.DiagError,
					Summary:  "Invalid version constraint",
					Detail:  fmt.Sprintf("Incorrect version constraint syntax: %s.", err.Error()),
					Subject: providerReqs.Requirement.DeclRange.Ptr(),
				})
			}
			reqs[fqn] = append(reqs[fqn], constraints...)
		}
	}
	for _, rc := range c.Module.ManagedResources {
		fqn := rc.Provider
		if _, exists := reqs[fqn]; exists {
			continue
		}
		reqs[fqn] = nil
	}
	for _, rc := range c.Module.DataResources {
		fqn := rc.Provider
		if _, exists := reqs[fqn]; exists {
			continue
		}
		reqs[fqn] = nil
	}
	for _, provider := range c.Module.ProviderConfigs {
		fqn := c.Module.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: provider.Name})
		if _, ok := reqs[fqn]; !ok {
			reqs[fqn] = nil
		}
		if provider.Version.Required != nil {
			constraints, err := getproviders.ParseVersionConstraints(provider.Version.Required.String())
			if err != nil {
				diags = diags.Append(&hcl.Diagnostic{
					Severity: hcl.DiagError,
					Summary:  "Invalid version constraint",
					Detail:  fmt.Sprintf("Incorrect version constraint syntax: %s.", err.Error()),
					Subject: provider.Version.DeclRange.Ptr(),
				})
			}
			reqs[fqn] = append(reqs[fqn], constraints...)
		}
	}
	if recurse {
		for _, childConfig := range c.Children {
			moreDiags := childConfig.addProviderRequirements(reqs, true)
			diags = append(diags, moreDiags...)
		}
	}
	return diags
}
func (c *Config) resolveProviderTypes() {
	for _, child := range c.Children {
		child.resolveProviderTypes()
	}
	providers := map[string]addrs.Provider{}
	for name, p := range c.Module.ProviderRequirements.RequiredProviders {
		providers[name] = p.Type
	}
	for _, p := range c.Module.ProviderConfigs {
		addr, required := providers[p.Name]
		if required {
			p.providerType = addr
		} else {
			addr := addrs.NewDefaultProvider(p.Name)
			p.providerType = addr
			providers[p.Name] = addr
		}
	}
	for _, mod := range c.Module.ModuleCalls {
		for _, p := range mod.Providers {
			if addr, known := providers[p.InParent.Name]; known {
				p.InParent.providerType = addr
			}
		}
	}
	if c.Parent != nil {
		for _, mod := range c.Parent.Module.ModuleCalls {
			for _, p := range mod.Providers {
				if addr, known := providers[p.InChild.Name]; known {
					p.InChild.providerType = addr
				}
			}
		}
	}
}
func (c *Config) ProviderTypes() []addrs.Provider {
	reqs, _ := c.ProviderRequirements()
	ret := make([]addrs.Provider, 0, len(reqs))
	for k := range reqs {
		ret = append(ret, k)
	}
	sort.Slice(ret, func(i, j int) bool {
		return ret[i].String() < ret[j].String()
	})
	return ret
}