aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/hcl2/hcldec/spec.go
diff options
context:
space:
mode:
authorNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
committerNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
commit107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch)
treeca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/hashicorp/hcl2/hcldec/spec.go
parent844b5a68d8af4791755b8f0ad293cc99f5959183 (diff)
downloadterraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/hashicorp/hcl2/hcldec/spec.go')
-rw-r--r--vendor/github.com/hashicorp/hcl2/hcldec/spec.go571
1 files changed, 570 insertions, 1 deletions
diff --git a/vendor/github.com/hashicorp/hcl2/hcldec/spec.go b/vendor/github.com/hashicorp/hcl2/hcldec/spec.go
index 25cafcd..f9da7f6 100644
--- a/vendor/github.com/hashicorp/hcl2/hcldec/spec.go
+++ b/vendor/github.com/hashicorp/hcl2/hcldec/spec.go
@@ -3,6 +3,7 @@ package hcldec
3import ( 3import (
4 "bytes" 4 "bytes"
5 "fmt" 5 "fmt"
6 "sort"
6 7
7 "github.com/hashicorp/hcl2/hcl" 8 "github.com/hashicorp/hcl2/hcl"
8 "github.com/zclconf/go-cty/cty" 9 "github.com/zclconf/go-cty/cty"
@@ -477,6 +478,44 @@ func (s *BlockListSpec) decode(content *hcl.BodyContent, blockLabels []blockLabe
477 if len(elems) == 0 { 478 if len(elems) == 0 {
478 ret = cty.ListValEmpty(s.Nested.impliedType()) 479 ret = cty.ListValEmpty(s.Nested.impliedType())
479 } else { 480 } else {
481 // Since our target is a list, all of the decoded elements must have the
482 // same type or cty.ListVal will panic below. Different types can arise
483 // if there is an attribute spec of type cty.DynamicPseudoType in the
484 // nested spec; all given values must be convertable to a single type
485 // in order for the result to be considered valid.
486 etys := make([]cty.Type, len(elems))
487 for i, v := range elems {
488 etys[i] = v.Type()
489 }
490 ety, convs := convert.UnifyUnsafe(etys)
491 if ety == cty.NilType {
492 // FIXME: This is a pretty terrible error message.
493 diags = append(diags, &hcl.Diagnostic{
494 Severity: hcl.DiagError,
495 Summary: fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
496 Detail: "Corresponding attributes in all blocks of this type must be the same.",
497 Subject: &sourceRanges[0],
498 })
499 return cty.DynamicVal, diags
500 }
501 for i, v := range elems {
502 if convs[i] != nil {
503 newV, err := convs[i](v)
504 if err != nil {
505 // FIXME: This is a pretty terrible error message.
506 diags = append(diags, &hcl.Diagnostic{
507 Severity: hcl.DiagError,
508 Summary: fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
509 Detail: fmt.Sprintf("Block with index %d has inconsistent argument types: %s.", i, err),
510 Subject: &sourceRanges[i],
511 })
512 // Bail early here so we won't panic below in cty.ListVal
513 return cty.DynamicVal, diags
514 }
515 elems[i] = newV
516 }
517 }
518
480 ret = cty.ListVal(elems) 519 ret = cty.ListVal(elems)
481 } 520 }
482 521
@@ -508,6 +547,127 @@ func (s *BlockListSpec) sourceRange(content *hcl.BodyContent, blockLabels []bloc
508 return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested) 547 return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
509} 548}
510 549
550// A BlockTupleSpec is a Spec that produces a cty tuple of the results of
551// decoding all of the nested blocks of a given type, using a nested spec.
552//
553// This is similar to BlockListSpec, but it permits the nested blocks to have
554// different result types in situations where cty.DynamicPseudoType attributes
555// are present.
556type BlockTupleSpec struct {
557 TypeName string
558 Nested Spec
559 MinItems int
560 MaxItems int
561}
562
563func (s *BlockTupleSpec) visitSameBodyChildren(cb visitFunc) {
564 // leaf node ("Nested" does not use the same body)
565}
566
567// blockSpec implementation
568func (s *BlockTupleSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
569 return []hcl.BlockHeaderSchema{
570 {
571 Type: s.TypeName,
572 LabelNames: findLabelSpecs(s.Nested),
573 },
574 }
575}
576
577// blockSpec implementation
578func (s *BlockTupleSpec) nestedSpec() Spec {
579 return s.Nested
580}
581
582// specNeedingVariables implementation
583func (s *BlockTupleSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
584 var ret []hcl.Traversal
585
586 for _, childBlock := range content.Blocks {
587 if childBlock.Type != s.TypeName {
588 continue
589 }
590
591 ret = append(ret, Variables(childBlock.Body, s.Nested)...)
592 }
593
594 return ret
595}
596
597func (s *BlockTupleSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
598 var diags hcl.Diagnostics
599
600 if s.Nested == nil {
601 panic("BlockListSpec with no Nested Spec")
602 }
603
604 var elems []cty.Value
605 var sourceRanges []hcl.Range
606 for _, childBlock := range content.Blocks {
607 if childBlock.Type != s.TypeName {
608 continue
609 }
610
611 val, _, childDiags := decode(childBlock.Body, labelsForBlock(childBlock), ctx, s.Nested, false)
612 diags = append(diags, childDiags...)
613 elems = append(elems, val)
614 sourceRanges = append(sourceRanges, sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested))
615 }
616
617 if len(elems) < s.MinItems {
618 diags = append(diags, &hcl.Diagnostic{
619 Severity: hcl.DiagError,
620 Summary: fmt.Sprintf("Insufficient %s blocks", s.TypeName),
621 Detail: fmt.Sprintf("At least %d %q blocks are required.", s.MinItems, s.TypeName),
622 Subject: &content.MissingItemRange,
623 })
624 } else if s.MaxItems > 0 && len(elems) > s.MaxItems {
625 diags = append(diags, &hcl.Diagnostic{
626 Severity: hcl.DiagError,
627 Summary: fmt.Sprintf("Too many %s blocks", s.TypeName),
628 Detail: fmt.Sprintf("No more than %d %q blocks are allowed", s.MaxItems, s.TypeName),
629 Subject: &sourceRanges[s.MaxItems],
630 })
631 }
632
633 var ret cty.Value
634
635 if len(elems) == 0 {
636 ret = cty.EmptyTupleVal
637 } else {
638 ret = cty.TupleVal(elems)
639 }
640
641 return ret, diags
642}
643
644func (s *BlockTupleSpec) impliedType() cty.Type {
645 // We can't predict our type, because we don't know how many blocks
646 // there will be until we decode.
647 return cty.DynamicPseudoType
648}
649
650func (s *BlockTupleSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
651 // We return the source range of the _first_ block of the given type,
652 // since they are not guaranteed to form a contiguous range.
653
654 var childBlock *hcl.Block
655 for _, candidate := range content.Blocks {
656 if candidate.Type != s.TypeName {
657 continue
658 }
659
660 childBlock = candidate
661 break
662 }
663
664 if childBlock == nil {
665 return content.MissingItemRange
666 }
667
668 return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
669}
670
511// A BlockSetSpec is a Spec that produces a cty set of the results of 671// A BlockSetSpec is a Spec that produces a cty set of the results of
512// decoding all of the nested blocks of a given type, using a nested spec. 672// decoding all of the nested blocks of a given type, using a nested spec.
513type BlockSetSpec struct { 673type BlockSetSpec struct {
@@ -592,6 +752,44 @@ func (s *BlockSetSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel
592 if len(elems) == 0 { 752 if len(elems) == 0 {
593 ret = cty.SetValEmpty(s.Nested.impliedType()) 753 ret = cty.SetValEmpty(s.Nested.impliedType())
594 } else { 754 } else {
755 // Since our target is a set, all of the decoded elements must have the
756 // same type or cty.SetVal will panic below. Different types can arise
757 // if there is an attribute spec of type cty.DynamicPseudoType in the
758 // nested spec; all given values must be convertable to a single type
759 // in order for the result to be considered valid.
760 etys := make([]cty.Type, len(elems))
761 for i, v := range elems {
762 etys[i] = v.Type()
763 }
764 ety, convs := convert.UnifyUnsafe(etys)
765 if ety == cty.NilType {
766 // FIXME: This is a pretty terrible error message.
767 diags = append(diags, &hcl.Diagnostic{
768 Severity: hcl.DiagError,
769 Summary: fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
770 Detail: "Corresponding attributes in all blocks of this type must be the same.",
771 Subject: &sourceRanges[0],
772 })
773 return cty.DynamicVal, diags
774 }
775 for i, v := range elems {
776 if convs[i] != nil {
777 newV, err := convs[i](v)
778 if err != nil {
779 // FIXME: This is a pretty terrible error message.
780 diags = append(diags, &hcl.Diagnostic{
781 Severity: hcl.DiagError,
782 Summary: fmt.Sprintf("Unconsistent argument types in %s blocks", s.TypeName),
783 Detail: fmt.Sprintf("Block with index %d has inconsistent argument types: %s.", i, err),
784 Subject: &sourceRanges[i],
785 })
786 // Bail early here so we won't panic below in cty.ListVal
787 return cty.DynamicVal, diags
788 }
789 elems[i] = newV
790 }
791 }
792
595 ret = cty.SetVal(elems) 793 ret = cty.SetVal(elems)
596 } 794 }
597 795
@@ -672,7 +870,10 @@ func (s *BlockMapSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel
672 var diags hcl.Diagnostics 870 var diags hcl.Diagnostics
673 871
674 if s.Nested == nil { 872 if s.Nested == nil {
675 panic("BlockSetSpec with no Nested Spec") 873 panic("BlockMapSpec with no Nested Spec")
874 }
875 if ImpliedType(s).HasDynamicTypes() {
876 panic("cty.DynamicPseudoType attributes may not be used inside a BlockMapSpec")
676 } 877 }
677 878
678 elems := map[string]interface{}{} 879 elems := map[string]interface{}{}
@@ -765,6 +966,307 @@ func (s *BlockMapSpec) sourceRange(content *hcl.BodyContent, blockLabels []block
765 return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested) 966 return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
766} 967}
767 968
969// A BlockObjectSpec is a Spec that produces a cty object of the results of
970// decoding all of the nested blocks of a given type, using a nested spec.
971//
972// One level of object structure is created for each of the given label names.
973// There must be at least one given label name.
974//
975// This is similar to BlockMapSpec, but it permits the nested blocks to have
976// different result types in situations where cty.DynamicPseudoType attributes
977// are present.
978type BlockObjectSpec struct {
979 TypeName string
980 LabelNames []string
981 Nested Spec
982}
983
984func (s *BlockObjectSpec) visitSameBodyChildren(cb visitFunc) {
985 // leaf node ("Nested" does not use the same body)
986}
987
988// blockSpec implementation
989func (s *BlockObjectSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
990 return []hcl.BlockHeaderSchema{
991 {
992 Type: s.TypeName,
993 LabelNames: append(s.LabelNames, findLabelSpecs(s.Nested)...),
994 },
995 }
996}
997
998// blockSpec implementation
999func (s *BlockObjectSpec) nestedSpec() Spec {
1000 return s.Nested
1001}
1002
1003// specNeedingVariables implementation
1004func (s *BlockObjectSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
1005 var ret []hcl.Traversal
1006
1007 for _, childBlock := range content.Blocks {
1008 if childBlock.Type != s.TypeName {
1009 continue
1010 }
1011
1012 ret = append(ret, Variables(childBlock.Body, s.Nested)...)
1013 }
1014
1015 return ret
1016}
1017
1018func (s *BlockObjectSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1019 var diags hcl.Diagnostics
1020
1021 if s.Nested == nil {
1022 panic("BlockObjectSpec with no Nested Spec")
1023 }
1024
1025 elems := map[string]interface{}{}
1026 for _, childBlock := range content.Blocks {
1027 if childBlock.Type != s.TypeName {
1028 continue
1029 }
1030
1031 childLabels := labelsForBlock(childBlock)
1032 val, _, childDiags := decode(childBlock.Body, childLabels[len(s.LabelNames):], ctx, s.Nested, false)
1033 targetMap := elems
1034 for _, key := range childBlock.Labels[:len(s.LabelNames)-1] {
1035 if _, exists := targetMap[key]; !exists {
1036 targetMap[key] = make(map[string]interface{})
1037 }
1038 targetMap = targetMap[key].(map[string]interface{})
1039 }
1040
1041 diags = append(diags, childDiags...)
1042
1043 key := childBlock.Labels[len(s.LabelNames)-1]
1044 if _, exists := targetMap[key]; exists {
1045 labelsBuf := bytes.Buffer{}
1046 for _, label := range childBlock.Labels {
1047 fmt.Fprintf(&labelsBuf, " %q", label)
1048 }
1049 diags = append(diags, &hcl.Diagnostic{
1050 Severity: hcl.DiagError,
1051 Summary: fmt.Sprintf("Duplicate %s block", s.TypeName),
1052 Detail: fmt.Sprintf(
1053 "A block for %s%s was already defined. The %s labels must be unique.",
1054 s.TypeName, labelsBuf.String(), s.TypeName,
1055 ),
1056 Subject: &childBlock.DefRange,
1057 })
1058 continue
1059 }
1060
1061 targetMap[key] = val
1062 }
1063
1064 if len(elems) == 0 {
1065 return cty.EmptyObjectVal, diags
1066 }
1067
1068 var ctyObj func(map[string]interface{}, int) cty.Value
1069 ctyObj = func(raw map[string]interface{}, depth int) cty.Value {
1070 vals := make(map[string]cty.Value, len(raw))
1071 if depth == 1 {
1072 for k, v := range raw {
1073 vals[k] = v.(cty.Value)
1074 }
1075 } else {
1076 for k, v := range raw {
1077 vals[k] = ctyObj(v.(map[string]interface{}), depth-1)
1078 }
1079 }
1080 return cty.ObjectVal(vals)
1081 }
1082
1083 return ctyObj(elems, len(s.LabelNames)), diags
1084}
1085
1086func (s *BlockObjectSpec) impliedType() cty.Type {
1087 // We can't predict our type, since we don't know how many blocks are
1088 // present and what labels they have until we decode.
1089 return cty.DynamicPseudoType
1090}
1091
1092func (s *BlockObjectSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
1093 // We return the source range of the _first_ block of the given type,
1094 // since they are not guaranteed to form a contiguous range.
1095
1096 var childBlock *hcl.Block
1097 for _, candidate := range content.Blocks {
1098 if candidate.Type != s.TypeName {
1099 continue
1100 }
1101
1102 childBlock = candidate
1103 break
1104 }
1105
1106 if childBlock == nil {
1107 return content.MissingItemRange
1108 }
1109
1110 return sourceRange(childBlock.Body, labelsForBlock(childBlock), s.Nested)
1111}
1112
1113// A BlockAttrsSpec is a Spec that interprets a single block as if it were
1114// a map of some element type. That is, each attribute within the block
1115// becomes a key in the resulting map and the attribute's value becomes the
1116// element value, after conversion to the given element type. The resulting
1117// value is a cty.Map of the given element type.
1118//
1119// This spec imposes a validation constraint that there be exactly one block
1120// of the given type name and that this block may contain only attributes. The
1121// block does not accept any labels.
1122//
1123// This is an alternative to an AttrSpec of a map type for situations where
1124// block syntax is desired. Note that block syntax does not permit dynamic
1125// keys, construction of the result via a "for" expression, etc. In most cases
1126// an AttrSpec is preferred if the desired result is a map whose keys are
1127// chosen by the user rather than by schema.
1128type BlockAttrsSpec struct {
1129 TypeName string
1130 ElementType cty.Type
1131 Required bool
1132}
1133
1134func (s *BlockAttrsSpec) visitSameBodyChildren(cb visitFunc) {
1135 // leaf node
1136}
1137
1138// blockSpec implementation
1139func (s *BlockAttrsSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
1140 return []hcl.BlockHeaderSchema{
1141 {
1142 Type: s.TypeName,
1143 LabelNames: nil,
1144 },
1145 }
1146}
1147
1148// blockSpec implementation
1149func (s *BlockAttrsSpec) nestedSpec() Spec {
1150 // This is an odd case: we aren't actually going to apply a nested spec
1151 // in this case, since we're going to interpret the body directly as
1152 // attributes, but we need to return something non-nil so that the
1153 // decoder will recognize this as a block spec. We won't actually be
1154 // using this for anything at decode time.
1155 return noopSpec{}
1156}
1157
1158// specNeedingVariables implementation
1159func (s *BlockAttrsSpec) variablesNeeded(content *hcl.BodyContent) []hcl.Traversal {
1160
1161 block, _ := s.findBlock(content)
1162 if block == nil {
1163 return nil
1164 }
1165
1166 var vars []hcl.Traversal
1167
1168 attrs, diags := block.Body.JustAttributes()
1169 if diags.HasErrors() {
1170 return nil
1171 }
1172
1173 for _, attr := range attrs {
1174 vars = append(vars, attr.Expr.Variables()...)
1175 }
1176
1177 // We'll return the variables references in source order so that any
1178 // error messages that result are also in source order.
1179 sort.Slice(vars, func(i, j int) bool {
1180 return vars[i].SourceRange().Start.Byte < vars[j].SourceRange().Start.Byte
1181 })
1182
1183 return vars
1184}
1185
1186func (s *BlockAttrsSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1187 var diags hcl.Diagnostics
1188
1189 block, other := s.findBlock(content)
1190 if block == nil {
1191 if s.Required {
1192 diags = append(diags, &hcl.Diagnostic{
1193 Severity: hcl.DiagError,
1194 Summary: fmt.Sprintf("Missing %s block", s.TypeName),
1195 Detail: fmt.Sprintf(
1196 "A block of type %q is required here.", s.TypeName,
1197 ),
1198 Subject: &content.MissingItemRange,
1199 })
1200 }
1201 return cty.NullVal(cty.Map(s.ElementType)), diags
1202 }
1203 if other != nil {
1204 diags = append(diags, &hcl.Diagnostic{
1205 Severity: hcl.DiagError,
1206 Summary: fmt.Sprintf("Duplicate %s block", s.TypeName),
1207 Detail: fmt.Sprintf(
1208 "Only one block of type %q is allowed. Previous definition was at %s.",
1209 s.TypeName, block.DefRange.String(),
1210 ),
1211 Subject: &other.DefRange,
1212 })
1213 }
1214
1215 attrs, attrDiags := block.Body.JustAttributes()
1216 diags = append(diags, attrDiags...)
1217
1218 if len(attrs) == 0 {
1219 return cty.MapValEmpty(s.ElementType), diags
1220 }
1221
1222 vals := make(map[string]cty.Value, len(attrs))
1223 for name, attr := range attrs {
1224 attrVal, attrDiags := attr.Expr.Value(ctx)
1225 diags = append(diags, attrDiags...)
1226
1227 attrVal, err := convert.Convert(attrVal, s.ElementType)
1228 if err != nil {
1229 diags = append(diags, &hcl.Diagnostic{
1230 Severity: hcl.DiagError,
1231 Summary: "Invalid attribute value",
1232 Detail: fmt.Sprintf("Invalid value for attribute of %q block: %s.", s.TypeName, err),
1233 Subject: attr.Expr.Range().Ptr(),
1234 })
1235 attrVal = cty.UnknownVal(s.ElementType)
1236 }
1237
1238 vals[name] = attrVal
1239 }
1240
1241 return cty.MapVal(vals), diags
1242}
1243
1244func (s *BlockAttrsSpec) impliedType() cty.Type {
1245 return cty.Map(s.ElementType)
1246}
1247
1248func (s *BlockAttrsSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
1249 block, _ := s.findBlock(content)
1250 if block == nil {
1251 return content.MissingItemRange
1252 }
1253 return block.DefRange
1254}
1255
1256func (s *BlockAttrsSpec) findBlock(content *hcl.BodyContent) (block *hcl.Block, other *hcl.Block) {
1257 for _, candidate := range content.Blocks {
1258 if candidate.Type != s.TypeName {
1259 continue
1260 }
1261 if block != nil {
1262 return block, candidate
1263 }
1264 block = candidate
1265 }
1266
1267 return block, nil
1268}
1269
768// A BlockLabelSpec is a Spec that returns a cty.String representing the 1270// A BlockLabelSpec is a Spec that returns a cty.String representing the
769// label of the block its given body belongs to, if indeed its given body 1271// label of the block its given body belongs to, if indeed its given body
770// belongs to a block. It is a programming error to use this in a non-block 1272// belongs to a block. It is a programming error to use this in a non-block
@@ -848,6 +1350,16 @@ func findLabelSpecs(spec Spec) []string {
848// 1350//
849// The two specifications must have the same implied result type for correct 1351// The two specifications must have the same implied result type for correct
850// operation. If not, the result is undefined. 1352// operation. If not, the result is undefined.
1353//
1354// Any requirements imposed by the "Default" spec apply even if "Primary" does
1355// not return null. For example, if the "Default" spec is for a required
1356// attribute then that attribute is always required, regardless of the result
1357// of the "Primary" spec.
1358//
1359// The "Default" spec must not describe a nested block, since otherwise the
1360// result of ChildBlockTypes would not be decidable without evaluation. If
1361// the default spec _does_ describe a nested block then the result is
1362// undefined.
851type DefaultSpec struct { 1363type DefaultSpec struct {
852 Primary Spec 1364 Primary Spec
853 Default Spec 1365 Default Spec
@@ -872,6 +1384,38 @@ func (s *DefaultSpec) impliedType() cty.Type {
872 return s.Primary.impliedType() 1384 return s.Primary.impliedType()
873} 1385}
874 1386
1387// attrSpec implementation
1388func (s *DefaultSpec) attrSchemata() []hcl.AttributeSchema {
1389 // We must pass through the union of both of our nested specs so that
1390 // we'll have both values available in the result.
1391 var ret []hcl.AttributeSchema
1392 if as, ok := s.Primary.(attrSpec); ok {
1393 ret = append(ret, as.attrSchemata()...)
1394 }
1395 if as, ok := s.Default.(attrSpec); ok {
1396 ret = append(ret, as.attrSchemata()...)
1397 }
1398 return ret
1399}
1400
1401// blockSpec implementation
1402func (s *DefaultSpec) blockHeaderSchemata() []hcl.BlockHeaderSchema {
1403 // Only the primary spec may describe a block, since otherwise
1404 // our nestedSpec method below can't know which to return.
1405 if bs, ok := s.Primary.(blockSpec); ok {
1406 return bs.blockHeaderSchemata()
1407 }
1408 return nil
1409}
1410
1411// blockSpec implementation
1412func (s *DefaultSpec) nestedSpec() Spec {
1413 if bs, ok := s.Primary.(blockSpec); ok {
1414 return bs.nestedSpec()
1415 }
1416 return nil
1417}
1418
875func (s *DefaultSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range { 1419func (s *DefaultSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
876 // We can't tell from here which of the two specs will ultimately be used 1420 // We can't tell from here which of the two specs will ultimately be used
877 // in our result, so we'll just assume the first. This is usually the right 1421 // in our result, so we'll just assume the first. This is usually the right
@@ -996,3 +1540,28 @@ func (s *TransformFuncSpec) sourceRange(content *hcl.BodyContent, blockLabels []
996 // not super-accurate, because there's nothing better to return. 1540 // not super-accurate, because there's nothing better to return.
997 return s.Wrapped.sourceRange(content, blockLabels) 1541 return s.Wrapped.sourceRange(content, blockLabels)
998} 1542}
1543
1544// noopSpec is a placeholder spec that does nothing, used in situations where
1545// a non-nil placeholder spec is required. It is not exported because there is
1546// no reason to use it directly; it is always an implementation detail only.
1547type noopSpec struct {
1548}
1549
1550func (s noopSpec) decode(content *hcl.BodyContent, blockLabels []blockLabel, ctx *hcl.EvalContext) (cty.Value, hcl.Diagnostics) {
1551 return cty.NullVal(cty.DynamicPseudoType), nil
1552}
1553
1554func (s noopSpec) impliedType() cty.Type {
1555 return cty.DynamicPseudoType
1556}
1557
1558func (s noopSpec) visitSameBodyChildren(cb visitFunc) {
1559 // nothing to do
1560}
1561
1562func (s noopSpec) sourceRange(content *hcl.BodyContent, blockLabels []blockLabel) hcl.Range {
1563 // No useful range for a noopSpec, and nobody should be calling this anyway.
1564 return hcl.Range{
1565 Filename: "noopSpec",
1566 }
1567}