4
4
"encoding/json"
5
5
"errors"
6
6
"fmt"
7
+ "reflect"
7
8
8
9
"github.com/hashicorp/hcl/v2"
9
10
"github.com/hashicorp/hcl/v2/ext/typeexpr"
@@ -24,6 +25,10 @@ var schemaTy = types.NewObject(
24
25
types .NewDynamicProperty (types .S , types .A ),
25
26
)
26
27
28
+ // Capsule type corresponding to "expr" in the extended schema type syntax.
29
+ // It is not intended as a general capsule type in the cty type system, but acts as the identifier for the keyword.
30
+ var exprCty cty.Type = cty .Capsule ("expr" , reflect .TypeOf ((* hcl .Expression )(nil )))
31
+
27
32
func jsonToSchema (in map [string ]any , tyMap map [string ]cty.Type , path string ) (* hclext.BodySchema , map [string ]cty.Type , error ) {
28
33
schema := & hclext.BodySchema {}
29
34
@@ -32,13 +37,19 @@ func jsonToSchema(in map[string]any, tyMap map[string]cty.Type, path string) (*h
32
37
33
38
switch cv := v .(type ) {
34
39
case string :
35
- expr , diags := hclsyntax .ParseExpression ([]byte (cv ), "" , hcl .InitialPos )
36
- if diags .HasErrors () {
37
- return schema , tyMap , fmt .Errorf ("type expr parse error in %s; %s" , key , withoutSubject (diags ))
38
- }
39
- ty , diags := typeexpr .TypeConstraint (expr )
40
- if diags .HasErrors () {
41
- return schema , tyMap , fmt .Errorf ("type constraint parse error in %s; %s" , key , withoutSubject (diags ))
40
+ var ty cty.Type
41
+ if cv == "expr" {
42
+ // "expr" is a special type that allows you to get the raw expression without evaluating it.
43
+ ty = exprCty
44
+ } else {
45
+ expr , diags := hclsyntax .ParseExpression ([]byte (cv ), "" , hcl .InitialPos )
46
+ if diags .HasErrors () {
47
+ return schema , tyMap , fmt .Errorf ("type expr parse error in %s; %s" , key , withoutSubject (diags ))
48
+ }
49
+ ty , diags = typeexpr .TypeConstraint (expr )
50
+ if diags .HasErrors () {
51
+ return schema , tyMap , fmt .Errorf ("type constraint parse error in %s; %s" , key , withoutSubject (diags ))
52
+ }
42
53
}
43
54
tyMap [key ] = ty
44
55
@@ -277,7 +288,36 @@ var exprTy = types.NewObject(
277
288
nil ,
278
289
)
279
290
291
+ // expr (object<expr: string, range: range>) representation of a raw expression
292
+ var rawExprTy = types .NewObject (
293
+ []* types.StaticProperty {
294
+ types .NewStaticProperty ("value" , types .S ),
295
+ types .NewStaticProperty ("range" , rangeTy ),
296
+ },
297
+ nil ,
298
+ )
299
+
280
300
func exprToJSON (expr hcl.Expression , tyMap map [string ]cty.Type , path string , runner tflint.Runner ) (map [string ]any , error ) {
301
+ ty , exists := tyMap [path ]
302
+ if ! exists {
303
+ // should never happen
304
+ panic (fmt .Sprintf ("cannot get type of %s" , path ))
305
+ }
306
+ // For the "expr" type, the expression is not evaluated
307
+ // and the "value" is the raw expression syntax.
308
+ if ty == exprCty {
309
+ file , err := runner .GetFile (expr .Range ().Filename )
310
+ if err != nil {
311
+ return map [string ]any {}, fmt .Errorf ("type error in %s; %w" , expr .Range (), err )
312
+ }
313
+ // "unknown", "sensitive", and "ephemeral" are undefined
314
+ // because the "value" has not been evaluated.
315
+ return map [string ]any {
316
+ "value" : string (expr .Range ().SliceBytes (file .Bytes )),
317
+ "range" : rangeToJSON (expr .Range ()),
318
+ }, nil
319
+ }
320
+
281
321
ret := map [string ]any {
282
322
"unknown" : false ,
283
323
"sensitive" : false ,
@@ -311,17 +351,11 @@ func exprToJSON(expr hcl.Expression, tyMap map[string]cty.Type, path string, run
311
351
return ret , nil
312
352
}
313
353
314
- ty , exists := tyMap [path ]
315
- if ! exists {
316
- // should never happen
317
- panic (fmt .Sprintf ("cannot get type of %s" , path ))
318
- }
319
354
if ty .HasDynamicTypes () {
320
355
// If a type has "any", it will be converted to JSON as a dynamic type, (e.g. {"value": 1, "type": "number"})
321
356
// so it will take advantage of the inferred type.
322
357
ty = value .Type ()
323
358
}
324
-
325
359
value , err = convert .Convert (value , ty )
326
360
if err != nil {
327
361
return ret , fmt .Errorf ("type error in %s; %w" , expr .Range (), err )
0 commit comments