diff options
author | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
---|---|---|
committer | Nathan Dench <ndenc2@gmail.com> | 2019-05-24 15:16:44 +1000 |
commit | 107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch) | |
tree | ca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/hashicorp/terraform-config-inspect | |
parent | 844b5a68d8af4791755b8f0ad293cc99f5959183 (diff) | |
download | terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip |
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/hashicorp/terraform-config-inspect')
14 files changed, 1589 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/LICENSE b/vendor/github.com/hashicorp/terraform-config-inspect/LICENSE new file mode 100644 index 0000000..82b4de9 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/LICENSE | |||
@@ -0,0 +1,353 @@ | |||
1 | Mozilla Public License, version 2.0 | ||
2 | |||
3 | 1. Definitions | ||
4 | |||
5 | 1.1. “Contributor” | ||
6 | |||
7 | means each individual or legal entity that creates, contributes to the | ||
8 | creation of, or owns Covered Software. | ||
9 | |||
10 | 1.2. “Contributor Version” | ||
11 | |||
12 | means the combination of the Contributions of others (if any) used by a | ||
13 | Contributor and that particular Contributor’s Contribution. | ||
14 | |||
15 | 1.3. “Contribution” | ||
16 | |||
17 | means Covered Software of a particular Contributor. | ||
18 | |||
19 | 1.4. “Covered Software” | ||
20 | |||
21 | means Source Code Form to which the initial Contributor has attached the | ||
22 | notice in Exhibit A, the Executable Form of such Source Code Form, and | ||
23 | Modifications of such Source Code Form, in each case including portions | ||
24 | thereof. | ||
25 | |||
26 | 1.5. “Incompatible With Secondary Licenses” | ||
27 | means | ||
28 | |||
29 | a. that the initial Contributor has attached the notice described in | ||
30 | Exhibit B to the Covered Software; or | ||
31 | |||
32 | b. that the Covered Software was made available under the terms of version | ||
33 | 1.1 or earlier of the License, but not also under the terms of a | ||
34 | Secondary License. | ||
35 | |||
36 | 1.6. “Executable Form” | ||
37 | |||
38 | means any form of the work other than Source Code Form. | ||
39 | |||
40 | 1.7. “Larger Work” | ||
41 | |||
42 | means a work that combines Covered Software with other material, in a separate | ||
43 | file or files, that is not Covered Software. | ||
44 | |||
45 | 1.8. “License” | ||
46 | |||
47 | means this document. | ||
48 | |||
49 | 1.9. “Licensable” | ||
50 | |||
51 | means having the right to grant, to the maximum extent possible, whether at the | ||
52 | time of the initial grant or subsequently, any and all of the rights conveyed by | ||
53 | this License. | ||
54 | |||
55 | 1.10. “Modifications” | ||
56 | |||
57 | means any of the following: | ||
58 | |||
59 | a. any file in Source Code Form that results from an addition to, deletion | ||
60 | from, or modification of the contents of Covered Software; or | ||
61 | |||
62 | b. any new file in Source Code Form that contains any Covered Software. | ||
63 | |||
64 | 1.11. “Patent Claims” of a Contributor | ||
65 | |||
66 | means any patent claim(s), including without limitation, method, process, | ||
67 | and apparatus claims, in any patent Licensable by such Contributor that | ||
68 | would be infringed, but for the grant of the License, by the making, | ||
69 | using, selling, offering for sale, having made, import, or transfer of | ||
70 | either its Contributions or its Contributor Version. | ||
71 | |||
72 | 1.12. “Secondary License” | ||
73 | |||
74 | means either the GNU General Public License, Version 2.0, the GNU Lesser | ||
75 | General Public License, Version 2.1, the GNU Affero General Public | ||
76 | License, Version 3.0, or any later versions of those licenses. | ||
77 | |||
78 | 1.13. “Source Code Form” | ||
79 | |||
80 | means the form of the work preferred for making modifications. | ||
81 | |||
82 | 1.14. “You” (or “Your”) | ||
83 | |||
84 | means an individual or a legal entity exercising rights under this | ||
85 | License. For legal entities, “You” includes any entity that controls, is | ||
86 | controlled by, or is under common control with You. For purposes of this | ||
87 | definition, “control” means (a) the power, direct or indirect, to cause | ||
88 | the direction or management of such entity, whether by contract or | ||
89 | otherwise, or (b) ownership of more than fifty percent (50%) of the | ||
90 | outstanding shares or beneficial ownership of such entity. | ||
91 | |||
92 | |||
93 | 2. License Grants and Conditions | ||
94 | |||
95 | 2.1. Grants | ||
96 | |||
97 | Each Contributor hereby grants You a world-wide, royalty-free, | ||
98 | non-exclusive license: | ||
99 | |||
100 | a. under intellectual property rights (other than patent or trademark) | ||
101 | Licensable by such Contributor to use, reproduce, make available, | ||
102 | modify, display, perform, distribute, and otherwise exploit its | ||
103 | Contributions, either on an unmodified basis, with Modifications, or as | ||
104 | part of a Larger Work; and | ||
105 | |||
106 | b. under Patent Claims of such Contributor to make, use, sell, offer for | ||
107 | sale, have made, import, and otherwise transfer either its Contributions | ||
108 | or its Contributor Version. | ||
109 | |||
110 | 2.2. Effective Date | ||
111 | |||
112 | The licenses granted in Section 2.1 with respect to any Contribution become | ||
113 | effective for each Contribution on the date the Contributor first distributes | ||
114 | such Contribution. | ||
115 | |||
116 | 2.3. Limitations on Grant Scope | ||
117 | |||
118 | The licenses granted in this Section 2 are the only rights granted under this | ||
119 | License. No additional rights or licenses will be implied from the distribution | ||
120 | or licensing of Covered Software under this License. Notwithstanding Section | ||
121 | 2.1(b) above, no patent license is granted by a Contributor: | ||
122 | |||
123 | a. for any code that a Contributor has removed from Covered Software; or | ||
124 | |||
125 | b. for infringements caused by: (i) Your and any other third party’s | ||
126 | modifications of Covered Software, or (ii) the combination of its | ||
127 | Contributions with other software (except as part of its Contributor | ||
128 | Version); or | ||
129 | |||
130 | c. under Patent Claims infringed by Covered Software in the absence of its | ||
131 | Contributions. | ||
132 | |||
133 | This License does not grant any rights in the trademarks, service marks, or | ||
134 | logos of any Contributor (except as may be necessary to comply with the | ||
135 | notice requirements in Section 3.4). | ||
136 | |||
137 | 2.4. Subsequent Licenses | ||
138 | |||
139 | No Contributor makes additional grants as a result of Your choice to | ||
140 | distribute the Covered Software under a subsequent version of this License | ||
141 | (see Section 10.2) or under the terms of a Secondary License (if permitted | ||
142 | under the terms of Section 3.3). | ||
143 | |||
144 | 2.5. Representation | ||
145 | |||
146 | Each Contributor represents that the Contributor believes its Contributions | ||
147 | are its original creation(s) or it has sufficient rights to grant the | ||
148 | rights to its Contributions conveyed by this License. | ||
149 | |||
150 | 2.6. Fair Use | ||
151 | |||
152 | This License is not intended to limit any rights You have under applicable | ||
153 | copyright doctrines of fair use, fair dealing, or other equivalents. | ||
154 | |||
155 | 2.7. Conditions | ||
156 | |||
157 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in | ||
158 | Section 2.1. | ||
159 | |||
160 | |||
161 | 3. Responsibilities | ||
162 | |||
163 | 3.1. Distribution of Source Form | ||
164 | |||
165 | All distribution of Covered Software in Source Code Form, including any | ||
166 | Modifications that You create or to which You contribute, must be under the | ||
167 | terms of this License. You must inform recipients that the Source Code Form | ||
168 | of the Covered Software is governed by the terms of this License, and how | ||
169 | they can obtain a copy of this License. You may not attempt to alter or | ||
170 | restrict the recipients’ rights in the Source Code Form. | ||
171 | |||
172 | 3.2. Distribution of Executable Form | ||
173 | |||
174 | If You distribute Covered Software in Executable Form then: | ||
175 | |||
176 | a. such Covered Software must also be made available in Source Code Form, | ||
177 | as described in Section 3.1, and You must inform recipients of the | ||
178 | Executable Form how they can obtain a copy of such Source Code Form by | ||
179 | reasonable means in a timely manner, at a charge no more than the cost | ||
180 | of distribution to the recipient; and | ||
181 | |||
182 | b. You may distribute such Executable Form under the terms of this License, | ||
183 | or sublicense it under different terms, provided that the license for | ||
184 | the Executable Form does not attempt to limit or alter the recipients’ | ||
185 | rights in the Source Code Form under this License. | ||
186 | |||
187 | 3.3. Distribution of a Larger Work | ||
188 | |||
189 | You may create and distribute a Larger Work under terms of Your choice, | ||
190 | provided that You also comply with the requirements of this License for the | ||
191 | Covered Software. If the Larger Work is a combination of Covered Software | ||
192 | with a work governed by one or more Secondary Licenses, and the Covered | ||
193 | Software is not Incompatible With Secondary Licenses, this License permits | ||
194 | You to additionally distribute such Covered Software under the terms of | ||
195 | such Secondary License(s), so that the recipient of the Larger Work may, at | ||
196 | their option, further distribute the Covered Software under the terms of | ||
197 | either this License or such Secondary License(s). | ||
198 | |||
199 | 3.4. Notices | ||
200 | |||
201 | You may not remove or alter the substance of any license notices (including | ||
202 | copyright notices, patent notices, disclaimers of warranty, or limitations | ||
203 | of liability) contained within the Source Code Form of the Covered | ||
204 | Software, except that You may alter any license notices to the extent | ||
205 | required to remedy known factual inaccuracies. | ||
206 | |||
207 | 3.5. Application of Additional Terms | ||
208 | |||
209 | You may choose to offer, and to charge a fee for, warranty, support, | ||
210 | indemnity or liability obligations to one or more recipients of Covered | ||
211 | Software. However, You may do so only on Your own behalf, and not on behalf | ||
212 | of any Contributor. You must make it absolutely clear that any such | ||
213 | warranty, support, indemnity, or liability obligation is offered by You | ||
214 | alone, and You hereby agree to indemnify every Contributor for any | ||
215 | liability incurred by such Contributor as a result of warranty, support, | ||
216 | indemnity or liability terms You offer. You may include additional | ||
217 | disclaimers of warranty and limitations of liability specific to any | ||
218 | jurisdiction. | ||
219 | |||
220 | 4. Inability to Comply Due to Statute or Regulation | ||
221 | |||
222 | If it is impossible for You to comply with any of the terms of this License | ||
223 | with respect to some or all of the Covered Software due to statute, judicial | ||
224 | order, or regulation then You must: (a) comply with the terms of this License | ||
225 | to the maximum extent possible; and (b) describe the limitations and the code | ||
226 | they affect. Such description must be placed in a text file included with all | ||
227 | distributions of the Covered Software under this License. Except to the | ||
228 | extent prohibited by statute or regulation, such description must be | ||
229 | sufficiently detailed for a recipient of ordinary skill to be able to | ||
230 | understand it. | ||
231 | |||
232 | 5. Termination | ||
233 | |||
234 | 5.1. The rights granted under this License will terminate automatically if You | ||
235 | fail to comply with any of its terms. However, if You become compliant, | ||
236 | then the rights granted under this License from a particular Contributor | ||
237 | are reinstated (a) provisionally, unless and until such Contributor | ||
238 | explicitly and finally terminates Your grants, and (b) on an ongoing basis, | ||
239 | if such Contributor fails to notify You of the non-compliance by some | ||
240 | reasonable means prior to 60 days after You have come back into compliance. | ||
241 | Moreover, Your grants from a particular Contributor are reinstated on an | ||
242 | ongoing basis if such Contributor notifies You of the non-compliance by | ||
243 | some reasonable means, this is the first time You have received notice of | ||
244 | non-compliance with this License from such Contributor, and You become | ||
245 | compliant prior to 30 days after Your receipt of the notice. | ||
246 | |||
247 | 5.2. If You initiate litigation against any entity by asserting a patent | ||
248 | infringement claim (excluding declaratory judgment actions, counter-claims, | ||
249 | and cross-claims) alleging that a Contributor Version directly or | ||
250 | indirectly infringes any patent, then the rights granted to You by any and | ||
251 | all Contributors for the Covered Software under Section 2.1 of this License | ||
252 | shall terminate. | ||
253 | |||
254 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user | ||
255 | license agreements (excluding distributors and resellers) which have been | ||
256 | validly granted by You or Your distributors under this License prior to | ||
257 | termination shall survive termination. | ||
258 | |||
259 | 6. Disclaimer of Warranty | ||
260 | |||
261 | Covered Software is provided under this License on an “as is” basis, without | ||
262 | warranty of any kind, either expressed, implied, or statutory, including, | ||
263 | without limitation, warranties that the Covered Software is free of defects, | ||
264 | merchantable, fit for a particular purpose or non-infringing. The entire | ||
265 | risk as to the quality and performance of the Covered Software is with You. | ||
266 | Should any Covered Software prove defective in any respect, You (not any | ||
267 | Contributor) assume the cost of any necessary servicing, repair, or | ||
268 | correction. This disclaimer of warranty constitutes an essential part of this | ||
269 | License. No use of any Covered Software is authorized under this License | ||
270 | except under this disclaimer. | ||
271 | |||
272 | 7. Limitation of Liability | ||
273 | |||
274 | Under no circumstances and under no legal theory, whether tort (including | ||
275 | negligence), contract, or otherwise, shall any Contributor, or anyone who | ||
276 | distributes Covered Software as permitted above, be liable to You for any | ||
277 | direct, indirect, special, incidental, or consequential damages of any | ||
278 | character including, without limitation, damages for lost profits, loss of | ||
279 | goodwill, work stoppage, computer failure or malfunction, or any and all | ||
280 | other commercial damages or losses, even if such party shall have been | ||
281 | informed of the possibility of such damages. This limitation of liability | ||
282 | shall not apply to liability for death or personal injury resulting from such | ||
283 | party’s negligence to the extent applicable law prohibits such limitation. | ||
284 | Some jurisdictions do not allow the exclusion or limitation of incidental or | ||
285 | consequential damages, so this exclusion and limitation may not apply to You. | ||
286 | |||
287 | 8. Litigation | ||
288 | |||
289 | Any litigation relating to this License may be brought only in the courts of | ||
290 | a jurisdiction where the defendant maintains its principal place of business | ||
291 | and such litigation shall be governed by laws of that jurisdiction, without | ||
292 | reference to its conflict-of-law provisions. Nothing in this Section shall | ||
293 | prevent a party’s ability to bring cross-claims or counter-claims. | ||
294 | |||
295 | 9. Miscellaneous | ||
296 | |||
297 | This License represents the complete agreement concerning the subject matter | ||
298 | hereof. If any provision of this License is held to be unenforceable, such | ||
299 | provision shall be reformed only to the extent necessary to make it | ||
300 | enforceable. Any law or regulation which provides that the language of a | ||
301 | contract shall be construed against the drafter shall not be used to construe | ||
302 | this License against a Contributor. | ||
303 | |||
304 | |||
305 | 10. Versions of the License | ||
306 | |||
307 | 10.1. New Versions | ||
308 | |||
309 | Mozilla Foundation is the license steward. Except as provided in Section | ||
310 | 10.3, no one other than the license steward has the right to modify or | ||
311 | publish new versions of this License. Each version will be given a | ||
312 | distinguishing version number. | ||
313 | |||
314 | 10.2. Effect of New Versions | ||
315 | |||
316 | You may distribute the Covered Software under the terms of the version of | ||
317 | the License under which You originally received the Covered Software, or | ||
318 | under the terms of any subsequent version published by the license | ||
319 | steward. | ||
320 | |||
321 | 10.3. Modified Versions | ||
322 | |||
323 | If you create software not governed by this License, and you want to | ||
324 | create a new license for such software, you may create and use a modified | ||
325 | version of this License if you rename the license and remove any | ||
326 | references to the name of the license steward (except to note that such | ||
327 | modified license differs from this License). | ||
328 | |||
329 | 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses | ||
330 | If You choose to distribute Source Code Form that is Incompatible With | ||
331 | Secondary Licenses under the terms of this version of the License, the | ||
332 | notice described in Exhibit B of this License must be attached. | ||
333 | |||
334 | Exhibit A - Source Code Form License Notice | ||
335 | |||
336 | This Source Code Form is subject to the | ||
337 | terms of the Mozilla Public License, v. | ||
338 | 2.0. If a copy of the MPL was not | ||
339 | distributed with this file, You can | ||
340 | obtain one at | ||
341 | http://mozilla.org/MPL/2.0/. | ||
342 | |||
343 | If it is not possible or desirable to put the notice in a particular file, then | ||
344 | You may include the notice in a location (such as a LICENSE file in a relevant | ||
345 | directory) where a recipient would be likely to look for such a notice. | ||
346 | |||
347 | You may add additional accurate notices of copyright ownership. | ||
348 | |||
349 | Exhibit B - “Incompatible With Secondary Licenses” Notice | ||
350 | |||
351 | This Source Code Form is “Incompatible | ||
352 | With Secondary Licenses”, as defined by | ||
353 | the Mozilla Public License, v. 2.0. | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go new file mode 100644 index 0000000..8d04ad4 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/diagnostic.go | |||
@@ -0,0 +1,138 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | |||
6 | legacyhclparser "github.com/hashicorp/hcl/hcl/parser" | ||
7 | "github.com/hashicorp/hcl2/hcl" | ||
8 | ) | ||
9 | |||
10 | // Diagnostic describes a problem (error or warning) encountered during | ||
11 | // configuration loading. | ||
12 | type Diagnostic struct { | ||
13 | Severity DiagSeverity `json:"severity"` | ||
14 | Summary string `json:"summary"` | ||
15 | Detail string `json:"detail,omitempty"` | ||
16 | |||
17 | // Pos is not populated for all diagnostics, but when populated should | ||
18 | // indicate a particular line that the described problem relates to. | ||
19 | Pos *SourcePos `json:"pos,omitempty"` | ||
20 | } | ||
21 | |||
22 | // Diagnostics represents a sequence of diagnostics. This is the type that | ||
23 | // should be returned from a function that might generate diagnostics. | ||
24 | type Diagnostics []Diagnostic | ||
25 | |||
26 | // HasErrors returns true if there is at least one Diagnostic of severity | ||
27 | // DiagError in the receiever. | ||
28 | // | ||
29 | // If a function returns a Diagnostics without errors then the result can | ||
30 | // be assumed to be complete within the "best effort" constraints of this | ||
31 | // library. If errors are present then the caller may wish to employ more | ||
32 | // caution in relying on the result. | ||
33 | func (diags Diagnostics) HasErrors() bool { | ||
34 | for _, diag := range diags { | ||
35 | if diag.Severity == DiagError { | ||
36 | return true | ||
37 | } | ||
38 | } | ||
39 | return false | ||
40 | } | ||
41 | |||
42 | func (diags Diagnostics) Error() string { | ||
43 | switch len(diags) { | ||
44 | case 0: | ||
45 | return "no problems" | ||
46 | case 1: | ||
47 | return fmt.Sprintf("%s: %s", diags[0].Summary, diags[0].Detail) | ||
48 | default: | ||
49 | return fmt.Sprintf("%s: %s (and %d other messages)", diags[0].Summary, diags[0].Detail, len(diags)-1) | ||
50 | } | ||
51 | } | ||
52 | |||
53 | // Err returns an error representing the receiver if the receiver HasErrors, or | ||
54 | // nil otherwise. | ||
55 | // | ||
56 | // The returned error can be type-asserted back to a Diagnostics if needed. | ||
57 | func (diags Diagnostics) Err() error { | ||
58 | if diags.HasErrors() { | ||
59 | return diags | ||
60 | } | ||
61 | return nil | ||
62 | } | ||
63 | |||
64 | // DiagSeverity describes the severity of a Diagnostic. | ||
65 | type DiagSeverity rune | ||
66 | |||
67 | // DiagError indicates a problem that prevented proper processing of the | ||
68 | // configuration. In the precense of DiagError diagnostics the result is | ||
69 | // likely to be incomplete. | ||
70 | const DiagError DiagSeverity = 'E' | ||
71 | |||
72 | // DiagWarning indicates a problem that the user may wish to consider but | ||
73 | // that did not prevent proper processing of the configuration. | ||
74 | const DiagWarning DiagSeverity = 'W' | ||
75 | |||
76 | // MarshalJSON is an implementation of encoding/json.Marshaler | ||
77 | func (s DiagSeverity) MarshalJSON() ([]byte, error) { | ||
78 | switch s { | ||
79 | case DiagError: | ||
80 | return []byte(`"error"`), nil | ||
81 | case DiagWarning: | ||
82 | return []byte(`"warning"`), nil | ||
83 | default: | ||
84 | return []byte(`"invalid"`), nil | ||
85 | } | ||
86 | } | ||
87 | |||
88 | func diagnosticsHCL(diags hcl.Diagnostics) Diagnostics { | ||
89 | if len(diags) == 0 { | ||
90 | return nil | ||
91 | } | ||
92 | ret := make(Diagnostics, len(diags)) | ||
93 | for i, diag := range diags { | ||
94 | ret[i] = Diagnostic{ | ||
95 | Summary: diag.Summary, | ||
96 | Detail: diag.Detail, | ||
97 | } | ||
98 | switch diag.Severity { | ||
99 | case hcl.DiagError: | ||
100 | ret[i].Severity = DiagError | ||
101 | case hcl.DiagWarning: | ||
102 | ret[i].Severity = DiagWarning | ||
103 | } | ||
104 | if diag.Subject != nil { | ||
105 | pos := sourcePosHCL(*diag.Subject) | ||
106 | ret[i].Pos = &pos | ||
107 | } | ||
108 | } | ||
109 | return ret | ||
110 | } | ||
111 | |||
112 | func diagnosticsError(err error) Diagnostics { | ||
113 | if err == nil { | ||
114 | return nil | ||
115 | } | ||
116 | |||
117 | if posErr, ok := err.(*legacyhclparser.PosError); ok { | ||
118 | pos := sourcePosLegacyHCL(posErr.Pos, "") | ||
119 | return Diagnostics{ | ||
120 | Diagnostic{ | ||
121 | Severity: DiagError, | ||
122 | Summary: posErr.Err.Error(), | ||
123 | Pos: &pos, | ||
124 | }, | ||
125 | } | ||
126 | } | ||
127 | |||
128 | return Diagnostics{ | ||
129 | Diagnostic{ | ||
130 | Severity: DiagError, | ||
131 | Summary: err.Error(), | ||
132 | }, | ||
133 | } | ||
134 | } | ||
135 | |||
136 | func diagnosticsErrorf(format string, args ...interface{}) Diagnostics { | ||
137 | return diagnosticsError(fmt.Errorf(format, args...)) | ||
138 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go new file mode 100644 index 0000000..1604a6e --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/doc.go | |||
@@ -0,0 +1,21 @@ | |||
1 | // Package tfconfig is a helper library that does careful, shallow parsing of | ||
2 | // Terraform modules to provide access to high-level metadata while | ||
3 | // remaining broadly compatible with configurations targeting various | ||
4 | // different Terraform versions. | ||
5 | // | ||
6 | // This packge focuses on describing top-level objects only, and in particular | ||
7 | // does not attempt any sort of processing that would require access to plugins. | ||
8 | // Currently it allows callers to extract high-level information about | ||
9 | // variables, outputs, resource blocks, provider dependencies, and Terraform | ||
10 | // Core dependencies. | ||
11 | // | ||
12 | // This package only works at the level of single modules. A full configuration | ||
13 | // is a tree of potentially several modules, some of which may be references | ||
14 | // to remote packages. There are some basic helpers for traversing calls to | ||
15 | // modules at relative local paths, however. | ||
16 | // | ||
17 | // This package employs a "best effort" parsing strategy, producing as complete | ||
18 | // a result as possible even though the input may not be entirely valid. The | ||
19 | // intended use-case is high-level analysis and indexing of externally-facing | ||
20 | // module characteristics, as opposed to validating or even applying the module. | ||
21 | package tfconfig | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go new file mode 100644 index 0000000..2d13fe1 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load.go | |||
@@ -0,0 +1,130 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "io/ioutil" | ||
6 | "path/filepath" | ||
7 | "strings" | ||
8 | |||
9 | "github.com/hashicorp/hcl2/hcl" | ||
10 | ) | ||
11 | |||
12 | // LoadModule reads the directory at the given path and attempts to interpret | ||
13 | // it as a Terraform module. | ||
14 | func LoadModule(dir string) (*Module, Diagnostics) { | ||
15 | |||
16 | // For broad compatibility here we actually have two separate loader | ||
17 | // codepaths. The main one uses the new HCL parser and API and is intended | ||
18 | // for configurations from Terraform 0.12 onwards (though will work for | ||
19 | // many older configurations too), but we'll also fall back on one that | ||
20 | // uses the _old_ HCL implementation so we can deal with some edge-cases | ||
21 | // that are not valid in new HCL. | ||
22 | |||
23 | module, diags := loadModule(dir) | ||
24 | if diags.HasErrors() { | ||
25 | // Try using the legacy HCL parser and see if we fare better. | ||
26 | legacyModule, legacyDiags := loadModuleLegacyHCL(dir) | ||
27 | if !legacyDiags.HasErrors() { | ||
28 | legacyModule.init(legacyDiags) | ||
29 | return legacyModule, legacyDiags | ||
30 | } | ||
31 | } | ||
32 | |||
33 | module.init(diags) | ||
34 | return module, diags | ||
35 | } | ||
36 | |||
37 | // IsModuleDir checks if the given path contains terraform configuration files. | ||
38 | // This allows the caller to decide how to handle directories that do not have tf files. | ||
39 | func IsModuleDir(dir string) bool { | ||
40 | primaryPaths, _ := dirFiles(dir) | ||
41 | if len(primaryPaths) == 0 { | ||
42 | return false | ||
43 | } | ||
44 | return true | ||
45 | } | ||
46 | |||
47 | func (m *Module) init(diags Diagnostics) { | ||
48 | // Fill in any additional provider requirements that are implied by | ||
49 | // resource configurations, to avoid the caller from needing to apply | ||
50 | // this logic itself. Implied requirements don't have version constraints, | ||
51 | // but we'll make sure the requirement value is still non-nil in this | ||
52 | // case so callers can easily recognize it. | ||
53 | for _, r := range m.ManagedResources { | ||
54 | if _, exists := m.RequiredProviders[r.Provider.Name]; !exists { | ||
55 | m.RequiredProviders[r.Provider.Name] = []string{} | ||
56 | } | ||
57 | } | ||
58 | for _, r := range m.DataResources { | ||
59 | if _, exists := m.RequiredProviders[r.Provider.Name]; !exists { | ||
60 | m.RequiredProviders[r.Provider.Name] = []string{} | ||
61 | } | ||
62 | } | ||
63 | |||
64 | // We redundantly also reference the diagnostics from inside the module | ||
65 | // object, primarily so that we can easily included in JSON-serialized | ||
66 | // versions of the module object. | ||
67 | m.Diagnostics = diags | ||
68 | } | ||
69 | |||
70 | func dirFiles(dir string) (primary []string, diags hcl.Diagnostics) { | ||
71 | infos, err := ioutil.ReadDir(dir) | ||
72 | if err != nil { | ||
73 | diags = append(diags, &hcl.Diagnostic{ | ||
74 | Severity: hcl.DiagError, | ||
75 | Summary: "Failed to read module directory", | ||
76 | Detail: fmt.Sprintf("Module directory %s does not exist or cannot be read.", dir), | ||
77 | }) | ||
78 | return | ||
79 | } | ||
80 | |||
81 | var override []string | ||
82 | for _, info := range infos { | ||
83 | if info.IsDir() { | ||
84 | // We only care about files | ||
85 | continue | ||
86 | } | ||
87 | |||
88 | name := info.Name() | ||
89 | ext := fileExt(name) | ||
90 | if ext == "" || isIgnoredFile(name) { | ||
91 | continue | ||
92 | } | ||
93 | |||
94 | baseName := name[:len(name)-len(ext)] // strip extension | ||
95 | isOverride := baseName == "override" || strings.HasSuffix(baseName, "_override") | ||
96 | |||
97 | fullPath := filepath.Join(dir, name) | ||
98 | if isOverride { | ||
99 | override = append(override, fullPath) | ||
100 | } else { | ||
101 | primary = append(primary, fullPath) | ||
102 | } | ||
103 | } | ||
104 | |||
105 | // We are assuming that any _override files will be logically named, | ||
106 | // and processing the files in alphabetical order. Primaries first, then overrides. | ||
107 | primary = append(primary, override...) | ||
108 | |||
109 | return | ||
110 | } | ||
111 | |||
112 | // fileExt returns the Terraform configuration extension of the given | ||
113 | // path, or a blank string if it is not a recognized extension. | ||
114 | func fileExt(path string) string { | ||
115 | if strings.HasSuffix(path, ".tf") { | ||
116 | return ".tf" | ||
117 | } else if strings.HasSuffix(path, ".tf.json") { | ||
118 | return ".tf.json" | ||
119 | } else { | ||
120 | return "" | ||
121 | } | ||
122 | } | ||
123 | |||
124 | // isIgnoredFile returns true if the given filename (which must not have a | ||
125 | // directory path ahead of it) should be ignored as e.g. an editor swap file. | ||
126 | func isIgnoredFile(name string) bool { | ||
127 | return strings.HasPrefix(name, ".") || // Unix-like hidden files | ||
128 | strings.HasSuffix(name, "~") || // vim | ||
129 | strings.HasPrefix(name, "#") && strings.HasSuffix(name, "#") // emacs | ||
130 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go new file mode 100644 index 0000000..72b5d4a --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_hcl.go | |||
@@ -0,0 +1,322 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | import ( | ||
4 | "encoding/json" | ||
5 | "fmt" | ||
6 | "strings" | ||
7 | |||
8 | "github.com/hashicorp/hcl2/hcl/hclsyntax" | ||
9 | |||
10 | "github.com/hashicorp/hcl2/gohcl" | ||
11 | "github.com/hashicorp/hcl2/hcl" | ||
12 | "github.com/hashicorp/hcl2/hclparse" | ||
13 | ctyjson "github.com/zclconf/go-cty/cty/json" | ||
14 | ) | ||
15 | |||
16 | func loadModule(dir string) (*Module, Diagnostics) { | ||
17 | mod := newModule(dir) | ||
18 | primaryPaths, diags := dirFiles(dir) | ||
19 | |||
20 | parser := hclparse.NewParser() | ||
21 | |||
22 | for _, filename := range primaryPaths { | ||
23 | var file *hcl.File | ||
24 | var fileDiags hcl.Diagnostics | ||
25 | if strings.HasSuffix(filename, ".json") { | ||
26 | file, fileDiags = parser.ParseJSONFile(filename) | ||
27 | } else { | ||
28 | file, fileDiags = parser.ParseHCLFile(filename) | ||
29 | } | ||
30 | diags = append(diags, fileDiags...) | ||
31 | if file == nil { | ||
32 | continue | ||
33 | } | ||
34 | |||
35 | content, _, contentDiags := file.Body.PartialContent(rootSchema) | ||
36 | diags = append(diags, contentDiags...) | ||
37 | |||
38 | for _, block := range content.Blocks { | ||
39 | switch block.Type { | ||
40 | |||
41 | case "terraform": | ||
42 | content, _, contentDiags := block.Body.PartialContent(terraformBlockSchema) | ||
43 | diags = append(diags, contentDiags...) | ||
44 | |||
45 | if attr, defined := content.Attributes["required_version"]; defined { | ||
46 | var version string | ||
47 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) | ||
48 | diags = append(diags, valDiags...) | ||
49 | if !valDiags.HasErrors() { | ||
50 | mod.RequiredCore = append(mod.RequiredCore, version) | ||
51 | } | ||
52 | } | ||
53 | |||
54 | for _, block := range content.Blocks { | ||
55 | // Our schema only allows required_providers here, so we | ||
56 | // assume that we'll only get that block type. | ||
57 | attrs, attrDiags := block.Body.JustAttributes() | ||
58 | diags = append(diags, attrDiags...) | ||
59 | |||
60 | for name, attr := range attrs { | ||
61 | var version string | ||
62 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) | ||
63 | diags = append(diags, valDiags...) | ||
64 | if !valDiags.HasErrors() { | ||
65 | mod.RequiredProviders[name] = append(mod.RequiredProviders[name], version) | ||
66 | } | ||
67 | } | ||
68 | } | ||
69 | |||
70 | case "variable": | ||
71 | content, _, contentDiags := block.Body.PartialContent(variableSchema) | ||
72 | diags = append(diags, contentDiags...) | ||
73 | |||
74 | name := block.Labels[0] | ||
75 | v := &Variable{ | ||
76 | Name: name, | ||
77 | Pos: sourcePosHCL(block.DefRange), | ||
78 | } | ||
79 | |||
80 | mod.Variables[name] = v | ||
81 | |||
82 | if attr, defined := content.Attributes["type"]; defined { | ||
83 | // We handle this particular attribute in a somewhat-tricky way: | ||
84 | // since Terraform may evolve its type expression syntax in | ||
85 | // future versions, we don't want to be overly-strict in how | ||
86 | // we handle it here, and so we'll instead just take the raw | ||
87 | // source provided by the user, using the source location | ||
88 | // information in the expression object. | ||
89 | // | ||
90 | // However, older versions of Terraform expected the type | ||
91 | // to be a string containing a keyword, so we'll need to | ||
92 | // handle that as a special case first for backward compatibility. | ||
93 | |||
94 | var typeExpr string | ||
95 | |||
96 | var typeExprAsStr string | ||
97 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &typeExprAsStr) | ||
98 | if !valDiags.HasErrors() { | ||
99 | typeExpr = typeExprAsStr | ||
100 | } else { | ||
101 | |||
102 | rng := attr.Expr.Range() | ||
103 | sourceFilename := rng.Filename | ||
104 | source, exists := parser.Sources()[sourceFilename] | ||
105 | if exists { | ||
106 | typeExpr = string(rng.SliceBytes(source)) | ||
107 | } else { | ||
108 | // This should never happen, so we'll just warn about it and leave the type unspecified. | ||
109 | diags = append(diags, &hcl.Diagnostic{ | ||
110 | Severity: hcl.DiagError, | ||
111 | Summary: "Source code not available", | ||
112 | Detail: fmt.Sprintf("Source code is not available for the file %q, which declares the variable %q.", sourceFilename, name), | ||
113 | Subject: &block.DefRange, | ||
114 | }) | ||
115 | typeExpr = "" | ||
116 | } | ||
117 | |||
118 | } | ||
119 | |||
120 | v.Type = typeExpr | ||
121 | } | ||
122 | |||
123 | if attr, defined := content.Attributes["description"]; defined { | ||
124 | var description string | ||
125 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &description) | ||
126 | diags = append(diags, valDiags...) | ||
127 | v.Description = description | ||
128 | } | ||
129 | |||
130 | if attr, defined := content.Attributes["default"]; defined { | ||
131 | // To avoid the caller needing to deal with cty here, we'll | ||
132 | // use its JSON encoding to convert into an | ||
133 | // approximately-equivalent plain Go interface{} value | ||
134 | // to return. | ||
135 | val, valDiags := attr.Expr.Value(nil) | ||
136 | diags = append(diags, valDiags...) | ||
137 | if val.IsWhollyKnown() { // should only be false if there are errors in the input | ||
138 | valJSON, err := ctyjson.Marshal(val, val.Type()) | ||
139 | if err != nil { | ||
140 | // Should never happen, since all possible known | ||
141 | // values have a JSON mapping. | ||
142 | panic(fmt.Errorf("failed to serialize default value as JSON: %s", err)) | ||
143 | } | ||
144 | var def interface{} | ||
145 | err = json.Unmarshal(valJSON, &def) | ||
146 | if err != nil { | ||
147 | // Again should never happen, because valJSON is | ||
148 | // guaranteed valid by ctyjson.Marshal. | ||
149 | panic(fmt.Errorf("failed to re-parse default value from JSON: %s", err)) | ||
150 | } | ||
151 | v.Default = def | ||
152 | } | ||
153 | } | ||
154 | |||
155 | case "output": | ||
156 | |||
157 | content, _, contentDiags := block.Body.PartialContent(outputSchema) | ||
158 | diags = append(diags, contentDiags...) | ||
159 | |||
160 | name := block.Labels[0] | ||
161 | o := &Output{ | ||
162 | Name: name, | ||
163 | Pos: sourcePosHCL(block.DefRange), | ||
164 | } | ||
165 | |||
166 | mod.Outputs[name] = o | ||
167 | |||
168 | if attr, defined := content.Attributes["description"]; defined { | ||
169 | var description string | ||
170 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &description) | ||
171 | diags = append(diags, valDiags...) | ||
172 | o.Description = description | ||
173 | } | ||
174 | |||
175 | case "provider": | ||
176 | |||
177 | content, _, contentDiags := block.Body.PartialContent(providerConfigSchema) | ||
178 | diags = append(diags, contentDiags...) | ||
179 | |||
180 | name := block.Labels[0] | ||
181 | |||
182 | if attr, defined := content.Attributes["version"]; defined { | ||
183 | var version string | ||
184 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) | ||
185 | diags = append(diags, valDiags...) | ||
186 | if !valDiags.HasErrors() { | ||
187 | mod.RequiredProviders[name] = append(mod.RequiredProviders[name], version) | ||
188 | } | ||
189 | } | ||
190 | |||
191 | // Even if there wasn't an explicit version required, we still | ||
192 | // need an entry in our map to signal the unversioned dependency. | ||
193 | if _, exists := mod.RequiredProviders[name]; !exists { | ||
194 | mod.RequiredProviders[name] = []string{} | ||
195 | } | ||
196 | |||
197 | case "resource", "data": | ||
198 | |||
199 | content, _, contentDiags := block.Body.PartialContent(resourceSchema) | ||
200 | diags = append(diags, contentDiags...) | ||
201 | |||
202 | typeName := block.Labels[0] | ||
203 | name := block.Labels[1] | ||
204 | |||
205 | r := &Resource{ | ||
206 | Type: typeName, | ||
207 | Name: name, | ||
208 | Pos: sourcePosHCL(block.DefRange), | ||
209 | } | ||
210 | |||
211 | var resourcesMap map[string]*Resource | ||
212 | |||
213 | switch block.Type { | ||
214 | case "resource": | ||
215 | r.Mode = ManagedResourceMode | ||
216 | resourcesMap = mod.ManagedResources | ||
217 | case "data": | ||
218 | r.Mode = DataResourceMode | ||
219 | resourcesMap = mod.DataResources | ||
220 | } | ||
221 | |||
222 | key := r.MapKey() | ||
223 | |||
224 | resourcesMap[key] = r | ||
225 | |||
226 | if attr, defined := content.Attributes["provider"]; defined { | ||
227 | // New style here is to provide this as a naked traversal | ||
228 | // expression, but we also support quoted references for | ||
229 | // older configurations that predated this convention. | ||
230 | traversal, travDiags := hcl.AbsTraversalForExpr(attr.Expr) | ||
231 | if travDiags.HasErrors() { | ||
232 | traversal = nil // in case we got any partial results | ||
233 | |||
234 | // Fall back on trying to parse as a string | ||
235 | var travStr string | ||
236 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &travStr) | ||
237 | if !valDiags.HasErrors() { | ||
238 | var strDiags hcl.Diagnostics | ||
239 | traversal, strDiags = hclsyntax.ParseTraversalAbs([]byte(travStr), "", hcl.Pos{}) | ||
240 | if strDiags.HasErrors() { | ||
241 | traversal = nil | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | // If we get out here with a nil traversal then we didn't | ||
247 | // succeed in processing the input. | ||
248 | if len(traversal) > 0 { | ||
249 | providerName := traversal.RootName() | ||
250 | alias := "" | ||
251 | if len(traversal) > 1 { | ||
252 | if getAttr, ok := traversal[1].(hcl.TraverseAttr); ok { | ||
253 | alias = getAttr.Name | ||
254 | } | ||
255 | } | ||
256 | r.Provider = ProviderRef{ | ||
257 | Name: providerName, | ||
258 | Alias: alias, | ||
259 | } | ||
260 | } else { | ||
261 | diags = append(diags, &hcl.Diagnostic{ | ||
262 | Severity: hcl.DiagError, | ||
263 | Summary: "Invalid provider reference", | ||
264 | Detail: "Provider argument requires a provider name followed by an optional alias, like \"aws.foo\".", | ||
265 | Subject: attr.Expr.Range().Ptr(), | ||
266 | }) | ||
267 | } | ||
268 | } else { | ||
269 | // If provider _isn't_ set then we'll infer it from the | ||
270 | // resource type. | ||
271 | r.Provider = ProviderRef{ | ||
272 | Name: resourceTypeDefaultProviderName(r.Type), | ||
273 | } | ||
274 | } | ||
275 | |||
276 | case "module": | ||
277 | |||
278 | content, _, contentDiags := block.Body.PartialContent(moduleCallSchema) | ||
279 | diags = append(diags, contentDiags...) | ||
280 | |||
281 | name := block.Labels[0] | ||
282 | mc := &ModuleCall{ | ||
283 | Name: block.Labels[0], | ||
284 | Pos: sourcePosHCL(block.DefRange), | ||
285 | } | ||
286 | |||
287 | // check if this is overriding an existing module | ||
288 | var origSource string | ||
289 | if origMod, exists := mod.ModuleCalls[name]; exists { | ||
290 | origSource = origMod.Source | ||
291 | } | ||
292 | |||
293 | mod.ModuleCalls[name] = mc | ||
294 | |||
295 | if attr, defined := content.Attributes["source"]; defined { | ||
296 | var source string | ||
297 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &source) | ||
298 | diags = append(diags, valDiags...) | ||
299 | mc.Source = source | ||
300 | } | ||
301 | |||
302 | if mc.Source == "" { | ||
303 | mc.Source = origSource | ||
304 | } | ||
305 | |||
306 | if attr, defined := content.Attributes["version"]; defined { | ||
307 | var version string | ||
308 | valDiags := gohcl.DecodeExpression(attr.Expr, nil, &version) | ||
309 | diags = append(diags, valDiags...) | ||
310 | mc.Version = version | ||
311 | } | ||
312 | |||
313 | default: | ||
314 | // Should never happen because our cases above should be | ||
315 | // exhaustive for our schema. | ||
316 | panic(fmt.Errorf("unhandled block type %q", block.Type)) | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | return mod, diagnosticsHCL(diags) | ||
322 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go new file mode 100644 index 0000000..86ffdf1 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/load_legacy.go | |||
@@ -0,0 +1,325 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | import ( | ||
4 | "io/ioutil" | ||
5 | "strings" | ||
6 | |||
7 | legacyhcl "github.com/hashicorp/hcl" | ||
8 | legacyast "github.com/hashicorp/hcl/hcl/ast" | ||
9 | ) | ||
10 | |||
11 | func loadModuleLegacyHCL(dir string) (*Module, Diagnostics) { | ||
12 | // This implementation is intentionally more quick-and-dirty than the | ||
13 | // main loader. In particular, it doesn't bother to keep careful track | ||
14 | // of multiple error messages because we always fall back on returning | ||
15 | // the main parser's error message if our fallback parsing produces | ||
16 | // an error, and thus the errors here are not seen by the end-caller. | ||
17 | mod := newModule(dir) | ||
18 | |||
19 | primaryPaths, diags := dirFiles(dir) | ||
20 | if diags.HasErrors() { | ||
21 | return mod, diagnosticsHCL(diags) | ||
22 | } | ||
23 | |||
24 | for _, filename := range primaryPaths { | ||
25 | src, err := ioutil.ReadFile(filename) | ||
26 | if err != nil { | ||
27 | return mod, diagnosticsErrorf("Error reading %s: %s", filename, err) | ||
28 | } | ||
29 | |||
30 | hclRoot, err := legacyhcl.Parse(string(src)) | ||
31 | if err != nil { | ||
32 | return mod, diagnosticsErrorf("Error parsing %s: %s", filename, err) | ||
33 | } | ||
34 | |||
35 | list, ok := hclRoot.Node.(*legacyast.ObjectList) | ||
36 | if !ok { | ||
37 | return mod, diagnosticsErrorf("Error parsing %s: no root object", filename) | ||
38 | } | ||
39 | |||
40 | for _, item := range list.Filter("terraform").Items { | ||
41 | if len(item.Keys) > 0 { | ||
42 | item = &legacyast.ObjectItem{ | ||
43 | Val: &legacyast.ObjectType{ | ||
44 | List: &legacyast.ObjectList{ | ||
45 | Items: []*legacyast.ObjectItem{item}, | ||
46 | }, | ||
47 | }, | ||
48 | } | ||
49 | } | ||
50 | |||
51 | type TerraformBlock struct { | ||
52 | RequiredVersion string `hcl:"required_version"` | ||
53 | } | ||
54 | var block TerraformBlock | ||
55 | err = legacyhcl.DecodeObject(&block, item.Val) | ||
56 | if err != nil { | ||
57 | return nil, diagnosticsErrorf("terraform block: %s", err) | ||
58 | } | ||
59 | |||
60 | if block.RequiredVersion != "" { | ||
61 | mod.RequiredCore = append(mod.RequiredCore, block.RequiredVersion) | ||
62 | } | ||
63 | } | ||
64 | |||
65 | if vars := list.Filter("variable"); len(vars.Items) > 0 { | ||
66 | vars = vars.Children() | ||
67 | type VariableBlock struct { | ||
68 | Type string `hcl:"type"` | ||
69 | Default interface{} | ||
70 | Description string | ||
71 | Fields []string `hcl:",decodedFields"` | ||
72 | } | ||
73 | |||
74 | for _, item := range vars.Items { | ||
75 | unwrapLegacyHCLObjectKeysFromJSON(item, 1) | ||
76 | |||
77 | if len(item.Keys) != 1 { | ||
78 | return nil, diagnosticsErrorf("variable block at %s has no label", item.Pos()) | ||
79 | } | ||
80 | |||
81 | name := item.Keys[0].Token.Value().(string) | ||
82 | |||
83 | var block VariableBlock | ||
84 | err := legacyhcl.DecodeObject(&block, item.Val) | ||
85 | if err != nil { | ||
86 | return nil, diagnosticsErrorf("invalid variable block at %s: %s", item.Pos(), err) | ||
87 | } | ||
88 | |||
89 | // Clean up legacy HCL decoding ambiguity by unwrapping list of maps | ||
90 | if ms, ok := block.Default.([]map[string]interface{}); ok { | ||
91 | def := make(map[string]interface{}) | ||
92 | for _, m := range ms { | ||
93 | for k, v := range m { | ||
94 | def[k] = v | ||
95 | } | ||
96 | } | ||
97 | block.Default = def | ||
98 | } | ||
99 | |||
100 | v := &Variable{ | ||
101 | Name: name, | ||
102 | Type: block.Type, | ||
103 | Description: block.Description, | ||
104 | Default: block.Default, | ||
105 | Pos: sourcePosLegacyHCL(item.Pos(), filename), | ||
106 | } | ||
107 | if _, exists := mod.Variables[name]; exists { | ||
108 | return nil, diagnosticsErrorf("duplicate variable block for %q", name) | ||
109 | } | ||
110 | mod.Variables[name] = v | ||
111 | |||
112 | } | ||
113 | } | ||
114 | |||
115 | if outputs := list.Filter("output"); len(outputs.Items) > 0 { | ||
116 | outputs = outputs.Children() | ||
117 | type OutputBlock struct { | ||
118 | Description string | ||
119 | } | ||
120 | |||
121 | for _, item := range outputs.Items { | ||
122 | unwrapLegacyHCLObjectKeysFromJSON(item, 1) | ||
123 | |||
124 | if len(item.Keys) != 1 { | ||
125 | return nil, diagnosticsErrorf("output block at %s has no label", item.Pos()) | ||
126 | } | ||
127 | |||
128 | name := item.Keys[0].Token.Value().(string) | ||
129 | |||
130 | var block OutputBlock | ||
131 | err := legacyhcl.DecodeObject(&block, item.Val) | ||
132 | if err != nil { | ||
133 | return nil, diagnosticsErrorf("invalid output block at %s: %s", item.Pos(), err) | ||
134 | } | ||
135 | |||
136 | o := &Output{ | ||
137 | Name: name, | ||
138 | Description: block.Description, | ||
139 | Pos: sourcePosLegacyHCL(item.Pos(), filename), | ||
140 | } | ||
141 | if _, exists := mod.Outputs[name]; exists { | ||
142 | return nil, diagnosticsErrorf("duplicate output block for %q", name) | ||
143 | } | ||
144 | mod.Outputs[name] = o | ||
145 | } | ||
146 | } | ||
147 | |||
148 | for _, blockType := range []string{"resource", "data"} { | ||
149 | if resources := list.Filter(blockType); len(resources.Items) > 0 { | ||
150 | resources = resources.Children() | ||
151 | type ResourceBlock struct { | ||
152 | Provider string | ||
153 | } | ||
154 | |||
155 | for _, item := range resources.Items { | ||
156 | unwrapLegacyHCLObjectKeysFromJSON(item, 2) | ||
157 | |||
158 | if len(item.Keys) != 2 { | ||
159 | return nil, diagnosticsErrorf("resource block at %s has wrong label count", item.Pos()) | ||
160 | } | ||
161 | |||
162 | typeName := item.Keys[0].Token.Value().(string) | ||
163 | name := item.Keys[1].Token.Value().(string) | ||
164 | var mode ResourceMode | ||
165 | var rMap map[string]*Resource | ||
166 | switch blockType { | ||
167 | case "resource": | ||
168 | mode = ManagedResourceMode | ||
169 | rMap = mod.ManagedResources | ||
170 | case "data": | ||
171 | mode = DataResourceMode | ||
172 | rMap = mod.DataResources | ||
173 | } | ||
174 | |||
175 | var block ResourceBlock | ||
176 | err := legacyhcl.DecodeObject(&block, item.Val) | ||
177 | if err != nil { | ||
178 | return nil, diagnosticsErrorf("invalid resource block at %s: %s", item.Pos(), err) | ||
179 | } | ||
180 | |||
181 | var providerName, providerAlias string | ||
182 | if dotPos := strings.IndexByte(block.Provider, '.'); dotPos != -1 { | ||
183 | providerName = block.Provider[:dotPos] | ||
184 | providerAlias = block.Provider[dotPos+1:] | ||
185 | } else { | ||
186 | providerName = block.Provider | ||
187 | } | ||
188 | if providerName == "" { | ||
189 | providerName = resourceTypeDefaultProviderName(typeName) | ||
190 | } | ||
191 | |||
192 | r := &Resource{ | ||
193 | Mode: mode, | ||
194 | Type: typeName, | ||
195 | Name: name, | ||
196 | Provider: ProviderRef{ | ||
197 | Name: providerName, | ||
198 | Alias: providerAlias, | ||
199 | }, | ||
200 | Pos: sourcePosLegacyHCL(item.Pos(), filename), | ||
201 | } | ||
202 | key := r.MapKey() | ||
203 | if _, exists := rMap[key]; exists { | ||
204 | return nil, diagnosticsErrorf("duplicate resource block for %q", key) | ||
205 | } | ||
206 | rMap[key] = r | ||
207 | } | ||
208 | } | ||
209 | |||
210 | } | ||
211 | |||
212 | if moduleCalls := list.Filter("module"); len(moduleCalls.Items) > 0 { | ||
213 | moduleCalls = moduleCalls.Children() | ||
214 | type ModuleBlock struct { | ||
215 | Source string | ||
216 | Version string | ||
217 | } | ||
218 | |||
219 | for _, item := range moduleCalls.Items { | ||
220 | unwrapLegacyHCLObjectKeysFromJSON(item, 1) | ||
221 | |||
222 | if len(item.Keys) != 1 { | ||
223 | return nil, diagnosticsErrorf("module block at %s has no label", item.Pos()) | ||
224 | } | ||
225 | |||
226 | name := item.Keys[0].Token.Value().(string) | ||
227 | |||
228 | var block ModuleBlock | ||
229 | err := legacyhcl.DecodeObject(&block, item.Val) | ||
230 | if err != nil { | ||
231 | return nil, diagnosticsErrorf("module block at %s: %s", item.Pos(), err) | ||
232 | } | ||
233 | |||
234 | mc := &ModuleCall{ | ||
235 | Name: name, | ||
236 | Source: block.Source, | ||
237 | Version: block.Version, | ||
238 | Pos: sourcePosLegacyHCL(item.Pos(), filename), | ||
239 | } | ||
240 | // it's possible this module call is from an override file | ||
241 | if origMod, exists := mod.ModuleCalls[name]; exists { | ||
242 | if mc.Source == "" { | ||
243 | mc.Source = origMod.Source | ||
244 | } | ||
245 | } | ||
246 | mod.ModuleCalls[name] = mc | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if providerConfigs := list.Filter("provider"); len(providerConfigs.Items) > 0 { | ||
251 | providerConfigs = providerConfigs.Children() | ||
252 | type ProviderBlock struct { | ||
253 | Version string | ||
254 | } | ||
255 | |||
256 | for _, item := range providerConfigs.Items { | ||
257 | unwrapLegacyHCLObjectKeysFromJSON(item, 1) | ||
258 | |||
259 | if len(item.Keys) != 1 { | ||
260 | return nil, diagnosticsErrorf("provider block at %s has no label", item.Pos()) | ||
261 | } | ||
262 | |||
263 | name := item.Keys[0].Token.Value().(string) | ||
264 | |||
265 | var block ProviderBlock | ||
266 | err := legacyhcl.DecodeObject(&block, item.Val) | ||
267 | if err != nil { | ||
268 | return nil, diagnosticsErrorf("invalid provider block at %s: %s", item.Pos(), err) | ||
269 | } | ||
270 | |||
271 | if block.Version != "" { | ||
272 | mod.RequiredProviders[name] = append(mod.RequiredProviders[name], block.Version) | ||
273 | } | ||
274 | |||
275 | // Even if there wasn't an explicit version required, we still | ||
276 | // need an entry in our map to signal the unversioned dependency. | ||
277 | if _, exists := mod.RequiredProviders[name]; !exists { | ||
278 | mod.RequiredProviders[name] = []string{} | ||
279 | } | ||
280 | |||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | return mod, nil | ||
286 | } | ||
287 | |||
288 | // unwrapLegacyHCLObjectKeysFromJSON cleans up an edge case that can occur when | ||
289 | // parsing JSON as input: if we're parsing JSON then directly nested | ||
290 | // items will show up as additional "keys". | ||
291 | // | ||
292 | // For objects that expect a fixed number of keys, this breaks the | ||
293 | // decoding process. This function unwraps the object into what it would've | ||
294 | // looked like if it came directly from HCL by specifying the number of keys | ||
295 | // you expect. | ||
296 | // | ||
297 | // Example: | ||
298 | // | ||
299 | // { "foo": { "baz": {} } } | ||
300 | // | ||
301 | // Will show up with Keys being: []string{"foo", "baz"} | ||
302 | // when we really just want the first two. This function will fix this. | ||
303 | func unwrapLegacyHCLObjectKeysFromJSON(item *legacyast.ObjectItem, depth int) { | ||
304 | if len(item.Keys) > depth && item.Keys[0].Token.JSON { | ||
305 | for len(item.Keys) > depth { | ||
306 | // Pop off the last key | ||
307 | n := len(item.Keys) | ||
308 | key := item.Keys[n-1] | ||
309 | item.Keys[n-1] = nil | ||
310 | item.Keys = item.Keys[:n-1] | ||
311 | |||
312 | // Wrap our value in a list | ||
313 | item.Val = &legacyast.ObjectType{ | ||
314 | List: &legacyast.ObjectList{ | ||
315 | Items: []*legacyast.ObjectItem{ | ||
316 | &legacyast.ObjectItem{ | ||
317 | Keys: []*legacyast.ObjectKey{key}, | ||
318 | Val: item.Val, | ||
319 | }, | ||
320 | }, | ||
321 | }, | ||
322 | } | ||
323 | } | ||
324 | } | ||
325 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go new file mode 100644 index 0000000..65ddb23 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module.go | |||
@@ -0,0 +1,35 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | // Module is the top-level type representing a parsed and processed Terraform | ||
4 | // module. | ||
5 | type Module struct { | ||
6 | // Path is the local filesystem directory where the module was loaded from. | ||
7 | Path string `json:"path"` | ||
8 | |||
9 | Variables map[string]*Variable `json:"variables"` | ||
10 | Outputs map[string]*Output `json:"outputs"` | ||
11 | |||
12 | RequiredCore []string `json:"required_core,omitempty"` | ||
13 | RequiredProviders map[string][]string `json:"required_providers"` | ||
14 | |||
15 | ManagedResources map[string]*Resource `json:"managed_resources"` | ||
16 | DataResources map[string]*Resource `json:"data_resources"` | ||
17 | ModuleCalls map[string]*ModuleCall `json:"module_calls"` | ||
18 | |||
19 | // Diagnostics records any errors and warnings that were detected during | ||
20 | // loading, primarily for inclusion in serialized forms of the module | ||
21 | // since this slice is also returned as a second argument from LoadModule. | ||
22 | Diagnostics Diagnostics `json:"diagnostics,omitempty"` | ||
23 | } | ||
24 | |||
25 | func newModule(path string) *Module { | ||
26 | return &Module{ | ||
27 | Path: path, | ||
28 | Variables: make(map[string]*Variable), | ||
29 | Outputs: make(map[string]*Output), | ||
30 | RequiredProviders: make(map[string][]string), | ||
31 | ManagedResources: make(map[string]*Resource), | ||
32 | DataResources: make(map[string]*Resource), | ||
33 | ModuleCalls: make(map[string]*ModuleCall), | ||
34 | } | ||
35 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go new file mode 100644 index 0000000..5e1e05a --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/module_call.go | |||
@@ -0,0 +1,11 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | // ModuleCall represents a "module" block within a module. That is, a | ||
4 | // declaration of a child module from inside its parent. | ||
5 | type ModuleCall struct { | ||
6 | Name string `json:"name"` | ||
7 | Source string `json:"source"` | ||
8 | Version string `json:"version,omitempty"` | ||
9 | |||
10 | Pos SourcePos `json:"pos"` | ||
11 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go new file mode 100644 index 0000000..890b25e --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/output.go | |||
@@ -0,0 +1,9 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | // Output represents a single output from a Terraform module. | ||
4 | type Output struct { | ||
5 | Name string `json:"name"` | ||
6 | Description string `json:"description,omitempty"` | ||
7 | |||
8 | Pos SourcePos `json:"pos"` | ||
9 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go new file mode 100644 index 0000000..d924837 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/provider_ref.go | |||
@@ -0,0 +1,9 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | // ProviderRef is a reference to a provider configuration within a module. | ||
4 | // It represents the contents of a "provider" argument in a resource, or | ||
5 | // a value in the "providers" map for a module call. | ||
6 | type ProviderRef struct { | ||
7 | Name string `json:"name"` | ||
8 | Alias string `json:"alias,omitempty"` // Empty if the default provider configuration is referenced | ||
9 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go new file mode 100644 index 0000000..401c8fc --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/resource.go | |||
@@ -0,0 +1,64 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | import ( | ||
4 | "fmt" | ||
5 | "strconv" | ||
6 | "strings" | ||
7 | ) | ||
8 | |||
9 | // Resource represents a single "resource" or "data" block within a module. | ||
10 | type Resource struct { | ||
11 | Mode ResourceMode `json:"mode"` | ||
12 | Type string `json:"type"` | ||
13 | Name string `json:"name"` | ||
14 | |||
15 | Provider ProviderRef `json:"provider"` | ||
16 | |||
17 | Pos SourcePos `json:"pos"` | ||
18 | } | ||
19 | |||
20 | // MapKey returns a string that can be used to uniquely identify the receiver | ||
21 | // in a map[string]*Resource. | ||
22 | func (r *Resource) MapKey() string { | ||
23 | switch r.Mode { | ||
24 | case ManagedResourceMode: | ||
25 | return fmt.Sprintf("%s.%s", r.Type, r.Name) | ||
26 | case DataResourceMode: | ||
27 | return fmt.Sprintf("data.%s.%s", r.Type, r.Name) | ||
28 | default: | ||
29 | // should never happen | ||
30 | return fmt.Sprintf("[invalid_mode!].%s.%s", r.Type, r.Name) | ||
31 | } | ||
32 | } | ||
33 | |||
34 | // ResourceMode represents the "mode" of a resource, which is used to | ||
35 | // distinguish between managed resources ("resource" blocks in config) and | ||
36 | // data resources ("data" blocks in config). | ||
37 | type ResourceMode rune | ||
38 | |||
39 | const InvalidResourceMode ResourceMode = 0 | ||
40 | const ManagedResourceMode ResourceMode = 'M' | ||
41 | const DataResourceMode ResourceMode = 'D' | ||
42 | |||
43 | func (m ResourceMode) String() string { | ||
44 | switch m { | ||
45 | case ManagedResourceMode: | ||
46 | return "managed" | ||
47 | case DataResourceMode: | ||
48 | return "data" | ||
49 | default: | ||
50 | return "" | ||
51 | } | ||
52 | } | ||
53 | |||
54 | // MarshalJSON implements encoding/json.Marshaler. | ||
55 | func (m ResourceMode) MarshalJSON() ([]byte, error) { | ||
56 | return []byte(strconv.Quote(m.String())), nil | ||
57 | } | ||
58 | |||
59 | func resourceTypeDefaultProviderName(typeName string) string { | ||
60 | if underPos := strings.IndexByte(typeName, '_'); underPos != -1 { | ||
61 | return typeName[:underPos] | ||
62 | } | ||
63 | return typeName | ||
64 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go new file mode 100644 index 0000000..3af742f --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/schema.go | |||
@@ -0,0 +1,106 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | import ( | ||
4 | "github.com/hashicorp/hcl2/hcl" | ||
5 | ) | ||
6 | |||
7 | var rootSchema = &hcl.BodySchema{ | ||
8 | Blocks: []hcl.BlockHeaderSchema{ | ||
9 | { | ||
10 | Type: "terraform", | ||
11 | LabelNames: nil, | ||
12 | }, | ||
13 | { | ||
14 | Type: "variable", | ||
15 | LabelNames: []string{"name"}, | ||
16 | }, | ||
17 | { | ||
18 | Type: "output", | ||
19 | LabelNames: []string{"name"}, | ||
20 | }, | ||
21 | { | ||
22 | Type: "provider", | ||
23 | LabelNames: []string{"name"}, | ||
24 | }, | ||
25 | { | ||
26 | Type: "resource", | ||
27 | LabelNames: []string{"type", "name"}, | ||
28 | }, | ||
29 | { | ||
30 | Type: "data", | ||
31 | LabelNames: []string{"type", "name"}, | ||
32 | }, | ||
33 | { | ||
34 | Type: "module", | ||
35 | LabelNames: []string{"name"}, | ||
36 | }, | ||
37 | }, | ||
38 | } | ||
39 | |||
40 | var terraformBlockSchema = &hcl.BodySchema{ | ||
41 | Attributes: []hcl.AttributeSchema{ | ||
42 | { | ||
43 | Name: "required_version", | ||
44 | }, | ||
45 | }, | ||
46 | Blocks: []hcl.BlockHeaderSchema{ | ||
47 | { | ||
48 | Type: "required_providers", | ||
49 | }, | ||
50 | }, | ||
51 | } | ||
52 | |||
53 | var providerConfigSchema = &hcl.BodySchema{ | ||
54 | Attributes: []hcl.AttributeSchema{ | ||
55 | { | ||
56 | Name: "version", | ||
57 | }, | ||
58 | { | ||
59 | Name: "alias", | ||
60 | }, | ||
61 | }, | ||
62 | } | ||
63 | |||
64 | var variableSchema = &hcl.BodySchema{ | ||
65 | Attributes: []hcl.AttributeSchema{ | ||
66 | { | ||
67 | Name: "type", | ||
68 | }, | ||
69 | { | ||
70 | Name: "description", | ||
71 | }, | ||
72 | { | ||
73 | Name: "default", | ||
74 | }, | ||
75 | }, | ||
76 | } | ||
77 | |||
78 | var outputSchema = &hcl.BodySchema{ | ||
79 | Attributes: []hcl.AttributeSchema{ | ||
80 | { | ||
81 | Name: "description", | ||
82 | }, | ||
83 | }, | ||
84 | } | ||
85 | |||
86 | var moduleCallSchema = &hcl.BodySchema{ | ||
87 | Attributes: []hcl.AttributeSchema{ | ||
88 | { | ||
89 | Name: "source", | ||
90 | }, | ||
91 | { | ||
92 | Name: "version", | ||
93 | }, | ||
94 | { | ||
95 | Name: "providers", | ||
96 | }, | ||
97 | }, | ||
98 | } | ||
99 | |||
100 | var resourceSchema = &hcl.BodySchema{ | ||
101 | Attributes: []hcl.AttributeSchema{ | ||
102 | { | ||
103 | Name: "provider", | ||
104 | }, | ||
105 | }, | ||
106 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go new file mode 100644 index 0000000..883914e --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/source_pos.go | |||
@@ -0,0 +1,50 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | import ( | ||
4 | legacyhcltoken "github.com/hashicorp/hcl/hcl/token" | ||
5 | "github.com/hashicorp/hcl2/hcl" | ||
6 | ) | ||
7 | |||
8 | // SourcePos is a pointer to a particular location in a source file. | ||
9 | // | ||
10 | // This type is embedded into other structs to allow callers to locate the | ||
11 | // definition of each described module element. The SourcePos of an element | ||
12 | // is usually the first line of its definition, although the definition can | ||
13 | // be a little "fuzzy" with JSON-based config files. | ||
14 | type SourcePos struct { | ||
15 | Filename string `json:"filename"` | ||
16 | Line int `json:"line"` | ||
17 | } | ||
18 | |||
19 | func sourcePos(filename string, line int) SourcePos { | ||
20 | return SourcePos{ | ||
21 | Filename: filename, | ||
22 | Line: line, | ||
23 | } | ||
24 | } | ||
25 | |||
26 | func sourcePosHCL(rng hcl.Range) SourcePos { | ||
27 | // We intentionally throw away the column information here because | ||
28 | // current and legacy HCL both disagree on the definition of a column | ||
29 | // and so a line-only reference is the best granularity we can do | ||
30 | // such that the result is consistent between both parsers. | ||
31 | return SourcePos{ | ||
32 | Filename: rng.Filename, | ||
33 | Line: rng.Start.Line, | ||
34 | } | ||
35 | } | ||
36 | |||
37 | func sourcePosLegacyHCL(pos legacyhcltoken.Pos, filename string) SourcePos { | ||
38 | useFilename := pos.Filename | ||
39 | // We'll try to use the filename given in legacy HCL position, but | ||
40 | // in practice there's no way to actually get this populated via | ||
41 | // the HCL API so it's usually empty except in some specialized | ||
42 | // situations, such as positions in error objects. | ||
43 | if useFilename == "" { | ||
44 | useFilename = filename | ||
45 | } | ||
46 | return SourcePos{ | ||
47 | Filename: useFilename, | ||
48 | Line: pos.Line, | ||
49 | } | ||
50 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go new file mode 100644 index 0000000..0f73fc9 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform-config-inspect/tfconfig/variable.go | |||
@@ -0,0 +1,16 @@ | |||
1 | package tfconfig | ||
2 | |||
3 | // Variable represents a single variable from a Terraform module. | ||
4 | type Variable struct { | ||
5 | Name string `json:"name"` | ||
6 | Type string `json:"type,omitempty"` | ||
7 | Description string `json:"description,omitempty"` | ||
8 | |||
9 | // Default is an approximate representation of the default value in | ||
10 | // the native Go type system. The conversion from the value given in | ||
11 | // configuration may be slightly lossy. Only values that can be | ||
12 | // serialized by json.Marshal will be included here. | ||
13 | Default interface{} `json:"default,omitempty"` | ||
14 | |||
15 | Pos SourcePos `json:"pos"` | ||
16 | } | ||