2017-09-11 23:40:37 +00:00
|
|
|
package hcl
|
2017-05-14 00:44:11 +00:00
|
|
|
|
|
|
|
import (
|
2017-05-28 00:35:44 +00:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
2017-05-14 00:44:11 +00:00
|
|
|
)
|
|
|
|
|
2017-09-12 01:36:56 +00:00
|
|
|
// File is the top-level node that results from parsing a HCL file.
|
2017-05-14 00:44:11 +00:00
|
|
|
type File struct {
|
2017-05-18 15:07:52 +00:00
|
|
|
Body Body
|
|
|
|
Bytes []byte
|
2017-05-20 01:56:39 +00:00
|
|
|
|
2017-09-12 01:36:56 +00:00
|
|
|
// Nav is used to integrate with the "hcled" editor integration package,
|
2017-05-20 01:56:39 +00:00
|
|
|
// and with diagnostic information formatters. It is not for direct use
|
|
|
|
// by a calling application.
|
|
|
|
Nav interface{}
|
2017-05-14 00:44:11 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:21:21 +00:00
|
|
|
// Block represents a nested block within a Body.
|
|
|
|
type Block struct {
|
2017-05-14 00:44:11 +00:00
|
|
|
Type string
|
|
|
|
Labels []string
|
|
|
|
Body Body
|
|
|
|
|
|
|
|
DefRange Range // Range that can be considered the "definition" for seeking in an editor
|
2017-05-18 14:21:21 +00:00
|
|
|
TypeRange Range // Range for the block type declaration specifically.
|
2017-05-14 00:44:11 +00:00
|
|
|
LabelRanges []Range // Ranges for the label values specifically.
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:21:21 +00:00
|
|
|
// Blocks is a sequence of Block.
|
|
|
|
type Blocks []*Block
|
2017-05-14 00:44:11 +00:00
|
|
|
|
2017-05-21 16:05:06 +00:00
|
|
|
// Attributes is a set of attributes keyed by their names.
|
|
|
|
type Attributes map[string]*Attribute
|
|
|
|
|
2017-05-18 14:21:21 +00:00
|
|
|
// Body is a container for attributes and blocks. It serves as the primary
|
2019-07-22 19:50:37 +00:00
|
|
|
// unit of hierarchical structure within configuration.
|
2017-05-14 00:44:11 +00:00
|
|
|
//
|
2019-07-22 19:50:37 +00:00
|
|
|
// The content of a body cannot be meaningfully interpreted without a schema,
|
2017-05-14 00:44:11 +00:00
|
|
|
// so Body represents the raw body content and has methods that allow the
|
|
|
|
// content to be extracted in terms of a given schema.
|
|
|
|
type Body interface {
|
|
|
|
// Content verifies that the entire body content conforms to the given
|
|
|
|
// schema and then returns it, and/or returns diagnostics. The returned
|
|
|
|
// body content is valid if non-nil, regardless of whether Diagnostics
|
|
|
|
// are provided, but diagnostics should still be eventually shown to
|
|
|
|
// the user.
|
|
|
|
Content(schema *BodySchema) (*BodyContent, Diagnostics)
|
|
|
|
|
|
|
|
// PartialContent is like Content except that it permits the configuration
|
2017-05-18 14:21:21 +00:00
|
|
|
// to contain additional blocks or attributes not specified in the
|
2017-05-14 00:44:11 +00:00
|
|
|
// schema. If any are present, the returned Body is non-nil and contains
|
|
|
|
// the remaining items from the body that were not selected by the schema.
|
|
|
|
PartialContent(schema *BodySchema) (*BodyContent, Body, Diagnostics)
|
2017-05-20 21:35:19 +00:00
|
|
|
|
|
|
|
// JustAttributes attempts to interpret all of the contents of the body
|
|
|
|
// as attributes, allowing for the contents to be accessed without a priori
|
|
|
|
// knowledge of the structure.
|
|
|
|
//
|
|
|
|
// The behavior of this method depends on the body's source language.
|
|
|
|
// Some languages, like JSON, can't distinguish between attributes and
|
|
|
|
// blocks without schema hints, but for languages that _can_ error
|
|
|
|
// diagnostics will be generated if any blocks are present in the body.
|
|
|
|
//
|
|
|
|
// Diagnostics may be produced for other reasons too, such as duplicate
|
|
|
|
// declarations of the same attribute.
|
2017-05-21 22:43:41 +00:00
|
|
|
JustAttributes() (Attributes, Diagnostics)
|
2017-05-21 18:46:58 +00:00
|
|
|
|
|
|
|
// MissingItemRange returns a range that represents where a missing item
|
|
|
|
// might hypothetically be inserted. This is used when producing
|
|
|
|
// diagnostics about missing required attributes or blocks. Not all bodies
|
|
|
|
// will have an obvious single insertion point, so the result here may
|
|
|
|
// be rather arbitrary.
|
|
|
|
MissingItemRange() Range
|
2017-05-14 00:44:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// BodyContent is the result of applying a BodySchema to a Body.
|
|
|
|
type BodyContent struct {
|
2017-05-21 16:05:06 +00:00
|
|
|
Attributes Attributes
|
2017-05-18 14:21:21 +00:00
|
|
|
Blocks Blocks
|
2017-06-03 23:46:49 +00:00
|
|
|
|
|
|
|
MissingItemRange Range
|
2017-05-14 00:44:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Attribute represents an attribute from within a body.
|
|
|
|
type Attribute struct {
|
|
|
|
Name string
|
|
|
|
Expr Expression
|
|
|
|
|
|
|
|
Range Range
|
|
|
|
NameRange Range
|
|
|
|
}
|
|
|
|
|
|
|
|
// Expression is a literal value or an expression provided in the
|
|
|
|
// configuration, which can be evaluated within a scope to produce a value.
|
|
|
|
type Expression interface {
|
2017-05-20 22:17:56 +00:00
|
|
|
// Value returns the value resulting from evaluating the expression
|
|
|
|
// in the given evaluation context.
|
|
|
|
//
|
|
|
|
// The context may be nil, in which case the expression may contain
|
|
|
|
// only constants and diagnostics will be produced for any non-constant
|
|
|
|
// sub-expressions. (The exact definition of this depends on the source
|
|
|
|
// language.)
|
|
|
|
//
|
|
|
|
// The context may instead be set but have either its Variables or
|
|
|
|
// Functions maps set to nil, in which case only use of these features
|
|
|
|
// will return diagnostics.
|
|
|
|
//
|
|
|
|
// Different diagnostics are provided depending on whether the given
|
|
|
|
// context maps are nil or empty. In the former case, the message
|
|
|
|
// tells the user that variables/functions are not permitted at all,
|
|
|
|
// while in the latter case usage will produce a "not found" error for
|
|
|
|
// the specific symbol in question.
|
|
|
|
Value(ctx *EvalContext) (cty.Value, Diagnostics)
|
|
|
|
|
2017-05-23 01:54:23 +00:00
|
|
|
// Variables returns a list of variables referenced in the receiving
|
|
|
|
// expression. These are expressed as absolute Traversals, so may include
|
|
|
|
// additional information about how the variable is used, such as
|
|
|
|
// attribute lookups, which the calling application can potentially use
|
|
|
|
// to only selectively populate the scope.
|
|
|
|
Variables() []Traversal
|
|
|
|
|
2017-05-21 00:40:03 +00:00
|
|
|
Range() Range
|
|
|
|
StartRange() Range
|
2017-05-14 00:44:11 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:21:21 +00:00
|
|
|
// OfType filters the receiving block sequence by block type name,
|
|
|
|
// returning a new block sequence including only the blocks of the
|
2017-05-14 00:44:11 +00:00
|
|
|
// requested type.
|
2017-05-18 14:21:21 +00:00
|
|
|
func (els Blocks) OfType(typeName string) Blocks {
|
|
|
|
ret := make(Blocks, 0)
|
2017-05-14 00:44:11 +00:00
|
|
|
for _, el := range els {
|
|
|
|
if el.Type == typeName {
|
|
|
|
ret = append(ret, el)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:21:21 +00:00
|
|
|
// ByType transforms the receiving block sequence into a map from type
|
|
|
|
// name to block sequences of only that type.
|
|
|
|
func (els Blocks) ByType() map[string]Blocks {
|
|
|
|
ret := make(map[string]Blocks)
|
2017-05-14 00:44:11 +00:00
|
|
|
for _, el := range els {
|
|
|
|
ty := el.Type
|
|
|
|
if ret[ty] == nil {
|
2017-05-18 14:21:21 +00:00
|
|
|
ret[ty] = make(Blocks, 0, 1)
|
2017-05-14 00:44:11 +00:00
|
|
|
}
|
|
|
|
ret[ty] = append(ret[ty], el)
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|