6 "github.com/hashicorp/hcl2/gohcl"
7 "github.com/hashicorp/hcl2/hcl"
8 "github.com/hashicorp/hcl2/hcl/hclsyntax"
11 // ModuleCall represents a "module" block in a module or file.
12 type ModuleCall struct {
16 SourceAddrRange hcl.Range
21 Version VersionConstraint
24 ForEach hcl.Expression
26 Providers []PassedProviderConfig
28 DependsOn []hcl.Traversal
33 func decodeModuleBlock(block *hcl.Block, override bool) (*ModuleCall, hcl.Diagnostics) {
35 Name: block.Labels[0],
36 DeclRange: block.DefRange,
39 schema := moduleBlockSchema
41 schema = schemaForOverrides(schema)
44 content, remain, diags := block.Body.PartialContent(schema)
47 if !hclsyntax.ValidIdentifier(mc.Name) {
48 diags = append(diags, &hcl.Diagnostic{
49 Severity: hcl.DiagError,
50 Summary: "Invalid module instance name",
51 Detail: badIdentifierDetail,
52 Subject: &block.LabelRanges[0],
56 if attr, exists := content.Attributes["source"]; exists {
57 valDiags := gohcl.DecodeExpression(attr.Expr, nil, &mc.SourceAddr)
58 diags = append(diags, valDiags...)
59 mc.SourceAddrRange = attr.Expr.Range()
63 if attr, exists := content.Attributes["version"]; exists {
64 var versionDiags hcl.Diagnostics
65 mc.Version, versionDiags = decodeVersionConstraint(attr)
66 diags = append(diags, versionDiags...)
69 if attr, exists := content.Attributes["count"]; exists {
72 // We currently parse this, but don't yet do anything with it.
73 diags = append(diags, &hcl.Diagnostic{
74 Severity: hcl.DiagError,
75 Summary: "Reserved argument name in module block",
76 Detail: fmt.Sprintf("The name %q is reserved for use in a future version of Terraform.", attr.Name),
77 Subject: &attr.NameRange,
81 if attr, exists := content.Attributes["for_each"]; exists {
82 mc.ForEach = attr.Expr
84 // We currently parse this, but don't yet do anything with it.
85 diags = append(diags, &hcl.Diagnostic{
86 Severity: hcl.DiagError,
87 Summary: "Reserved argument name in module block",
88 Detail: fmt.Sprintf("The name %q is reserved for use in a future version of Terraform.", attr.Name),
89 Subject: &attr.NameRange,
93 if attr, exists := content.Attributes["depends_on"]; exists {
94 deps, depsDiags := decodeDependsOn(attr)
95 diags = append(diags, depsDiags...)
96 mc.DependsOn = append(mc.DependsOn, deps...)
98 // We currently parse this, but don't yet do anything with it.
99 diags = append(diags, &hcl.Diagnostic{
100 Severity: hcl.DiagError,
101 Summary: "Reserved argument name in module block",
102 Detail: fmt.Sprintf("The name %q is reserved for use in a future version of Terraform.", attr.Name),
103 Subject: &attr.NameRange,
107 if attr, exists := content.Attributes["providers"]; exists {
108 seen := make(map[string]hcl.Range)
109 pairs, pDiags := hcl.ExprMap(attr.Expr)
110 diags = append(diags, pDiags...)
111 for _, pair := range pairs {
112 key, keyDiags := decodeProviderConfigRef(pair.Key, "providers")
113 diags = append(diags, keyDiags...)
114 value, valueDiags := decodeProviderConfigRef(pair.Value, "providers")
115 diags = append(diags, valueDiags...)
116 if keyDiags.HasErrors() || valueDiags.HasErrors() {
120 matchKey := key.String()
121 if prev, exists := seen[matchKey]; exists {
122 diags = append(diags, &hcl.Diagnostic{
123 Severity: hcl.DiagError,
124 Summary: "Duplicate provider address",
125 Detail: fmt.Sprintf("A provider configuration was already passed to %s at %s. Each child provider configuration can be assigned only once.", matchKey, prev),
126 Subject: pair.Value.Range().Ptr(),
131 rng := hcl.RangeBetween(pair.Key.Range(), pair.Value.Range())
133 mc.Providers = append(mc.Providers, PassedProviderConfig{
140 // Reserved block types (all of them)
141 for _, block := range content.Blocks {
142 diags = append(diags, &hcl.Diagnostic{
143 Severity: hcl.DiagError,
144 Summary: "Reserved block type name in module block",
145 Detail: fmt.Sprintf("The block type name %q is reserved for use by Terraform in a future version.", block.Type),
146 Subject: &block.TypeRange,
153 // PassedProviderConfig represents a provider config explicitly passed down to
154 // a child module, possibly giving it a new local address in the process.
155 type PassedProviderConfig struct {
156 InChild *ProviderConfigRef
157 InParent *ProviderConfigRef
160 var moduleBlockSchema = &hcl.BodySchema{
161 Attributes: []hcl.AttributeSchema{
182 Blocks: []hcl.BlockHeaderSchema{
183 // These are all reserved for future use.
186 {Type: "provider", LabelNames: []string{"type"}},