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 }