github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/configs/compat_shim.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package configs
     5  
     6  import (
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/hashicorp/hcl/v2/hclsyntax"
     9  	"github.com/zclconf/go-cty/cty"
    10  )
    11  
    12  // -------------------------------------------------------------------------
    13  // Functions in this file are compatibility shims intended to ease conversion
    14  // from the old configuration loader. Any use of these functions that makes
    15  // a change should generate a deprecation warning explaining to the user how
    16  // to update their code for new patterns.
    17  //
    18  // Shims are particularly important for any patterns that have been widely
    19  // documented in books, tutorials, etc. Users will still be starting from
    20  // these examples and we want to help them adopt the latest patterns rather
    21  // than leave them stranded.
    22  // -------------------------------------------------------------------------
    23  
    24  // shimTraversalInString takes any arbitrary expression and checks if it is
    25  // a quoted string in the native syntax. If it _is_, then it is parsed as a
    26  // traversal and re-wrapped into a synthetic traversal expression and a
    27  // warning is generated. Otherwise, the given expression is just returned
    28  // verbatim.
    29  //
    30  // This function has no effect on expressions from the JSON syntax, since
    31  // traversals in strings are the required pattern in that syntax.
    32  //
    33  // If wantKeyword is set, the generated warning diagnostic will talk about
    34  // keywords rather than references. The behavior is otherwise unchanged, and
    35  // the caller remains responsible for checking that the result is indeed
    36  // a keyword, e.g. using hcl.ExprAsKeyword.
    37  func shimTraversalInString(expr hcl.Expression, wantKeyword bool) (hcl.Expression, hcl.Diagnostics) {
    38  	// ObjectConsKeyExpr is a special wrapper type used for keys on object
    39  	// constructors to deal with the fact that naked identifiers are normally
    40  	// handled as "bareword" strings rather than as variable references. Since
    41  	// we know we're interpreting as a traversal anyway (and thus it won't
    42  	// matter whether it's a string or an identifier) we can safely just unwrap
    43  	// here and then process whatever we find inside as normal.
    44  	if ocke, ok := expr.(*hclsyntax.ObjectConsKeyExpr); ok {
    45  		expr = ocke.Wrapped
    46  	}
    47  
    48  	if !exprIsNativeQuotedString(expr) {
    49  		return expr, nil
    50  	}
    51  
    52  	strVal, diags := expr.Value(nil)
    53  	if diags.HasErrors() || strVal.IsNull() || !strVal.IsKnown() {
    54  		// Since we're not even able to attempt a shim here, we'll discard
    55  		// the diagnostics we saw so far and let the caller's own error
    56  		// handling take care of reporting the invalid expression.
    57  		return expr, nil
    58  	}
    59  
    60  	// The position handling here isn't _quite_ right because it won't
    61  	// take into account any escape sequences in the literal string, but
    62  	// it should be close enough for any error reporting to make sense.
    63  	srcRange := expr.Range()
    64  	startPos := srcRange.Start // copy
    65  	startPos.Column++          // skip initial quote
    66  	startPos.Byte++            // skip initial quote
    67  
    68  	traversal, tDiags := hclsyntax.ParseTraversalAbs(
    69  		[]byte(strVal.AsString()),
    70  		srcRange.Filename,
    71  		startPos,
    72  	)
    73  	diags = append(diags, tDiags...)
    74  
    75  	if wantKeyword {
    76  		diags = append(diags, &hcl.Diagnostic{
    77  			Severity: hcl.DiagWarning,
    78  			Summary:  "Quoted keywords are deprecated",
    79  			Detail:   "In this context, keywords are expected literally rather than in quotes. Terraform 0.11 and earlier required quotes, but quoted keywords are now deprecated and will be removed in a future version of Terraform. Remove the quotes surrounding this keyword to silence this warning.",
    80  			Subject:  &srcRange,
    81  		})
    82  	} else {
    83  		diags = append(diags, &hcl.Diagnostic{
    84  			Severity: hcl.DiagWarning,
    85  			Summary:  "Quoted references are deprecated",
    86  			Detail:   "In this context, references are expected literally rather than in quotes. Terraform 0.11 and earlier required quotes, but quoted references are now deprecated and will be removed in a future version of Terraform. Remove the quotes surrounding this reference to silence this warning.",
    87  			Subject:  &srcRange,
    88  		})
    89  	}
    90  
    91  	return &hclsyntax.ScopeTraversalExpr{
    92  		Traversal: traversal,
    93  		SrcRange:  srcRange,
    94  	}, diags
    95  }
    96  
    97  // shimIsIgnoreChangesStar returns true if the given expression seems to be
    98  // a string literal whose value is "*". This is used to support a legacy
    99  // form of ignore_changes = all .
   100  //
   101  // This function does not itself emit any diagnostics, so it's the caller's
   102  // responsibility to emit a warning diagnostic when this function returns true.
   103  func shimIsIgnoreChangesStar(expr hcl.Expression) bool {
   104  	val, valDiags := expr.Value(nil)
   105  	if valDiags.HasErrors() {
   106  		return false
   107  	}
   108  	if val.Type() != cty.String || val.IsNull() || !val.IsKnown() {
   109  		return false
   110  	}
   111  	return val.AsString() == "*"
   112  }