]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/hcl2/hcl/hclsyntax/structure.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / hcl2 / hcl / hclsyntax / structure.go
1 package hclsyntax
2
3 import (
4 "fmt"
5 "strings"
6
7 "github.com/hashicorp/hcl2/hcl"
8 )
9
10 // AsHCLBlock returns the block data expressed as a *hcl.Block.
11 func (b *Block) AsHCLBlock() *hcl.Block {
12 if b == nil {
13 return nil
14 }
15
16 lastHeaderRange := b.TypeRange
17 if len(b.LabelRanges) > 0 {
18 lastHeaderRange = b.LabelRanges[len(b.LabelRanges)-1]
19 }
20
21 return &hcl.Block{
22 Type: b.Type,
23 Labels: b.Labels,
24 Body: b.Body,
25
26 DefRange: hcl.RangeBetween(b.TypeRange, lastHeaderRange),
27 TypeRange: b.TypeRange,
28 LabelRanges: b.LabelRanges,
29 }
30 }
31
32 // Body is the implementation of hcl.Body for the HCL native syntax.
33 type Body struct {
34 Attributes Attributes
35 Blocks Blocks
36
37 // These are used with PartialContent to produce a "remaining items"
38 // body to return. They are nil on all bodies fresh out of the parser.
39 hiddenAttrs map[string]struct{}
40 hiddenBlocks map[string]struct{}
41
42 SrcRange hcl.Range
43 EndRange hcl.Range // Final token of the body, for reporting missing items
44 }
45
46 // Assert that *Body implements hcl.Body
47 var assertBodyImplBody hcl.Body = &Body{}
48
49 func (b *Body) walkChildNodes(w internalWalkFunc) {
50 w(b.Attributes)
51 w(b.Blocks)
52 }
53
54 func (b *Body) Range() hcl.Range {
55 return b.SrcRange
56 }
57
58 func (b *Body) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
59 content, remainHCL, diags := b.PartialContent(schema)
60
61 // No we'll see if anything actually remains, to produce errors about
62 // extraneous items.
63 remain := remainHCL.(*Body)
64
65 for name, attr := range b.Attributes {
66 if _, hidden := remain.hiddenAttrs[name]; !hidden {
67 var suggestions []string
68 for _, attrS := range schema.Attributes {
69 if _, defined := content.Attributes[attrS.Name]; defined {
70 continue
71 }
72 suggestions = append(suggestions, attrS.Name)
73 }
74 suggestion := nameSuggestion(name, suggestions)
75 if suggestion != "" {
76 suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
77 } else {
78 // Is there a block of the same name?
79 for _, blockS := range schema.Blocks {
80 if blockS.Type == name {
81 suggestion = fmt.Sprintf(" Did you mean to define a block of type %q?", name)
82 break
83 }
84 }
85 }
86
87 diags = append(diags, &hcl.Diagnostic{
88 Severity: hcl.DiagError,
89 Summary: "Unsupported argument",
90 Detail: fmt.Sprintf("An argument named %q is not expected here.%s", name, suggestion),
91 Subject: &attr.NameRange,
92 })
93 }
94 }
95
96 for _, block := range b.Blocks {
97 blockTy := block.Type
98 if _, hidden := remain.hiddenBlocks[blockTy]; !hidden {
99 var suggestions []string
100 for _, blockS := range schema.Blocks {
101 suggestions = append(suggestions, blockS.Type)
102 }
103 suggestion := nameSuggestion(blockTy, suggestions)
104 if suggestion != "" {
105 suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
106 } else {
107 // Is there an attribute of the same name?
108 for _, attrS := range schema.Attributes {
109 if attrS.Name == blockTy {
110 suggestion = fmt.Sprintf(" Did you mean to define argument %q? If so, use the equals sign to assign it a value.", blockTy)
111 break
112 }
113 }
114 }
115
116 diags = append(diags, &hcl.Diagnostic{
117 Severity: hcl.DiagError,
118 Summary: "Unsupported block type",
119 Detail: fmt.Sprintf("Blocks of type %q are not expected here.%s", blockTy, suggestion),
120 Subject: &block.TypeRange,
121 })
122 }
123 }
124
125 return content, diags
126 }
127
128 func (b *Body) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
129 attrs := make(hcl.Attributes)
130 var blocks hcl.Blocks
131 var diags hcl.Diagnostics
132 hiddenAttrs := make(map[string]struct{})
133 hiddenBlocks := make(map[string]struct{})
134
135 if b.hiddenAttrs != nil {
136 for k, v := range b.hiddenAttrs {
137 hiddenAttrs[k] = v
138 }
139 }
140 if b.hiddenBlocks != nil {
141 for k, v := range b.hiddenBlocks {
142 hiddenBlocks[k] = v
143 }
144 }
145
146 for _, attrS := range schema.Attributes {
147 name := attrS.Name
148 attr, exists := b.Attributes[name]
149 _, hidden := hiddenAttrs[name]
150 if hidden || !exists {
151 if attrS.Required {
152 diags = append(diags, &hcl.Diagnostic{
153 Severity: hcl.DiagError,
154 Summary: "Missing required argument",
155 Detail: fmt.Sprintf("The argument %q is required, but no definition was found.", attrS.Name),
156 Subject: b.MissingItemRange().Ptr(),
157 })
158 }
159 continue
160 }
161
162 hiddenAttrs[name] = struct{}{}
163 attrs[name] = attr.AsHCLAttribute()
164 }
165
166 blocksWanted := make(map[string]hcl.BlockHeaderSchema)
167 for _, blockS := range schema.Blocks {
168 blocksWanted[blockS.Type] = blockS
169 }
170
171 for _, block := range b.Blocks {
172 if _, hidden := hiddenBlocks[block.Type]; hidden {
173 continue
174 }
175 blockS, wanted := blocksWanted[block.Type]
176 if !wanted {
177 continue
178 }
179
180 if len(block.Labels) > len(blockS.LabelNames) {
181 name := block.Type
182 if len(blockS.LabelNames) == 0 {
183 diags = append(diags, &hcl.Diagnostic{
184 Severity: hcl.DiagError,
185 Summary: fmt.Sprintf("Extraneous label for %s", name),
186 Detail: fmt.Sprintf(
187 "No labels are expected for %s blocks.", name,
188 ),
189 Subject: block.LabelRanges[0].Ptr(),
190 Context: hcl.RangeBetween(block.TypeRange, block.OpenBraceRange).Ptr(),
191 })
192 } else {
193 diags = append(diags, &hcl.Diagnostic{
194 Severity: hcl.DiagError,
195 Summary: fmt.Sprintf("Extraneous label for %s", name),
196 Detail: fmt.Sprintf(
197 "Only %d labels (%s) are expected for %s blocks.",
198 len(blockS.LabelNames), strings.Join(blockS.LabelNames, ", "), name,
199 ),
200 Subject: block.LabelRanges[len(blockS.LabelNames)].Ptr(),
201 Context: hcl.RangeBetween(block.TypeRange, block.OpenBraceRange).Ptr(),
202 })
203 }
204 continue
205 }
206
207 if len(block.Labels) < len(blockS.LabelNames) {
208 name := block.Type
209 diags = append(diags, &hcl.Diagnostic{
210 Severity: hcl.DiagError,
211 Summary: fmt.Sprintf("Missing %s for %s", blockS.LabelNames[len(block.Labels)], name),
212 Detail: fmt.Sprintf(
213 "All %s blocks must have %d labels (%s).",
214 name, len(blockS.LabelNames), strings.Join(blockS.LabelNames, ", "),
215 ),
216 Subject: &block.OpenBraceRange,
217 Context: hcl.RangeBetween(block.TypeRange, block.OpenBraceRange).Ptr(),
218 })
219 continue
220 }
221
222 blocks = append(blocks, block.AsHCLBlock())
223 }
224
225 // We hide blocks only after we've processed all of them, since otherwise
226 // we can't process more than one of the same type.
227 for _, blockS := range schema.Blocks {
228 hiddenBlocks[blockS.Type] = struct{}{}
229 }
230
231 remain := &Body{
232 Attributes: b.Attributes,
233 Blocks: b.Blocks,
234
235 hiddenAttrs: hiddenAttrs,
236 hiddenBlocks: hiddenBlocks,
237
238 SrcRange: b.SrcRange,
239 EndRange: b.EndRange,
240 }
241
242 return &hcl.BodyContent{
243 Attributes: attrs,
244 Blocks: blocks,
245
246 MissingItemRange: b.MissingItemRange(),
247 }, remain, diags
248 }
249
250 func (b *Body) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
251 attrs := make(hcl.Attributes)
252 var diags hcl.Diagnostics
253
254 if len(b.Blocks) > 0 {
255 example := b.Blocks[0]
256 diags = append(diags, &hcl.Diagnostic{
257 Severity: hcl.DiagError,
258 Summary: fmt.Sprintf("Unexpected %q block", example.Type),
259 Detail: "Blocks are not allowed here.",
260 Subject: &example.TypeRange,
261 })
262 // we will continue processing anyway, and return the attributes
263 // we are able to find so that certain analyses can still be done
264 // in the face of errors.
265 }
266
267 if b.Attributes == nil {
268 return attrs, diags
269 }
270
271 for name, attr := range b.Attributes {
272 if _, hidden := b.hiddenAttrs[name]; hidden {
273 continue
274 }
275 attrs[name] = attr.AsHCLAttribute()
276 }
277
278 return attrs, diags
279 }
280
281 func (b *Body) MissingItemRange() hcl.Range {
282 return hcl.Range{
283 Filename: b.SrcRange.Filename,
284 Start: b.SrcRange.Start,
285 End: b.SrcRange.Start,
286 }
287 }
288
289 // Attributes is the collection of attribute definitions within a body.
290 type Attributes map[string]*Attribute
291
292 func (a Attributes) walkChildNodes(w internalWalkFunc) {
293 for _, attr := range a {
294 w(attr)
295 }
296 }
297
298 // Range returns the range of some arbitrary point within the set of
299 // attributes, or an invalid range if there are no attributes.
300 //
301 // This is provided only to complete the Node interface, but has no practical
302 // use.
303 func (a Attributes) Range() hcl.Range {
304 // An attributes doesn't really have a useful range to report, since
305 // it's just a grouping construct. So we'll arbitrarily take the
306 // range of one of the attributes, or produce an invalid range if we have
307 // none. In practice, there's little reason to ask for the range of
308 // an Attributes.
309 for _, attr := range a {
310 return attr.Range()
311 }
312 return hcl.Range{
313 Filename: "<unknown>",
314 }
315 }
316
317 // Attribute represents a single attribute definition within a body.
318 type Attribute struct {
319 Name string
320 Expr Expression
321
322 SrcRange hcl.Range
323 NameRange hcl.Range
324 EqualsRange hcl.Range
325 }
326
327 func (a *Attribute) walkChildNodes(w internalWalkFunc) {
328 w(a.Expr)
329 }
330
331 func (a *Attribute) Range() hcl.Range {
332 return a.SrcRange
333 }
334
335 // AsHCLAttribute returns the block data expressed as a *hcl.Attribute.
336 func (a *Attribute) AsHCLAttribute() *hcl.Attribute {
337 if a == nil {
338 return nil
339 }
340 return &hcl.Attribute{
341 Name: a.Name,
342 Expr: a.Expr,
343
344 Range: a.SrcRange,
345 NameRange: a.NameRange,
346 }
347 }
348
349 // Blocks is the list of nested blocks within a body.
350 type Blocks []*Block
351
352 func (bs Blocks) walkChildNodes(w internalWalkFunc) {
353 for _, block := range bs {
354 w(block)
355 }
356 }
357
358 // Range returns the range of some arbitrary point within the list of
359 // blocks, or an invalid range if there are no blocks.
360 //
361 // This is provided only to complete the Node interface, but has no practical
362 // use.
363 func (bs Blocks) Range() hcl.Range {
364 if len(bs) > 0 {
365 return bs[0].Range()
366 }
367 return hcl.Range{
368 Filename: "<unknown>",
369 }
370 }
371
372 // Block represents a nested block structure
373 type Block struct {
374 Type string
375 Labels []string
376 Body *Body
377
378 TypeRange hcl.Range
379 LabelRanges []hcl.Range
380 OpenBraceRange hcl.Range
381 CloseBraceRange hcl.Range
382 }
383
384 func (b *Block) walkChildNodes(w internalWalkFunc) {
385 w(b.Body)
386 }
387
388 func (b *Block) Range() hcl.Range {
389 return hcl.RangeBetween(b.TypeRange, b.CloseBraceRange)
390 }
391
392 func (b *Block) DefRange() hcl.Range {
393 return hcl.RangeBetween(b.TypeRange, b.OpenBraceRange)
394 }