github.com/crossplane/upjet@v1.3.0/pkg/types/reference.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Crossplane Authors <https://crossplane.io>
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package types
     6  
     7  import (
     8  	"fmt"
     9  	"go/token"
    10  	"go/types"
    11  	"reflect"
    12  	"strings"
    13  
    14  	"k8s.io/utils/ptr"
    15  
    16  	"github.com/crossplane/upjet/pkg/types/comments"
    17  	"github.com/crossplane/upjet/pkg/types/markers"
    18  	"github.com/crossplane/upjet/pkg/types/name"
    19  )
    20  
    21  const (
    22  	// PackagePathXPCommonAPIs is the go path for the Crossplane Runtime package
    23  	// with common APIs
    24  	PackagePathXPCommonAPIs = "github.com/crossplane/crossplane-runtime/apis/common/v1"
    25  )
    26  
    27  // Types to use from by reference generator.
    28  var (
    29  	typeReferenceField types.Type = types.NewNamed(
    30  		types.NewTypeName(token.NoPos, types.NewPackage(PackagePathXPCommonAPIs, "v1"), "Reference", nil),
    31  		types.NewStruct(nil, nil),
    32  		nil,
    33  	)
    34  	typeSelectorField types.Type = types.NewNamed(
    35  		types.NewTypeName(token.NoPos, types.NewPackage(PackagePathXPCommonAPIs, "v1"), "Selector", nil),
    36  		types.NewStruct(nil, nil),
    37  		nil,
    38  	)
    39  	typeSecretKeySelector types.Type = types.NewNamed(
    40  		types.NewTypeName(token.NoPos, types.NewPackage(PackagePathXPCommonAPIs, "v1"), "SecretKeySelector", nil),
    41  		types.NewStruct(nil, nil),
    42  		nil,
    43  	)
    44  	typeSecretReference types.Type = types.NewNamed(
    45  		types.NewTypeName(token.NoPos, types.NewPackage(PackagePathXPCommonAPIs, "v1"), "SecretReference", nil),
    46  		types.NewStruct(nil, nil),
    47  		nil,
    48  	)
    49  	commentOptional = &comments.Comment{
    50  		Options: markers.Options{
    51  			KubebuilderOptions: markers.KubebuilderOptions{
    52  				Required: ptr.To(false),
    53  			},
    54  		},
    55  	}
    56  )
    57  
    58  func (g *Builder) generateReferenceFields(t *types.TypeName, f *Field) (fields []*types.Var, tags []string) {
    59  	_, isSlice := f.FieldType.(*types.Slice)
    60  
    61  	rfn := name.ReferenceFieldName(f.Name, isSlice, f.Reference.RefFieldName)
    62  	sfn := name.SelectorFieldName(f.Name, f.Reference.SelectorFieldName)
    63  
    64  	refTag := fmt.Sprintf(`json:"%s,omitempty" tf:"-"`, rfn.LowerCamelComputed)
    65  	selTag := fmt.Sprintf(`json:"%s,omitempty" tf:"-"`, sfn.LowerCamelComputed)
    66  
    67  	var tr types.Type
    68  	tr = types.NewPointer(typeReferenceField)
    69  	refComment := fmt.Sprintf("// Reference to a %s to populate %s.\n%s",
    70  		friendlyTypeDescription(f.Reference.Type), f.Name.LowerCamelComputed, commentOptional.Build())
    71  	selComment := fmt.Sprintf("// Selector for a %s to populate %s.\n%s",
    72  		friendlyTypeDescription(f.Reference.Type), f.Name.LowerCamelComputed, commentOptional.Build())
    73  	if isSlice {
    74  		tr = types.NewSlice(typeReferenceField)
    75  		refComment = fmt.Sprintf("// References to %s to populate %s.\n%s",
    76  			friendlyTypeDescription(f.Reference.Type), f.Name.LowerCamelComputed, commentOptional.Build())
    77  		selComment = fmt.Sprintf("// Selector for a list of %s to populate %s.\n%s",
    78  			friendlyTypeDescription(f.Reference.Type), f.Name.LowerCamelComputed, commentOptional.Build())
    79  	}
    80  	ref := types.NewField(token.NoPos, g.Package, rfn.Camel, tr, false)
    81  	sel := types.NewField(token.NoPos, g.Package, sfn.Camel, types.NewPointer(typeSelectorField), false)
    82  
    83  	g.comments.AddFieldComment(t, rfn.Camel, refComment)
    84  	g.comments.AddFieldComment(t, sfn.Camel, selComment)
    85  	f.TransformedName = rfn.LowerCamelComputed
    86  	f.SelectorName = sfn.LowerCamelComputed
    87  
    88  	return []*types.Var{ref, sel}, []string{refTag, selTag}
    89  }
    90  
    91  // TypePath returns go package path for the input type. This is a helper
    92  // function to be used whenever this information is needed, like configuring to
    93  // reference to a type. Should not be used if the type is in the same package as
    94  // the caller.
    95  func TypePath(i any) string {
    96  	return reflect.TypeOf(i).PkgPath() + "." + reflect.TypeOf(i).Name()
    97  }
    98  
    99  func friendlyTypeDescription(path string) string {
   100  	if !strings.Contains(path, ".") {
   101  		return path
   102  	}
   103  	typeName := path[strings.LastIndex(path, ".")+1:]
   104  	dirs := strings.Split(path, "/")
   105  	groupName := dirs[len(dirs)-2]
   106  	return fmt.Sprintf("%s in %s", typeName, groupName)
   107  }