| package hcldec |
| |
| import ( |
| "github.com/hashicorp/hcl/v2" |
| "github.com/zclconf/go-cty/cty" |
| ) |
| |
| // Decode interprets the given body using the given specification and returns |
| // the resulting value. If the given body is not valid per the spec, error |
| // diagnostics are returned and the returned value is likely to be incomplete. |
| // |
| // The ctx argument may be nil, in which case any references to variables or |
| // functions will produce error diagnostics. |
| func Decode(body hcl.Body, spec Spec, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) { |
| val, _, diags := decode(body, nil, ctx, spec, false) |
| return val, diags |
| } |
| |
| // PartialDecode is like Decode except that it permits "leftover" items in |
| // the top-level body, which are returned as a new body to allow for |
| // further processing. |
| // |
| // Any descendent block bodies are _not_ decoded partially and thus must |
| // be fully described by the given specification. |
| func PartialDecode(body hcl.Body, spec Spec, ctx *hcl.EvalContext) (cty.Value, hcl.Body, hcl.Diagnostics) { |
| return decode(body, nil, ctx, spec, true) |
| } |
| |
| // ImpliedType returns the value type that should result from decoding the |
| // given spec. |
| func ImpliedType(spec Spec) cty.Type { |
| return impliedType(spec) |
| } |
| |
| // SourceRange interprets the given body using the given specification and |
| // then returns the source range of the value that would be used to |
| // fulfill the spec. |
| // |
| // This can be used if application-level validation detects value errors, to |
| // obtain a reasonable SourceRange to use for generated diagnostics. It works |
| // best when applied to specific body items (e.g. using AttrSpec, BlockSpec, ...) |
| // as opposed to entire bodies using ObjectSpec, TupleSpec. The result will |
| // be less useful the broader the specification, so e.g. a spec that returns |
| // the entirety of all of the blocks of a given type is likely to be |
| // _particularly_ arbitrary and useless. |
| // |
| // If the given body is not valid per the given spec, the result is best-effort |
| // and may not actually be something ideal. It's expected that an application |
| // will already have used Decode or PartialDecode earlier and thus had an |
| // opportunity to detect and report spec violations. |
| func SourceRange(body hcl.Body, spec Spec) hcl.Range { |
| return sourceRange(body, nil, spec) |
| } |
| |
| // ChildBlockTypes returns a map of all of the child block types declared |
| // by the given spec, with block type names as keys and the associated |
| // nested body specs as values. |
| func ChildBlockTypes(spec Spec) map[string]Spec { |
| ret := map[string]Spec{} |
| |
| // visitSameBodyChildren walks through the spec structure, calling |
| // the given callback for each descendent spec encountered. We are |
| // interested in the specs that reference attributes and blocks. |
| var visit visitFunc |
| visit = func(s Spec) { |
| if bs, ok := s.(blockSpec); ok { |
| for _, blockS := range bs.blockHeaderSchemata() { |
| nested := bs.nestedSpec() |
| if nested != nil { // nil can be returned to dynamically opt out of this interface |
| ret[blockS.Type] = nested |
| } |
| } |
| } |
| |
| s.visitSameBodyChildren(visit) |
| } |
| |
| visit(spec) |
| |
| return ret |
| } |