@@ -8,8 +8,193 @@ import (
8
8
hcl "github.com/hashicorp/hcl/v2"
9
9
"github.com/hashicorp/hcl/v2/hclsyntax"
10
10
"github.com/terraform-linters/tflint-plugin-sdk/terraform"
11
+ "github.com/terraform-linters/tflint-plugin-sdk/terraform/addrs"
12
+ "github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
13
+ "github.com/terraform-linters/tflint-plugin-sdk/terraform/experiments"
11
14
)
12
15
16
+ // Config is an intermediate representation of configs.Config.
17
+ type Config struct {
18
+ Path addrs.Module
19
+ Module * Module
20
+ CallRange hcl.Range
21
+ SourceAddr string
22
+ SourceAddrRange hcl.Range
23
+ Version string
24
+ }
25
+
26
+ func decodeConfig (config * Config ) (* configs.Config , hcl.Diagnostics ) {
27
+ module , diags := decodeModule (config .Module )
28
+ if diags .HasErrors () {
29
+ return nil , diags
30
+ }
31
+
32
+ var ver * version.Version
33
+ var err error
34
+ if config .Version != "" {
35
+ ver , err = version .NewVersion (config .Version )
36
+ if err != nil {
37
+ return nil , hcl.Diagnostics {
38
+ & hcl.Diagnostic {
39
+ Severity : hcl .DiagError ,
40
+ Summary : "Failed to reparse version" ,
41
+ Detail : err .Error (),
42
+ },
43
+ }
44
+ }
45
+ }
46
+
47
+ return & configs.Config {
48
+ Path : config .Path ,
49
+ Module : module ,
50
+ CallRange : config .CallRange ,
51
+ SourceAddr : config .SourceAddr ,
52
+ SourceAddrRange : config .SourceAddrRange ,
53
+ Version : ver ,
54
+ }, nil
55
+ }
56
+
57
+ // Module is an intermediate representation of configs.Module.
58
+ type Module struct {
59
+ SourceDir string
60
+
61
+ CoreVersionConstraints []string
62
+ CoreVersionConstraintRanges []hcl.Range
63
+
64
+ ActiveExperiments experiments.Set
65
+
66
+ Backend * Backend
67
+ ProviderConfigs map [string ]* Provider
68
+ ProviderRequirements * RequiredProviders
69
+ ProviderLocalNames map [terraform.Provider ]string
70
+ ProviderMetas map [terraform.Provider ]* ProviderMeta
71
+
72
+ Variables map [string ]* Variable
73
+ Locals map [string ]* Local
74
+ Outputs map [string ]* Output
75
+
76
+ ModuleCalls map [string ]* ModuleCall
77
+
78
+ ManagedResources map [string ]* Resource
79
+ DataResources map [string ]* Resource
80
+ }
81
+
82
+ func decodeModule (module * Module ) (* configs.Module , hcl.Diagnostics ) {
83
+ versionConstraints := make ([]terraform.VersionConstraint , len (module .CoreVersionConstraints ))
84
+ for i , v := range module .CoreVersionConstraints {
85
+ constraint , diags := parseVersionConstraint (v , module .CoreVersionConstraintRanges [i ])
86
+ if diags .HasErrors () {
87
+ return nil , diags
88
+ }
89
+ versionConstraints [i ] = constraint
90
+ }
91
+
92
+ backend , diags := decodeBackend (module .Backend )
93
+ if diags .HasErrors () {
94
+ return nil , diags
95
+ }
96
+
97
+ providers := map [string ]* configs.Provider {}
98
+ for k , v := range module .ProviderConfigs {
99
+ p , diags := decodeProvider (v )
100
+ if diags .HasErrors () {
101
+ return nil , diags
102
+ }
103
+ providers [k ] = p
104
+ }
105
+
106
+ requirements , diags := decodeRequiredProviders (module .ProviderRequirements )
107
+ if diags .HasErrors () {
108
+ return nil , diags
109
+ }
110
+
111
+ metas := map [terraform.Provider ]* configs.ProviderMeta {}
112
+ for k , v := range module .ProviderMetas {
113
+ m , diags := decodeProviderMeta (v )
114
+ if diags .HasErrors () {
115
+ return nil , diags
116
+ }
117
+ metas [k ] = m
118
+ }
119
+
120
+ variables := map [string ]* configs.Variable {}
121
+ for k , v := range module .Variables {
122
+ variable , diags := decodeVariable (v )
123
+ if diags .HasErrors () {
124
+ return nil , diags
125
+ }
126
+ variables [k ] = variable
127
+ }
128
+
129
+ locals := map [string ]* configs.Local {}
130
+ for k , v := range module .Locals {
131
+ l , diags := decodeLocal (v )
132
+ if diags .HasErrors () {
133
+ return nil , diags
134
+ }
135
+ locals [k ] = l
136
+ }
137
+
138
+ outputs := map [string ]* configs.Output {}
139
+ for k , v := range module .Outputs {
140
+ o , diags := decodeOutput (v )
141
+ if diags .HasErrors () {
142
+ return nil , diags
143
+ }
144
+ outputs [k ] = o
145
+ }
146
+
147
+ calls := map [string ]* terraform.ModuleCall {}
148
+ for k , v := range module .ModuleCalls {
149
+ c , diags := decodeModuleCall (v )
150
+ if diags .HasErrors () {
151
+ return nil , diags
152
+ }
153
+ calls [k ] = c
154
+ }
155
+
156
+ managed := map [string ]* terraform.Resource {}
157
+ for k , v := range module .ManagedResources {
158
+ r , diags := decodeResource (v )
159
+ if diags .HasErrors () {
160
+ return nil , diags
161
+ }
162
+ managed [k ] = r
163
+ }
164
+
165
+ data := map [string ]* terraform.Resource {}
166
+ for k , v := range module .DataResources {
167
+ d , diags := decodeResource (v )
168
+ if diags .HasErrors () {
169
+ return nil , diags
170
+ }
171
+ data [k ] = d
172
+ }
173
+
174
+ return & configs.Module {
175
+ SourceDir : module .SourceDir ,
176
+
177
+ CoreVersionConstraints : versionConstraints ,
178
+
179
+ ActiveExperiments : module .ActiveExperiments ,
180
+
181
+ Backend : backend ,
182
+ ProviderConfigs : providers ,
183
+ ProviderRequirements : requirements ,
184
+ ProviderLocalNames : module .ProviderLocalNames ,
185
+ ProviderMetas : metas ,
186
+
187
+ Variables : variables ,
188
+ Locals : locals ,
189
+ Outputs : outputs ,
190
+
191
+ ModuleCalls : calls ,
192
+
193
+ ManagedResources : managed ,
194
+ DataResources : data ,
195
+ }, nil
196
+ }
197
+
13
198
// Attribute is an intermediate representation of hcl.Attribute.
14
199
type Attribute struct {
15
200
Name string
@@ -141,6 +326,10 @@ type ManagedResource struct {
141
326
}
142
327
143
328
func decodeManagedResource (resource * ManagedResource ) (* terraform.ManagedResource , hcl.Diagnostics ) {
329
+ if resource == nil {
330
+ return nil , nil
331
+ }
332
+
144
333
connection , diags := decodeConnection (resource .Connection )
145
334
if diags .HasErrors () {
146
335
return nil , diags
@@ -229,28 +418,9 @@ func decodeModuleCall(call *ModuleCall) (*terraform.ModuleCall, hcl.Diagnostics)
229
418
})
230
419
}
231
420
232
- versionConstraint := terraform.VersionConstraint {DeclRange : call .VersionRange }
233
- if ! call .VersionRange .Empty () {
234
- required , err := version .NewConstraint (call .Version )
235
- if err != nil {
236
- detail := fmt .Sprintf (
237
- "ModuleCall '%s' version constraint '%s' parse error: %s" ,
238
- call .Name ,
239
- call .Version ,
240
- err ,
241
- )
242
-
243
- return nil , hcl.Diagnostics {
244
- & hcl.Diagnostic {
245
- Severity : hcl .DiagError ,
246
- Summary : "Failed to reparse module version constraint" ,
247
- Detail : detail ,
248
- Subject : & call .VersionRange ,
249
- },
250
- }
251
- }
252
-
253
- versionConstraint .Required = required
421
+ versionConstraint , diags := parseVersionConstraint (call .Version , call .VersionRange )
422
+ if diags .HasErrors () {
423
+ return nil , diags
254
424
}
255
425
256
426
return & terraform.ModuleCall {
@@ -394,3 +564,29 @@ func parseConfig(src []byte, filename string, start hcl.Pos) (*hcl.File, hcl.Dia
394
564
395
565
panic (fmt .Sprintf ("Unexpected file: %s" , filename ))
396
566
}
567
+
568
+ func parseVersionConstraint (versionStr string , versionRange hcl.Range ) (terraform.VersionConstraint , hcl.Diagnostics ) {
569
+ versionConstraint := terraform.VersionConstraint {DeclRange : versionRange }
570
+ if ! versionRange .Empty () {
571
+ required , err := version .NewConstraint (versionStr )
572
+ if err != nil {
573
+ detail := fmt .Sprintf (
574
+ "Version constraint '%s' parse error: %s" ,
575
+ versionStr ,
576
+ err ,
577
+ )
578
+
579
+ return versionConstraint , hcl.Diagnostics {
580
+ & hcl.Diagnostic {
581
+ Severity : hcl .DiagError ,
582
+ Summary : "Failed to reparse version constraint" ,
583
+ Detail : detail ,
584
+ Subject : & versionRange ,
585
+ },
586
+ }
587
+ }
588
+
589
+ versionConstraint .Required = required
590
+ }
591
+ return versionConstraint , nil
592
+ }
0 commit comments