]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | package configschema |
2 | ||
3 | import ( | |
4 | "github.com/hashicorp/hcl2/hcldec" | |
5 | "github.com/zclconf/go-cty/cty" | |
6 | ) | |
7 | ||
8 | var mapLabelNames = []string{"key"} | |
9 | ||
10 | // DecoderSpec returns a hcldec.Spec that can be used to decode a HCL Body | |
11 | // using the facilities in the hcldec package. | |
12 | // | |
13 | // The returned specification is guaranteed to return a value of the same type | |
14 | // returned by method ImpliedType, but it may contain null or unknown values if | |
15 | // any of the block attributes are defined as optional and/or computed | |
16 | // respectively. | |
17 | func (b *Block) DecoderSpec() hcldec.Spec { | |
18 | ret := hcldec.ObjectSpec{} | |
19 | if b == nil { | |
20 | return ret | |
21 | } | |
22 | ||
23 | for name, attrS := range b.Attributes { | |
24 | switch { | |
25 | case attrS.Computed && attrS.Optional: | |
26 | // In this special case we use an unknown value as a default | |
27 | // to get the intended behavior that the result is computed | |
28 | // unless it has been explicitly set in config. | |
29 | ret[name] = &hcldec.DefaultSpec{ | |
30 | Primary: &hcldec.AttrSpec{ | |
31 | Name: name, | |
32 | Type: attrS.Type, | |
33 | }, | |
34 | Default: &hcldec.LiteralSpec{ | |
35 | Value: cty.UnknownVal(attrS.Type), | |
36 | }, | |
37 | } | |
38 | case attrS.Computed: | |
39 | ret[name] = &hcldec.LiteralSpec{ | |
40 | Value: cty.UnknownVal(attrS.Type), | |
41 | } | |
42 | default: | |
43 | ret[name] = &hcldec.AttrSpec{ | |
44 | Name: name, | |
45 | Type: attrS.Type, | |
46 | Required: attrS.Required, | |
47 | } | |
48 | } | |
49 | } | |
50 | ||
51 | for name, blockS := range b.BlockTypes { | |
52 | if _, exists := ret[name]; exists { | |
53 | // This indicates an invalid schema, since it's not valid to | |
54 | // define both an attribute and a block type of the same name. | |
55 | // However, we don't raise this here since it's checked by | |
56 | // InternalValidate. | |
57 | continue | |
58 | } | |
59 | ||
60 | childSpec := blockS.Block.DecoderSpec() | |
61 | ||
62 | switch blockS.Nesting { | |
63 | case NestingSingle: | |
64 | ret[name] = &hcldec.BlockSpec{ | |
65 | TypeName: name, | |
66 | Nested: childSpec, | |
67 | Required: blockS.MinItems == 1 && blockS.MaxItems >= 1, | |
68 | } | |
69 | case NestingList: | |
70 | ret[name] = &hcldec.BlockListSpec{ | |
71 | TypeName: name, | |
72 | Nested: childSpec, | |
73 | MinItems: blockS.MinItems, | |
74 | MaxItems: blockS.MaxItems, | |
75 | } | |
76 | case NestingSet: | |
77 | ret[name] = &hcldec.BlockSetSpec{ | |
78 | TypeName: name, | |
79 | Nested: childSpec, | |
80 | MinItems: blockS.MinItems, | |
81 | MaxItems: blockS.MaxItems, | |
82 | } | |
83 | case NestingMap: | |
84 | ret[name] = &hcldec.BlockMapSpec{ | |
85 | TypeName: name, | |
86 | Nested: childSpec, | |
87 | LabelNames: mapLabelNames, | |
88 | } | |
89 | default: | |
90 | // Invalid nesting type is just ignored. It's checked by | |
91 | // InternalValidate. | |
92 | continue | |
93 | } | |
94 | } | |
95 | ||
96 | return ret | |
97 | } |