github.com/hashicorp/hcl/v2@v2.20.0/structure.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package hcl
     5  
     6  import (
     7  	"github.com/zclconf/go-cty/cty"
     8  )
     9  
    10  // File is the top-level node that results from parsing a HCL file.
    11  type File struct {
    12  	Body  Body
    13  	Bytes []byte
    14  
    15  	// Nav is used to integrate with the "hcled" editor integration package,
    16  	// and with diagnostic information formatters. It is not for direct use
    17  	// by a calling application.
    18  	Nav interface{}
    19  }
    20  
    21  // Block represents a nested block within a Body.
    22  type Block struct {
    23  	Type   string
    24  	Labels []string
    25  	Body   Body
    26  
    27  	DefRange    Range   // Range that can be considered the "definition" for seeking in an editor
    28  	TypeRange   Range   // Range for the block type declaration specifically.
    29  	LabelRanges []Range // Ranges for the label values specifically.
    30  }
    31  
    32  // Blocks is a sequence of Block.
    33  type Blocks []*Block
    34  
    35  // Attributes is a set of attributes keyed by their names.
    36  type Attributes map[string]*Attribute
    37  
    38  // Body is a container for attributes and blocks. It serves as the primary
    39  // unit of hierarchical structure within configuration.
    40  //
    41  // The content of a body cannot be meaningfully interpreted without a schema,
    42  // so Body represents the raw body content and has methods that allow the
    43  // content to be extracted in terms of a given schema.
    44  type Body interface {
    45  	// Content verifies that the entire body content conforms to the given
    46  	// schema and then returns it, and/or returns diagnostics. The returned
    47  	// body content is valid if non-nil, regardless of whether Diagnostics
    48  	// are provided, but diagnostics should still be eventually shown to
    49  	// the user.
    50  	Content(schema *BodySchema) (*BodyContent, Diagnostics)
    51  
    52  	// PartialContent is like Content except that it permits the configuration
    53  	// to contain additional blocks or attributes not specified in the
    54  	// schema. If any are present, the returned Body is non-nil and contains
    55  	// the remaining items from the body that were not selected by the schema.
    56  	PartialContent(schema *BodySchema) (*BodyContent, Body, Diagnostics)
    57  
    58  	// JustAttributes attempts to interpret all of the contents of the body
    59  	// as attributes, allowing for the contents to be accessed without a priori
    60  	// knowledge of the structure.
    61  	//
    62  	// The behavior of this method depends on the body's source language.
    63  	// Some languages, like JSON, can't distinguish between attributes and
    64  	// blocks without schema hints, but for languages that _can_ error
    65  	// diagnostics will be generated if any blocks are present in the body.
    66  	//
    67  	// Diagnostics may be produced for other reasons too, such as duplicate
    68  	// declarations of the same attribute.
    69  	JustAttributes() (Attributes, Diagnostics)
    70  
    71  	// MissingItemRange returns a range that represents where a missing item
    72  	// might hypothetically be inserted. This is used when producing
    73  	// diagnostics about missing required attributes or blocks. Not all bodies
    74  	// will have an obvious single insertion point, so the result here may
    75  	// be rather arbitrary.
    76  	MissingItemRange() Range
    77  }
    78  
    79  // BodyContent is the result of applying a BodySchema to a Body.
    80  type BodyContent struct {
    81  	Attributes Attributes
    82  	Blocks     Blocks
    83  
    84  	MissingItemRange Range
    85  }
    86  
    87  // Attribute represents an attribute from within a body.
    88  type Attribute struct {
    89  	Name string
    90  	Expr Expression
    91  
    92  	Range     Range
    93  	NameRange Range
    94  }
    95  
    96  // Expression is a literal value or an expression provided in the
    97  // configuration, which can be evaluated within a scope to produce a value.
    98  type Expression interface {
    99  	// Value returns the value resulting from evaluating the expression
   100  	// in the given evaluation context.
   101  	//
   102  	// The context may be nil, in which case the expression may contain
   103  	// only constants and diagnostics will be produced for any non-constant
   104  	// sub-expressions. (The exact definition of this depends on the source
   105  	// language.)
   106  	//
   107  	// The context may instead be set but have either its Variables or
   108  	// Functions maps set to nil, in which case only use of these features
   109  	// will return diagnostics.
   110  	//
   111  	// Different diagnostics are provided depending on whether the given
   112  	// context maps are nil or empty. In the former case, the message
   113  	// tells the user that variables/functions are not permitted at all,
   114  	// while in the latter case usage will produce a "not found" error for
   115  	// the specific symbol in question.
   116  	Value(ctx *EvalContext) (cty.Value, Diagnostics)
   117  
   118  	// Variables returns a list of variables referenced in the receiving
   119  	// expression. These are expressed as absolute Traversals, so may include
   120  	// additional information about how the variable is used, such as
   121  	// attribute lookups, which the calling application can potentially use
   122  	// to only selectively populate the scope.
   123  	Variables() []Traversal
   124  
   125  	Range() Range
   126  	StartRange() Range
   127  }
   128  
   129  // OfType filters the receiving block sequence by block type name,
   130  // returning a new block sequence including only the blocks of the
   131  // requested type.
   132  func (els Blocks) OfType(typeName string) Blocks {
   133  	ret := make(Blocks, 0)
   134  	for _, el := range els {
   135  		if el.Type == typeName {
   136  			ret = append(ret, el)
   137  		}
   138  	}
   139  	return ret
   140  }
   141  
   142  // ByType transforms the receiving block sequence into a map from type
   143  // name to block sequences of only that type.
   144  func (els Blocks) ByType() map[string]Blocks {
   145  	ret := make(map[string]Blocks)
   146  	for _, el := range els {
   147  		ty := el.Type
   148  		if ret[ty] == nil {
   149  			ret[ty] = make(Blocks, 0, 1)
   150  		}
   151  		ret[ty] = append(ret[ty], el)
   152  	}
   153  	return ret
   154  }