]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | package hcldec |
2 | ||
3 | import ( | |
4 | "github.com/hashicorp/hcl2/hcl" | |
5 | "github.com/zclconf/go-cty/cty" | |
6 | ) | |
7 | ||
8 | // Decode interprets the given body using the given specification and returns | |
9 | // the resulting value. If the given body is not valid per the spec, error | |
10 | // diagnostics are returned and the returned value is likely to be incomplete. | |
11 | // | |
12 | // The ctx argument may be nil, in which case any references to variables or | |
13 | // functions will produce error diagnostics. | |
14 | func Decode(body hcl.Body, spec Spec, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { | |
15 | val, _, diags := decode(body, nil, ctx, spec, false) | |
16 | return val, diags | |
17 | } | |
18 | ||
19 | // PartialDecode is like Decode except that it permits "leftover" items in | |
20 | // the top-level body, which are returned as a new body to allow for | |
21 | // further processing. | |
22 | // | |
23 | // Any descendent block bodies are _not_ decoded partially and thus must | |
24 | // be fully described by the given specification. | |
25 | func PartialDecode(body hcl.Body, spec Spec, ctx *hcl.EvalContext) (cty.Value, hcl.Body, hcl.Diagnostics) { | |
26 | return decode(body, nil, ctx, spec, true) | |
27 | } | |
28 | ||
29 | // ImpliedType returns the value type that should result from decoding the | |
30 | // given spec. | |
31 | func ImpliedType(spec Spec) cty.Type { | |
32 | return impliedType(spec) | |
33 | } | |
34 | ||
35 | // SourceRange interprets the given body using the given specification and | |
36 | // then returns the source range of the value that would be used to | |
37 | // fulfill the spec. | |
38 | // | |
39 | // This can be used if application-level validation detects value errors, to | |
40 | // obtain a reasonable SourceRange to use for generated diagnostics. It works | |
41 | // best when applied to specific body items (e.g. using AttrSpec, BlockSpec, ...) | |
42 | // as opposed to entire bodies using ObjectSpec, TupleSpec. The result will | |
43 | // be less useful the broader the specification, so e.g. a spec that returns | |
44 | // the entirety of all of the blocks of a given type is likely to be | |
45 | // _particularly_ arbitrary and useless. | |
46 | // | |
47 | // If the given body is not valid per the given spec, the result is best-effort | |
48 | // and may not actually be something ideal. It's expected that an application | |
49 | // will already have used Decode or PartialDecode earlier and thus had an | |
50 | // opportunity to detect and report spec violations. | |
51 | func SourceRange(body hcl.Body, spec Spec) hcl.Range { | |
52 | return sourceRange(body, nil, spec) | |
53 | } | |
54 | ||
55 | // ChildBlockTypes returns a map of all of the child block types declared | |
56 | // by the given spec, with block type names as keys and the associated | |
57 | // nested body specs as values. | |
58 | func ChildBlockTypes(spec Spec) map[string]Spec { | |
59 | ret := map[string]Spec{} | |
60 | ||
61 | // visitSameBodyChildren walks through the spec structure, calling | |
62 | // the given callback for each descendent spec encountered. We are | |
63 | // interested in the specs that reference attributes and blocks. | |
64 | var visit visitFunc | |
65 | visit = func(s Spec) { | |
66 | if bs, ok := s.(blockSpec); ok { | |
67 | for _, blockS := range bs.blockHeaderSchemata() { | |
107c1cdb ND |
68 | nested := bs.nestedSpec() |
69 | if nested != nil { // nil can be returned to dynamically opt out of this interface | |
70 | ret[blockS.Type] = nested | |
71 | } | |
15c0b25d AP |
72 | } |
73 | } | |
74 | ||
75 | s.visitSameBodyChildren(visit) | |
76 | } | |
77 | ||
78 | visit(spec) | |
79 | ||
80 | return ret | |
81 | } |