github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/codegen/utilities_types.go (about)

     1  package codegen
     2  
     3  import (
     4  	"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
     5  )
     6  
     7  func visitTypeClosure(t schema.Type, visitor func(t schema.Type), seen Set) {
     8  	if seen.Has(t) {
     9  		return
    10  	}
    11  	seen.Add(t)
    12  
    13  	visitor(t)
    14  
    15  	switch st := t.(type) {
    16  	case *schema.ArrayType:
    17  		visitTypeClosure(st.ElementType, visitor, seen)
    18  	case *schema.MapType:
    19  		visitTypeClosure(st.ElementType, visitor, seen)
    20  	case *schema.ObjectType:
    21  		for _, p := range st.Properties {
    22  			visitTypeClosure(p.Type, visitor, seen)
    23  		}
    24  	case *schema.UnionType:
    25  		for _, e := range st.ElementTypes {
    26  			visitTypeClosure(e, visitor, seen)
    27  		}
    28  	case *schema.InputType:
    29  		visitTypeClosure(st.ElementType, visitor, seen)
    30  	case *schema.OptionalType:
    31  		visitTypeClosure(st.ElementType, visitor, seen)
    32  	}
    33  }
    34  
    35  func VisitTypeClosure(properties []*schema.Property, visitor func(t schema.Type)) {
    36  	seen := Set{}
    37  	for _, p := range properties {
    38  		visitTypeClosure(p.Type, visitor, seen)
    39  	}
    40  }
    41  
    42  func SimplifyInputUnion(t schema.Type) schema.Type {
    43  	union, ok := t.(*schema.UnionType)
    44  	if !ok {
    45  		return t
    46  	}
    47  
    48  	elements := make([]schema.Type, len(union.ElementTypes))
    49  	for i, et := range union.ElementTypes {
    50  		if input, ok := et.(*schema.InputType); ok {
    51  			elements[i] = input.ElementType
    52  		} else {
    53  			elements[i] = et
    54  		}
    55  	}
    56  	return &schema.UnionType{
    57  		ElementTypes:  elements,
    58  		DefaultType:   union.DefaultType,
    59  		Discriminator: union.Discriminator,
    60  		Mapping:       union.Mapping,
    61  	}
    62  }
    63  
    64  // RequiredType unwraps the OptionalType enclosing the Property's type, if any.
    65  func RequiredType(p *schema.Property) schema.Type {
    66  	if optional, ok := p.Type.(*schema.OptionalType); ok {
    67  		return optional.ElementType
    68  	}
    69  	return p.Type
    70  }
    71  
    72  // OptionalType wraps the Property's type in an OptionalType if it is not already optional.
    73  func OptionalType(p *schema.Property) schema.Type {
    74  	if optional, ok := p.Type.(*schema.OptionalType); ok {
    75  		return optional
    76  	}
    77  	return &schema.OptionalType{ElementType: p.Type}
    78  }
    79  
    80  // UnwrapType removes any outer OptionalTypes and InputTypes from t.
    81  func UnwrapType(t schema.Type) schema.Type {
    82  	for {
    83  		switch typ := t.(type) {
    84  		case *schema.InputType:
    85  			t = typ.ElementType
    86  		case *schema.OptionalType:
    87  			t = typ.ElementType
    88  		default:
    89  			return t
    90  		}
    91  	}
    92  }
    93  
    94  // MapInnerType applies f to the first non-wrapper type in t.
    95  // MapInnerType does not mutate it's input, and t should not either.
    96  func MapInnerType(t schema.Type, f func(schema.Type) schema.Type) schema.Type {
    97  	switch t := t.(type) {
    98  	case *schema.InputType:
    99  		return &schema.InputType{ElementType: MapInnerType(t.ElementType, f)}
   100  	case *schema.OptionalType:
   101  		return &schema.OptionalType{ElementType: MapInnerType(t.ElementType, f)}
   102  	case *schema.ArrayType:
   103  		return &schema.ArrayType{ElementType: MapInnerType(t.ElementType, f)}
   104  	case *schema.MapType:
   105  		return &schema.MapType{ElementType: MapInnerType(t.ElementType, f)}
   106  	default:
   107  		return f(t)
   108  	}
   109  }
   110  
   111  // Applies f to the first non-optional type in t.
   112  // If t is Optional{v} then returns Optional{f(v)}, otherwise f(t) is returned
   113  func MapOptionalType(t schema.Type, f func(schema.Type) schema.Type) schema.Type {
   114  	if opt, ok := t.(*schema.OptionalType); ok {
   115  		return &schema.OptionalType{ElementType: f(opt.ElementType)}
   116  	}
   117  	return f(t)
   118  }
   119  
   120  func IsNOptionalInput(t schema.Type) bool {
   121  	for {
   122  		switch typ := t.(type) {
   123  		case *schema.InputType:
   124  			return true
   125  		case *schema.OptionalType:
   126  			t = typ.ElementType
   127  		default:
   128  			return false
   129  		}
   130  	}
   131  }
   132  
   133  func resolvedType(t schema.Type, plainObjects bool) schema.Type {
   134  	switch typ := t.(type) {
   135  	case *schema.InputType:
   136  		return resolvedType(typ.ElementType, plainObjects)
   137  	case *schema.OptionalType:
   138  		e := resolvedType(typ.ElementType, plainObjects)
   139  		if e == typ.ElementType {
   140  			return typ
   141  		}
   142  		return &schema.OptionalType{ElementType: e}
   143  	case *schema.ArrayType:
   144  		e := resolvedType(typ.ElementType, plainObjects)
   145  		if e == typ.ElementType {
   146  			return typ
   147  		}
   148  		return &schema.ArrayType{ElementType: e}
   149  	case *schema.MapType:
   150  		e := resolvedType(typ.ElementType, plainObjects)
   151  		if e == typ.ElementType {
   152  			return typ
   153  		}
   154  		return &schema.MapType{ElementType: e}
   155  	case *schema.ObjectType:
   156  		if !plainObjects || !typ.IsInputShape() {
   157  			return typ
   158  		}
   159  		return typ.PlainShape
   160  	case *schema.UnionType:
   161  		elems, changed := make([]schema.Type, len(typ.ElementTypes)), false
   162  		for i, e := range typ.ElementTypes {
   163  			elems[i] = resolvedType(e, plainObjects)
   164  			changed = changed || elems[i] != e
   165  		}
   166  		if !changed {
   167  			return typ
   168  		}
   169  		return &schema.UnionType{
   170  			ElementTypes:  elems,
   171  			DefaultType:   typ.DefaultType,
   172  			Discriminator: typ.Discriminator,
   173  			Mapping:       typ.Mapping,
   174  		}
   175  	default:
   176  		return t
   177  	}
   178  }
   179  
   180  // PlainType deeply removes any InputTypes from t, with the exception of argument structs. Use ResolvedType to
   181  // unwrap argument structs as well.
   182  func PlainType(t schema.Type) schema.Type {
   183  	return resolvedType(t, false)
   184  }
   185  
   186  // ResolvedType deeply removes any InputTypes from t.
   187  func ResolvedType(t schema.Type) schema.Type {
   188  	return resolvedType(t, true)
   189  }
   190  
   191  // If a helper function needs to be invoked to provide default values for a
   192  // plain type. The provided map cannot be reused.
   193  func IsProvideDefaultsFuncRequired(t schema.Type) bool {
   194  	return isProvideDefaultsFuncRequiredHelper(t, map[string]bool{})
   195  }
   196  
   197  func isProvideDefaultsFuncRequiredHelper(t schema.Type, seen map[string]bool) bool {
   198  	if seen[t.String()] {
   199  		return false
   200  	}
   201  	seen[t.String()] = true
   202  	t = UnwrapType(t)
   203  	object, ok := t.(*schema.ObjectType)
   204  	if !ok {
   205  		return false
   206  	}
   207  	for _, p := range object.Properties {
   208  		if p.DefaultValue != nil || isProvideDefaultsFuncRequiredHelper(p.Type, seen) {
   209  			return true
   210  		}
   211  	}
   212  	return false
   213  }