1package hcl2shim
2
3import (
4	"fmt"
5
6	hcl2 "github.com/hashicorp/hcl/v2"
7)
8
9// SingleAttrBody is a weird implementation of hcl2.Body that acts as if
10// it has a single attribute whose value is the given expression.
11//
12// This is used to shim Resource.RawCount and Output.RawConfig to behave
13// more like they do in the old HCL loader.
14type SingleAttrBody struct {
15	Name string
16	Expr hcl2.Expression
17}
18
19var _ hcl2.Body = SingleAttrBody{}
20
21func (b SingleAttrBody) Content(schema *hcl2.BodySchema) (*hcl2.BodyContent, hcl2.Diagnostics) {
22	content, all, diags := b.content(schema)
23	if !all {
24		// This should never happen because this body implementation should only
25		// be used by code that is aware that it's using a single-attr body.
26		diags = append(diags, &hcl2.Diagnostic{
27			Severity: hcl2.DiagError,
28			Summary:  "Invalid attribute",
29			Detail:   fmt.Sprintf("The correct attribute name is %q.", b.Name),
30			Subject:  b.Expr.Range().Ptr(),
31		})
32	}
33	return content, diags
34}
35
36func (b SingleAttrBody) PartialContent(schema *hcl2.BodySchema) (*hcl2.BodyContent, hcl2.Body, hcl2.Diagnostics) {
37	content, all, diags := b.content(schema)
38	var remain hcl2.Body
39	if all {
40		// If the request matched the one attribute we represent, then the
41		// remaining body is empty.
42		remain = hcl2.EmptyBody()
43	} else {
44		remain = b
45	}
46	return content, remain, diags
47}
48
49func (b SingleAttrBody) content(schema *hcl2.BodySchema) (*hcl2.BodyContent, bool, hcl2.Diagnostics) {
50	ret := &hcl2.BodyContent{}
51	all := false
52	var diags hcl2.Diagnostics
53
54	for _, attrS := range schema.Attributes {
55		if attrS.Name == b.Name {
56			attrs, _ := b.JustAttributes()
57			ret.Attributes = attrs
58			all = true
59		} else if attrS.Required {
60			diags = append(diags, &hcl2.Diagnostic{
61				Severity: hcl2.DiagError,
62				Summary:  "Missing attribute",
63				Detail:   fmt.Sprintf("The attribute %q is required.", attrS.Name),
64				Subject:  b.Expr.Range().Ptr(),
65			})
66		}
67	}
68
69	return ret, all, diags
70}
71
72func (b SingleAttrBody) JustAttributes() (hcl2.Attributes, hcl2.Diagnostics) {
73	return hcl2.Attributes{
74		b.Name: {
75			Expr:      b.Expr,
76			Name:      b.Name,
77			NameRange: b.Expr.Range(),
78			Range:     b.Expr.Range(),
79		},
80	}, nil
81}
82
83func (b SingleAttrBody) MissingItemRange() hcl2.Range {
84	return b.Expr.Range()
85}
86