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

     1  // Copyright 2016-2021, Pulumi Corporation.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Pulling out some of the repeated strings tokens into constants would harm readability, so we just ignore the
    16  // goconst linter's warning.
    17  //
    18  // nolint: lll, goconst
    19  package gen
    20  
    21  import (
    22  	"bytes"
    23  	"fmt"
    24  	"go/format"
    25  	"io"
    26  	"os"
    27  	"path"
    28  	"reflect"
    29  	"sort"
    30  	"strconv"
    31  	"strings"
    32  	"sync"
    33  
    34  	"github.com/pulumi/pulumi/pkg/v3/codegen"
    35  	"github.com/pulumi/pulumi/pkg/v3/codegen/cgstrings"
    36  	"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
    37  	"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
    38  	"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
    39  	"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
    40  	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
    41  )
    42  
    43  type typeDetails struct {
    44  	// Note: if any of {ptr,array,map}Input are set, input and the corresponding output field must also be set. The
    45  	// mark* functions ensure that these invariants hold.
    46  	input      bool
    47  	ptrInput   bool
    48  	arrayInput bool
    49  	mapInput   bool
    50  
    51  	// Note: if any of {ptr,array,map}Output are set, output must also be set. The mark* functions ensure that these
    52  	// invariants hold.
    53  	output      bool
    54  	ptrOutput   bool
    55  	arrayOutput bool
    56  	mapOutput   bool
    57  }
    58  
    59  func (d *typeDetails) hasOutputs() bool {
    60  	return d.output || d.ptrOutput || d.arrayOutput || d.mapOutput
    61  }
    62  
    63  func (d *typeDetails) mark(input, output bool) {
    64  	d.input = d.input || input
    65  	d.output = d.output || input || output
    66  }
    67  
    68  func (d *typeDetails) markPtr(input, output bool) {
    69  	d.mark(input, output)
    70  	d.ptrInput = d.ptrInput || input
    71  	d.ptrOutput = d.ptrOutput || input || output
    72  }
    73  
    74  func (d *typeDetails) markArray(input, output bool) {
    75  	d.mark(input, output)
    76  	d.arrayInput = d.arrayInput || input
    77  	d.arrayOutput = d.arrayOutput || input || output
    78  }
    79  
    80  func (d *typeDetails) markMap(input, output bool) {
    81  	d.mark(input, output)
    82  	d.mapInput = d.mapInput || input
    83  	d.mapOutput = d.mapOutput || input || output
    84  }
    85  
    86  // Title converts the input string to a title case
    87  // where only the initial letter is upper-cased.
    88  // It also removes $-prefix if any.
    89  func Title(s string) string {
    90  	if s == "" {
    91  		return ""
    92  	}
    93  	if s[0] == '$' {
    94  		return Title(s[1:])
    95  	}
    96  	s = cgstrings.UppercaseFirst(s)
    97  	s = cgstrings.Unhyphenate(s)
    98  	return s
    99  }
   100  
   101  func tokenToPackage(pkg *schema.Package, overrides map[string]string, tok string) string {
   102  	mod := pkg.TokenToModule(tok)
   103  	if override, ok := overrides[mod]; ok {
   104  		mod = override
   105  	}
   106  	return strings.ToLower(mod)
   107  }
   108  
   109  // A threadsafe cache for sharing between invocations of GenerateProgram.
   110  type Cache struct {
   111  	externalPackages map[*schema.Package]map[string]*pkgContext
   112  	m                *sync.Mutex
   113  }
   114  
   115  var globalCache = NewCache()
   116  
   117  func NewCache() *Cache {
   118  	return &Cache{
   119  		externalPackages: map[*schema.Package]map[string]*pkgContext{},
   120  		m:                new(sync.Mutex),
   121  	}
   122  }
   123  
   124  func (c *Cache) lookupContextMap(pkg *schema.Package) (map[string]*pkgContext, bool) {
   125  	c.m.Lock()
   126  	defer c.m.Unlock()
   127  	m, ok := c.externalPackages[pkg]
   128  	return m, ok
   129  }
   130  
   131  func (c *Cache) setContextMap(pkg *schema.Package, m map[string]*pkgContext) {
   132  	c.m.Lock()
   133  	defer c.m.Unlock()
   134  	c.externalPackages[pkg] = m
   135  }
   136  
   137  type pkgContext struct {
   138  	pkg             *schema.Package
   139  	mod             string
   140  	importBasePath  string
   141  	rootPackageName string
   142  	typeDetails     map[schema.Type]*typeDetails
   143  	enums           []*schema.EnumType
   144  	types           []*schema.ObjectType
   145  	resources       []*schema.Resource
   146  	functions       []*schema.Function
   147  
   148  	// schemaNames tracks the names of types/resources as specified in the schema
   149  	schemaNames codegen.StringSet
   150  	names       codegen.StringSet
   151  	renamed     map[string]string
   152  
   153  	// A mapping between external packages and their bound contents.
   154  	externalPackages *Cache
   155  
   156  	// duplicateTokens tracks tokens that exist for both types and resources
   157  	duplicateTokens map[string]bool
   158  	functionNames   map[*schema.Function]string
   159  	needsUtils      bool
   160  	tool            string
   161  	packages        map[string]*pkgContext
   162  
   163  	// Name overrides set in GoPackageInfo
   164  	modToPkg         map[string]string // Module name -> package name
   165  	pkgImportAliases map[string]string // Package name -> import alias
   166  
   167  	// Determines whether to make single-return-value methods return an output struct or the value
   168  	liftSingleValueMethodReturns bool
   169  
   170  	// Determines if we should emit type registration code
   171  	disableInputTypeRegistrations bool
   172  
   173  	// Determines if we should emit object defaults code
   174  	disableObjectDefaults bool
   175  }
   176  
   177  func (pkg *pkgContext) detailsForType(t schema.Type) *typeDetails {
   178  	if obj, ok := t.(*schema.ObjectType); ok && obj.IsInputShape() {
   179  		t = obj.PlainShape
   180  	}
   181  
   182  	details, ok := pkg.typeDetails[t]
   183  	if !ok {
   184  		details = &typeDetails{}
   185  		pkg.typeDetails[t] = details
   186  	}
   187  	return details
   188  }
   189  
   190  func (pkg *pkgContext) tokenToPackage(tok string) string {
   191  	return tokenToPackage(pkg.pkg, pkg.modToPkg, tok)
   192  }
   193  
   194  func (pkg *pkgContext) tokenToType(tok string) string {
   195  	// token := pkg : module : member
   196  	// module := path/to/module
   197  
   198  	components := strings.Split(tok, ":")
   199  	contract.Assertf(len(components) == 3, "tok: %s", tok)
   200  	if pkg == nil {
   201  		panic(fmt.Errorf("pkg is nil. token %s", tok))
   202  	}
   203  	if pkg.pkg == nil {
   204  		panic(fmt.Errorf("pkg.pkg is nil. token %s", tok))
   205  	}
   206  
   207  	mod, name := pkg.tokenToPackage(tok), components[2]
   208  
   209  	name = Title(name)
   210  	if modPkg, ok := pkg.packages[mod]; ok {
   211  		newName, renamed := modPkg.renamed[name]
   212  		if renamed {
   213  			name = newName
   214  		} else if modPkg.duplicateTokens[strings.ToLower(tok)] {
   215  			// maintain support for duplicate tokens for types and resources in Kubernetes
   216  			name += "Type"
   217  		}
   218  	}
   219  
   220  	if mod == pkg.mod {
   221  		return name
   222  	}
   223  	if mod == "" {
   224  		mod = packageRoot(pkg.pkg)
   225  	}
   226  
   227  	var importPath string
   228  	if alias, hasAlias := pkg.pkgImportAliases[path.Join(pkg.importBasePath, mod)]; hasAlias {
   229  		importPath = alias
   230  	} else {
   231  		importPath = strings.ReplaceAll(mod, "/", "")
   232  		importPath = strings.ReplaceAll(importPath, "-", "")
   233  	}
   234  
   235  	return strings.ReplaceAll(importPath+"."+name, "-provider", "")
   236  }
   237  
   238  // Resolve a enum type to its name.
   239  func (pkg *pkgContext) resolveEnumType(t *schema.EnumType) string {
   240  	if !pkg.isExternalReference(t) {
   241  		return pkg.tokenToEnum(t.Token)
   242  	}
   243  
   244  	extPkgCtx, _ := pkg.contextForExternalReference(t)
   245  	enumType := extPkgCtx.tokenToEnum(t.Token)
   246  	if !strings.Contains(enumType, ".") {
   247  		enumType = fmt.Sprintf("%s.%s", extPkgCtx.pkg.Name, enumType)
   248  	}
   249  	return enumType
   250  }
   251  
   252  func (pkg *pkgContext) tokenToEnum(tok string) string {
   253  	// token := pkg : module : member
   254  	// module := path/to/module
   255  
   256  	components := strings.Split(tok, ":")
   257  	contract.Assert(len(components) == 3)
   258  	if pkg == nil {
   259  		panic(fmt.Errorf("pkg is nil. token %s", tok))
   260  	}
   261  	if pkg.pkg == nil {
   262  		panic(fmt.Errorf("pkg.pkg is nil. token %s", tok))
   263  	}
   264  
   265  	mod, name := pkg.tokenToPackage(tok), components[2]
   266  
   267  	name = Title(name)
   268  
   269  	if modPkg, ok := pkg.packages[mod]; ok {
   270  		newName, renamed := modPkg.renamed[name]
   271  		if renamed {
   272  			name = newName
   273  		} else if modPkg.duplicateTokens[tok] {
   274  			// If the package containing the enum's token already has a resource or type with the
   275  			// same name, add an `Enum` suffix.
   276  			name += "Enum"
   277  		}
   278  	}
   279  
   280  	if mod == pkg.mod {
   281  		return name
   282  	}
   283  	if mod == "" {
   284  		mod = components[0]
   285  	}
   286  
   287  	var importPath string
   288  	if alias, hasAlias := pkg.pkgImportAliases[path.Join(pkg.importBasePath, mod)]; hasAlias {
   289  		importPath = alias
   290  	} else {
   291  		importPath = strings.ReplaceAll(mod, "/", "")
   292  	}
   293  
   294  	return importPath + "." + name
   295  }
   296  
   297  func (pkg *pkgContext) tokenToResource(tok string) string {
   298  	// token := pkg : module : member
   299  	// module := path/to/module
   300  
   301  	components := strings.Split(tok, ":")
   302  	contract.Assert(len(components) == 3)
   303  	if pkg == nil {
   304  		panic(fmt.Errorf("pkg is nil. token %s", tok))
   305  	}
   306  	if pkg.pkg == nil {
   307  		panic(fmt.Errorf("pkg.pkg is nil. token %s", tok))
   308  	}
   309  
   310  	// Is it a provider resource?
   311  	if components[0] == "pulumi" && components[1] == "providers" {
   312  		return fmt.Sprintf("%s.Provider", components[2])
   313  	}
   314  
   315  	mod, name := pkg.tokenToPackage(tok), components[2]
   316  
   317  	name = Title(name)
   318  
   319  	if mod == pkg.mod {
   320  		return name
   321  	}
   322  	if mod == "" {
   323  		mod = components[0]
   324  	}
   325  
   326  	var importPath string
   327  	if alias, hasAlias := pkg.pkgImportAliases[path.Join(pkg.importBasePath, mod)]; hasAlias {
   328  		importPath = alias
   329  	} else {
   330  		importPath = strings.ReplaceAll(mod, "/", "")
   331  	}
   332  
   333  	return importPath + "." + name
   334  }
   335  
   336  func tokenToModule(tok string) string {
   337  	// token := pkg : module : member
   338  	// module := path/to/module
   339  
   340  	components := strings.Split(tok, ":")
   341  	contract.Assert(len(components) == 3)
   342  	return components[1]
   343  }
   344  
   345  func tokenToName(tok string) string {
   346  	components := strings.Split(tok, ":")
   347  	contract.Assert(len(components) == 3)
   348  	return Title(components[2])
   349  }
   350  
   351  // disambiguatedResourceName gets the name of a resource as it should appear in source, resolving conflicts in the process.
   352  func disambiguatedResourceName(r *schema.Resource, pkg *pkgContext) string {
   353  	name := rawResourceName(r)
   354  	if renamed, ok := pkg.renamed[name]; ok {
   355  		name = renamed
   356  	}
   357  	return name
   358  }
   359  
   360  // rawResourceName produces raw resource name translated from schema type token without resolving conflicts or dupes.
   361  func rawResourceName(r *schema.Resource) string {
   362  	if r.IsProvider {
   363  		return "Provider"
   364  	}
   365  	return tokenToName(r.Token)
   366  }
   367  
   368  // If `nil` is a valid value of type `t`.
   369  func isNilType(t schema.Type) bool {
   370  	switch t := t.(type) {
   371  	case *schema.OptionalType, *schema.ArrayType, *schema.MapType, *schema.ResourceType, *schema.InputType:
   372  		return true
   373  	case *schema.TokenType:
   374  		// Use the underlying type for now.
   375  		if t.UnderlyingType != nil {
   376  			return isNilType(t.UnderlyingType)
   377  		}
   378  	case *schema.UnionType:
   379  		// If the union is actually a relaxed enum type, use the underlying
   380  		// type for the enum instead
   381  		for _, e := range t.ElementTypes {
   382  			if typ, ok := e.(*schema.EnumType); ok {
   383  				return isNilType(typ.ElementType)
   384  			}
   385  		}
   386  	default:
   387  		switch t {
   388  		case schema.ArchiveType, schema.AssetType, schema.JSONType, schema.AnyType:
   389  			return true
   390  		}
   391  	}
   392  	return false
   393  }
   394  
   395  func (pkg *pkgContext) inputType(t schema.Type) (result string) {
   396  	switch t := codegen.SimplifyInputUnion(t).(type) {
   397  	case *schema.OptionalType:
   398  		return pkg.typeString(t)
   399  	case *schema.InputType:
   400  		return pkg.inputType(t.ElementType)
   401  	case *schema.EnumType:
   402  		// Since enum type is itself an input
   403  		return pkg.resolveEnumType(t) + "Input"
   404  	case *schema.ArrayType:
   405  		en := pkg.inputType(t.ElementType)
   406  		return strings.TrimSuffix(en, "Input") + "ArrayInput"
   407  	case *schema.MapType:
   408  		en := pkg.inputType(t.ElementType)
   409  		return strings.TrimSuffix(en, "Input") + "MapInput"
   410  	case *schema.ObjectType:
   411  		if t.IsInputShape() {
   412  			t = t.PlainShape
   413  		}
   414  		return pkg.resolveObjectType(t) + "Input"
   415  	case *schema.ResourceType:
   416  		return pkg.resolveResourceType(t) + "Input"
   417  	case *schema.TokenType:
   418  		// Use the underlying type for now.
   419  		if t.UnderlyingType != nil {
   420  			return pkg.inputType(t.UnderlyingType)
   421  		}
   422  		return pkg.tokenToType(t.Token) + "Input"
   423  	case *schema.UnionType:
   424  		// If the union is actually a relaxed enum type, use the underlying
   425  		// type for the input instead
   426  		for _, e := range t.ElementTypes {
   427  			if typ, ok := e.(*schema.EnumType); ok {
   428  				return pkg.inputType(typ.ElementType)
   429  			}
   430  		}
   431  		// TODO(pdg): union types
   432  		return "pulumi.Input"
   433  	default:
   434  		switch t {
   435  		case schema.BoolType:
   436  			return "pulumi.BoolInput"
   437  		case schema.IntType:
   438  			return "pulumi.IntInput"
   439  		case schema.NumberType:
   440  			return "pulumi.Float64Input"
   441  		case schema.StringType:
   442  			return "pulumi.StringInput"
   443  		case schema.ArchiveType:
   444  			return "pulumi.ArchiveInput"
   445  		case schema.AssetType:
   446  			return "pulumi.AssetOrArchiveInput"
   447  		case schema.JSONType:
   448  			fallthrough
   449  		case schema.AnyType:
   450  			return "pulumi.Input"
   451  		}
   452  	}
   453  
   454  	panic(fmt.Errorf("unexpected type %T", t))
   455  }
   456  
   457  func (pkg *pkgContext) argsTypeImpl(t schema.Type) (result string) {
   458  	switch t := codegen.SimplifyInputUnion(t).(type) {
   459  	case *schema.OptionalType:
   460  		return pkg.typeStringImpl(t, true)
   461  	case *schema.InputType:
   462  		return pkg.argsTypeImpl(t.ElementType)
   463  	case *schema.EnumType:
   464  		// Since enum type is itself an input
   465  		return pkg.resolveEnumType(t)
   466  	case *schema.ArrayType:
   467  		en := pkg.argsTypeImpl(t.ElementType)
   468  		return strings.TrimSuffix(en, "Args") + "Array"
   469  	case *schema.MapType:
   470  		en := pkg.argsTypeImpl(t.ElementType)
   471  		return strings.TrimSuffix(en, "Args") + "Map"
   472  	case *schema.ObjectType:
   473  		return pkg.resolveObjectType(t)
   474  	case *schema.ResourceType:
   475  		return pkg.resolveResourceType(t)
   476  	case *schema.TokenType:
   477  		// Use the underlying type for now.
   478  		if t.UnderlyingType != nil {
   479  			return pkg.argsTypeImpl(t.UnderlyingType)
   480  		}
   481  		return pkg.tokenToType(t.Token)
   482  	case *schema.UnionType:
   483  		// If the union is actually a relaxed enum type, use the underlying
   484  		// type for the input instead
   485  		for _, e := range t.ElementTypes {
   486  			if typ, ok := e.(*schema.EnumType); ok {
   487  				return pkg.argsTypeImpl(typ.ElementType)
   488  			}
   489  		}
   490  		return "pulumi.Any"
   491  	default:
   492  		switch t {
   493  		case schema.BoolType:
   494  			return "pulumi.Bool"
   495  		case schema.IntType:
   496  			return "pulumi.Int"
   497  		case schema.NumberType:
   498  			return "pulumi.Float64"
   499  		case schema.StringType:
   500  			return "pulumi.String"
   501  		case schema.ArchiveType:
   502  			return "pulumi.Archive"
   503  		case schema.AssetType:
   504  			return "pulumi.AssetOrArchive"
   505  		case schema.JSONType:
   506  			fallthrough
   507  		case schema.AnyType:
   508  			return "pulumi.Any"
   509  		}
   510  	}
   511  
   512  	panic(fmt.Errorf("unexpected type %T", t))
   513  }
   514  
   515  func (pkg *pkgContext) argsType(t schema.Type) string {
   516  	return pkg.typeStringImpl(t, true)
   517  }
   518  
   519  func (pkg *pkgContext) typeStringImpl(t schema.Type, argsType bool) string {
   520  	switch t := t.(type) {
   521  	case *schema.OptionalType:
   522  		if input, isInputType := t.ElementType.(*schema.InputType); isInputType {
   523  			elem := pkg.inputType(input.ElementType)
   524  			if isNilType(input.ElementType) || elem == "pulumi.Input" {
   525  				return elem
   526  			}
   527  			if pkg.isExternalReference(input.ElementType) {
   528  				_, details := pkg.contextForExternalReference(input.ElementType)
   529  
   530  				switch input.ElementType.(type) {
   531  				case *schema.ObjectType:
   532  					if !details.ptrInput {
   533  						return "*" + elem
   534  					}
   535  				case *schema.EnumType:
   536  					if !(details.ptrInput || details.input) {
   537  						return "*" + elem
   538  					}
   539  				}
   540  			}
   541  			if argsType {
   542  				return elem + "Ptr"
   543  			}
   544  			return strings.TrimSuffix(elem, "Input") + "PtrInput"
   545  		}
   546  
   547  		elementType := pkg.typeStringImpl(t.ElementType, argsType)
   548  		if isNilType(t.ElementType) || elementType == "interface{}" {
   549  			return elementType
   550  		}
   551  		return "*" + elementType
   552  	case *schema.InputType:
   553  		if argsType {
   554  			return pkg.argsTypeImpl(t.ElementType)
   555  		}
   556  		return pkg.inputType(t.ElementType)
   557  	case *schema.EnumType:
   558  		return pkg.resolveEnumType(t)
   559  	case *schema.ArrayType:
   560  		typ := "[]"
   561  		return typ + pkg.typeStringImpl(t.ElementType, argsType)
   562  	case *schema.MapType:
   563  		typ := "map[string]"
   564  		return typ + pkg.typeStringImpl(t.ElementType, argsType)
   565  	case *schema.ObjectType:
   566  		return pkg.resolveObjectType(t)
   567  	case *schema.ResourceType:
   568  		return "*" + pkg.resolveResourceType(t)
   569  	case *schema.TokenType:
   570  		// Use the underlying type for now.
   571  		if t.UnderlyingType != nil {
   572  			return pkg.typeStringImpl(t.UnderlyingType, argsType)
   573  		}
   574  		return pkg.tokenToType(t.Token)
   575  	case *schema.UnionType:
   576  		// If the union is actually a relaxed enum type, use the underlying
   577  		// type for the enum instead
   578  		for _, e := range t.ElementTypes {
   579  			if typ, ok := e.(*schema.EnumType); ok {
   580  				return pkg.typeStringImpl(typ.ElementType, argsType)
   581  			}
   582  		}
   583  		// TODO(pdg): union types
   584  		return "interface{}"
   585  	default:
   586  		switch t {
   587  		case schema.BoolType:
   588  			return "bool"
   589  		case schema.IntType:
   590  			return "int"
   591  		case schema.NumberType:
   592  			return "float64"
   593  		case schema.StringType:
   594  			return "string"
   595  		case schema.ArchiveType:
   596  			return "pulumi.Archive"
   597  		case schema.AssetType:
   598  			return "pulumi.AssetOrArchive"
   599  		case schema.JSONType:
   600  			fallthrough
   601  		case schema.AnyType:
   602  			return "interface{}"
   603  		}
   604  	}
   605  
   606  	panic(fmt.Errorf("unexpected type %T", t))
   607  }
   608  
   609  func (pkg *pkgContext) typeString(t schema.Type) string {
   610  	s := pkg.typeStringImpl(t, false)
   611  	if s == "pulumi." {
   612  		return "pulumi.Any"
   613  	}
   614  	return s
   615  
   616  }
   617  
   618  func (pkg *pkgContext) isExternalReference(t schema.Type) bool {
   619  	isExternal, _, _ := pkg.isExternalReferenceWithPackage(t)
   620  	return isExternal
   621  }
   622  
   623  // Return if `t` is external to `pkg`. If so, the associated foreign schema.Package is returned.
   624  func (pkg *pkgContext) isExternalReferenceWithPackage(t schema.Type) (
   625  	isExternal bool, extPkg *schema.Package, token string) {
   626  	var err error
   627  	switch typ := t.(type) {
   628  	case *schema.ObjectType:
   629  		isExternal = typ.Package != nil && pkg.pkg != nil && typ.Package != pkg.pkg
   630  		if isExternal {
   631  			extPkg, err = typ.PackageReference.Definition()
   632  			contract.AssertNoError(err)
   633  			token = typ.Token
   634  		}
   635  		return
   636  	case *schema.ResourceType:
   637  		isExternal = typ.Resource != nil && pkg.pkg != nil && typ.Resource.Package != pkg.pkg
   638  		if isExternal {
   639  			extPkg, err = typ.Resource.PackageReference.Definition()
   640  			contract.AssertNoError(err)
   641  			token = typ.Token
   642  		}
   643  		return
   644  	case *schema.EnumType:
   645  		isExternal = pkg.pkg != nil && typ.Package != pkg.pkg
   646  		if isExternal {
   647  			extPkg, err = typ.PackageReference.Definition()
   648  			contract.AssertNoError(err)
   649  			token = typ.Token
   650  		}
   651  		return
   652  	}
   653  	return
   654  }
   655  
   656  // resolveResourceType resolves resource references in properties while
   657  // taking into account potential external resources. Returned type is
   658  // always marked as required. Caller should check if the property is
   659  // optional and convert the type to a pointer if necessary.
   660  func (pkg *pkgContext) resolveResourceType(t *schema.ResourceType) string {
   661  	if !pkg.isExternalReference(t) {
   662  		return pkg.tokenToResource(t.Token)
   663  	}
   664  	extPkgCtx, _ := pkg.contextForExternalReference(t)
   665  	resType := extPkgCtx.tokenToResource(t.Token)
   666  	if !strings.Contains(resType, ".") {
   667  		resType = fmt.Sprintf("%s.%s", extPkgCtx.pkg.Name, resType)
   668  	}
   669  	return resType
   670  }
   671  
   672  // resolveObjectType resolves resource references in properties while
   673  // taking into account potential external resources. Returned type is
   674  // always marked as required. Caller should check if the property is
   675  // optional and convert the type to a pointer if necessary.
   676  func (pkg *pkgContext) resolveObjectType(t *schema.ObjectType) string {
   677  	isExternal, _, _ := pkg.isExternalReferenceWithPackage(t)
   678  
   679  	if !isExternal {
   680  		name := pkg.tokenToType(t.Token)
   681  		if t.IsInputShape() {
   682  			return name + "Args"
   683  		}
   684  		return name
   685  	}
   686  	extPkg, _ := pkg.contextForExternalReference(t)
   687  	return extPkg.typeString(t)
   688  }
   689  
   690  func (pkg *pkgContext) contextForExternalReference(t schema.Type) (*pkgContext, typeDetails) {
   691  	isExternal, extPkg, token := pkg.isExternalReferenceWithPackage(t)
   692  	contract.Assert(isExternal)
   693  
   694  	var goInfo GoPackageInfo
   695  	contract.AssertNoError(extPkg.ImportLanguages(map[string]schema.Language{"go": Importer}))
   696  	if info, ok := extPkg.Language["go"].(GoPackageInfo); ok {
   697  		goInfo = info
   698  	} else {
   699  		goInfo.ImportBasePath = extractImportBasePath(extPkg)
   700  	}
   701  
   702  	pkgImportAliases := goInfo.PackageImportAliases
   703  
   704  	// Ensure that any package import aliases we have specified locally take precedence over those
   705  	// specified in the remote package.
   706  	if ourPkgGoInfoI, has := pkg.pkg.Language["go"]; has {
   707  		ourPkgGoInfo := ourPkgGoInfoI.(GoPackageInfo)
   708  		if len(ourPkgGoInfo.PackageImportAliases) > 0 {
   709  			pkgImportAliases = make(map[string]string)
   710  			// Copy the external import aliases.
   711  			for k, v := range goInfo.PackageImportAliases {
   712  				pkgImportAliases[k] = v
   713  			}
   714  			// Copy the local import aliases, overwriting any external aliases.
   715  			for k, v := range ourPkgGoInfo.PackageImportAliases {
   716  				pkgImportAliases[k] = v
   717  			}
   718  		}
   719  	}
   720  
   721  	var maps map[string]*pkgContext
   722  
   723  	if extMap, ok := pkg.externalPackages.lookupContextMap(extPkg); ok {
   724  		maps = extMap
   725  	} else {
   726  		maps = generatePackageContextMap(pkg.tool, extPkg, goInfo, pkg.externalPackages)
   727  		pkg.externalPackages.setContextMap(extPkg, maps)
   728  	}
   729  	extPkgCtx := maps[""]
   730  	extPkgCtx.pkgImportAliases = pkgImportAliases
   731  	extPkgCtx.externalPackages = pkg.externalPackages
   732  	mod := tokenToPackage(extPkg, goInfo.ModuleToPackage, token)
   733  
   734  	return extPkgCtx, *maps[mod].detailsForType(t)
   735  }
   736  
   737  // outputTypeImpl does the meat of the generation of output type names from schema types. This function should only be
   738  // called with a fully-resolved type (e.g. the result of codegen.ResolvedType). Instead of calling this function, you
   739  // probably want to call pkgContext.outputType, which ensures that its argument is resolved.
   740  func (pkg *pkgContext) outputTypeImpl(t schema.Type) string {
   741  	switch t := t.(type) {
   742  	case *schema.OptionalType:
   743  		elem := pkg.outputTypeImpl(t.ElementType)
   744  		if isNilType(t.ElementType) || elem == "pulumi.AnyOutput" {
   745  			return elem
   746  		}
   747  		if pkg.isExternalReference(t.ElementType) {
   748  			_, details := pkg.contextForExternalReference(t.ElementType)
   749  			switch t.ElementType.(type) {
   750  			case *schema.ObjectType:
   751  				if !details.ptrOutput {
   752  					return "*" + elem
   753  				}
   754  			case *schema.EnumType:
   755  				if !(details.ptrOutput || details.output) {
   756  					return "*" + elem
   757  				}
   758  			}
   759  		}
   760  		return strings.TrimSuffix(elem, "Output") + "PtrOutput"
   761  	case *schema.EnumType:
   762  		return pkg.resolveEnumType(t) + "Output"
   763  	case *schema.ArrayType:
   764  		en := strings.TrimSuffix(pkg.outputTypeImpl(t.ElementType), "Output")
   765  		if en == "pulumi.Any" {
   766  			return "pulumi.ArrayOutput"
   767  		}
   768  		return en + "ArrayOutput"
   769  	case *schema.MapType:
   770  		en := strings.TrimSuffix(pkg.outputTypeImpl(t.ElementType), "Output")
   771  		if en == "pulumi.Any" {
   772  			return "pulumi.MapOutput"
   773  		}
   774  		return en + "MapOutput"
   775  	case *schema.ObjectType:
   776  		return pkg.resolveObjectType(t) + "Output"
   777  	case *schema.ResourceType:
   778  		return pkg.resolveResourceType(t) + "Output"
   779  	case *schema.TokenType:
   780  		// Use the underlying type for now.
   781  		if t.UnderlyingType != nil {
   782  			return pkg.outputTypeImpl(t.UnderlyingType)
   783  		}
   784  		return pkg.tokenToType(t.Token) + "Output"
   785  	case *schema.UnionType:
   786  		// If the union is actually a relaxed enum type, use the underlying
   787  		// type for the output instead
   788  		for _, e := range t.ElementTypes {
   789  			if typ, ok := e.(*schema.EnumType); ok {
   790  				return pkg.outputTypeImpl(typ.ElementType)
   791  			}
   792  		}
   793  		// TODO(pdg): union types
   794  		return "pulumi.AnyOutput"
   795  	case *schema.InputType:
   796  		// We can't make output types for input types. We instead strip the input and try again.
   797  		return pkg.outputTypeImpl(t.ElementType)
   798  	default:
   799  		switch t {
   800  		case schema.BoolType:
   801  			return "pulumi.BoolOutput"
   802  		case schema.IntType:
   803  			return "pulumi.IntOutput"
   804  		case schema.NumberType:
   805  			return "pulumi.Float64Output"
   806  		case schema.StringType:
   807  			return "pulumi.StringOutput"
   808  		case schema.ArchiveType:
   809  			return "pulumi.ArchiveOutput"
   810  		case schema.AssetType:
   811  			return "pulumi.AssetOrArchiveOutput"
   812  		case schema.JSONType:
   813  			fallthrough
   814  		case schema.AnyType:
   815  			return "pulumi.AnyOutput"
   816  		}
   817  	}
   818  
   819  	panic(fmt.Errorf("unexpected type %T", t))
   820  }
   821  
   822  // outputType returns a reference to the Go output type that corresponds to the given schema type. For example, given
   823  // a schema.String, outputType returns "pulumi.String", and given a *schema.ObjectType with the token pkg:mod:Name,
   824  // outputType returns "mod.NameOutput" or "NameOutput", depending on whether or not the object type lives in a
   825  // different module than the one associated with the receiver.
   826  func (pkg *pkgContext) outputType(t schema.Type) string {
   827  	return pkg.outputTypeImpl(codegen.ResolvedType(t))
   828  }
   829  
   830  // toOutputMethod returns the name of the "ToXXXOutput" method for the given schema type. For example, given a
   831  // schema.String, toOutputMethod returns "ToStringOutput", and given a *schema.ObjectType with the token pkg:mod:Name,
   832  // outputType returns "ToNameOutput".
   833  func (pkg *pkgContext) toOutputMethod(t schema.Type) string {
   834  	outputTypeName := pkg.outputType(t)
   835  	if i := strings.LastIndexByte(outputTypeName, '.'); i != -1 {
   836  		outputTypeName = outputTypeName[i+1:]
   837  	}
   838  	return "To" + outputTypeName
   839  }
   840  
   841  func printComment(w io.Writer, comment string, indent bool) int {
   842  	comment = codegen.FilterExamples(comment, "go")
   843  
   844  	lines := strings.Split(comment, "\n")
   845  	for len(lines) > 0 && lines[len(lines)-1] == "" {
   846  		lines = lines[:len(lines)-1]
   847  	}
   848  	for _, l := range lines {
   849  		if indent {
   850  			fmt.Fprintf(w, "\t")
   851  		}
   852  		if l == "" {
   853  			fmt.Fprintf(w, "//\n")
   854  		} else {
   855  			fmt.Fprintf(w, "// %s\n", l)
   856  		}
   857  	}
   858  	return len(lines)
   859  }
   860  
   861  func printCommentWithDeprecationMessage(w io.Writer, comment, deprecationMessage string, indent bool) {
   862  	lines := printComment(w, comment, indent)
   863  	if deprecationMessage != "" {
   864  		if lines > 0 {
   865  			fmt.Fprintf(w, "//\n")
   866  		}
   867  		printComment(w, fmt.Sprintf("Deprecated: %s", deprecationMessage), indent)
   868  	}
   869  }
   870  
   871  func (pkg *pkgContext) genInputInterface(w io.Writer, name string) {
   872  	printComment(w, pkg.getInputUsage(name), false)
   873  	fmt.Fprintf(w, "type %sInput interface {\n", name)
   874  	fmt.Fprintf(w, "\tpulumi.Input\n\n")
   875  	fmt.Fprintf(w, "\tTo%sOutput() %sOutput\n", Title(name), name)
   876  	fmt.Fprintf(w, "\tTo%sOutputWithContext(context.Context) %sOutput\n", Title(name), name)
   877  	fmt.Fprintf(w, "}\n\n")
   878  }
   879  
   880  func (pkg *pkgContext) getUsageForNestedType(name, baseTypeName string) string {
   881  	const defaultExampleFormat = "%sArgs{...}"
   882  	example := fmt.Sprintf(defaultExampleFormat, baseTypeName)
   883  
   884  	trimmer := func(typeName string) string {
   885  		if strings.HasSuffix(typeName, "Array") {
   886  			return typeName[:strings.LastIndex(typeName, "Array")]
   887  		}
   888  		if strings.HasSuffix(typeName, "Map") {
   889  			return typeName[:strings.LastIndex(typeName, "Map")]
   890  		}
   891  		return typeName
   892  	}
   893  
   894  	// If not a nested collection type, use the default example format
   895  	if trimmer(name) == name {
   896  		return example
   897  	}
   898  
   899  	if strings.HasSuffix(name, "Map") {
   900  		if pkg.schemaNames.Has(baseTypeName) {
   901  			return fmt.Sprintf("%s{ \"key\": %s }", name, example)
   902  		}
   903  		return fmt.Sprintf("%s{ \"key\": %s }", name, pkg.getUsageForNestedType(baseTypeName, trimmer(baseTypeName)))
   904  	}
   905  
   906  	if strings.HasSuffix(name, "Array") {
   907  		if pkg.schemaNames.Has(baseTypeName) {
   908  			return fmt.Sprintf("%s{ %s }", name, example)
   909  		}
   910  		return fmt.Sprintf("%s{ %s }", name, pkg.getUsageForNestedType(baseTypeName, trimmer(baseTypeName)))
   911  	}
   912  	return example
   913  }
   914  
   915  func (pkg *pkgContext) getInputUsage(name string) string {
   916  	if strings.HasSuffix(name, "Array") {
   917  		baseTypeName := name[:strings.LastIndex(name, "Array")]
   918  		return strings.Join([]string{
   919  			fmt.Sprintf("%sInput is an input type that accepts %s and %sOutput values.", name, name, name),
   920  			fmt.Sprintf("You can construct a concrete instance of `%sInput` via:", name),
   921  			"",
   922  			"\t\t " + pkg.getUsageForNestedType(name, baseTypeName),
   923  			" ",
   924  		}, "\n")
   925  	}
   926  
   927  	if strings.HasSuffix(name, "Map") {
   928  		baseTypeName := name[:strings.LastIndex(name, "Map")]
   929  		return strings.Join([]string{
   930  			fmt.Sprintf("%sInput is an input type that accepts %s and %sOutput values.", name, name, name),
   931  			fmt.Sprintf("You can construct a concrete instance of `%sInput` via:", name),
   932  			"",
   933  			"\t\t " + pkg.getUsageForNestedType(name, baseTypeName),
   934  			" ",
   935  		}, "\n")
   936  	}
   937  
   938  	if strings.HasSuffix(name, "Ptr") {
   939  		baseTypeName := name[:strings.LastIndex(name, "Ptr")]
   940  		return strings.Join([]string{
   941  			fmt.Sprintf("%sInput is an input type that accepts %sArgs, %s and %sOutput values.", name, baseTypeName, name, name),
   942  			fmt.Sprintf("You can construct a concrete instance of `%sInput` via:", name),
   943  			"",
   944  			fmt.Sprintf("\t\t %sArgs{...}", baseTypeName),
   945  			"",
   946  			" or:",
   947  			"",
   948  			"\t\t nil",
   949  			" ",
   950  		}, "\n")
   951  	}
   952  
   953  	return strings.Join([]string{
   954  		fmt.Sprintf("%sInput is an input type that accepts %sArgs and %sOutput values.", name, name, name),
   955  		fmt.Sprintf("You can construct a concrete instance of `%sInput` via:", name),
   956  		"",
   957  		fmt.Sprintf("\t\t %sArgs{...}", name),
   958  		" ",
   959  	}, "\n")
   960  }
   961  
   962  type genInputImplementationArgs struct {
   963  	name            string
   964  	receiverType    string
   965  	elementType     string
   966  	ptrMethods      bool
   967  	toOutputMethods bool
   968  }
   969  
   970  func genInputImplementation(w io.Writer, name, receiverType, elementType string, ptrMethods bool) {
   971  	genInputImplementationWithArgs(w, genInputImplementationArgs{
   972  		name:            name,
   973  		receiverType:    receiverType,
   974  		elementType:     elementType,
   975  		ptrMethods:      ptrMethods,
   976  		toOutputMethods: true,
   977  	})
   978  }
   979  
   980  func genInputImplementationWithArgs(w io.Writer, genArgs genInputImplementationArgs) {
   981  	name := genArgs.name
   982  	receiverType := genArgs.receiverType
   983  	elementType := genArgs.elementType
   984  
   985  	fmt.Fprintf(w, "func (%s) ElementType() reflect.Type {\n", receiverType)
   986  	fmt.Fprintf(w, "\treturn reflect.TypeOf((*%s)(nil)).Elem()\n", elementType)
   987  	fmt.Fprintf(w, "}\n\n")
   988  
   989  	if genArgs.toOutputMethods {
   990  		fmt.Fprintf(w, "func (i %s) To%sOutput() %sOutput {\n", receiverType, Title(name), name)
   991  		fmt.Fprintf(w, "\treturn i.To%sOutputWithContext(context.Background())\n", Title(name))
   992  		fmt.Fprintf(w, "}\n\n")
   993  
   994  		fmt.Fprintf(w, "func (i %s) To%sOutputWithContext(ctx context.Context) %sOutput {\n", receiverType, Title(name), name)
   995  		fmt.Fprintf(w, "\treturn pulumi.ToOutputWithContext(ctx, i).(%sOutput)\n", name)
   996  		fmt.Fprintf(w, "}\n\n")
   997  	}
   998  
   999  	if genArgs.ptrMethods {
  1000  		fmt.Fprintf(w, "func (i %s) To%sPtrOutput() %sPtrOutput {\n", receiverType, Title(name), name)
  1001  		fmt.Fprintf(w, "\treturn i.To%sPtrOutputWithContext(context.Background())\n", Title(name))
  1002  		fmt.Fprintf(w, "}\n\n")
  1003  
  1004  		fmt.Fprintf(w, "func (i %s) To%sPtrOutputWithContext(ctx context.Context) %sPtrOutput {\n", receiverType, Title(name), name)
  1005  		if strings.HasSuffix(receiverType, "Args") {
  1006  			fmt.Fprintf(w, "\treturn pulumi.ToOutputWithContext(ctx, i).(%[1]sOutput).To%[1]sPtrOutputWithContext(ctx)\n", name)
  1007  		} else {
  1008  			fmt.Fprintf(w, "\treturn pulumi.ToOutputWithContext(ctx, i).(%sPtrOutput)\n", name)
  1009  		}
  1010  		fmt.Fprintf(w, "}\n\n")
  1011  	}
  1012  }
  1013  
  1014  func genOutputType(w io.Writer, baseName, elementType string, ptrMethods bool) {
  1015  	fmt.Fprintf(w, "type %sOutput struct { *pulumi.OutputState }\n\n", baseName)
  1016  
  1017  	fmt.Fprintf(w, "func (%sOutput) ElementType() reflect.Type {\n", baseName)
  1018  	fmt.Fprintf(w, "\treturn reflect.TypeOf((*%s)(nil)).Elem()\n", elementType)
  1019  	fmt.Fprintf(w, "}\n\n")
  1020  
  1021  	fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sOutput() %[1]sOutput {\n", baseName, Title(baseName))
  1022  	fmt.Fprintf(w, "\treturn o\n")
  1023  	fmt.Fprintf(w, "}\n\n")
  1024  
  1025  	fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sOutputWithContext(ctx context.Context) %[1]sOutput {\n", baseName, Title(baseName))
  1026  	fmt.Fprintf(w, "\treturn o\n")
  1027  	fmt.Fprintf(w, "}\n\n")
  1028  
  1029  	if ptrMethods {
  1030  		fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sPtrOutput() %[1]sPtrOutput {\n", baseName, Title(baseName))
  1031  		fmt.Fprintf(w, "\treturn o.To%sPtrOutputWithContext(context.Background())\n", Title(baseName))
  1032  		fmt.Fprintf(w, "}\n\n")
  1033  
  1034  		fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sPtrOutputWithContext(ctx context.Context) %[1]sPtrOutput {\n", baseName, Title(baseName))
  1035  		fmt.Fprintf(w, "\treturn o.ApplyTWithContext(ctx, func(_ context.Context, v %[1]s) *%[1]s {\n", elementType)
  1036  		fmt.Fprintf(w, "\t\treturn &v\n")
  1037  		fmt.Fprintf(w, "\t}).(%sPtrOutput)\n", baseName)
  1038  		fmt.Fprintf(w, "}\n\n")
  1039  	}
  1040  }
  1041  
  1042  func genArrayOutput(w io.Writer, baseName, elementType string) {
  1043  	genOutputType(w, baseName+"Array", "[]"+elementType, false)
  1044  
  1045  	fmt.Fprintf(w, "func (o %[1]sArrayOutput) Index(i pulumi.IntInput) %[1]sOutput {\n", baseName)
  1046  	fmt.Fprintf(w, "\treturn pulumi.All(o, i).ApplyT(func (vs []interface{}) %s {\n", elementType)
  1047  	fmt.Fprintf(w, "\t\treturn vs[0].([]%s)[vs[1].(int)]\n", elementType)
  1048  	fmt.Fprintf(w, "\t}).(%sOutput)\n", baseName)
  1049  	fmt.Fprintf(w, "}\n\n")
  1050  }
  1051  
  1052  func genMapOutput(w io.Writer, baseName, elementType string) {
  1053  	genOutputType(w, baseName+"Map", "map[string]"+elementType, false)
  1054  
  1055  	fmt.Fprintf(w, "func (o %[1]sMapOutput) MapIndex(k pulumi.StringInput) %[1]sOutput {\n", baseName)
  1056  	fmt.Fprintf(w, "\treturn pulumi.All(o, k).ApplyT(func (vs []interface{}) %s{\n", elementType)
  1057  	fmt.Fprintf(w, "\t\treturn vs[0].(map[string]%s)[vs[1].(string)]\n", elementType)
  1058  	fmt.Fprintf(w, "\t}).(%sOutput)\n", baseName)
  1059  	fmt.Fprintf(w, "}\n\n")
  1060  }
  1061  
  1062  func genPtrOutput(w io.Writer, baseName, elementType string) {
  1063  	genOutputType(w, baseName+"Ptr", "*"+elementType, false)
  1064  
  1065  	fmt.Fprintf(w, "func (o %[1]sPtrOutput) Elem() %[1]sOutput {\n", baseName)
  1066  	fmt.Fprintf(w, "\treturn o.ApplyT(func(v *%[1]s) %[1]s {\n", baseName)
  1067  	fmt.Fprint(w, "\t\tif v != nil {\n")
  1068  	fmt.Fprintf(w, "\t\t\treturn *v\n")
  1069  	fmt.Fprint(w, "\t\t}\n")
  1070  	fmt.Fprintf(w, "\t\tvar ret %s\n", baseName)
  1071  	fmt.Fprint(w, "\t\treturn ret\n")
  1072  	fmt.Fprintf(w, "\t}).(%sOutput)\n", baseName)
  1073  	fmt.Fprint(w, "}\n\n")
  1074  }
  1075  
  1076  func (pkg *pkgContext) genEnum(w io.Writer, enumType *schema.EnumType) error {
  1077  	name := pkg.tokenToEnum(enumType.Token)
  1078  
  1079  	mod := pkg.tokenToPackage(enumType.Token)
  1080  	modPkg, ok := pkg.packages[mod]
  1081  	contract.Assert(ok)
  1082  
  1083  	printCommentWithDeprecationMessage(w, enumType.Comment, "", false)
  1084  
  1085  	elementArgsType := pkg.argsTypeImpl(enumType.ElementType)
  1086  	elementGoType := pkg.typeString(enumType.ElementType)
  1087  	asFuncName := strings.TrimPrefix(elementArgsType, "pulumi.")
  1088  
  1089  	fmt.Fprintf(w, "type %s %s\n\n", name, elementGoType)
  1090  
  1091  	fmt.Fprintln(w, "const (")
  1092  	for _, e := range enumType.Elements {
  1093  		printCommentWithDeprecationMessage(w, e.Comment, e.DeprecationMessage, true)
  1094  
  1095  		var elementName = e.Name
  1096  		if e.Name == "" {
  1097  			elementName = fmt.Sprintf("%v", e.Value)
  1098  		}
  1099  		enumName, err := makeSafeEnumName(elementName, name)
  1100  		if err != nil {
  1101  			return err
  1102  		}
  1103  		e.Name = enumName
  1104  		contract.Assertf(!modPkg.names.Has(e.Name), "Name collision for enum constant: %s for %s",
  1105  			e.Name, enumType.Token)
  1106  
  1107  		switch reflect.TypeOf(e.Value).Kind() {
  1108  		case reflect.String:
  1109  			fmt.Fprintf(w, "%s = %s(%q)\n", e.Name, name, e.Value)
  1110  		default:
  1111  			fmt.Fprintf(w, "%s = %s(%v)\n", e.Name, name, e.Value)
  1112  		}
  1113  	}
  1114  	fmt.Fprintln(w, ")")
  1115  
  1116  	details := pkg.detailsForType(enumType)
  1117  	if details.input || details.ptrInput {
  1118  		inputType := pkg.inputType(enumType)
  1119  		pkg.genEnumInputFuncs(w, name, enumType, elementArgsType, inputType, asFuncName)
  1120  	}
  1121  
  1122  	if details.output || details.ptrOutput {
  1123  		pkg.genEnumOutputTypes(w, name, elementArgsType, elementGoType, asFuncName)
  1124  	}
  1125  	if details.input || details.ptrInput {
  1126  		pkg.genEnumInputTypes(w, name, enumType, elementGoType)
  1127  	}
  1128  
  1129  	// Generate the array input.
  1130  	if details.arrayInput {
  1131  		pkg.genInputInterface(w, name+"Array")
  1132  
  1133  		fmt.Fprintf(w, "type %[1]sArray []%[1]s\n\n", name)
  1134  
  1135  		genInputImplementation(w, name+"Array", name+"Array", "[]"+name, false)
  1136  	}
  1137  
  1138  	// Generate the map input.
  1139  	if details.mapInput {
  1140  		pkg.genInputInterface(w, name+"Map")
  1141  
  1142  		fmt.Fprintf(w, "type %[1]sMap map[string]%[1]s\n\n", name)
  1143  
  1144  		genInputImplementation(w, name+"Map", name+"Map", "map[string]"+name, false)
  1145  	}
  1146  
  1147  	// Generate the array output
  1148  	if details.arrayOutput {
  1149  		genArrayOutput(w, name, name)
  1150  	}
  1151  
  1152  	// Generate the map output.
  1153  	if details.mapOutput {
  1154  		genMapOutput(w, name, name)
  1155  	}
  1156  
  1157  	return nil
  1158  }
  1159  
  1160  func (pkg *pkgContext) genEnumOutputTypes(w io.Writer, name, elementArgsType, elementGoType, asFuncName string) {
  1161  	genOutputType(w, name, name, true)
  1162  
  1163  	fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sOutput() %[3]sOutput {\n", name, asFuncName, elementArgsType)
  1164  	fmt.Fprintf(w, "return o.To%sOutputWithContext(context.Background())\n", asFuncName)
  1165  	fmt.Fprint(w, "}\n\n")
  1166  
  1167  	fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sOutputWithContext(ctx context.Context) %[3]sOutput {\n", name, asFuncName, elementArgsType)
  1168  	fmt.Fprintf(w, "return o.ApplyTWithContext(ctx, func(_ context.Context, e %s) %s {\n", name, elementGoType)
  1169  	fmt.Fprintf(w, "return %s(e)\n", elementGoType)
  1170  	fmt.Fprintf(w, "}).(%sOutput)\n", elementArgsType)
  1171  	fmt.Fprint(w, "}\n\n")
  1172  
  1173  	fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sPtrOutput() %[3]sPtrOutput {\n", name, asFuncName, elementArgsType)
  1174  	fmt.Fprintf(w, "return o.To%sPtrOutputWithContext(context.Background())\n", asFuncName)
  1175  	fmt.Fprint(w, "}\n\n")
  1176  
  1177  	fmt.Fprintf(w, "func (o %[1]sOutput) To%[2]sPtrOutputWithContext(ctx context.Context) %[3]sPtrOutput {\n", name, asFuncName, elementArgsType)
  1178  	fmt.Fprintf(w, "return o.ApplyTWithContext(ctx, func(_ context.Context, e %s) *%s {\n", name, elementGoType)
  1179  	fmt.Fprintf(w, "v := %s(e)\n", elementGoType)
  1180  	fmt.Fprintf(w, "return &v\n")
  1181  	fmt.Fprintf(w, "}).(%sPtrOutput)\n", elementArgsType)
  1182  	fmt.Fprint(w, "}\n\n")
  1183  
  1184  	genPtrOutput(w, name, name)
  1185  
  1186  	fmt.Fprintf(w, "func (o %[1]sPtrOutput) To%[2]sPtrOutput() %[3]sPtrOutput {\n", name, asFuncName, elementArgsType)
  1187  	fmt.Fprintf(w, "return o.To%sPtrOutputWithContext(context.Background())\n", asFuncName)
  1188  	fmt.Fprint(w, "}\n\n")
  1189  
  1190  	fmt.Fprintf(w, "func (o %[1]sPtrOutput) To%[2]sPtrOutputWithContext(ctx context.Context) %[3]sPtrOutput {\n", name, asFuncName, elementArgsType)
  1191  	fmt.Fprintf(w, "return o.ApplyTWithContext(ctx, func(_ context.Context, e *%s) *%s {\n", name, elementGoType)
  1192  	fmt.Fprintf(w, "if e == nil {\n")
  1193  	fmt.Fprintf(w, "return nil\n")
  1194  	fmt.Fprintf(w, "}\n")
  1195  	fmt.Fprintf(w, "v := %s(*e)\n", elementGoType)
  1196  	fmt.Fprintf(w, "return &v\n")
  1197  	fmt.Fprintf(w, "}).(%sPtrOutput)\n", elementArgsType)
  1198  	fmt.Fprint(w, "}\n\n")
  1199  }
  1200  
  1201  func (pkg *pkgContext) genEnumInputTypes(w io.Writer, name string, enumType *schema.EnumType, elementGoType string) {
  1202  	pkg.genInputInterface(w, name)
  1203  
  1204  	typeName := cgstrings.Camel(name)
  1205  	fmt.Fprintf(w, "var %sPtrType = reflect.TypeOf((**%s)(nil)).Elem()\n", typeName, name)
  1206  	fmt.Fprintln(w)
  1207  
  1208  	fmt.Fprintf(w, "type %sPtrInput interface {\n", name)
  1209  	fmt.Fprint(w, "pulumi.Input\n\n")
  1210  	fmt.Fprintf(w, "To%[1]sPtrOutput() %[1]sPtrOutput\n", name)
  1211  	fmt.Fprintf(w, "To%[1]sPtrOutputWithContext(context.Context) %[1]sPtrOutput\n", name)
  1212  	fmt.Fprintf(w, "}\n")
  1213  	fmt.Fprintln(w)
  1214  
  1215  	fmt.Fprintf(w, "type %sPtr %s\n", typeName, elementGoType)
  1216  	fmt.Fprintln(w)
  1217  
  1218  	fmt.Fprintf(w, "func %[1]sPtr(v %[2]s) %[1]sPtrInput {\n", name, elementGoType)
  1219  	fmt.Fprintf(w, "return (*%sPtr)(&v)\n", typeName)
  1220  	fmt.Fprintf(w, "}\n")
  1221  	fmt.Fprintln(w)
  1222  
  1223  	fmt.Fprintf(w, "func (*%sPtr) ElementType() reflect.Type {\n", typeName)
  1224  	fmt.Fprintf(w, "return %sPtrType\n", typeName)
  1225  	fmt.Fprintf(w, "}\n")
  1226  	fmt.Fprintln(w)
  1227  
  1228  	fmt.Fprintf(w, "func (in *%[1]sPtr) To%[2]sPtrOutput() %[2]sPtrOutput {\n", typeName, name)
  1229  	fmt.Fprintf(w, "return pulumi.ToOutput(in).(%sPtrOutput)\n", name)
  1230  	fmt.Fprintf(w, "}\n")
  1231  	fmt.Fprintln(w)
  1232  
  1233  	fmt.Fprintf(w, "func (in *%[1]sPtr) To%[2]sPtrOutputWithContext(ctx context.Context) %[2]sPtrOutput {\n", cgstrings.Camel(name), name)
  1234  	fmt.Fprintf(w, "return pulumi.ToOutputWithContext(ctx, in).(%sPtrOutput)\n", name)
  1235  	fmt.Fprintf(w, "}\n")
  1236  	fmt.Fprintln(w)
  1237  }
  1238  
  1239  func (pkg *pkgContext) genEnumInputFuncs(w io.Writer, typeName string, enum *schema.EnumType, elementArgsType, inputType, asFuncName string) {
  1240  	fmt.Fprintln(w)
  1241  	fmt.Fprintf(w, "func (%s) ElementType() reflect.Type {\n", typeName)
  1242  	fmt.Fprintf(w, "return reflect.TypeOf((*%s)(nil)).Elem()\n", typeName)
  1243  	fmt.Fprintln(w, "}")
  1244  	fmt.Fprintln(w)
  1245  
  1246  	fmt.Fprintf(w, "func (e %[1]s) To%[1]sOutput() %[1]sOutput {\n", typeName)
  1247  	fmt.Fprintf(w, "return pulumi.ToOutput(e).(%sOutput)\n", typeName)
  1248  	fmt.Fprintln(w, "}")
  1249  	fmt.Fprintln(w)
  1250  
  1251  	fmt.Fprintf(w, "func (e %[1]s) To%[1]sOutputWithContext(ctx context.Context) %[1]sOutput {\n", typeName)
  1252  	fmt.Fprintf(w, "return pulumi.ToOutputWithContext(ctx, e).(%sOutput)\n", typeName)
  1253  	fmt.Fprintln(w, "}")
  1254  	fmt.Fprintln(w)
  1255  
  1256  	fmt.Fprintf(w, "func (e %[1]s) To%[1]sPtrOutput() %[1]sPtrOutput {\n", typeName)
  1257  	fmt.Fprintf(w, "return e.To%sPtrOutputWithContext(context.Background())\n", typeName)
  1258  	fmt.Fprintln(w, "}")
  1259  	fmt.Fprintln(w)
  1260  
  1261  	fmt.Fprintf(w, "func (e %[1]s) To%[1]sPtrOutputWithContext(ctx context.Context) %[1]sPtrOutput {\n", typeName)
  1262  	fmt.Fprintf(w, "return %[1]s(e).To%[1]sOutputWithContext(ctx).To%[1]sPtrOutputWithContext(ctx)\n", typeName)
  1263  	fmt.Fprintln(w, "}")
  1264  	fmt.Fprintln(w)
  1265  
  1266  	fmt.Fprintf(w, "func (e %[1]s) To%[2]sOutput() %[3]sOutput {\n", typeName, asFuncName, elementArgsType)
  1267  	fmt.Fprintf(w, "return pulumi.ToOutput(%[1]s(e)).(%[1]sOutput)\n", elementArgsType)
  1268  	fmt.Fprintln(w, "}")
  1269  	fmt.Fprintln(w)
  1270  
  1271  	fmt.Fprintf(w, "func (e %[1]s) To%[2]sOutputWithContext(ctx context.Context) %[3]sOutput {\n", typeName, asFuncName, elementArgsType)
  1272  	fmt.Fprintf(w, "return pulumi.ToOutputWithContext(ctx, %[1]s(e)).(%[1]sOutput)\n", elementArgsType)
  1273  	fmt.Fprintln(w, "}")
  1274  	fmt.Fprintln(w)
  1275  
  1276  	fmt.Fprintf(w, "func (e %[1]s) To%[2]sPtrOutput() %[3]sPtrOutput {\n", typeName, asFuncName, elementArgsType)
  1277  	fmt.Fprintf(w, "return %s(e).To%sPtrOutputWithContext(context.Background())\n", elementArgsType, asFuncName)
  1278  	fmt.Fprintln(w, "}")
  1279  	fmt.Fprintln(w)
  1280  
  1281  	fmt.Fprintf(w, "func (e %[1]s) To%[2]sPtrOutputWithContext(ctx context.Context) %[3]sPtrOutput {\n", typeName, asFuncName, elementArgsType)
  1282  	fmt.Fprintf(w, "return %[1]s(e).To%[2]sOutputWithContext(ctx).To%[2]sPtrOutputWithContext(ctx)\n", elementArgsType, asFuncName)
  1283  	fmt.Fprintln(w, "}")
  1284  	fmt.Fprintln(w)
  1285  }
  1286  
  1287  func (pkg *pkgContext) assignProperty(w io.Writer, p *schema.Property, object, value string, indirectAssign bool) {
  1288  	t := strings.TrimSuffix(pkg.typeString(p.Type), "Input")
  1289  	switch codegen.UnwrapType(p.Type).(type) {
  1290  	case *schema.EnumType:
  1291  		t = ""
  1292  	}
  1293  
  1294  	if codegen.IsNOptionalInput(p.Type) {
  1295  		if t != "" {
  1296  			value = fmt.Sprintf("%s(%s)", t, value)
  1297  		}
  1298  		fmt.Fprintf(w, "\t%s.%s = %s\n", object, pkg.fieldName(nil, p), value)
  1299  	} else if indirectAssign {
  1300  		tmpName := cgstrings.Camel(p.Name) + "_"
  1301  		fmt.Fprintf(w, "%s := %s\n", tmpName, value)
  1302  		fmt.Fprintf(w, "%s.%s = &%s\n", object, pkg.fieldName(nil, p), tmpName)
  1303  	} else {
  1304  		fmt.Fprintf(w, "%s.%s = %s\n", object, pkg.fieldName(nil, p), value)
  1305  	}
  1306  }
  1307  
  1308  func (pkg *pkgContext) fieldName(r *schema.Resource, field *schema.Property) string {
  1309  	contract.Assert(field != nil)
  1310  	return fieldName(pkg, r, field)
  1311  }
  1312  
  1313  func (pkg *pkgContext) genPlainType(w io.Writer, name, comment, deprecationMessage string,
  1314  	properties []*schema.Property) {
  1315  
  1316  	printCommentWithDeprecationMessage(w, comment, deprecationMessage, false)
  1317  	fmt.Fprintf(w, "type %s struct {\n", name)
  1318  	for _, p := range properties {
  1319  		printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1320  		fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", pkg.fieldName(nil, p), pkg.typeString(codegen.ResolvedType(p.Type)), p.Name)
  1321  	}
  1322  	fmt.Fprintf(w, "}\n\n")
  1323  }
  1324  
  1325  func (pkg *pkgContext) genObjectDefaultFunc(w io.Writer, name string,
  1326  	properties []*schema.Property) error {
  1327  	defaults := []*schema.Property{}
  1328  	for _, p := range properties {
  1329  		if p.DefaultValue != nil || codegen.IsProvideDefaultsFuncRequired(p.Type) {
  1330  			defaults = append(defaults, p)
  1331  		}
  1332  	}
  1333  
  1334  	// There are no defaults, so we don't need to generate a defaults function.
  1335  	if len(defaults) == 0 {
  1336  		return nil
  1337  	}
  1338  
  1339  	printComment(w, fmt.Sprintf("%s sets the appropriate defaults for %s", ProvideDefaultsMethodName, name), false)
  1340  	fmt.Fprintf(w, "func (val *%[1]s) %[2]s() *%[1]s {\n", name, ProvideDefaultsMethodName)
  1341  	fmt.Fprintf(w, "if val == nil {\n return nil\n}\n")
  1342  	fmt.Fprintf(w, "tmp := *val\n")
  1343  	for _, p := range defaults {
  1344  		if p.DefaultValue != nil {
  1345  			dv, err := pkg.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
  1346  			if err != nil {
  1347  				return err
  1348  			}
  1349  			pkg.needsUtils = true
  1350  			fmt.Fprintf(w, "if isZero(tmp.%s) {\n", pkg.fieldName(nil, p))
  1351  			pkg.assignProperty(w, p, "tmp", dv, !p.IsRequired())
  1352  			fmt.Fprintf(w, "}\n")
  1353  		} else if funcName := pkg.provideDefaultsFuncName(p.Type); funcName != "" {
  1354  			var member string
  1355  			if codegen.IsNOptionalInput(p.Type) {
  1356  				// f := fmt.Sprintf("func(v %[1]s) %[1]s { return *v.%[2]s() }", name, funcName)
  1357  				// member = fmt.Sprintf("tmp.%[1]s.ApplyT(%[2]s)", pkg.fieldName(nil, p), f)
  1358  			} else {
  1359  				member = fmt.Sprintf("tmp.%[1]s.%[2]s()", pkg.fieldName(nil, p), funcName)
  1360  				sigil := ""
  1361  				if p.IsRequired() {
  1362  					sigil = "*"
  1363  				}
  1364  				pkg.assignProperty(w, p, "tmp", sigil+member, false)
  1365  			}
  1366  			fmt.Fprintln(w)
  1367  		} else {
  1368  			panic(fmt.Sprintf("Property %s[%s] should not be in the default list", p.Name, p.Type.String()))
  1369  		}
  1370  	}
  1371  
  1372  	fmt.Fprintf(w, "return &tmp\n}\n")
  1373  	return nil
  1374  }
  1375  
  1376  // The name of the method used to instantiate defaults.
  1377  const ProvideDefaultsMethodName = "Defaults"
  1378  
  1379  func (pkg *pkgContext) provideDefaultsFuncName(typ schema.Type) string {
  1380  	if !codegen.IsProvideDefaultsFuncRequired(typ) {
  1381  		return ""
  1382  	}
  1383  	return ProvideDefaultsMethodName
  1384  }
  1385  
  1386  func (pkg *pkgContext) genInputTypes(w io.Writer, t *schema.ObjectType, details *typeDetails) error {
  1387  	contract.Assert(t.IsInputShape())
  1388  
  1389  	name := pkg.tokenToType(t.Token)
  1390  
  1391  	// Generate the plain inputs.
  1392  	if details.input {
  1393  		pkg.genInputInterface(w, name)
  1394  
  1395  		inputName := name + "Args"
  1396  		pkg.genInputArgsStruct(w, inputName, t)
  1397  		if !pkg.disableObjectDefaults {
  1398  			if err := pkg.genObjectDefaultFunc(w, inputName, t.Properties); err != nil {
  1399  				return err
  1400  			}
  1401  		}
  1402  
  1403  		genInputImplementation(w, name, inputName, name, details.ptrInput)
  1404  
  1405  	}
  1406  
  1407  	// Generate the pointer input.
  1408  	if details.ptrInput {
  1409  		pkg.genInputInterface(w, name+"Ptr")
  1410  
  1411  		ptrTypeName := cgstrings.Camel(name) + "PtrType"
  1412  
  1413  		fmt.Fprintf(w, "type %s %sArgs\n\n", ptrTypeName, name)
  1414  
  1415  		fmt.Fprintf(w, "func %[1]sPtr(v *%[1]sArgs) %[1]sPtrInput {", name)
  1416  		fmt.Fprintf(w, "\treturn (*%s)(v)\n", ptrTypeName)
  1417  		fmt.Fprintf(w, "}\n\n")
  1418  
  1419  		genInputImplementation(w, name+"Ptr", "*"+ptrTypeName, "*"+name, false)
  1420  	}
  1421  
  1422  	// Generate the array input.
  1423  	if details.arrayInput && !pkg.names.Has(name+"Array") {
  1424  		pkg.genInputInterface(w, name+"Array")
  1425  
  1426  		fmt.Fprintf(w, "type %[1]sArray []%[1]sInput\n\n", name)
  1427  
  1428  		genInputImplementation(w, name+"Array", name+"Array", "[]"+name, false)
  1429  	}
  1430  
  1431  	// Generate the map input.
  1432  	if details.mapInput && !pkg.names.Has(name+"Map") {
  1433  		pkg.genInputInterface(w, name+"Map")
  1434  
  1435  		fmt.Fprintf(w, "type %[1]sMap map[string]%[1]sInput\n\n", name)
  1436  
  1437  		genInputImplementation(w, name+"Map", name+"Map", "map[string]"+name, false)
  1438  	}
  1439  	return nil
  1440  }
  1441  
  1442  func (pkg *pkgContext) genInputArgsStruct(w io.Writer, typeName string, t *schema.ObjectType) {
  1443  	contract.Assert(t.IsInputShape())
  1444  
  1445  	printComment(w, t.Comment, false)
  1446  	fmt.Fprintf(w, "type %s struct {\n", typeName)
  1447  	for _, p := range t.Properties {
  1448  		printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1449  		fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", pkg.fieldName(nil, p), pkg.typeString(p.Type), p.Name)
  1450  	}
  1451  	fmt.Fprintf(w, "}\n\n")
  1452  }
  1453  
  1454  type genOutputTypesArgs struct {
  1455  	t *schema.ObjectType
  1456  
  1457  	// optional type name override
  1458  	name string
  1459  }
  1460  
  1461  func (pkg *pkgContext) genOutputTypes(w io.Writer, genArgs genOutputTypesArgs) {
  1462  	t := genArgs.t
  1463  	details := pkg.detailsForType(t)
  1464  
  1465  	contract.Assert(!t.IsInputShape())
  1466  
  1467  	name := genArgs.name
  1468  	if name == "" {
  1469  		name = pkg.tokenToType(t.Token)
  1470  	}
  1471  
  1472  	if details.output {
  1473  		printComment(w, t.Comment, false)
  1474  		genOutputType(w,
  1475  			name,             /* baseName */
  1476  			name,             /* elementType */
  1477  			details.ptrInput, /* ptrMethods */
  1478  		)
  1479  
  1480  		for _, p := range t.Properties {
  1481  			printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, false)
  1482  			outputType, applyType := pkg.outputType(p.Type), pkg.typeString(p.Type)
  1483  
  1484  			propName := pkg.fieldName(nil, p)
  1485  			switch strings.ToLower(p.Name) {
  1486  			case "elementtype", "issecret":
  1487  				propName = "Get" + propName
  1488  			}
  1489  			fmt.Fprintf(w, "func (o %sOutput) %s() %s {\n", name, propName, outputType)
  1490  			fmt.Fprintf(w, "\treturn o.ApplyT(func (v %s) %s { return v.%s }).(%s)\n",
  1491  				name, applyType, pkg.fieldName(nil, p), outputType)
  1492  			fmt.Fprintf(w, "}\n\n")
  1493  		}
  1494  	}
  1495  
  1496  	if details.ptrOutput {
  1497  		genPtrOutput(w, name, name)
  1498  
  1499  		for _, p := range t.Properties {
  1500  			printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, false)
  1501  			optionalType := codegen.OptionalType(p)
  1502  			outputType, applyType := pkg.outputType(optionalType), pkg.typeString(optionalType)
  1503  			deref := ""
  1504  			// If the property was required, but the type it needs to return is an explicit pointer type, then we need
  1505  			// to dereference it, unless it is a resource type which should remain a pointer.
  1506  			_, isResourceType := p.Type.(*schema.ResourceType)
  1507  			if p.IsRequired() && applyType[0] == '*' && !isResourceType {
  1508  				deref = "&"
  1509  			}
  1510  
  1511  			funcName := Title(p.Name)
  1512  			// Avoid conflicts with Output interface for lifted attributes.
  1513  			switch funcName {
  1514  			case "IsSecret", "ElementType":
  1515  				funcName = funcName + "Prop"
  1516  			}
  1517  
  1518  			fmt.Fprintf(w, "func (o %sPtrOutput) %s() %s {\n", name, funcName, outputType)
  1519  			fmt.Fprintf(w, "\treturn o.ApplyT(func (v *%s) %s {\n", name, applyType)
  1520  			fmt.Fprintf(w, "\t\tif v == nil {\n")
  1521  			fmt.Fprintf(w, "\t\t\treturn nil\n")
  1522  			fmt.Fprintf(w, "\t\t}\n")
  1523  			fmt.Fprintf(w, "\t\treturn %sv.%s\n", deref, pkg.fieldName(nil, p))
  1524  			fmt.Fprintf(w, "\t}).(%s)\n", outputType)
  1525  			fmt.Fprintf(w, "}\n\n")
  1526  		}
  1527  	}
  1528  
  1529  	if details.arrayOutput && !pkg.names.Has(name+"Array") {
  1530  		genArrayOutput(w, name, name)
  1531  	}
  1532  
  1533  	if details.mapOutput && !pkg.names.Has(name+"Map") {
  1534  		genMapOutput(w, name, name)
  1535  	}
  1536  }
  1537  
  1538  func goPrimitiveValue(value interface{}) (string, error) {
  1539  	v := reflect.ValueOf(value)
  1540  	if v.Kind() == reflect.Interface {
  1541  		v = v.Elem()
  1542  	}
  1543  
  1544  	switch v.Kind() {
  1545  	case reflect.Bool:
  1546  		if v.Bool() {
  1547  			return "true", nil
  1548  		}
  1549  		return "false", nil
  1550  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
  1551  		return strconv.FormatInt(v.Int(), 10), nil
  1552  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
  1553  		return strconv.FormatUint(v.Uint(), 10), nil
  1554  	case reflect.Float32, reflect.Float64:
  1555  		value := strconv.FormatFloat(v.Float(), 'f', -1, 64)
  1556  		if !strings.ContainsRune(value, '.') {
  1557  			value += ".0"
  1558  		}
  1559  		return value, nil
  1560  	case reflect.String:
  1561  		return fmt.Sprintf("%q", v.String()), nil
  1562  	default:
  1563  		return "", fmt.Errorf("unsupported default value of type %T", value)
  1564  	}
  1565  }
  1566  
  1567  func (pkg *pkgContext) getConstValue(cv interface{}) (string, error) {
  1568  	var val string
  1569  	if cv != nil {
  1570  		v, err := goPrimitiveValue(cv)
  1571  		if err != nil {
  1572  			return "", err
  1573  		}
  1574  		val = v
  1575  	}
  1576  
  1577  	return val, nil
  1578  }
  1579  
  1580  func (pkg *pkgContext) getDefaultValue(dv *schema.DefaultValue, t schema.Type) (string, error) {
  1581  	var val string
  1582  	if dv.Value != nil {
  1583  		v, err := goPrimitiveValue(dv.Value)
  1584  		if err != nil {
  1585  			return "", err
  1586  		}
  1587  		val = v
  1588  		switch t.(type) {
  1589  		case *schema.EnumType:
  1590  			typeName := strings.TrimSuffix(pkg.typeString(codegen.UnwrapType(t)), "Input")
  1591  			val = fmt.Sprintf("%s(%s)", typeName, val)
  1592  		}
  1593  	}
  1594  
  1595  	if len(dv.Environment) > 0 {
  1596  		pkg.needsUtils = true
  1597  
  1598  		parser, typDefault, typ := "nil", "\"\"", "string"
  1599  		switch codegen.UnwrapType(t).(type) {
  1600  		case *schema.ArrayType:
  1601  			parser, typDefault, typ = "parseEnvStringArray", "pulumi.StringArray{}", "pulumi.StringArray"
  1602  		}
  1603  		switch t {
  1604  		case schema.BoolType:
  1605  			parser, typDefault, typ = "parseEnvBool", "false", "bool"
  1606  		case schema.IntType:
  1607  			parser, typDefault, typ = "parseEnvInt", "0", "int"
  1608  		case schema.NumberType:
  1609  			parser, typDefault, typ = "parseEnvFloat", "0.0", "float64"
  1610  		}
  1611  
  1612  		if val == "" {
  1613  			val = typDefault
  1614  		}
  1615  
  1616  		val = fmt.Sprintf("getEnvOrDefault(%s, %s", val, parser)
  1617  		for _, e := range dv.Environment {
  1618  			val += fmt.Sprintf(", %q", e)
  1619  		}
  1620  		val = fmt.Sprintf("%s).(%s)", val, typ)
  1621  	}
  1622  
  1623  	return val, nil
  1624  }
  1625  
  1626  func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateResourceContainerTypes bool) error {
  1627  	name := disambiguatedResourceName(r, pkg)
  1628  
  1629  	printCommentWithDeprecationMessage(w, r.Comment, r.DeprecationMessage, false)
  1630  	fmt.Fprintf(w, "type %s struct {\n", name)
  1631  
  1632  	switch {
  1633  	case r.IsProvider:
  1634  		fmt.Fprintf(w, "\tpulumi.ProviderResourceState\n\n")
  1635  	case r.IsComponent:
  1636  		fmt.Fprintf(w, "\tpulumi.ResourceState\n\n")
  1637  	default:
  1638  		fmt.Fprintf(w, "\tpulumi.CustomResourceState\n\n")
  1639  	}
  1640  
  1641  	var secretProps []*schema.Property
  1642  	var secretInputProps []*schema.Property
  1643  
  1644  	for _, p := range r.Properties {
  1645  		printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1646  		fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", pkg.fieldName(r, p), pkg.outputType(p.Type), p.Name)
  1647  
  1648  		if p.Secret {
  1649  			secretProps = append(secretProps, p)
  1650  		}
  1651  	}
  1652  	fmt.Fprintf(w, "}\n\n")
  1653  
  1654  	// Create a constructor function that registers a new instance of this resource.
  1655  	fmt.Fprintf(w, "// New%s registers a new resource with the given unique name, arguments, and options.\n", name)
  1656  	fmt.Fprintf(w, "func New%s(ctx *pulumi.Context,\n", name)
  1657  	fmt.Fprintf(w, "\tname string, args *%[1]sArgs, opts ...pulumi.ResourceOption) (*%[1]s, error) {\n", name)
  1658  
  1659  	// Ensure required arguments are present.
  1660  	hasRequired := false
  1661  	for _, p := range r.InputProperties {
  1662  		if p.IsRequired() {
  1663  			hasRequired = true
  1664  		}
  1665  	}
  1666  
  1667  	// Various validation checks
  1668  	fmt.Fprintf(w, "\tif args == nil {\n")
  1669  	if !hasRequired {
  1670  		fmt.Fprintf(w, "\t\targs = &%sArgs{}\n", name)
  1671  	} else {
  1672  		fmt.Fprintln(w, "\t\treturn nil, errors.New(\"missing one or more required arguments\")")
  1673  	}
  1674  	fmt.Fprintf(w, "\t}\n\n")
  1675  
  1676  	// Produce the inputs.
  1677  
  1678  	// Check all required inputs are present
  1679  	for _, p := range r.InputProperties {
  1680  		if p.IsRequired() && isNilType(p.Type) && p.DefaultValue == nil {
  1681  			fmt.Fprintf(w, "\tif args.%s == nil {\n", pkg.fieldName(r, p))
  1682  			fmt.Fprintf(w, "\t\treturn nil, errors.New(\"invalid value for required argument '%s'\")\n", pkg.fieldName(r, p))
  1683  			fmt.Fprintf(w, "\t}\n")
  1684  		}
  1685  
  1686  		if p.Secret {
  1687  			secretInputProps = append(secretInputProps, p)
  1688  		}
  1689  	}
  1690  
  1691  	assign := func(p *schema.Property, value string) {
  1692  		pkg.assignProperty(w, p, "args", value, isNilType(p.Type))
  1693  	}
  1694  
  1695  	for _, p := range r.InputProperties {
  1696  		if p.ConstValue != nil {
  1697  			v, err := pkg.getConstValue(p.ConstValue)
  1698  			if err != nil {
  1699  				return err
  1700  			}
  1701  			assign(p, v)
  1702  		} else if p.DefaultValue != nil {
  1703  			dv, err := pkg.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
  1704  			if err != nil {
  1705  				return err
  1706  			}
  1707  			pkg.needsUtils = true
  1708  			fmt.Fprintf(w, "\tif isZero(args.%s) {\n", pkg.fieldName(r, p))
  1709  			assign(p, dv)
  1710  			fmt.Fprintf(w, "\t}\n")
  1711  		} else if name := pkg.provideDefaultsFuncName(p.Type); name != "" && !pkg.disableObjectDefaults {
  1712  			optionalDeref := ""
  1713  			if p.IsRequired() {
  1714  				optionalDeref = "*"
  1715  			}
  1716  
  1717  			toOutputMethod := pkg.toOutputMethod(p.Type)
  1718  			outputType := pkg.outputType(p.Type)
  1719  			resolvedType := pkg.typeString(codegen.ResolvedType(p.Type))
  1720  			originalValue := fmt.Sprintf("args.%s.%s()", pkg.fieldName(r, p), toOutputMethod)
  1721  			valueWithDefaults := fmt.Sprintf("%[1]v.ApplyT(func (v %[2]s) %[2]s { return %[3]sv.%[4]s() }).(%[5]s)",
  1722  				originalValue, resolvedType, optionalDeref, name, outputType)
  1723  			if p.Plain {
  1724  				valueWithDefaults = fmt.Sprintf("args.%v.Defaults()", pkg.fieldName(r, p))
  1725  			}
  1726  
  1727  			if !p.IsRequired() {
  1728  				fmt.Fprintf(w, "if args.%s != nil {\n", pkg.fieldName(r, p))
  1729  				fmt.Fprintf(w, "args.%[1]s = %s\n", pkg.fieldName(r, p), valueWithDefaults)
  1730  				fmt.Fprint(w, "}\n")
  1731  			} else {
  1732  				fmt.Fprintf(w, "args.%[1]s = %s\n", pkg.fieldName(r, p), valueWithDefaults)
  1733  			}
  1734  
  1735  		}
  1736  	}
  1737  
  1738  	// Set any defined aliases.
  1739  	if len(r.Aliases) > 0 {
  1740  		fmt.Fprintf(w, "\taliases := pulumi.Aliases([]pulumi.Alias{\n")
  1741  		for _, alias := range r.Aliases {
  1742  			s := "\t\t{\n"
  1743  			if alias.Name != nil {
  1744  				s += fmt.Sprintf("\t\t\tName: pulumi.String(%q),\n", *alias.Name)
  1745  			}
  1746  			if alias.Project != nil {
  1747  				s += fmt.Sprintf("\t\t\tProject: pulumi.String(%q),\n", *alias.Project)
  1748  			}
  1749  			if alias.Type != nil {
  1750  				s += fmt.Sprintf("\t\t\tType: pulumi.String(%q),\n", *alias.Type)
  1751  			}
  1752  			s += "\t\t},\n"
  1753  			fmt.Fprint(w, s)
  1754  		}
  1755  		fmt.Fprintf(w, "\t})\n")
  1756  		fmt.Fprintf(w, "\topts = append(opts, aliases)\n")
  1757  	}
  1758  
  1759  	// Setup secrets
  1760  	for _, p := range secretInputProps {
  1761  		fmt.Fprintf(w, "\tif args.%s != nil {\n", pkg.fieldName(r, p))
  1762  		fmt.Fprintf(w, "\t\targs.%[1]s = pulumi.ToSecret(args.%[1]s).(%[2]s)\n", pkg.fieldName(r, p), pkg.outputType(p.Type))
  1763  		fmt.Fprintf(w, "\t}\n")
  1764  	}
  1765  	if len(secretProps) > 0 {
  1766  		fmt.Fprintf(w, "\tsecrets := pulumi.AdditionalSecretOutputs([]string{\n")
  1767  		for _, sp := range secretProps {
  1768  			fmt.Fprintf(w, "\t\t\t%q,\n", sp.Name)
  1769  		}
  1770  		fmt.Fprintf(w, "\t})\n")
  1771  		fmt.Fprintf(w, "\topts = append(opts, secrets)\n")
  1772  	}
  1773  
  1774  	// Setup replaceOnChange
  1775  	replaceOnChangesProps, errList := r.ReplaceOnChanges()
  1776  	for _, err := range errList {
  1777  		cmdutil.Diag().Warningf(&diag.Diag{Message: err.Error()})
  1778  	}
  1779  	replaceOnChangesStrings := schema.PropertyListJoinToString(replaceOnChangesProps,
  1780  		func(x string) string { return x })
  1781  	if len(replaceOnChangesProps) > 0 {
  1782  		fmt.Fprint(w, "\treplaceOnChanges := pulumi.ReplaceOnChanges([]string{\n")
  1783  		for _, p := range replaceOnChangesStrings {
  1784  			fmt.Fprintf(w, "\t\t%q,\n", p)
  1785  		}
  1786  		fmt.Fprint(w, "\t})\n")
  1787  		fmt.Fprint(w, "\topts = append(opts, replaceOnChanges)\n")
  1788  	}
  1789  
  1790  	pkg.GenPkgDefaultsOptsCall(w, false /*invoke*/)
  1791  
  1792  	// Finally make the call to registration.
  1793  	fmt.Fprintf(w, "\tvar resource %s\n", name)
  1794  	if r.IsComponent {
  1795  		fmt.Fprintf(w, "\terr := ctx.RegisterRemoteComponentResource(\"%s\", name, args, &resource, opts...)\n", r.Token)
  1796  	} else {
  1797  		fmt.Fprintf(w, "\terr := ctx.RegisterResource(\"%s\", name, args, &resource, opts...)\n", r.Token)
  1798  	}
  1799  	fmt.Fprintf(w, "\tif err != nil {\n")
  1800  	fmt.Fprintf(w, "\t\treturn nil, err\n")
  1801  	fmt.Fprintf(w, "\t}\n")
  1802  	fmt.Fprintf(w, "\treturn &resource, nil\n")
  1803  	fmt.Fprintf(w, "}\n\n")
  1804  
  1805  	// Emit a factory function that reads existing instances of this resource.
  1806  	if !r.IsProvider && !r.IsComponent {
  1807  		fmt.Fprintf(w, "// Get%[1]s gets an existing %[1]s resource's state with the given name, ID, and optional\n", name)
  1808  		fmt.Fprintf(w, "// state properties that are used to uniquely qualify the lookup (nil if not required).\n")
  1809  		fmt.Fprintf(w, "func Get%s(ctx *pulumi.Context,\n", name)
  1810  		fmt.Fprintf(w, "\tname string, id pulumi.IDInput, state *%[1]sState, opts ...pulumi.ResourceOption) (*%[1]s, error) {\n", name)
  1811  		fmt.Fprintf(w, "\tvar resource %s\n", name)
  1812  		fmt.Fprintf(w, "\terr := ctx.ReadResource(\"%s\", name, id, state, &resource, opts...)\n", r.Token)
  1813  		fmt.Fprintf(w, "\tif err != nil {\n")
  1814  		fmt.Fprintf(w, "\t\treturn nil, err\n")
  1815  		fmt.Fprintf(w, "\t}\n")
  1816  		fmt.Fprintf(w, "\treturn &resource, nil\n")
  1817  		fmt.Fprintf(w, "}\n\n")
  1818  
  1819  		// Emit the state types for get methods.
  1820  		fmt.Fprintf(w, "// Input properties used for looking up and filtering %s resources.\n", name)
  1821  		fmt.Fprintf(w, "type %sState struct {\n", cgstrings.Camel(name))
  1822  		if r.StateInputs != nil {
  1823  			for _, p := range r.StateInputs.Properties {
  1824  				printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1825  				fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", pkg.fieldName(r, p), pkg.typeString(codegen.ResolvedType(codegen.OptionalType(p))), p.Name)
  1826  			}
  1827  		}
  1828  		fmt.Fprintf(w, "}\n\n")
  1829  
  1830  		fmt.Fprintf(w, "type %sState struct {\n", name)
  1831  		if r.StateInputs != nil {
  1832  			for _, p := range r.StateInputs.Properties {
  1833  				printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1834  				fmt.Fprintf(w, "\t%s %s\n", pkg.fieldName(r, p), pkg.inputType(p.Type))
  1835  			}
  1836  		}
  1837  		fmt.Fprintf(w, "}\n\n")
  1838  
  1839  		fmt.Fprintf(w, "func (%sState) ElementType() reflect.Type {\n", name)
  1840  		fmt.Fprintf(w, "\treturn reflect.TypeOf((*%sState)(nil)).Elem()\n", cgstrings.Camel(name))
  1841  		fmt.Fprintf(w, "}\n\n")
  1842  	}
  1843  
  1844  	// Emit the args types.
  1845  	fmt.Fprintf(w, "type %sArgs struct {\n", cgstrings.Camel(name))
  1846  	for _, p := range r.InputProperties {
  1847  		printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1848  		fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", pkg.fieldName(r, p), pkg.typeString(codegen.ResolvedType(p.Type)), p.Name)
  1849  	}
  1850  	fmt.Fprintf(w, "}\n\n")
  1851  
  1852  	fmt.Fprintf(w, "// The set of arguments for constructing a %s resource.\n", name)
  1853  	fmt.Fprintf(w, "type %sArgs struct {\n", name)
  1854  	for _, p := range r.InputProperties {
  1855  		typ := p.Type
  1856  		if p.Plain {
  1857  			typ = codegen.MapOptionalType(typ, func(typ schema.Type) schema.Type {
  1858  				if input, ok := typ.(*schema.InputType); ok {
  1859  					return input.ElementType
  1860  				}
  1861  				return typ
  1862  			})
  1863  		}
  1864  
  1865  		printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1866  		fmt.Fprintf(w, "\t%s %s\n", pkg.fieldName(r, p), pkg.typeString(typ))
  1867  	}
  1868  	fmt.Fprintf(w, "}\n\n")
  1869  
  1870  	fmt.Fprintf(w, "func (%sArgs) ElementType() reflect.Type {\n", name)
  1871  	fmt.Fprintf(w, "\treturn reflect.TypeOf((*%sArgs)(nil)).Elem()\n", cgstrings.Camel(name))
  1872  	fmt.Fprintf(w, "}\n")
  1873  
  1874  	// Emit resource methods.
  1875  	for _, method := range r.Methods {
  1876  		methodName := Title(method.Name)
  1877  		f := method.Function
  1878  
  1879  		shouldLiftReturn := pkg.liftSingleValueMethodReturns && f.Outputs != nil && len(f.Outputs.Properties) == 1
  1880  
  1881  		var args []*schema.Property
  1882  		if f.Inputs != nil {
  1883  			for _, arg := range f.Inputs.InputShape.Properties {
  1884  				if arg.Name == "__self__" {
  1885  					continue
  1886  				}
  1887  				args = append(args, arg)
  1888  			}
  1889  		}
  1890  
  1891  		// Now emit the method signature.
  1892  		argsig := "ctx *pulumi.Context"
  1893  		if len(args) > 0 {
  1894  			argsig = fmt.Sprintf("%s, args *%s%sArgs", argsig, name, methodName)
  1895  		}
  1896  		var retty string
  1897  		if f.Outputs == nil {
  1898  			retty = "error"
  1899  		} else if shouldLiftReturn {
  1900  			retty = fmt.Sprintf("(%s, error)", pkg.outputType(f.Outputs.Properties[0].Type))
  1901  		} else {
  1902  			retty = fmt.Sprintf("(%s%sResultOutput, error)", name, methodName)
  1903  		}
  1904  		fmt.Fprintf(w, "\n")
  1905  		printCommentWithDeprecationMessage(w, f.Comment, f.DeprecationMessage, false)
  1906  		fmt.Fprintf(w, "func (r *%s) %s(%s) %s {\n", name, methodName, argsig, retty)
  1907  
  1908  		resultVar := "_"
  1909  		if f.Outputs != nil {
  1910  			resultVar = "out"
  1911  		}
  1912  
  1913  		// Make a map of inputs to pass to the runtime function.
  1914  		inputsVar := "nil"
  1915  		if len(args) > 0 {
  1916  			inputsVar = "args"
  1917  		}
  1918  
  1919  		// Now simply invoke the runtime function with the arguments.
  1920  		outputsType := "pulumi.AnyOutput"
  1921  		if f.Outputs != nil {
  1922  			if shouldLiftReturn {
  1923  				outputsType = fmt.Sprintf("%s%sResultOutput", cgstrings.Camel(name), methodName)
  1924  			} else {
  1925  				outputsType = fmt.Sprintf("%s%sResultOutput", name, methodName)
  1926  			}
  1927  		}
  1928  		fmt.Fprintf(w, "\t%s, err := ctx.Call(%q, %s, %s{}, r)\n", resultVar, f.Token, inputsVar, outputsType)
  1929  		if f.Outputs == nil {
  1930  			fmt.Fprintf(w, "\treturn err\n")
  1931  		} else if shouldLiftReturn {
  1932  			// Check the error before proceeding.
  1933  			fmt.Fprintf(w, "\tif err != nil {\n")
  1934  			fmt.Fprintf(w, "\t\treturn %s{}, err\n", pkg.outputType(f.Outputs.Properties[0].Type))
  1935  			fmt.Fprintf(w, "\t}\n")
  1936  
  1937  			// Get the name of the method to return the output
  1938  			fmt.Fprintf(w, "\treturn %s.(%s).%s(), nil\n", resultVar, cgstrings.Camel(outputsType), Title(f.Outputs.Properties[0].Name))
  1939  		} else {
  1940  			// Check the error before proceeding.
  1941  			fmt.Fprintf(w, "\tif err != nil {\n")
  1942  			fmt.Fprintf(w, "\t\treturn %s{}, err\n", outputsType)
  1943  			fmt.Fprintf(w, "\t}\n")
  1944  
  1945  			// Return the result.
  1946  			fmt.Fprintf(w, "\treturn %s.(%s), nil\n", resultVar, outputsType)
  1947  		}
  1948  		fmt.Fprintf(w, "}\n")
  1949  
  1950  		// If there are argument and/or return types, emit them.
  1951  		if len(args) > 0 {
  1952  			fmt.Fprintf(w, "\n")
  1953  			fmt.Fprintf(w, "type %s%sArgs struct {\n", cgstrings.Camel(name), methodName)
  1954  			for _, p := range args {
  1955  				printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1956  				fmt.Fprintf(w, "\t%s %s `pulumi:\"%s\"`\n", pkg.fieldName(nil, p), pkg.typeString(codegen.ResolvedType(p.Type)),
  1957  					p.Name)
  1958  			}
  1959  			fmt.Fprintf(w, "}\n\n")
  1960  
  1961  			fmt.Fprintf(w, "// The set of arguments for the %s method of the %s resource.\n", methodName, name)
  1962  			fmt.Fprintf(w, "type %s%sArgs struct {\n", name, methodName)
  1963  			for _, p := range args {
  1964  				printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, true)
  1965  				fmt.Fprintf(w, "\t%s %s\n", pkg.fieldName(nil, p), pkg.typeString(p.Type))
  1966  			}
  1967  			fmt.Fprintf(w, "}\n\n")
  1968  
  1969  			fmt.Fprintf(w, "func (%s%sArgs) ElementType() reflect.Type {\n", name, methodName)
  1970  			fmt.Fprintf(w, "\treturn reflect.TypeOf((*%s%sArgs)(nil)).Elem()\n", cgstrings.Camel(name), methodName)
  1971  			fmt.Fprintf(w, "}\n\n")
  1972  		}
  1973  		if f.Outputs != nil {
  1974  			outputStructName := name
  1975  
  1976  			// Don't export the result struct if we're lifting the value
  1977  			if shouldLiftReturn {
  1978  				outputStructName = cgstrings.Camel(name)
  1979  			}
  1980  
  1981  			fmt.Fprintf(w, "\n")
  1982  			pkg.genPlainType(w, fmt.Sprintf("%s%sResult", outputStructName, methodName), f.Outputs.Comment, "",
  1983  				f.Outputs.Properties)
  1984  
  1985  			fmt.Fprintf(w, "\n")
  1986  			fmt.Fprintf(w, "type %s%sResultOutput struct{ *pulumi.OutputState }\n\n", outputStructName, methodName)
  1987  
  1988  			fmt.Fprintf(w, "func (%s%sResultOutput) ElementType() reflect.Type {\n", outputStructName, methodName)
  1989  			fmt.Fprintf(w, "\treturn reflect.TypeOf((*%s%sResult)(nil)).Elem()\n", outputStructName, methodName)
  1990  			fmt.Fprintf(w, "}\n")
  1991  
  1992  			for _, p := range f.Outputs.Properties {
  1993  				fmt.Fprintf(w, "\n")
  1994  				printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, false)
  1995  				fmt.Fprintf(w, "func (o %s%sResultOutput) %s() %s {\n", outputStructName, methodName, Title(p.Name),
  1996  					pkg.outputType(p.Type))
  1997  				fmt.Fprintf(w, "\treturn o.ApplyT(func(v %s%sResult) %s { return v.%s }).(%s)\n", outputStructName, methodName,
  1998  					pkg.typeString(codegen.ResolvedType(p.Type)), Title(p.Name), pkg.outputType(p.Type))
  1999  				fmt.Fprintf(w, "}\n")
  2000  			}
  2001  		}
  2002  	}
  2003  
  2004  	// Emit the resource input type.
  2005  	fmt.Fprintf(w, "\n")
  2006  	fmt.Fprintf(w, "type %sInput interface {\n", name)
  2007  	fmt.Fprintf(w, "\tpulumi.Input\n\n")
  2008  	fmt.Fprintf(w, "\tTo%[1]sOutput() %[1]sOutput\n", name)
  2009  	fmt.Fprintf(w, "\tTo%[1]sOutputWithContext(ctx context.Context) %[1]sOutput\n", name)
  2010  	fmt.Fprintf(w, "}\n\n")
  2011  
  2012  	genInputImplementation(w, name, "*"+name, "*"+name, false)
  2013  
  2014  	if generateResourceContainerTypes && !r.IsProvider {
  2015  		// Generate the resource array input.
  2016  		pkg.genInputInterface(w, name+"Array")
  2017  		fmt.Fprintf(w, "type %[1]sArray []%[1]sInput\n\n", name)
  2018  		genInputImplementation(w, name+"Array", name+"Array", "[]*"+name, false)
  2019  
  2020  		// Generate the resource map input.
  2021  		pkg.genInputInterface(w, name+"Map")
  2022  		fmt.Fprintf(w, "type %[1]sMap map[string]%[1]sInput\n\n", name)
  2023  		genInputImplementation(w, name+"Map", name+"Map", "map[string]*"+name, false)
  2024  	}
  2025  
  2026  	// Emit the resource output type.
  2027  	genOutputType(w, name, "*"+name, false)
  2028  
  2029  	// Emit chaining methods for the resource output type.
  2030  	for _, p := range r.Properties {
  2031  		printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, false)
  2032  		outputType := pkg.outputType(p.Type)
  2033  
  2034  		propName := pkg.fieldName(r, p)
  2035  		switch strings.ToLower(p.Name) {
  2036  		case "elementtype", "issecret":
  2037  			propName = "Get" + propName
  2038  		}
  2039  		fmt.Fprintf(w, "func (o %sOutput) %s() %s {\n", name, propName, outputType)
  2040  		fmt.Fprintf(w, "\treturn o.ApplyT(func (v *%s) %s { return v.%s }).(%s)\n",
  2041  			name, outputType, pkg.fieldName(r, p), outputType)
  2042  		fmt.Fprintf(w, "}\n\n")
  2043  	}
  2044  
  2045  	if generateResourceContainerTypes && !r.IsProvider {
  2046  		genArrayOutput(w, name, "*"+name)
  2047  		genMapOutput(w, name, "*"+name)
  2048  	}
  2049  
  2050  	pkg.genResourceRegistrations(w, r, generateResourceContainerTypes)
  2051  
  2052  	return nil
  2053  }
  2054  
  2055  func NeedsGoOutputVersion(f *schema.Function) bool {
  2056  	fPkg := f.Package
  2057  
  2058  	var goInfo GoPackageInfo
  2059  
  2060  	contract.AssertNoError(fPkg.ImportLanguages(map[string]schema.Language{"go": Importer}))
  2061  	if info, ok := fPkg.Language["go"].(GoPackageInfo); ok {
  2062  		goInfo = info
  2063  	}
  2064  
  2065  	if goInfo.DisableFunctionOutputVersions {
  2066  		return false
  2067  	}
  2068  
  2069  	return f.NeedsOutputVersion()
  2070  }
  2071  
  2072  func (pkg *pkgContext) genFunctionCodeFile(f *schema.Function) (string, error) {
  2073  	importsAndAliases := map[string]string{}
  2074  	pkg.getImports(f, importsAndAliases)
  2075  	importsAndAliases["github.com/pulumi/pulumi/sdk/v3/go/pulumi"] = ""
  2076  
  2077  	buffer := &bytes.Buffer{}
  2078  
  2079  	var imports []string
  2080  	if NeedsGoOutputVersion(f) {
  2081  		imports = []string{"context", "reflect"}
  2082  	}
  2083  
  2084  	pkg.genHeader(buffer, imports, importsAndAliases)
  2085  	if err := pkg.genFunction(buffer, f); err != nil {
  2086  		return "", err
  2087  	}
  2088  	pkg.genFunctionOutputVersion(buffer, f)
  2089  	return buffer.String(), nil
  2090  }
  2091  
  2092  func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error {
  2093  	name := pkg.functionName(f)
  2094  	printCommentWithDeprecationMessage(w, f.Comment, f.DeprecationMessage, false)
  2095  
  2096  	// Now, emit the function signature.
  2097  	argsig := "ctx *pulumi.Context"
  2098  	if f.Inputs != nil {
  2099  		argsig = fmt.Sprintf("%s, args *%sArgs", argsig, name)
  2100  	}
  2101  	var retty string
  2102  	if f.Outputs == nil {
  2103  		retty = "error"
  2104  	} else {
  2105  		retty = fmt.Sprintf("(*%sResult, error)", name)
  2106  	}
  2107  	fmt.Fprintf(w, "func %s(%s, opts ...pulumi.InvokeOption) %s {\n", name, argsig, retty)
  2108  
  2109  	// Make a map of inputs to pass to the runtime function.
  2110  	var inputsVar string
  2111  	if f.Inputs == nil {
  2112  		inputsVar = "nil"
  2113  	} else if codegen.IsProvideDefaultsFuncRequired(f.Inputs) && !pkg.disableObjectDefaults {
  2114  		inputsVar = "args.Defaults()"
  2115  	} else {
  2116  		inputsVar = "args"
  2117  	}
  2118  
  2119  	// Now simply invoke the runtime function with the arguments.
  2120  	var outputsType string
  2121  	if f.Outputs == nil {
  2122  		outputsType = "struct{}"
  2123  	} else {
  2124  		outputsType = name + "Result"
  2125  	}
  2126  
  2127  	pkg.GenPkgDefaultsOptsCall(w, true /*invoke*/)
  2128  
  2129  	fmt.Fprintf(w, "\tvar rv %s\n", outputsType)
  2130  	fmt.Fprintf(w, "\terr := ctx.Invoke(\"%s\", %s, &rv, opts...)\n", f.Token, inputsVar)
  2131  
  2132  	if f.Outputs == nil {
  2133  		fmt.Fprintf(w, "\treturn err\n")
  2134  	} else {
  2135  		// Check the error before proceeding.
  2136  		fmt.Fprintf(w, "\tif err != nil {\n")
  2137  		fmt.Fprintf(w, "\t\treturn nil, err\n")
  2138  		fmt.Fprintf(w, "\t}\n")
  2139  
  2140  		// Return the result.
  2141  		var retValue string
  2142  		if codegen.IsProvideDefaultsFuncRequired(f.Outputs) && !pkg.disableObjectDefaults {
  2143  			retValue = "rv.Defaults()"
  2144  		} else {
  2145  			retValue = "&rv"
  2146  		}
  2147  		fmt.Fprintf(w, "\treturn %s, nil\n", retValue)
  2148  	}
  2149  	fmt.Fprintf(w, "}\n")
  2150  
  2151  	// If there are argument and/or return types, emit them.
  2152  	if f.Inputs != nil {
  2153  		fmt.Fprintf(w, "\n")
  2154  		fnInputsName := pkg.functionArgsTypeName(f)
  2155  		pkg.genPlainType(w, fnInputsName, f.Inputs.Comment, "", f.Inputs.Properties)
  2156  		if codegen.IsProvideDefaultsFuncRequired(f.Inputs) && !pkg.disableObjectDefaults {
  2157  			if err := pkg.genObjectDefaultFunc(w, fnInputsName, f.Inputs.Properties); err != nil {
  2158  				return err
  2159  			}
  2160  		}
  2161  	}
  2162  	if f.Outputs != nil {
  2163  		fmt.Fprintf(w, "\n")
  2164  		fnOutputsName := pkg.functionResultTypeName(f)
  2165  		pkg.genPlainType(w, fnOutputsName, f.Outputs.Comment, "", f.Outputs.Properties)
  2166  		if codegen.IsProvideDefaultsFuncRequired(f.Outputs) && !pkg.disableObjectDefaults {
  2167  			if err := pkg.genObjectDefaultFunc(w, fnOutputsName, f.Outputs.Properties); err != nil {
  2168  				return err
  2169  			}
  2170  		}
  2171  	}
  2172  	return nil
  2173  }
  2174  
  2175  func (pkg *pkgContext) functionName(f *schema.Function) string {
  2176  	// If the function starts with New or Get, it will conflict; so rename them.
  2177  	name, hasName := pkg.functionNames[f]
  2178  
  2179  	if !hasName {
  2180  		panic(fmt.Sprintf("No function name found for %v", f))
  2181  	}
  2182  
  2183  	return name
  2184  }
  2185  
  2186  func (pkg *pkgContext) functionArgsTypeName(f *schema.Function) string {
  2187  	name := pkg.functionName(f)
  2188  	return fmt.Sprintf("%sArgs", name)
  2189  }
  2190  
  2191  func (pkg *pkgContext) functionResultTypeName(f *schema.Function) string {
  2192  	name := pkg.functionName(f)
  2193  	return fmt.Sprintf("%sResult", name)
  2194  }
  2195  
  2196  func (pkg *pkgContext) genFunctionOutputVersion(w io.Writer, f *schema.Function) {
  2197  	if !NeedsGoOutputVersion(f) {
  2198  		return
  2199  	}
  2200  
  2201  	originalName := pkg.functionName(f)
  2202  	name := originalName + "Output"
  2203  	originalResultTypeName := pkg.functionResultTypeName(f)
  2204  	resultTypeName := originalResultTypeName + "Output"
  2205  
  2206  	code := `
  2207  func ${fn}Output(ctx *pulumi.Context, args ${fn}OutputArgs, opts ...pulumi.InvokeOption) ${outputType} {
  2208  	return pulumi.ToOutputWithContext(context.Background(), args).
  2209  		ApplyT(func(v interface{}) (${fn}Result, error) {
  2210  			args := v.(${fn}Args)
  2211  			r, err := ${fn}(ctx, &args, opts...)
  2212  			var s ${fn}Result
  2213  			if r != nil {
  2214  				s = *r
  2215  			}
  2216  			return s, err
  2217  		}).(${outputType})
  2218  }
  2219  
  2220  `
  2221  
  2222  	code = strings.ReplaceAll(code, "${fn}", originalName)
  2223  	code = strings.ReplaceAll(code, "${outputType}", resultTypeName)
  2224  	fmt.Fprintf(w, code)
  2225  
  2226  	pkg.genInputArgsStruct(w, name+"Args", f.Inputs.InputShape)
  2227  
  2228  	genInputImplementationWithArgs(w, genInputImplementationArgs{
  2229  		name:         name + "Args",
  2230  		receiverType: name + "Args",
  2231  		elementType:  pkg.functionArgsTypeName(f),
  2232  	})
  2233  
  2234  	pkg.genOutputTypes(w, genOutputTypesArgs{
  2235  		t:    f.Outputs,
  2236  		name: originalResultTypeName,
  2237  	})
  2238  
  2239  	// Assuming the file represented by `w` only has one function,
  2240  	// generate an `init()` for Output type init.
  2241  	initCode := `
  2242  func init() {
  2243          pulumi.RegisterOutputType(${outputType}{})
  2244  }
  2245  
  2246  `
  2247  	initCode = strings.ReplaceAll(initCode, "${outputType}", resultTypeName)
  2248  	fmt.Fprintf(w, initCode)
  2249  }
  2250  
  2251  type objectProperty struct {
  2252  	object   *schema.ObjectType
  2253  	property *schema.Property
  2254  }
  2255  
  2256  // When computing the type name for a field of an object type, we must ensure that we do not generate invalid recursive
  2257  // struct types. A struct type T contains invalid recursion if the closure of its fields and its struct-typed fields'
  2258  // fields includes a field of type T. A few examples:
  2259  //
  2260  // Directly invalid:
  2261  //
  2262  //	type T struct {
  2263  //	    Invalid T
  2264  //	}
  2265  //
  2266  // Indirectly invalid:
  2267  //
  2268  //	type T struct {
  2269  //	    Invalid S
  2270  //	}
  2271  //
  2272  //	type S struct {
  2273  //	    Invalid T
  2274  //	}
  2275  //
  2276  // In order to avoid generating invalid struct types, we replace all references to types involved in a cyclical
  2277  // definition with *T. The examples above therefore become:
  2278  //
  2279  // (1)
  2280  //
  2281  //	type T struct {
  2282  //	    Valid *T
  2283  //	}
  2284  //
  2285  // (2)
  2286  //
  2287  //	type T struct {
  2288  //	    Valid *S
  2289  //	}
  2290  //
  2291  //	type S struct {
  2292  //	    Valid *T
  2293  //	}
  2294  //
  2295  // We do this using a rewriter that turns all fields involved in reference cycles into optional fields.
  2296  func rewriteCyclicField(rewritten codegen.Set, path []objectProperty, op objectProperty) {
  2297  	// If this property refers to an Input<> type, unwrap the type. This ensures that the plain and input shapes of an
  2298  	// object type remain identical.
  2299  	t := op.property.Type
  2300  	if inputType, isInputType := op.property.Type.(*schema.InputType); isInputType {
  2301  		t = inputType.ElementType
  2302  	}
  2303  
  2304  	// If this property does not refer to an object type, it cannot be involved in a cycle. Skip it.
  2305  	objectType, isObjectType := t.(*schema.ObjectType)
  2306  	if !isObjectType {
  2307  		return
  2308  	}
  2309  
  2310  	path = append(path, op)
  2311  
  2312  	// Check the current path for cycles by crawling backwards until reaching the start of the path
  2313  	// or finding a property that is a member of the current object type.
  2314  	var cycle []objectProperty
  2315  	for i := len(path) - 1; i > 0; i-- {
  2316  		if path[i].object == objectType {
  2317  			cycle = path[i:]
  2318  			break
  2319  		}
  2320  	}
  2321  
  2322  	// If the current path does not involve a cycle, recur into the current object type.
  2323  	if len(cycle) == 0 {
  2324  		rewriteCyclicFields(rewritten, path, objectType)
  2325  		return
  2326  	}
  2327  
  2328  	// If we've found a cycle, mark each property involved in the cycle as optional.
  2329  	//
  2330  	// NOTE: this overestimates the set of properties that must be marked as optional. For example, in case (2) above,
  2331  	// only one of T.Invalid or S.Invalid needs to be marked as optional in order to break the cycle. However, choosing
  2332  	// a minimal set of properties that is also deterministic and resilient to changes in visit order is difficult and
  2333  	// seems to add little value.
  2334  	for _, p := range cycle {
  2335  		p.property.Type = codegen.OptionalType(p.property)
  2336  	}
  2337  }
  2338  
  2339  func rewriteCyclicFields(rewritten codegen.Set, path []objectProperty, obj *schema.ObjectType) {
  2340  	if !rewritten.Has(obj) {
  2341  		rewritten.Add(obj)
  2342  		for _, property := range obj.Properties {
  2343  			rewriteCyclicField(rewritten, path, objectProperty{obj, property})
  2344  		}
  2345  	}
  2346  }
  2347  
  2348  func rewriteCyclicObjectFields(pkg *schema.Package) {
  2349  	rewritten := codegen.Set{}
  2350  	for _, t := range pkg.Types {
  2351  		if obj, ok := t.(*schema.ObjectType); ok && !obj.IsInputShape() {
  2352  			rewriteCyclicFields(rewritten, nil, obj)
  2353  			rewriteCyclicFields(rewritten, nil, obj.InputShape)
  2354  		}
  2355  	}
  2356  }
  2357  
  2358  func (pkg *pkgContext) genType(w io.Writer, obj *schema.ObjectType) error {
  2359  	contract.Assert(!obj.IsInputShape())
  2360  	if obj.IsOverlay {
  2361  		// This type is generated by the provider, so no further action is required.
  2362  		return nil
  2363  	}
  2364  
  2365  	plainName := pkg.tokenToType(obj.Token)
  2366  	pkg.genPlainType(w, plainName, obj.Comment, "", obj.Properties)
  2367  	if !pkg.disableObjectDefaults {
  2368  		if err := pkg.genObjectDefaultFunc(w, plainName, obj.Properties); err != nil {
  2369  			return err
  2370  		}
  2371  	}
  2372  
  2373  	if err := pkg.genInputTypes(w, obj.InputShape, pkg.detailsForType(obj)); err != nil {
  2374  		return err
  2375  	}
  2376  	pkg.genOutputTypes(w, genOutputTypesArgs{t: obj})
  2377  	return nil
  2378  }
  2379  
  2380  func (pkg *pkgContext) addSuffixesToName(typ schema.Type, name string) []string {
  2381  	var names []string
  2382  	details := pkg.detailsForType(typ)
  2383  	if details.arrayInput {
  2384  		names = append(names, name+"ArrayInput")
  2385  	}
  2386  	if details.arrayOutput || details.arrayInput {
  2387  		names = append(names, name+"ArrayOutput")
  2388  	}
  2389  	if details.mapInput {
  2390  		names = append(names, name+"MapInput")
  2391  	}
  2392  	if details.mapOutput || details.mapInput {
  2393  		names = append(names, name+"MapOutput")
  2394  	}
  2395  	return names
  2396  }
  2397  
  2398  type nestedTypeInfo struct {
  2399  	resolvedElementType string
  2400  	names               map[string]bool
  2401  }
  2402  
  2403  // collectNestedCollectionTypes builds a deduped mapping of element types -> associated collection types.
  2404  // different shapes of known types can resolve to the same element type. by collecting types in one step and emitting types
  2405  // in a second step, we avoid collision and redeclaration.
  2406  func (pkg *pkgContext) collectNestedCollectionTypes(types map[string]*nestedTypeInfo, typ schema.Type) {
  2407  	var elementTypeName string
  2408  	var names []string
  2409  	switch t := typ.(type) {
  2410  	case *schema.ArrayType:
  2411  		// Builtins already cater to primitive arrays
  2412  		if schema.IsPrimitiveType(t.ElementType) {
  2413  			return
  2414  		}
  2415  		elementTypeName = pkg.nestedTypeToType(t.ElementType)
  2416  		elementTypeName = strings.TrimSuffix(elementTypeName, "Args") + "Array"
  2417  
  2418  		// We make sure that subsidiary elements are marked for array as well
  2419  		details := pkg.detailsForType(t)
  2420  		pkg.detailsForType(t.ElementType).markArray(details.arrayInput, details.arrayOutput)
  2421  
  2422  		names = pkg.addSuffixesToName(t, elementTypeName)
  2423  		defer pkg.collectNestedCollectionTypes(types, t.ElementType)
  2424  	case *schema.MapType:
  2425  		// Builtins already cater to primitive maps
  2426  		if schema.IsPrimitiveType(t.ElementType) {
  2427  			return
  2428  		}
  2429  		elementTypeName = pkg.nestedTypeToType(t.ElementType)
  2430  		elementTypeName = strings.TrimSuffix(elementTypeName, "Args") + "Map"
  2431  
  2432  		// We make sure that subsidiary elements are marked for map as well
  2433  		details := pkg.detailsForType(t)
  2434  		pkg.detailsForType(t.ElementType).markMap(details.mapInput, details.mapOutput)
  2435  
  2436  		names = pkg.addSuffixesToName(t, elementTypeName)
  2437  		defer pkg.collectNestedCollectionTypes(types, t.ElementType)
  2438  	default:
  2439  		return
  2440  	}
  2441  	nti, ok := types[elementTypeName]
  2442  	if !ok {
  2443  		nti = &nestedTypeInfo{
  2444  			names:               map[string]bool{},
  2445  			resolvedElementType: pkg.typeString(codegen.ResolvedType(typ)),
  2446  		}
  2447  		types[elementTypeName] = nti
  2448  	}
  2449  	for _, n := range names {
  2450  		nti.names[n] = true
  2451  	}
  2452  }
  2453  
  2454  // genNestedCollectionTypes emits nested collection types given the deduped mapping of element types -> associated collection types.
  2455  // different shapes of known types can resolve to the same element type. by collecting types in one step and emitting types
  2456  // in a second step, we avoid collision and redeclaration.
  2457  func (pkg *pkgContext) genNestedCollectionTypes(w io.Writer, types map[string]*nestedTypeInfo) []string {
  2458  	var names []string
  2459  
  2460  	// map iteration is unstable so sort items for deterministic codegen
  2461  	sortedElems := []string{}
  2462  	for k := range types {
  2463  		sortedElems = append(sortedElems, k)
  2464  	}
  2465  	sort.Strings(sortedElems)
  2466  
  2467  	for _, elementTypeName := range sortedElems {
  2468  		info := types[elementTypeName]
  2469  
  2470  		collectionTypes := []string{}
  2471  		for k := range info.names {
  2472  			collectionTypes = append(collectionTypes, k)
  2473  		}
  2474  		sort.Strings(collectionTypes)
  2475  		for _, name := range collectionTypes {
  2476  			names = append(names, name)
  2477  			switch {
  2478  			case strings.HasSuffix(name, "ArrayInput"):
  2479  				name = strings.TrimSuffix(name, "Input")
  2480  				fmt.Fprintf(w, "type %s []%sInput\n\n", name, elementTypeName)
  2481  				genInputImplementation(w, name, name, "[]"+info.resolvedElementType, false)
  2482  
  2483  				pkg.genInputInterface(w, name)
  2484  			case strings.HasSuffix(name, "ArrayOutput"):
  2485  				genArrayOutput(w, strings.TrimSuffix(name, "ArrayOutput"), info.resolvedElementType)
  2486  			case strings.HasSuffix(name, "MapInput"):
  2487  				name = strings.TrimSuffix(name, "Input")
  2488  				fmt.Fprintf(w, "type %s map[string]%sInput\n\n", name, elementTypeName)
  2489  				genInputImplementation(w, name, name, "map[string]"+info.resolvedElementType, false)
  2490  
  2491  				pkg.genInputInterface(w, name)
  2492  			case strings.HasSuffix(name, "MapOutput"):
  2493  				genMapOutput(w, strings.TrimSuffix(name, "MapOutput"), info.resolvedElementType)
  2494  			}
  2495  		}
  2496  	}
  2497  
  2498  	return names
  2499  }
  2500  
  2501  func (pkg *pkgContext) nestedTypeToType(typ schema.Type) string {
  2502  	switch t := codegen.UnwrapType(typ).(type) {
  2503  	case *schema.ArrayType:
  2504  		return pkg.nestedTypeToType(t.ElementType) + "Array"
  2505  	case *schema.MapType:
  2506  		return pkg.nestedTypeToType(t.ElementType) + "Map"
  2507  	case *schema.ObjectType:
  2508  		return pkg.resolveObjectType(t)
  2509  	}
  2510  	return strings.TrimSuffix(pkg.tokenToType(typ.String()), "Args")
  2511  }
  2512  
  2513  func (pkg *pkgContext) genTypeRegistrations(w io.Writer, objTypes []*schema.ObjectType, types ...string) {
  2514  	fmt.Fprintf(w, "func init() {\n")
  2515  
  2516  	// Input types.
  2517  	if !pkg.disableInputTypeRegistrations {
  2518  		for _, obj := range objTypes {
  2519  			if obj.IsOverlay {
  2520  				// This type is generated by the provider, so no further action is required.
  2521  				continue
  2522  			}
  2523  			name, details := pkg.tokenToType(obj.Token), pkg.detailsForType(obj)
  2524  			if details.input {
  2525  				fmt.Fprintf(w,
  2526  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sInput)(nil)).Elem(), %[1]sArgs{})\n", name)
  2527  			}
  2528  			if details.ptrInput {
  2529  				fmt.Fprintf(w,
  2530  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sPtrInput)(nil)).Elem(), %[1]sArgs{})\n", name)
  2531  			}
  2532  			if details.arrayInput && !pkg.names.Has(name+"Array") {
  2533  				fmt.Fprintf(w,
  2534  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sArrayInput)(nil)).Elem(), %[1]sArray{})\n", name)
  2535  			}
  2536  			if details.mapInput && !pkg.names.Has(name+"Map") {
  2537  				fmt.Fprintf(w,
  2538  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sMapInput)(nil)).Elem(), %[1]sMap{})\n", name)
  2539  			}
  2540  		}
  2541  		for _, t := range types {
  2542  			if strings.HasSuffix(t, "Input") {
  2543  				fmt.Fprintf(w, "\tpulumi.RegisterInputType(reflect.TypeOf((*%s)(nil)).Elem(), %s{})\n", t, strings.TrimSuffix(t, "Input"))
  2544  			}
  2545  		}
  2546  	}
  2547  
  2548  	// Output types.
  2549  	for _, obj := range objTypes {
  2550  		if obj.IsOverlay {
  2551  			// This type is generated by the provider, so no further action is required.
  2552  			continue
  2553  		}
  2554  		name, details := pkg.tokenToType(obj.Token), pkg.detailsForType(obj)
  2555  		if details.output {
  2556  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sOutput{})\n", name)
  2557  		}
  2558  		if details.ptrOutput {
  2559  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sPtrOutput{})\n", name)
  2560  		}
  2561  		if details.arrayOutput {
  2562  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sArrayOutput{})\n", name)
  2563  		}
  2564  		if details.mapOutput {
  2565  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sMapOutput{})\n", name)
  2566  		}
  2567  	}
  2568  	for _, t := range types {
  2569  		if strings.HasSuffix(t, "Output") {
  2570  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%s{})\n", t)
  2571  		}
  2572  	}
  2573  
  2574  	fmt.Fprintf(w, "}\n")
  2575  }
  2576  
  2577  func (pkg *pkgContext) genEnumRegistrations(w io.Writer) {
  2578  	fmt.Fprintf(w, "func init() {\n")
  2579  	// Register all input types
  2580  	if !pkg.disableInputTypeRegistrations {
  2581  		for _, e := range pkg.enums {
  2582  			// Enums are guaranteed to have at least one element when they are
  2583  			// bound into a schema.
  2584  			contract.Assert(len(e.Elements) > 0)
  2585  			name, details := pkg.tokenToEnum(e.Token), pkg.detailsForType(e)
  2586  			instance := fmt.Sprintf("%#v", e.Elements[0].Value)
  2587  			if details.input || details.ptrInput {
  2588  				fmt.Fprintf(w,
  2589  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sInput)(nil)).Elem(), %[1]s(%[2]s))\n",
  2590  					name, instance)
  2591  				fmt.Fprintf(w,
  2592  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sPtrInput)(nil)).Elem(), %[1]s(%[2]s))\n",
  2593  					name, instance)
  2594  			}
  2595  			if details.arrayInput {
  2596  				fmt.Fprintf(w,
  2597  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sArrayInput)(nil)).Elem(), %[1]sArray{})\n",
  2598  					name)
  2599  			}
  2600  			if details.mapInput {
  2601  				fmt.Fprintf(w,
  2602  					"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sMapInput)(nil)).Elem(), %[1]sMap{})\n",
  2603  					name)
  2604  			}
  2605  		}
  2606  	}
  2607  	// Register all output types
  2608  	for _, e := range pkg.enums {
  2609  		name, details := pkg.tokenToEnum(e.Token), pkg.detailsForType(e)
  2610  		if details.output || details.ptrOutput {
  2611  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sOutput{})\n", name)
  2612  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sPtrOutput{})\n", name)
  2613  		}
  2614  		if details.arrayOutput {
  2615  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sArrayOutput{})\n", name)
  2616  		}
  2617  		if details.mapOutput {
  2618  			fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sMapOutput{})\n", name)
  2619  		}
  2620  	}
  2621  	fmt.Fprintf(w, "}\n\n")
  2622  }
  2623  
  2624  func (pkg *pkgContext) genResourceRegistrations(w io.Writer, r *schema.Resource, generateResourceContainerTypes bool) {
  2625  	name := disambiguatedResourceName(r, pkg)
  2626  	fmt.Fprintf(w, "func init() {\n")
  2627  	// Register input type
  2628  	if !pkg.disableInputTypeRegistrations {
  2629  		fmt.Fprintf(w,
  2630  			"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sInput)(nil)).Elem(), &%[1]s{})\n",
  2631  			name)
  2632  		if generateResourceContainerTypes && !r.IsProvider {
  2633  			fmt.Fprintf(w,
  2634  				"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sArrayInput)(nil)).Elem(), %[1]sArray{})\n",
  2635  				name)
  2636  			fmt.Fprintf(w,
  2637  				"\tpulumi.RegisterInputType(reflect.TypeOf((*%[1]sMapInput)(nil)).Elem(), %[1]sMap{})\n",
  2638  				name)
  2639  		}
  2640  	}
  2641  	// Register all output types
  2642  	fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sOutput{})\n", name)
  2643  	for _, method := range r.Methods {
  2644  		if method.Function.Outputs != nil {
  2645  			if pkg.liftSingleValueMethodReturns && len(method.Function.Outputs.Properties) == 1 {
  2646  				fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%s%sResultOutput{})\n", cgstrings.Camel(name), Title(method.Name))
  2647  			} else {
  2648  				fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%s%sResultOutput{})\n", name, Title(method.Name))
  2649  			}
  2650  		}
  2651  	}
  2652  
  2653  	if generateResourceContainerTypes && !r.IsProvider {
  2654  		fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sArrayOutput{})\n", name)
  2655  		fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sMapOutput{})\n", name)
  2656  	}
  2657  	fmt.Fprintf(w, "}\n\n")
  2658  }
  2659  
  2660  func (pkg *pkgContext) getTypeImports(t schema.Type, recurse bool, importsAndAliases map[string]string, seen map[schema.Type]struct{}) {
  2661  	if _, ok := seen[t]; ok {
  2662  		return
  2663  	}
  2664  	seen[t] = struct{}{}
  2665  
  2666  	// Import an external type with `token` and return true.
  2667  	// If the type is not external, return false.
  2668  	importExternal := func(token string) bool {
  2669  		if pkg.isExternalReference(t) {
  2670  			extPkgCtx, _ := pkg.contextForExternalReference(t)
  2671  			mod := extPkgCtx.tokenToPackage(token)
  2672  			imp := path.Join(extPkgCtx.importBasePath, mod)
  2673  			importsAndAliases[imp] = extPkgCtx.pkgImportAliases[imp]
  2674  			return true
  2675  		}
  2676  		return false
  2677  	}
  2678  
  2679  	switch t := t.(type) {
  2680  	case *schema.OptionalType:
  2681  		pkg.getTypeImports(t.ElementType, recurse, importsAndAliases, seen)
  2682  	case *schema.InputType:
  2683  		pkg.getTypeImports(t.ElementType, recurse, importsAndAliases, seen)
  2684  	case *schema.EnumType:
  2685  		if importExternal(t.Token) {
  2686  			break
  2687  		}
  2688  
  2689  		mod := pkg.tokenToPackage(t.Token)
  2690  		if mod != pkg.mod {
  2691  			p := path.Join(pkg.importBasePath, mod)
  2692  			importsAndAliases[path.Join(pkg.importBasePath, mod)] = pkg.pkgImportAliases[p]
  2693  		}
  2694  	case *schema.ArrayType:
  2695  		pkg.getTypeImports(t.ElementType, recurse, importsAndAliases, seen)
  2696  	case *schema.MapType:
  2697  		pkg.getTypeImports(t.ElementType, recurse, importsAndAliases, seen)
  2698  	case *schema.ObjectType:
  2699  		if importExternal(t.Token) {
  2700  			break
  2701  		}
  2702  
  2703  		mod := pkg.tokenToPackage(t.Token)
  2704  		if mod != pkg.mod {
  2705  			p := path.Join(pkg.importBasePath, mod)
  2706  			importsAndAliases[path.Join(pkg.importBasePath, mod)] = pkg.pkgImportAliases[p]
  2707  		}
  2708  
  2709  		if recurse {
  2710  			for _, p := range t.Properties {
  2711  				// We only recurse one level into objects, since we need to name
  2712  				// their properties but not the properties named in their
  2713  				// properties.
  2714  				pkg.getTypeImports(p.Type, false, importsAndAliases, seen)
  2715  			}
  2716  		}
  2717  	case *schema.ResourceType:
  2718  		if importExternal(t.Token) {
  2719  			break
  2720  		}
  2721  		mod := pkg.tokenToPackage(t.Token)
  2722  		if mod != pkg.mod {
  2723  			p := path.Join(pkg.importBasePath, mod)
  2724  			importsAndAliases[path.Join(pkg.importBasePath, mod)] = pkg.pkgImportAliases[p]
  2725  		}
  2726  	case *schema.UnionType:
  2727  		for _, e := range t.ElementTypes {
  2728  			pkg.getTypeImports(e, recurse, importsAndAliases, seen)
  2729  		}
  2730  	}
  2731  }
  2732  
  2733  func extractImportBasePath(extPkg *schema.Package) string {
  2734  	version := extPkg.Version.Major
  2735  	var vPath string
  2736  	if version > 1 {
  2737  		vPath = fmt.Sprintf("/v%d", version)
  2738  	}
  2739  	return fmt.Sprintf("github.com/pulumi/pulumi-%s/sdk%s/go/%s", extPkg.Name, vPath, extPkg.Name)
  2740  }
  2741  
  2742  func (pkg *pkgContext) getImports(member interface{}, importsAndAliases map[string]string) {
  2743  	seen := map[schema.Type]struct{}{}
  2744  	switch member := member.(type) {
  2745  	case *schema.ObjectType:
  2746  		pkg.getTypeImports(member, true, importsAndAliases, seen)
  2747  	case *schema.ResourceType:
  2748  		pkg.getTypeImports(member, true, importsAndAliases, seen)
  2749  	case *schema.Resource:
  2750  		for _, p := range member.Properties {
  2751  			pkg.getTypeImports(p.Type, false, importsAndAliases, seen)
  2752  		}
  2753  		for _, p := range member.InputProperties {
  2754  			pkg.getTypeImports(p.Type, false, importsAndAliases, seen)
  2755  
  2756  			if p.IsRequired() {
  2757  				importsAndAliases["github.com/pkg/errors"] = ""
  2758  			}
  2759  		}
  2760  		for _, method := range member.Methods {
  2761  			if method.Function.Inputs != nil {
  2762  				for _, p := range method.Function.Inputs.InputShape.Properties {
  2763  					if p.Name == "__self__" {
  2764  						continue
  2765  					}
  2766  					pkg.getTypeImports(p.Type, false, importsAndAliases, seen)
  2767  				}
  2768  			}
  2769  			if method.Function.Outputs != nil {
  2770  				for _, p := range method.Function.Outputs.Properties {
  2771  					pkg.getTypeImports(p.Type, false, importsAndAliases, seen)
  2772  				}
  2773  			}
  2774  		}
  2775  	case *schema.Function:
  2776  		if member.Inputs != nil {
  2777  			pkg.getTypeImports(member.Inputs, true, importsAndAliases, seen)
  2778  		}
  2779  		if member.Outputs != nil {
  2780  			pkg.getTypeImports(member.Outputs, true, importsAndAliases, seen)
  2781  		}
  2782  	case []*schema.Property:
  2783  		for _, p := range member {
  2784  			pkg.getTypeImports(p.Type, false, importsAndAliases, seen)
  2785  		}
  2786  	default:
  2787  		return
  2788  	}
  2789  }
  2790  
  2791  func (pkg *pkgContext) genHeader(w io.Writer, goImports []string, importsAndAliases map[string]string) {
  2792  	fmt.Fprintf(w, "// Code generated by %v DO NOT EDIT.\n", pkg.tool)
  2793  	fmt.Fprintf(w, "// *** WARNING: Do not edit by hand unless you're certain you know what you are doing! ***\n\n")
  2794  
  2795  	var pkgName string
  2796  	if pkg.mod == "" {
  2797  		pkgName = packageName(pkg.pkg)
  2798  	} else {
  2799  		pkgName = path.Base(pkg.mod)
  2800  	}
  2801  
  2802  	fmt.Fprintf(w, "package %s\n\n", pkgName)
  2803  
  2804  	var imports []string
  2805  	if len(importsAndAliases) > 0 {
  2806  		for k := range importsAndAliases {
  2807  			imports = append(imports, k)
  2808  		}
  2809  		sort.Strings(imports)
  2810  
  2811  		for i, k := range imports {
  2812  			if alias := importsAndAliases[k]; alias != "" {
  2813  				imports[i] = fmt.Sprintf(`%s "%s"`, alias, k)
  2814  			}
  2815  		}
  2816  	}
  2817  
  2818  	if len(goImports) > 0 {
  2819  		if len(imports) > 0 {
  2820  			goImports = append(goImports, "")
  2821  		}
  2822  		imports = append(goImports, imports...)
  2823  	}
  2824  	if len(imports) > 0 {
  2825  		fmt.Fprintf(w, "import (\n")
  2826  		for _, i := range imports {
  2827  			if i == "" {
  2828  				fmt.Fprintf(w, "\n")
  2829  			} else {
  2830  				if strings.Contains(i, `"`) { // Imports with aliases already include quotes.
  2831  					fmt.Fprintf(w, "\t%s\n", i)
  2832  				} else {
  2833  					fmt.Fprintf(w, "\t%q\n", i)
  2834  				}
  2835  			}
  2836  		}
  2837  		fmt.Fprintf(w, ")\n\n")
  2838  	}
  2839  }
  2840  
  2841  func (pkg *pkgContext) genConfig(w io.Writer, variables []*schema.Property) error {
  2842  	importsAndAliases := map[string]string{
  2843  		"github.com/pulumi/pulumi/sdk/v3/go/pulumi/config": "",
  2844  		"github.com/pulumi/pulumi/sdk/v3/go/pulumi":        "",
  2845  	}
  2846  	pkg.getImports(variables, importsAndAliases)
  2847  
  2848  	pkg.genHeader(w, nil, importsAndAliases)
  2849  
  2850  	for _, p := range variables {
  2851  		getfunc := "Get"
  2852  
  2853  		var getType string
  2854  		var funcType string
  2855  		switch codegen.UnwrapType(p.Type) {
  2856  		case schema.BoolType:
  2857  			getType, funcType = "bool", "Bool"
  2858  		case schema.IntType:
  2859  			getType, funcType = "int", "Int"
  2860  		case schema.NumberType:
  2861  			getType, funcType = "float64", "Float64"
  2862  		default:
  2863  			getType, funcType = "string", ""
  2864  		}
  2865  
  2866  		printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, false)
  2867  		configKey := fmt.Sprintf("\"%s:%s\"", pkg.pkg.Name, cgstrings.Camel(p.Name))
  2868  
  2869  		fmt.Fprintf(w, "func Get%s(ctx *pulumi.Context) %s {\n", Title(p.Name), getType)
  2870  		if p.DefaultValue != nil {
  2871  			defaultValue, err := pkg.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
  2872  			if err != nil {
  2873  				return err
  2874  			}
  2875  
  2876  			fmt.Fprintf(w, "\tv, err := config.Try%s(ctx, %s)\n", funcType, configKey)
  2877  			fmt.Fprintf(w, "\tif err == nil {\n")
  2878  			fmt.Fprintf(w, "\t\treturn v\n")
  2879  			fmt.Fprintf(w, "\t}\n")
  2880  			fmt.Fprintf(w, "\treturn %s", defaultValue)
  2881  		} else {
  2882  			fmt.Fprintf(w, "\treturn config.%s%s(ctx, %s)\n", getfunc, funcType, configKey)
  2883  		}
  2884  		fmt.Fprintf(w, "}\n")
  2885  	}
  2886  
  2887  	return nil
  2888  }
  2889  
  2890  // genResourceModule generates a ResourceModule definition and the code to register an instance thereof with the
  2891  // Pulumi runtime. The generated ResourceModule supports the deserialization of resource references into fully-
  2892  // hydrated Resource instances. If this is the root module, this function also generates a ResourcePackage
  2893  // definition and its registration to support rehydrating providers.
  2894  func (pkg *pkgContext) genResourceModule(w io.Writer) {
  2895  	contract.Assert(len(pkg.resources) != 0)
  2896  	allResourcesAreOverlays := true
  2897  	for _, r := range pkg.resources {
  2898  		if !r.IsOverlay {
  2899  			allResourcesAreOverlays = false
  2900  			break
  2901  		}
  2902  	}
  2903  	if allResourcesAreOverlays {
  2904  		// If all resources in this module are overlays, skip further code generation.
  2905  		return
  2906  	}
  2907  
  2908  	basePath := pkg.importBasePath
  2909  
  2910  	imports := map[string]string{
  2911  		"github.com/blang/semver":                   "",
  2912  		"github.com/pulumi/pulumi/sdk/v3/go/pulumi": "",
  2913  	}
  2914  
  2915  	topLevelModule := pkg.mod == ""
  2916  	if !topLevelModule {
  2917  		if alias, ok := pkg.pkgImportAliases[basePath]; ok {
  2918  			imports[basePath] = alias
  2919  		} else {
  2920  			imports[basePath] = ""
  2921  		}
  2922  	}
  2923  
  2924  	// If there are any internal dependencies, include them as blank imports.
  2925  	if topLevelModule {
  2926  		if goInfo, ok := pkg.pkg.Language["go"].(GoPackageInfo); ok {
  2927  			for _, dep := range goInfo.InternalDependencies {
  2928  				imports[dep] = "_"
  2929  			}
  2930  		}
  2931  	}
  2932  
  2933  	pkg.genHeader(w, []string{"fmt"}, imports)
  2934  
  2935  	var provider *schema.Resource
  2936  	registrations := codegen.StringSet{}
  2937  	if providerOnly := len(pkg.resources) == 1 && pkg.resources[0].IsProvider; providerOnly {
  2938  		provider = pkg.resources[0]
  2939  	} else {
  2940  		fmt.Fprintf(w, "type module struct {\n")
  2941  		fmt.Fprintf(w, "\tversion semver.Version\n")
  2942  		fmt.Fprintf(w, "}\n\n")
  2943  
  2944  		fmt.Fprintf(w, "func (m *module) Version() semver.Version {\n")
  2945  		fmt.Fprintf(w, "\treturn m.version\n")
  2946  		fmt.Fprintf(w, "}\n\n")
  2947  
  2948  		fmt.Fprintf(w, "func (m *module) Construct(ctx *pulumi.Context, name, typ, urn string) (r pulumi.Resource, err error) {\n")
  2949  		fmt.Fprintf(w, "\tswitch typ {\n")
  2950  		for _, r := range pkg.resources {
  2951  			if r.IsOverlay {
  2952  				// This resource code is generated by the provider, so no further action is required.
  2953  				continue
  2954  			}
  2955  			if r.IsProvider {
  2956  				contract.Assert(provider == nil)
  2957  				provider = r
  2958  				continue
  2959  			}
  2960  
  2961  			registrations.Add(tokenToModule(r.Token))
  2962  			fmt.Fprintf(w, "\tcase %q:\n", r.Token)
  2963  			fmt.Fprintf(w, "\t\tr = &%s{}\n", disambiguatedResourceName(r, pkg))
  2964  		}
  2965  		fmt.Fprintf(w, "\tdefault:\n")
  2966  		fmt.Fprintf(w, "\t\treturn nil, fmt.Errorf(\"unknown resource type: %%s\", typ)\n")
  2967  		fmt.Fprintf(w, "\t}\n\n")
  2968  		fmt.Fprintf(w, "\terr = ctx.RegisterResource(typ, name, nil, r, pulumi.URN_(urn))\n")
  2969  		fmt.Fprintf(w, "\treturn\n")
  2970  		fmt.Fprintf(w, "}\n\n")
  2971  	}
  2972  
  2973  	if provider != nil {
  2974  		fmt.Fprintf(w, "type pkg struct {\n")
  2975  		fmt.Fprintf(w, "\tversion semver.Version\n")
  2976  		fmt.Fprintf(w, "}\n\n")
  2977  
  2978  		fmt.Fprintf(w, "func (p *pkg) Version() semver.Version {\n")
  2979  		fmt.Fprintf(w, "\treturn p.version\n")
  2980  		fmt.Fprintf(w, "}\n\n")
  2981  
  2982  		fmt.Fprintf(w, "func (p *pkg) ConstructProvider(ctx *pulumi.Context, name, typ, urn string) (pulumi.ProviderResource, error) {\n")
  2983  		fmt.Fprintf(w, "\tif typ != \"pulumi:providers:%s\" {\n", pkg.pkg.Name)
  2984  		fmt.Fprintf(w, "\t\treturn nil, fmt.Errorf(\"unknown provider type: %%s\", typ)\n")
  2985  		fmt.Fprintf(w, "\t}\n\n")
  2986  		fmt.Fprintf(w, "\tr := &Provider{}\n")
  2987  		fmt.Fprintf(w, "\terr := ctx.RegisterResource(typ, name, nil, r, pulumi.URN_(urn))\n")
  2988  		fmt.Fprintf(w, "\treturn r, err\n")
  2989  		fmt.Fprintf(w, "}\n\n")
  2990  	}
  2991  
  2992  	fmt.Fprintf(w, "func init() {\n")
  2993  	if topLevelModule {
  2994  		fmt.Fprintf(w, "\tversion, _ := PkgVersion()\n")
  2995  	} else {
  2996  		// Some package names contain '-' characters, so grab the name from the base path, unless there is an alias
  2997  		// in which case we use that instead.
  2998  		var pkgName string
  2999  		if alias, ok := pkg.pkgImportAliases[basePath]; ok {
  3000  			pkgName = alias
  3001  		} else {
  3002  			pkgName = basePath[strings.LastIndex(basePath, "/")+1:]
  3003  		}
  3004  		pkgName = strings.ReplaceAll(pkgName, "-", "")
  3005  		fmt.Fprintf(w, "\tversion, err := %s.PkgVersion()\n", pkgName)
  3006  		// To avoid breaking compatibility, we don't change the function
  3007  		// signature. We instead just ignore the error.
  3008  		fmt.Fprintf(w, "\tif err != nil {\n")
  3009  		fmt.Fprintf(w, "\t\tversion = semver.Version{Major: 1}\n")
  3010  		fmt.Fprintf(w, "\t}\n")
  3011  	}
  3012  	if len(registrations) > 0 {
  3013  		for _, mod := range registrations.SortedValues() {
  3014  			fmt.Fprintf(w, "\tpulumi.RegisterResourceModule(\n")
  3015  			fmt.Fprintf(w, "\t\t%q,\n", pkg.pkg.Name)
  3016  			fmt.Fprintf(w, "\t\t%q,\n", mod)
  3017  			fmt.Fprintf(w, "\t\t&module{version},\n")
  3018  			fmt.Fprintf(w, "\t)\n")
  3019  		}
  3020  	}
  3021  	if provider != nil {
  3022  		fmt.Fprintf(w, "\tpulumi.RegisterResourcePackage(\n")
  3023  		fmt.Fprintf(w, "\t\t%q,\n", pkg.pkg.Name)
  3024  		fmt.Fprintf(w, "\t\t&pkg{version},\n")
  3025  		fmt.Fprintf(w, "\t)\n")
  3026  	}
  3027  	fmt.Fprintf(w, "}\n")
  3028  }
  3029  
  3030  // generatePackageContextMap groups resources, types, and functions into Go packages.
  3031  func generatePackageContextMap(tool string, pkg *schema.Package, goInfo GoPackageInfo, externalPkgs *Cache) map[string]*pkgContext {
  3032  	packages := map[string]*pkgContext{}
  3033  
  3034  	// Share the cache
  3035  	if externalPkgs == nil {
  3036  		externalPkgs = globalCache
  3037  	}
  3038  
  3039  	getPkg := func(mod string) *pkgContext {
  3040  		pack, ok := packages[mod]
  3041  		if !ok {
  3042  			pack = &pkgContext{
  3043  				pkg:                           pkg,
  3044  				mod:                           mod,
  3045  				importBasePath:                goInfo.ImportBasePath,
  3046  				rootPackageName:               goInfo.RootPackageName,
  3047  				typeDetails:                   map[schema.Type]*typeDetails{},
  3048  				names:                         codegen.NewStringSet(),
  3049  				schemaNames:                   codegen.NewStringSet(),
  3050  				renamed:                       map[string]string{},
  3051  				duplicateTokens:               map[string]bool{},
  3052  				functionNames:                 map[*schema.Function]string{},
  3053  				tool:                          tool,
  3054  				modToPkg:                      goInfo.ModuleToPackage,
  3055  				pkgImportAliases:              goInfo.PackageImportAliases,
  3056  				packages:                      packages,
  3057  				liftSingleValueMethodReturns:  goInfo.LiftSingleValueMethodReturns,
  3058  				disableInputTypeRegistrations: goInfo.DisableInputTypeRegistrations,
  3059  				disableObjectDefaults:         goInfo.DisableObjectDefaults,
  3060  				externalPackages:              externalPkgs,
  3061  			}
  3062  			packages[mod] = pack
  3063  		}
  3064  		return pack
  3065  	}
  3066  
  3067  	getPkgFromToken := func(token string) *pkgContext {
  3068  		return getPkg(tokenToPackage(pkg, goInfo.ModuleToPackage, token))
  3069  	}
  3070  
  3071  	var getPkgFromType func(schema.Type) *pkgContext
  3072  	getPkgFromType = func(typ schema.Type) *pkgContext {
  3073  		switch t := codegen.UnwrapType(typ).(type) {
  3074  		case *schema.ArrayType:
  3075  			return getPkgFromType(t.ElementType)
  3076  		case *schema.MapType:
  3077  			return getPkgFromType(t.ElementType)
  3078  		default:
  3079  			return getPkgFromToken(t.String())
  3080  		}
  3081  	}
  3082  
  3083  	if len(pkg.Config) > 0 {
  3084  		_ = getPkg("config")
  3085  	}
  3086  
  3087  	// For any optional properties, we must generate a pointer type for the corresponding property type.
  3088  	// In addition, if the optional property's type is itself an object type, we also need to generate pointer
  3089  	// types corresponding to all of it's nested properties, as our accessor methods will lift `nil` into
  3090  	// those nested types.
  3091  	var populateDetailsForPropertyTypes func(seen codegen.StringSet, props []*schema.Property, optional, input, output bool)
  3092  	var populateDetailsForTypes func(seen codegen.StringSet, schemaType schema.Type, optional, input, output bool)
  3093  
  3094  	seenKey := func(t schema.Type, optional, input, output bool) string {
  3095  		var key string
  3096  		switch t := t.(type) {
  3097  		case *schema.ObjectType:
  3098  			key = t.Token
  3099  		case *schema.EnumType:
  3100  			key = t.Token
  3101  		default:
  3102  			key = t.String()
  3103  		}
  3104  		if optional {
  3105  			key += ",optional"
  3106  		}
  3107  		if input {
  3108  			key += ",input"
  3109  		}
  3110  		if output {
  3111  			key += ",output"
  3112  		}
  3113  		return key
  3114  	}
  3115  
  3116  	populateDetailsForPropertyTypes = func(seen codegen.StringSet, props []*schema.Property, optional, input, output bool) {
  3117  		for _, p := range props {
  3118  			if obj, ok := codegen.UnwrapType(p.Type).(*schema.ObjectType); ok && p.Plain {
  3119  				pkg := getPkgFromToken(obj.Token)
  3120  				details := pkg.detailsForType(obj)
  3121  				details.mark(true, false)
  3122  				input = true
  3123  				_, hasOptional := p.Type.(*schema.OptionalType)
  3124  				details.markPtr(hasOptional, false)
  3125  			}
  3126  			populateDetailsForTypes(seen, p.Type, !p.IsRequired() || optional, input, output)
  3127  		}
  3128  	}
  3129  
  3130  	populateDetailsForTypes = func(seen codegen.StringSet, schemaType schema.Type, optional, input, output bool) {
  3131  		key := seenKey(schemaType, optional, input, output)
  3132  		if seen.Has(key) {
  3133  			return
  3134  		}
  3135  		seen.Add(key)
  3136  
  3137  		switch typ := schemaType.(type) {
  3138  		case *schema.InputType:
  3139  			populateDetailsForTypes(seen, typ.ElementType, optional, true, false)
  3140  		case *schema.OptionalType:
  3141  			populateDetailsForTypes(seen, typ.ElementType, true, input, output)
  3142  		case *schema.ObjectType:
  3143  			pkg := getPkgFromToken(typ.Token)
  3144  			pkg.detailsForType(typ).mark(input || goInfo.GenerateExtraInputTypes, output)
  3145  
  3146  			if optional {
  3147  				pkg.detailsForType(typ).markPtr(input || goInfo.GenerateExtraInputTypes, output)
  3148  			}
  3149  
  3150  			pkg.schemaNames.Add(tokenToName(typ.Token))
  3151  
  3152  			populateDetailsForPropertyTypes(seen, typ.Properties, optional, input, output)
  3153  		case *schema.EnumType:
  3154  			pkg := getPkgFromToken(typ.Token)
  3155  			pkg.detailsForType(typ).mark(input || goInfo.GenerateExtraInputTypes, output)
  3156  
  3157  			if optional {
  3158  				pkg.detailsForType(typ).markPtr(input || goInfo.GenerateExtraInputTypes, output)
  3159  			}
  3160  
  3161  			pkg.schemaNames.Add(tokenToName(typ.Token))
  3162  		case *schema.ArrayType:
  3163  			details := getPkgFromType(typ.ElementType).detailsForType(codegen.UnwrapType(typ.ElementType))
  3164  			details.markArray(input || goInfo.GenerateExtraInputTypes, output)
  3165  			populateDetailsForTypes(seen, typ.ElementType, false, input, output)
  3166  		case *schema.MapType:
  3167  			details := getPkgFromType(typ.ElementType).detailsForType(codegen.UnwrapType(typ.ElementType))
  3168  			details.markMap(input || goInfo.GenerateExtraInputTypes, output)
  3169  			populateDetailsForTypes(seen, typ.ElementType, false, input, output)
  3170  		}
  3171  	}
  3172  
  3173  	// Rewrite cyclic types. See the docs on rewriteCyclicFields for the motivation.
  3174  	rewriteCyclicObjectFields(pkg)
  3175  
  3176  	// Use a string set to track object types that have already been processed.
  3177  	// This avoids recursively processing the same type. For example, in the
  3178  	// Kubernetes package, JSONSchemaProps have properties whose type is itself.
  3179  	seenMap := codegen.NewStringSet()
  3180  	for _, t := range pkg.Types {
  3181  		switch typ := t.(type) {
  3182  		case *schema.ArrayType:
  3183  			details := getPkgFromType(typ.ElementType).detailsForType(codegen.UnwrapType(typ.ElementType))
  3184  			details.markArray(goInfo.GenerateExtraInputTypes, false)
  3185  		case *schema.MapType:
  3186  			details := getPkgFromType(typ.ElementType).detailsForType(codegen.UnwrapType(typ.ElementType))
  3187  			details.markMap(goInfo.GenerateExtraInputTypes, false)
  3188  		case *schema.ObjectType:
  3189  			pkg := getPkgFromToken(typ.Token)
  3190  			if !typ.IsInputShape() {
  3191  				pkg.types = append(pkg.types, typ)
  3192  			}
  3193  			populateDetailsForTypes(seenMap, typ, false, false, false)
  3194  		case *schema.EnumType:
  3195  			if !typ.IsOverlay {
  3196  				pkg := getPkgFromToken(typ.Token)
  3197  				pkg.enums = append(pkg.enums, typ)
  3198  
  3199  				populateDetailsForTypes(seenMap, typ, false, false, false)
  3200  			}
  3201  		}
  3202  	}
  3203  
  3204  	resSeen := map[string]bool{}
  3205  	typeSeen := map[string]bool{}
  3206  
  3207  	// compute set of names generated by a resource
  3208  	// handling any potential collisions via remapping along the way
  3209  	scanResource := func(r *schema.Resource) {
  3210  		if resSeen[strings.ToLower(r.Token)] {
  3211  			return
  3212  		}
  3213  		resSeen[strings.ToLower(r.Token)] = true
  3214  		pkg := getPkgFromToken(r.Token)
  3215  		pkg.resources = append(pkg.resources, r)
  3216  		pkg.schemaNames.Add(tokenToName(r.Token))
  3217  
  3218  		getNames := func(suffix string) []string {
  3219  			names := []string{}
  3220  			names = append(names, rawResourceName(r)+suffix)
  3221  			names = append(names, rawResourceName(r)+suffix+"Input")
  3222  			names = append(names, rawResourceName(r)+suffix+"Output")
  3223  			names = append(names, rawResourceName(r)+suffix+"Args")
  3224  			names = append(names, cgstrings.Camel(rawResourceName(r))+suffix+"Args")
  3225  			names = append(names, "New"+rawResourceName(r)+suffix)
  3226  			if !r.IsProvider && !r.IsComponent {
  3227  				names = append(names, rawResourceName(r)+suffix+"State")
  3228  				names = append(names, cgstrings.Camel(rawResourceName(r))+suffix+"State")
  3229  				names = append(names, "Get"+rawResourceName(r)+suffix)
  3230  			}
  3231  			if goInfo.GenerateResourceContainerTypes && !r.IsProvider {
  3232  				names = append(names, rawResourceName(r)+suffix+"Array")
  3233  				names = append(names, rawResourceName(r)+suffix+"Map")
  3234  			}
  3235  			return names
  3236  		}
  3237  
  3238  		suffixes := []string{"", "Resource", "Res"}
  3239  		suffix := ""
  3240  		suffixIndex := 0
  3241  		canGenerate := false
  3242  
  3243  		for !canGenerate && suffixIndex <= len(suffixes) {
  3244  			suffix = suffixes[suffixIndex]
  3245  			candidates := getNames(suffix)
  3246  			conflict := false
  3247  			for _, c := range candidates {
  3248  				if pkg.names.Has(c) {
  3249  					conflict = true
  3250  				}
  3251  			}
  3252  			if !conflict {
  3253  				canGenerate = true
  3254  				break
  3255  			}
  3256  
  3257  			suffixIndex++
  3258  		}
  3259  
  3260  		if !canGenerate {
  3261  			panic(fmt.Sprintf("unable to generate Go SDK, schema has unresolvable overlapping resource: %s", rawResourceName(r)))
  3262  		}
  3263  
  3264  		names := getNames(suffix)
  3265  		originalNames := getNames("")
  3266  		for i, n := range names {
  3267  			pkg.names.Add(n)
  3268  			if suffix != "" {
  3269  				pkg.renamed[originalNames[i]] = names[i]
  3270  			}
  3271  		}
  3272  
  3273  		populateDetailsForPropertyTypes(seenMap, r.InputProperties, r.IsProvider, false, false)
  3274  		populateDetailsForPropertyTypes(seenMap, r.Properties, r.IsProvider, false, true)
  3275  
  3276  		if r.StateInputs != nil {
  3277  			populateDetailsForPropertyTypes(seenMap, r.StateInputs.Properties,
  3278  				r.IsProvider, false /*input*/, false /*output*/)
  3279  		}
  3280  
  3281  		for _, method := range r.Methods {
  3282  			if method.Function.Inputs != nil {
  3283  				pkg.names.Add(rawResourceName(r) + Title(method.Name) + "Args")
  3284  			}
  3285  			if method.Function.Outputs != nil {
  3286  				pkg.names.Add(rawResourceName(r) + Title(method.Name) + "Result")
  3287  			}
  3288  		}
  3289  	}
  3290  
  3291  	scanResource(pkg.Provider)
  3292  	for _, r := range pkg.Resources {
  3293  		scanResource(r)
  3294  	}
  3295  
  3296  	// compute set of names generated by a type
  3297  	// handling any potential collisions via remapping along the way
  3298  	scanType := func(t schema.Type) {
  3299  		getNames := func(name, suffix string) []string {
  3300  			return []string{name + suffix, name + suffix + "Input", name + suffix + "Output"}
  3301  		}
  3302  
  3303  		switch t := t.(type) {
  3304  		case *schema.ObjectType:
  3305  			pkg := getPkgFromToken(t.Token)
  3306  			// maintain support for duplicate tokens for types and resources in Kubernetes
  3307  			if resSeen[strings.ToLower(t.Token)] {
  3308  				pkg.duplicateTokens[strings.ToLower(t.Token)] = true
  3309  			}
  3310  			if typeSeen[strings.ToLower(t.Token)] {
  3311  				return
  3312  			}
  3313  			typeSeen[strings.ToLower(t.Token)] = true
  3314  
  3315  			name := pkg.tokenToType(t.Token)
  3316  			suffixes := []string{"", "Type", "Typ"}
  3317  			suffix := ""
  3318  			suffixIndex := 0
  3319  			canGenerate := false
  3320  
  3321  			for !canGenerate && suffixIndex <= len(suffixes) {
  3322  				suffix = suffixes[suffixIndex]
  3323  				candidates := getNames(name, suffix)
  3324  				conflict := false
  3325  				for _, c := range candidates {
  3326  					if pkg.names.Has(c) {
  3327  						conflict = true
  3328  					}
  3329  				}
  3330  				if !conflict {
  3331  					canGenerate = true
  3332  					break
  3333  				}
  3334  
  3335  				suffixIndex++
  3336  			}
  3337  
  3338  			if !canGenerate {
  3339  				panic(fmt.Sprintf("unable to generate Go SDK, schema has unresolvable overlapping type: %s", name))
  3340  			}
  3341  
  3342  			names := getNames(name, suffix)
  3343  			originalNames := getNames(name, "")
  3344  			for i, n := range names {
  3345  				pkg.names.Add(n)
  3346  				if suffix != "" {
  3347  					pkg.renamed[originalNames[i]] = names[i]
  3348  				}
  3349  			}
  3350  		case *schema.EnumType:
  3351  			pkg := getPkgFromToken(t.Token)
  3352  			if resSeen[t.Token] {
  3353  				pkg.duplicateTokens[strings.ToLower(t.Token)] = true
  3354  			}
  3355  			if typeSeen[t.Token] {
  3356  				return
  3357  			}
  3358  			typeSeen[t.Token] = true
  3359  
  3360  			name := pkg.tokenToEnum(t.Token)
  3361  			suffixes := []string{"", "Enum"}
  3362  			suffix := ""
  3363  			suffixIndex := 0
  3364  			canGenerate := false
  3365  
  3366  			for !canGenerate && suffixIndex <= len(suffixes) {
  3367  				suffix = suffixes[suffixIndex]
  3368  				candidates := getNames(name, suffix)
  3369  				conflict := false
  3370  				for _, c := range candidates {
  3371  					if pkg.names.Has(c) {
  3372  						conflict = true
  3373  					}
  3374  				}
  3375  				if !conflict {
  3376  					canGenerate = true
  3377  					break
  3378  				}
  3379  
  3380  				suffixIndex++
  3381  			}
  3382  
  3383  			if !canGenerate {
  3384  				panic(fmt.Sprintf("unable to generate Go SDK, schema has unresolvable overlapping type: %s", name))
  3385  			}
  3386  
  3387  			names := getNames(name, suffix)
  3388  			originalNames := getNames(name, "")
  3389  			for i, n := range names {
  3390  				pkg.names.Add(n)
  3391  				if suffix != "" {
  3392  					pkg.renamed[originalNames[i]] = names[i]
  3393  				}
  3394  			}
  3395  		default:
  3396  			return
  3397  		}
  3398  	}
  3399  
  3400  	for _, t := range pkg.Types {
  3401  		scanType(t)
  3402  	}
  3403  
  3404  	// For fnApply function versions, we need to register any
  3405  	// input or output property type metadata, in case they have
  3406  	// types used in array or pointer element positions.
  3407  	if !goInfo.DisableFunctionOutputVersions || goInfo.GenerateExtraInputTypes {
  3408  		for _, f := range pkg.Functions {
  3409  			if f.NeedsOutputVersion() || goInfo.GenerateExtraInputTypes {
  3410  				optional := false
  3411  				if f.Inputs != nil {
  3412  					populateDetailsForPropertyTypes(seenMap, f.Inputs.InputShape.Properties, optional, false, false)
  3413  				}
  3414  				if f.Outputs != nil {
  3415  					populateDetailsForTypes(seenMap, f.Outputs, optional, false, true)
  3416  				}
  3417  			}
  3418  		}
  3419  	}
  3420  
  3421  	for _, f := range pkg.Functions {
  3422  		if f.IsMethod {
  3423  			continue
  3424  		}
  3425  
  3426  		pkg := getPkgFromToken(f.Token)
  3427  		pkg.functions = append(pkg.functions, f)
  3428  
  3429  		name := tokenToName(f.Token)
  3430  
  3431  		if pkg.names.Has(name) ||
  3432  			pkg.names.Has(name+"Args") ||
  3433  			pkg.names.Has(name+"Result") {
  3434  			switch {
  3435  			case strings.HasPrefix(name, "New"):
  3436  				name = "Create" + name[3:]
  3437  			case strings.HasPrefix(name, "Get"):
  3438  				name = "Lookup" + name[3:]
  3439  			}
  3440  		}
  3441  		pkg.names.Add(name)
  3442  		pkg.functionNames[f] = name
  3443  
  3444  		if f.Inputs != nil {
  3445  			pkg.names.Add(name + "Args")
  3446  		}
  3447  		if f.Outputs != nil {
  3448  			pkg.names.Add(name + "Result")
  3449  		}
  3450  	}
  3451  
  3452  	return packages
  3453  }
  3454  
  3455  // LanguageResource is derived from the schema and can be used by downstream codegen.
  3456  type LanguageResource struct {
  3457  	*schema.Resource
  3458  
  3459  	Alias   string // The package alias (e.g. appsv1)
  3460  	Name    string // The resource name (e.g. Deployment)
  3461  	Package string // The package name (e.g. github.com/pulumi/pulumi-kubernetes/sdk/v2/go/kubernetes/apps/v1)
  3462  }
  3463  
  3464  // LanguageResources returns a map of resources that can be used by downstream codegen. The map
  3465  // key is the resource schema token.
  3466  func LanguageResources(tool string, pkg *schema.Package) (map[string]LanguageResource, error) {
  3467  	resources := map[string]LanguageResource{}
  3468  
  3469  	if err := pkg.ImportLanguages(map[string]schema.Language{"go": Importer}); err != nil {
  3470  		return nil, err
  3471  	}
  3472  
  3473  	var goPkgInfo GoPackageInfo
  3474  	if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
  3475  		goPkgInfo = goInfo
  3476  	}
  3477  	packages := generatePackageContextMap(tool, pkg, goPkgInfo, globalCache)
  3478  
  3479  	// emit each package
  3480  	var pkgMods []string
  3481  	for mod := range packages {
  3482  		pkgMods = append(pkgMods, mod)
  3483  	}
  3484  	sort.Strings(pkgMods)
  3485  
  3486  	for _, mod := range pkgMods {
  3487  		if mod == "" {
  3488  			continue
  3489  		}
  3490  		pkg := packages[mod]
  3491  
  3492  		for _, r := range pkg.resources {
  3493  			if r.IsOverlay {
  3494  				// This resource code is generated by the provider, so no further action is required.
  3495  				continue
  3496  			}
  3497  
  3498  			packagePath := path.Join(goPkgInfo.ImportBasePath, pkg.mod)
  3499  			resources[r.Token] = LanguageResource{
  3500  				Resource: r,
  3501  				Alias:    goPkgInfo.PackageImportAliases[packagePath],
  3502  				Name:     tokenToName(r.Token),
  3503  				Package:  packagePath,
  3504  			}
  3505  		}
  3506  	}
  3507  
  3508  	return resources, nil
  3509  }
  3510  
  3511  // packageRoot is the relative root file for go code. That means that every go
  3512  // source file should be under this root. For example:
  3513  //
  3514  // root = aws => sdk/go/aws/*.go
  3515  func packageRoot(pkg *schema.Package) string {
  3516  	var info GoPackageInfo
  3517  	if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
  3518  		info = goInfo
  3519  	}
  3520  	if info.RootPackageName != "" {
  3521  		// package structure is flat
  3522  		return ""
  3523  	}
  3524  	if info.ImportBasePath != "" {
  3525  		return path.Base(info.ImportBasePath)
  3526  	}
  3527  	return goPackage(pkg.Name)
  3528  }
  3529  
  3530  // packageName is the go package name for the generated package.
  3531  func packageName(pkg *schema.Package) string {
  3532  	var info GoPackageInfo
  3533  	if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
  3534  		info = goInfo
  3535  	}
  3536  	if info.RootPackageName != "" {
  3537  		return info.RootPackageName
  3538  	}
  3539  	return goPackage(packageRoot(pkg))
  3540  }
  3541  
  3542  func GeneratePackage(tool string, pkg *schema.Package) (map[string][]byte, error) {
  3543  	if err := pkg.ImportLanguages(map[string]schema.Language{"go": Importer}); err != nil {
  3544  		return nil, err
  3545  	}
  3546  
  3547  	var goPkgInfo GoPackageInfo
  3548  	if goInfo, ok := pkg.Language["go"].(GoPackageInfo); ok {
  3549  		goPkgInfo = goInfo
  3550  	}
  3551  	packages := generatePackageContextMap(tool, pkg, goPkgInfo, NewCache())
  3552  
  3553  	// emit each package
  3554  	var pkgMods []string
  3555  	for mod := range packages {
  3556  		pkgMods = append(pkgMods, mod)
  3557  	}
  3558  	sort.Strings(pkgMods)
  3559  
  3560  	name := packageName(pkg)
  3561  	pathPrefix := packageRoot(pkg)
  3562  
  3563  	files := codegen.Fs{}
  3564  
  3565  	// Generate pulumi-plugin.json
  3566  	pulumiPlugin := &plugin.PulumiPluginJSON{
  3567  		Resource: true,
  3568  		Name:     pkg.Name,
  3569  		Server:   pkg.PluginDownloadURL,
  3570  	}
  3571  	if goPkgInfo.RespectSchemaVersion && pkg.Version != nil {
  3572  		pulumiPlugin.Version = pkg.Version.String()
  3573  	}
  3574  	pulumiPluginJSON, err := pulumiPlugin.JSON()
  3575  	if err != nil {
  3576  		return nil, fmt.Errorf("Failed to format pulumi-plugin.json: %w", err)
  3577  	}
  3578  	files.Add(path.Join(pathPrefix, "pulumi-plugin.json"), pulumiPluginJSON)
  3579  
  3580  	setFile := func(relPath, contents string) {
  3581  		relPath = path.Join(pathPrefix, relPath)
  3582  
  3583  		// Run Go formatter on the code before saving to disk
  3584  		formattedSource, err := format.Source([]byte(contents))
  3585  		if err != nil {
  3586  			fmt.Fprintf(os.Stderr, "Invalid content:\n%s\n%s\n", relPath, contents)
  3587  			panic(fmt.Errorf("invalid Go source code:\n\n%s\n: %w", relPath, err))
  3588  		}
  3589  
  3590  		files.Add(relPath, formattedSource)
  3591  	}
  3592  
  3593  	for _, mod := range pkgMods {
  3594  		pkg := packages[mod]
  3595  
  3596  		// Config, description
  3597  		switch mod {
  3598  		case "":
  3599  			buffer := &bytes.Buffer{}
  3600  			if pkg.pkg.Description != "" {
  3601  				printComment(buffer, pkg.pkg.Description, false)
  3602  			} else {
  3603  				fmt.Fprintf(buffer, "// Package %[1]s exports types, functions, subpackages for provisioning %[1]s resources.\n", name)
  3604  			}
  3605  			fmt.Fprintf(buffer, "\n")
  3606  			fmt.Fprintf(buffer, "package %s\n", name)
  3607  
  3608  			setFile(path.Join(mod, "doc.go"), buffer.String())
  3609  
  3610  		case "config":
  3611  			if len(pkg.pkg.Config) > 0 {
  3612  				buffer := &bytes.Buffer{}
  3613  				if err := pkg.genConfig(buffer, pkg.pkg.Config); err != nil {
  3614  					return nil, err
  3615  				}
  3616  
  3617  				setFile(path.Join(mod, "config.go"), buffer.String())
  3618  			}
  3619  		}
  3620  
  3621  		// Resources
  3622  		for _, r := range pkg.resources {
  3623  			if r.IsOverlay {
  3624  				// This resource code is generated by the provider, so no further action is required.
  3625  				continue
  3626  			}
  3627  
  3628  			importsAndAliases := map[string]string{}
  3629  			pkg.getImports(r, importsAndAliases)
  3630  			importsAndAliases["github.com/pulumi/pulumi/sdk/v3/go/pulumi"] = ""
  3631  
  3632  			buffer := &bytes.Buffer{}
  3633  			pkg.genHeader(buffer, []string{"context", "reflect"}, importsAndAliases)
  3634  
  3635  			if err := pkg.genResource(buffer, r, goPkgInfo.GenerateResourceContainerTypes); err != nil {
  3636  				return nil, err
  3637  			}
  3638  
  3639  			setFile(path.Join(mod, cgstrings.Camel(rawResourceName(r))+".go"), buffer.String())
  3640  		}
  3641  
  3642  		// Functions
  3643  		for _, f := range pkg.functions {
  3644  			if f.IsOverlay {
  3645  				// This function code is generated by the provider, so no further action is required.
  3646  				continue
  3647  			}
  3648  
  3649  			fileName := path.Join(mod, cgstrings.Camel(tokenToName(f.Token))+".go")
  3650  			code, err := pkg.genFunctionCodeFile(f)
  3651  			if err != nil {
  3652  				return nil, err
  3653  			}
  3654  			setFile(fileName, code)
  3655  		}
  3656  
  3657  		knownTypes := make(map[schema.Type]struct{}, len(pkg.typeDetails))
  3658  		for t := range pkg.typeDetails {
  3659  			knownTypes[t] = struct{}{}
  3660  		}
  3661  
  3662  		// Enums
  3663  		if len(pkg.enums) > 0 {
  3664  			hasOutputs, imports := false, map[string]string{}
  3665  			for _, e := range pkg.enums {
  3666  				pkg.getImports(e, imports)
  3667  				hasOutputs = hasOutputs || pkg.detailsForType(e).hasOutputs()
  3668  			}
  3669  			var goImports []string
  3670  			if hasOutputs {
  3671  				goImports = []string{"context", "reflect"}
  3672  				imports["github.com/pulumi/pulumi/sdk/v3/go/pulumi"] = ""
  3673  			}
  3674  
  3675  			buffer := &bytes.Buffer{}
  3676  			pkg.genHeader(buffer, goImports, imports)
  3677  
  3678  			for _, e := range pkg.enums {
  3679  				if err := pkg.genEnum(buffer, e); err != nil {
  3680  					return nil, err
  3681  				}
  3682  				delete(knownTypes, e)
  3683  			}
  3684  			pkg.genEnumRegistrations(buffer)
  3685  			setFile(path.Join(mod, "pulumiEnums.go"), buffer.String())
  3686  		}
  3687  
  3688  		// Types
  3689  		sortedKnownTypes := make([]schema.Type, 0, len(knownTypes))
  3690  		for k := range knownTypes {
  3691  			sortedKnownTypes = append(sortedKnownTypes, k)
  3692  		}
  3693  		sort.Slice(sortedKnownTypes, func(i, j int) bool {
  3694  			return sortedKnownTypes[i].String() < sortedKnownTypes[j].String()
  3695  		})
  3696  
  3697  		for types, i := pkg.types, 0; len(types) > 0; i++ {
  3698  			// 500 types corresponds to approximately 5M or 40_000 lines of code.
  3699  			const chunkSize = 500
  3700  			chunk := types
  3701  			if len(chunk) > chunkSize {
  3702  				chunk = chunk[:chunkSize]
  3703  			}
  3704  			types = types[len(chunk):]
  3705  
  3706  			buffer := &bytes.Buffer{}
  3707  			err := generateTypes(buffer, pkg, chunk, sortedKnownTypes)
  3708  			if err != nil {
  3709  				return nil, err
  3710  			}
  3711  
  3712  			typePath := "pulumiTypes"
  3713  			if i != 0 {
  3714  				typePath = fmt.Sprintf("%s%d", typePath, i)
  3715  			}
  3716  			setFile(path.Join(mod, typePath+".go"), buffer.String())
  3717  		}
  3718  
  3719  		// Utilities
  3720  		if pkg.needsUtils || len(mod) == 0 {
  3721  			buffer := &bytes.Buffer{}
  3722  			importsAndAliases := map[string]string{
  3723  				"github.com/blang/semver":                   "",
  3724  				"github.com/pulumi/pulumi/sdk/v3/go/pulumi": "",
  3725  			}
  3726  			pkg.genHeader(buffer, []string{"fmt", "os", "reflect", "regexp", "strconv", "strings"}, importsAndAliases)
  3727  
  3728  			packageRegex := fmt.Sprintf("^.*/pulumi-%s/sdk(/v\\d+)?", pkg.pkg.Name)
  3729  			if pkg.rootPackageName != "" {
  3730  				packageRegex = fmt.Sprintf("^%s(/v\\d+)?", pkg.importBasePath)
  3731  			}
  3732  
  3733  			pkg.GenUtilitiesFile(buffer, packageRegex)
  3734  
  3735  			setFile(path.Join(mod, "pulumiUtilities.go"), buffer.String())
  3736  		}
  3737  
  3738  		// If there are resources in this module, register the module with the runtime.
  3739  		if len(pkg.resources) != 0 && !allResourcesAreOverlays(pkg.resources) {
  3740  			buffer := &bytes.Buffer{}
  3741  			pkg.genResourceModule(buffer)
  3742  
  3743  			setFile(path.Join(mod, "init.go"), buffer.String())
  3744  		}
  3745  	}
  3746  
  3747  	return files, nil
  3748  }
  3749  
  3750  func generateTypes(w io.Writer, pkg *pkgContext, types []*schema.ObjectType, knownTypes []schema.Type) error {
  3751  	hasOutputs, importsAndAliases := false, map[string]string{}
  3752  	for _, t := range types {
  3753  		pkg.getImports(t, importsAndAliases)
  3754  		hasOutputs = hasOutputs || pkg.detailsForType(t).hasOutputs()
  3755  	}
  3756  
  3757  	collectionTypes := map[string]*nestedTypeInfo{}
  3758  	for _, t := range knownTypes {
  3759  		pkg.collectNestedCollectionTypes(collectionTypes, t)
  3760  	}
  3761  
  3762  	// All collection types have Outputs
  3763  	if len(collectionTypes) > 0 {
  3764  		hasOutputs = true
  3765  	}
  3766  
  3767  	var goImports []string
  3768  	if hasOutputs {
  3769  		goImports = []string{"context", "reflect"}
  3770  		importsAndAliases["github.com/pulumi/pulumi/sdk/v3/go/pulumi"] = ""
  3771  	}
  3772  
  3773  	pkg.genHeader(w, goImports, importsAndAliases)
  3774  
  3775  	for _, t := range types {
  3776  		if err := pkg.genType(w, t); err != nil {
  3777  			return err
  3778  		}
  3779  	}
  3780  
  3781  	typeNames := pkg.genNestedCollectionTypes(w, collectionTypes)
  3782  
  3783  	pkg.genTypeRegistrations(w, types, typeNames...)
  3784  	return nil
  3785  }
  3786  
  3787  func allResourcesAreOverlays(resources []*schema.Resource) bool {
  3788  	for _, r := range resources {
  3789  		if !r.IsOverlay {
  3790  			return false
  3791  		}
  3792  	}
  3793  	return true
  3794  }
  3795  
  3796  // goPackage returns the suggested package name for the given string.
  3797  func goPackage(name string) string {
  3798  	return strings.ReplaceAll(name, "-", "")
  3799  }
  3800  
  3801  func (pkg *pkgContext) GenUtilitiesFile(w io.Writer, packageRegex string) {
  3802  	const utilitiesFile = `
  3803  type envParser func(v string) interface{}
  3804  
  3805  func parseEnvBool(v string) interface{} {
  3806  	b, err := strconv.ParseBool(v)
  3807  	if err != nil {
  3808  		return nil
  3809  	}
  3810  	return b
  3811  }
  3812  
  3813  func parseEnvInt(v string) interface{} {
  3814  	i, err := strconv.ParseInt(v, 0, 0)
  3815  	if err != nil {
  3816  		return nil
  3817  	}
  3818  	return int(i)
  3819  }
  3820  
  3821  func parseEnvFloat(v string) interface{} {
  3822  	f, err := strconv.ParseFloat(v, 64)
  3823  	if err != nil {
  3824  		return nil
  3825  	}
  3826  	return f
  3827  }
  3828  
  3829  func parseEnvStringArray(v string) interface{} {
  3830  	var result pulumi.StringArray
  3831  	for _, item := range strings.Split(v, ";") {
  3832  		result = append(result, pulumi.String(item))
  3833  	}
  3834  	return result
  3835  }
  3836  
  3837  func getEnvOrDefault(def interface{}, parser envParser, vars ...string) interface{} {
  3838  	for _, v := range vars {
  3839  		if value := os.Getenv(v); value != "" {
  3840  			if parser != nil {
  3841  				return parser(value)
  3842  			}
  3843  			return value
  3844  		}
  3845  	}
  3846  	return def
  3847  }
  3848  
  3849  // PkgVersion uses reflection to determine the version of the current package.
  3850  // If a version cannot be determined, v1 will be assumed. The second return
  3851  // value is always nil.
  3852  func PkgVersion() (semver.Version, error) {
  3853  	type sentinal struct{}
  3854  	pkgPath := reflect.TypeOf(sentinal{}).PkgPath()
  3855  	re := regexp.MustCompile(%q)
  3856  	if match := re.FindStringSubmatch(pkgPath); match != nil {
  3857  		vStr := match[1]
  3858  		if len(vStr) == 0 { // If the version capture group was empty, default to v1.
  3859  			return semver.Version{Major: 1}, nil
  3860  		}
  3861  		return semver.MustParse(fmt.Sprintf("%%s.0.0", vStr[2:])), nil
  3862  	}
  3863  	return semver.Version{Major: 1}, nil
  3864  }
  3865  
  3866  // isZero is a null safe check for if a value is it's types zero value.
  3867  func isZero(v interface{}) bool {
  3868  	if v == nil {
  3869  		return true
  3870  	}
  3871  	return reflect.ValueOf(v).IsZero()
  3872  }
  3873  `
  3874  	_, err := fmt.Fprintf(w, utilitiesFile, packageRegex)
  3875  	contract.AssertNoError(err)
  3876  	pkg.GenPkgDefaultOpts(w)
  3877  }
  3878  
  3879  func (pkg *pkgContext) GenPkgDefaultOpts(w io.Writer) {
  3880  	url := pkg.pkg.PluginDownloadURL
  3881  	if url == "" {
  3882  		return
  3883  	}
  3884  	const template string = `
  3885  // pkg%[1]sDefaultOpts provides package level defaults to pulumi.Option%[1]s.
  3886  func pkg%[1]sDefaultOpts(opts []pulumi.%[1]sOption) []pulumi.%[1]sOption {
  3887  	defaults := []pulumi.%[1]sOption{%[2]s%[3]s}
  3888  
  3889  	return append(defaults, opts...)
  3890  }
  3891  `
  3892  	pluginDownloadURL := fmt.Sprintf("pulumi.PluginDownloadURL(%q)", url)
  3893  	version := ""
  3894  	if info := pkg.pkg.Language["go"]; info != nil {
  3895  		if info.(GoPackageInfo).RespectSchemaVersion && pkg.pkg.Version != nil {
  3896  			version = fmt.Sprintf(", pulumi.Version(%q)", pkg.pkg.Version.String())
  3897  		}
  3898  	}
  3899  	for _, typ := range []string{"Resource", "Invoke"} {
  3900  		_, err := fmt.Fprintf(w, template, typ, pluginDownloadURL, version)
  3901  		contract.AssertNoError(err)
  3902  	}
  3903  }
  3904  
  3905  // GenPkgDefaultsOptsCall generates a call to Pkg{TYPE}DefaultsOpts.
  3906  func (pkg *pkgContext) GenPkgDefaultsOptsCall(w io.Writer, invoke bool) {
  3907  	// The `pkg%sDefaultOpts` call won't do anything, so we don't insert it.
  3908  	if pkg.pkg.PluginDownloadURL == "" {
  3909  		return
  3910  	}
  3911  	pkg.needsUtils = true
  3912  	typ := "Resource"
  3913  	if invoke {
  3914  		typ = "Invoke"
  3915  	}
  3916  	_, err := fmt.Fprintf(w, "\topts = pkg%sDefaultOpts(opts)\n", typ)
  3917  	contract.AssertNoError(err)
  3918  }