2022-09-01 22:42:44 +00:00
|
|
|
// Copyright 2016-2022, Pulumi Corporation.
|
2020-01-21 22:45:48 +00:00
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
// Pulling out some of the repeated strings tokens into constants would harm readability, so we just ignore the
|
|
|
|
// goconst linter's warning.
|
|
|
|
//
|
2023-01-06 00:07:45 +00:00
|
|
|
//nolint:lll, goconst
|
2020-01-21 22:45:48 +00:00
|
|
|
package nodejs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
_ "embed"
|
2020-01-21 22:45:48 +00:00
|
|
|
"encoding/json"
|
2021-11-13 02:37:17 +00:00
|
|
|
"errors"
|
2020-01-21 22:45:48 +00:00
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"path"
|
|
|
|
"path/filepath"
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"unicode"
|
|
|
|
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/codegen"
|
2023-02-09 04:27:41 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/codegen/nodejs/tstypes"
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/pkg/v3/codegen/schema"
|
2021-10-04 21:26:49 +00:00
|
|
|
|
2021-09-08 05:23:30 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/diag"
|
2022-05-24 19:28:06 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
|
2023-06-28 16:02:04 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/slice"
|
2021-09-08 05:23:30 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
|
2020-01-21 22:45:48 +00:00
|
|
|
)
|
|
|
|
|
2022-11-09 22:04:48 +00:00
|
|
|
// The minimum version of @pulumi/pulumi compatible with the generated SDK.
|
2023-03-03 16:36:39 +00:00
|
|
|
const (
|
|
|
|
MinimumValidSDKVersion string = "^3.42.0"
|
|
|
|
MinimumTypescriptVersion string = "^4.3.5"
|
|
|
|
MinimumNodeTypesVersion string = "^14"
|
|
|
|
)
|
2022-11-09 22:04:48 +00:00
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
type typeDetails struct {
|
2021-04-19 23:40:39 +00:00
|
|
|
outputType bool
|
|
|
|
inputType bool
|
2021-10-07 19:39:19 +00:00
|
|
|
|
|
|
|
usedInFunctionOutputVersionInputs bool // helps decide naming under the tfbridge20 flag
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-09-20 17:11:44 +00:00
|
|
|
// title capitalizes the first rune in s.
|
|
|
|
//
|
|
|
|
// Examples:
|
|
|
|
// "hello" => "Hello"
|
|
|
|
// "hiAlice" => "HiAlice"
|
|
|
|
// "hi.Bob" => "Hi.Bob"
|
|
|
|
//
|
|
|
|
// Note: This is expected to work on strings which are not valid identifiers.
|
2020-01-21 22:45:48 +00:00
|
|
|
func title(s string) string {
|
|
|
|
if s == "" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
runes := []rune(s)
|
|
|
|
return string(append([]rune{unicode.ToUpper(runes[0])}, runes[1:]...))
|
|
|
|
}
|
|
|
|
|
2021-09-20 17:11:44 +00:00
|
|
|
// camel converts s to camel case.
|
|
|
|
//
|
|
|
|
// Examples:
|
|
|
|
// "helloWorld" => "helloWorld"
|
|
|
|
// "HelloWorld" => "helloWorld"
|
|
|
|
// "JSONObject" => "jsonobject"
|
|
|
|
// "My-FRIEND.Bob" => "my-FRIEND.Bob"
|
2020-01-21 22:45:48 +00:00
|
|
|
func camel(s string) string {
|
|
|
|
if s == "" {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
runes := []rune(s)
|
2023-06-28 16:02:04 +00:00
|
|
|
res := slice.Prealloc[rune](len(runes))
|
2020-01-21 22:45:48 +00:00
|
|
|
for i, r := range runes {
|
|
|
|
if unicode.IsLower(r) {
|
|
|
|
res = append(res, runes[i:]...)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
res = append(res, unicode.ToLower(r))
|
|
|
|
}
|
|
|
|
return string(res)
|
|
|
|
}
|
|
|
|
|
2021-09-20 17:11:44 +00:00
|
|
|
// pascal converts s to pascal case. Word breaks are signified by illegal
|
|
|
|
// identifier runes (excluding '.'). These are found by use of
|
|
|
|
// isLegalIdentifierPart.
|
|
|
|
//
|
|
|
|
// Examples:
|
|
|
|
// "My-Friend.Bob" => "MyFriend.Bob"
|
|
|
|
// "JSONObject" => "JSONObject"'
|
|
|
|
// "a-glad-dayTime" => "AGladDayTime"
|
|
|
|
//
|
|
|
|
// Note: because camel aggressively down-cases the first continuous sub-string
|
|
|
|
// of uppercase characters, we cannot define pascal as title(camel(x)).
|
|
|
|
func pascal(s string) string {
|
|
|
|
split := [][]rune{{}}
|
gosimple: Simplify loops
This replaces for loops and slice appends reported by gosimple
with simpler variants.
Specifically,
for _, x := range src {
dst = append(dst, x)
}
// can be replaced with
dst = append(dst, src...)
And,
for i, x := range src {
dst[i] = x
}
// can be replaced with
copy(dst, src)
And,
for true { ... }
// can be replaced with
for { ... }
And, given a string `s`,
for _, r := range []rune(s) { .. }
// can be replaced with
for _, r := range s { .. }
Lastly, this fixes in ineffective break statement
also reported by the linter.
Inside a switch block,
`break` affects the current `case` only.
The outer loop needs a label.
2023-01-11 15:58:17 +00:00
|
|
|
for _, r := range s {
|
2021-09-20 17:11:44 +00:00
|
|
|
if !isLegalIdentifierPart(r) && r != '.' {
|
|
|
|
split = append(split, []rune{})
|
|
|
|
} else {
|
|
|
|
split[len(split)-1] = append(split[len(split)-1], r)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
words := make([]string, len(split))
|
|
|
|
for i, v := range split {
|
|
|
|
words[i] = title(string(v))
|
|
|
|
}
|
|
|
|
return strings.Join(words, "")
|
|
|
|
}
|
|
|
|
|
|
|
|
// externalModuleName Formats the name of package to comply with an external
|
|
|
|
// module.
|
|
|
|
func externalModuleName(s string) string {
|
2023-12-12 12:19:42 +00:00
|
|
|
return "pulumi" + pascal(s)
|
2021-09-20 17:11:44 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
type modContext struct {
|
2022-12-08 13:36:44 +00:00
|
|
|
pkg schema.PackageReference
|
2020-06-07 16:21:09 +00:00
|
|
|
mod string
|
|
|
|
types []*schema.ObjectType
|
2020-10-08 01:13:10 +00:00
|
|
|
enums []*schema.EnumType
|
2020-06-07 16:21:09 +00:00
|
|
|
resources []*schema.Resource
|
|
|
|
functions []*schema.Function
|
|
|
|
typeDetails map[*schema.ObjectType]*typeDetails
|
|
|
|
children []*modContext
|
|
|
|
extraSourceFiles []string
|
|
|
|
tool string
|
2020-05-13 17:55:37 +00:00
|
|
|
|
|
|
|
// Name overrides set in NodeJSInfo
|
2020-06-03 01:15:21 +00:00
|
|
|
modToPkg map[string]string // Module name -> package name
|
|
|
|
compatibility string // Toggle compatibility mode for a specified target.
|
|
|
|
disableUnionOutputTypes bool // Disable unions in output types.
|
2021-10-01 18:33:02 +00:00
|
|
|
|
|
|
|
// Determine whether to lift single-value method return values
|
|
|
|
liftSingleValueMethodReturns bool
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2020-11-06 17:29:49 +00:00
|
|
|
func (mod *modContext) String() string {
|
|
|
|
return mod.mod
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
func (mod *modContext) details(t *schema.ObjectType) *typeDetails {
|
|
|
|
details, ok := mod.typeDetails[t]
|
|
|
|
if !ok {
|
|
|
|
details = &typeDetails{}
|
|
|
|
if mod.typeDetails == nil {
|
|
|
|
mod.typeDetails = map[*schema.ObjectType]*typeDetails{}
|
|
|
|
}
|
|
|
|
mod.typeDetails[t] = details
|
|
|
|
}
|
|
|
|
return details
|
|
|
|
}
|
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
func (mod *modContext) tokenToModName(tok string) string {
|
2020-01-21 22:45:48 +00:00
|
|
|
components := strings.Split(tok, ":")
|
|
|
|
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
modName := mod.pkg.TokenToModule(tok)
|
2020-05-13 17:55:37 +00:00
|
|
|
if override, ok := mod.modToPkg[modName]; ok {
|
|
|
|
modName = override
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
if modName != "" {
|
2023-02-23 20:51:11 +00:00
|
|
|
modName = strings.ReplaceAll(modName, "/", ".") + "."
|
2020-09-25 19:35:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return modName
|
|
|
|
}
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
func (mod *modContext) namingContext(pkg schema.PackageReference) (namingCtx *modContext, pkgName string, external bool) {
|
2021-01-30 00:52:00 +00:00
|
|
|
namingCtx = mod
|
2022-12-08 13:36:44 +00:00
|
|
|
if pkg != nil && !codegen.PkgEquals(pkg, mod.pkg) {
|
2021-01-30 00:52:00 +00:00
|
|
|
external = true
|
2022-12-08 13:36:44 +00:00
|
|
|
pkgName = pkg.Name() + "."
|
2020-09-25 19:35:27 +00:00
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
var info NodePackageInfo
|
2022-12-08 13:36:44 +00:00
|
|
|
def, err := pkg.Definition()
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "error loading definition for package %q", pkg.Name())
|
|
|
|
contract.AssertNoErrorf(
|
|
|
|
def.ImportLanguages(map[string]schema.Language{"nodejs": Importer}),
|
|
|
|
"failed to import nodejs language for package %v", pkg.Name())
|
2022-12-08 13:36:44 +00:00
|
|
|
if v, ok := def.Language["nodejs"].(NodePackageInfo); ok {
|
2021-01-30 00:52:00 +00:00
|
|
|
info = v
|
|
|
|
}
|
|
|
|
namingCtx = &modContext{
|
|
|
|
pkg: pkg,
|
|
|
|
modToPkg: info.ModuleToPackage,
|
|
|
|
compatibility: info.Compatibility,
|
|
|
|
}
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
2021-01-30 00:52:00 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
func (mod *modContext) objectType(pkg schema.PackageReference, details *typeDetails, tok string, input, args, enum bool) string {
|
2020-01-21 22:45:48 +00:00
|
|
|
root := "outputs."
|
|
|
|
if input {
|
|
|
|
root = "inputs."
|
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
namingCtx, pkgName, external := mod.namingContext(pkg)
|
|
|
|
if external {
|
2021-09-20 17:11:44 +00:00
|
|
|
pkgName = externalModuleName(pkgName)
|
2021-01-30 00:52:00 +00:00
|
|
|
root = "types.output."
|
|
|
|
if input {
|
|
|
|
root = "types.input."
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
modName, name := namingCtx.tokenToModName(tok), tokenToName(tok)
|
|
|
|
|
|
|
|
if enum {
|
2022-07-29 15:07:27 +00:00
|
|
|
prefix := "enums."
|
|
|
|
if external {
|
|
|
|
prefix = pkgName
|
|
|
|
}
|
|
|
|
return prefix + modName + title(name)
|
2021-01-30 00:52:00 +00:00
|
|
|
}
|
2021-04-16 02:03:28 +00:00
|
|
|
|
2021-10-07 19:39:19 +00:00
|
|
|
if args && input && details != nil && details.usedInFunctionOutputVersionInputs {
|
|
|
|
name += "Args"
|
2022-01-28 21:28:55 +00:00
|
|
|
} else if args && namingCtx.compatibility != tfbridge20 && namingCtx.compatibility != kubernetes20 {
|
2021-04-16 02:03:28 +00:00
|
|
|
name += "Args"
|
|
|
|
}
|
2021-10-07 19:39:19 +00:00
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
return pkgName + root + modName + title(name)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
func (mod *modContext) resourceType(r *schema.ResourceType) string {
|
|
|
|
if strings.HasPrefix(r.Token, "pulumi:providers:") {
|
|
|
|
pkgName := strings.TrimPrefix(r.Token, "pulumi:providers:")
|
2022-12-08 13:36:44 +00:00
|
|
|
if pkgName != mod.pkg.Name() {
|
2021-09-20 17:11:44 +00:00
|
|
|
pkgName = externalModuleName(pkgName)
|
2021-07-16 17:27:20 +00:00
|
|
|
}
|
|
|
|
|
2023-12-12 12:19:42 +00:00
|
|
|
return pkgName + ".Provider"
|
2021-01-30 00:52:00 +00:00
|
|
|
}
|
2020-09-25 19:35:27 +00:00
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
pkg := mod.pkg
|
|
|
|
if r.Resource != nil {
|
2022-12-08 13:36:44 +00:00
|
|
|
pkg = r.Resource.PackageReference
|
2021-01-30 00:52:00 +00:00
|
|
|
}
|
2021-07-16 17:27:20 +00:00
|
|
|
namingCtx, pkgName, external := mod.namingContext(pkg)
|
2022-11-24 15:07:12 +00:00
|
|
|
if !external {
|
|
|
|
name := tokenToName(r.Token)
|
|
|
|
return title(name)
|
2021-07-16 17:27:20 +00:00
|
|
|
}
|
2021-01-30 00:52:00 +00:00
|
|
|
|
2022-11-24 15:07:12 +00:00
|
|
|
pkgName = externalModuleName(pkgName)
|
2021-01-30 00:52:00 +00:00
|
|
|
modName, name := namingCtx.tokenToModName(r.Token), tokenToName(r.Token)
|
|
|
|
|
|
|
|
return pkgName + modName + title(name)
|
2020-09-25 19:35:27 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
func tokenToName(tok string) string {
|
|
|
|
components := strings.Split(tok, ":")
|
|
|
|
contract.Assertf(len(components) == 3, "malformed token %v", tok)
|
|
|
|
return title(components[2])
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceName(r *schema.Resource) string {
|
|
|
|
if r.IsProvider {
|
|
|
|
return "Provider"
|
|
|
|
}
|
|
|
|
return tokenToName(r.Token)
|
|
|
|
}
|
|
|
|
|
2020-12-02 21:45:25 +00:00
|
|
|
func (mod *modContext) resourceFileName(r *schema.Resource) string {
|
|
|
|
fileName := camel(resourceName(r)) + ".ts"
|
|
|
|
if mod.isReservedSourceFileName(fileName) {
|
|
|
|
fileName = camel(resourceName(r)) + "_.ts"
|
|
|
|
}
|
|
|
|
return fileName
|
|
|
|
}
|
|
|
|
|
2020-04-28 00:47:01 +00:00
|
|
|
func tokenToFunctionName(tok string) string {
|
|
|
|
return camel(tokenToName(tok))
|
|
|
|
}
|
|
|
|
|
2021-10-04 21:26:49 +00:00
|
|
|
func (mod *modContext) typeAst(t schema.Type, input bool, constValue interface{}) tstypes.TypeAst {
|
2020-01-21 22:45:48 +00:00
|
|
|
switch t := t.(type) {
|
2021-06-24 16:17:55 +00:00
|
|
|
case *schema.OptionalType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Union(
|
|
|
|
mod.typeAst(t.ElementType, input, constValue),
|
|
|
|
tstypes.Identifier("undefined"),
|
|
|
|
)
|
2021-06-24 16:17:55 +00:00
|
|
|
case *schema.InputType:
|
|
|
|
typ := mod.typeString(codegen.SimplifyInputUnion(t.ElementType), input, constValue)
|
|
|
|
if typ == "any" {
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier("any")
|
2021-06-24 16:17:55 +00:00
|
|
|
}
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier(fmt.Sprintf("pulumi.Input<%s>", typ))
|
2020-10-08 01:13:10 +00:00
|
|
|
case *schema.EnumType:
|
2022-12-08 13:36:44 +00:00
|
|
|
return tstypes.Identifier(mod.objectType(t.PackageReference, nil, t.Token, input, false, true))
|
2020-01-21 22:45:48 +00:00
|
|
|
case *schema.ArrayType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Array(mod.typeAst(t.ElementType, input, constValue))
|
2020-01-21 22:45:48 +00:00
|
|
|
case *schema.MapType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.StringMap(mod.typeAst(t.ElementType, input, constValue))
|
2020-01-21 22:45:48 +00:00
|
|
|
case *schema.ObjectType:
|
2021-10-07 19:39:19 +00:00
|
|
|
details := mod.details(t)
|
2022-12-08 13:36:44 +00:00
|
|
|
return tstypes.Identifier(mod.objectType(t.PackageReference, details, t.Token, input, t.IsInputShape(), false))
|
2020-09-25 19:35:27 +00:00
|
|
|
case *schema.ResourceType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier(mod.resourceType(t))
|
2020-01-21 22:45:48 +00:00
|
|
|
case *schema.TokenType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier(tokenToName(t.Token))
|
2020-01-21 22:45:48 +00:00
|
|
|
case *schema.UnionType:
|
2020-06-03 01:15:21 +00:00
|
|
|
if !input && mod.disableUnionOutputTypes {
|
|
|
|
if t.DefaultType != nil {
|
2021-10-04 21:26:49 +00:00
|
|
|
return mod.typeAst(t.DefaultType, input, constValue)
|
2020-05-13 17:55:37 +00:00
|
|
|
}
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier("any")
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2021-06-24 16:17:55 +00:00
|
|
|
|
2021-10-04 21:26:49 +00:00
|
|
|
elements := make([]tstypes.TypeAst, len(t.ElementTypes))
|
2021-06-24 16:17:55 +00:00
|
|
|
for i, e := range t.ElementTypes {
|
2021-10-04 21:26:49 +00:00
|
|
|
elements[i] = mod.typeAst(e, input, constValue)
|
2021-06-24 16:17:55 +00:00
|
|
|
}
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Union(elements...)
|
2020-01-21 22:45:48 +00:00
|
|
|
default:
|
|
|
|
switch t {
|
|
|
|
case schema.BoolType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier("boolean")
|
2020-01-21 22:45:48 +00:00
|
|
|
case schema.IntType, schema.NumberType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier("number")
|
2020-01-21 22:45:48 +00:00
|
|
|
case schema.StringType:
|
2021-06-24 16:17:55 +00:00
|
|
|
if constValue != nil {
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier(fmt.Sprintf("%q", constValue.(string)))
|
2021-06-24 16:17:55 +00:00
|
|
|
}
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier("string")
|
2020-01-21 22:45:48 +00:00
|
|
|
case schema.ArchiveType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier("pulumi.asset.Archive")
|
2020-01-21 22:45:48 +00:00
|
|
|
case schema.AssetType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Union(
|
|
|
|
tstypes.Identifier("pulumi.asset.Asset"),
|
|
|
|
tstypes.Identifier("pulumi.asset.Archive"),
|
|
|
|
)
|
2020-05-19 09:41:06 +00:00
|
|
|
case schema.JSONType:
|
|
|
|
fallthrough
|
2020-01-21 22:45:48 +00:00
|
|
|
case schema.AnyType:
|
2021-10-04 21:26:49 +00:00
|
|
|
return tstypes.Identifier("any")
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
2021-06-24 16:17:55 +00:00
|
|
|
panic(fmt.Errorf("unexpected type %T", t))
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-10-04 21:26:49 +00:00
|
|
|
func (mod *modContext) typeString(t schema.Type, input bool, constValue interface{}) string {
|
|
|
|
return tstypes.TypeLiteral(tstypes.Normalize(mod.typeAst(t, input, constValue)))
|
|
|
|
}
|
|
|
|
|
2020-02-07 17:43:20 +00:00
|
|
|
func isStringType(t schema.Type) bool {
|
2021-06-24 16:17:55 +00:00
|
|
|
t = codegen.UnwrapType(t)
|
|
|
|
|
2021-09-24 22:02:56 +00:00
|
|
|
switch typ := t.(type) {
|
|
|
|
case *schema.TokenType:
|
|
|
|
t = typ.UnderlyingType
|
|
|
|
case *schema.EnumType:
|
|
|
|
t = typ.ElementType
|
|
|
|
case *schema.UnionType:
|
|
|
|
// The following case detects for relaxed string enums. If it's a Union, check if one ElementType is an EnumType.
|
|
|
|
// If yes, t is the ElementType of the EnumType.
|
|
|
|
for _, tt := range typ.ElementTypes {
|
|
|
|
t = codegen.UnwrapType(tt)
|
|
|
|
if typ, ok := t.(*schema.EnumType); ok {
|
|
|
|
t = typ.ElementType
|
|
|
|
}
|
|
|
|
}
|
2020-02-07 17:43:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return t == schema.StringType
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
func sanitizeComment(str string) string {
|
2023-02-23 20:51:11 +00:00
|
|
|
return strings.ReplaceAll(str, "*/", "*/")
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2020-02-06 17:29:06 +00:00
|
|
|
func printComment(w io.Writer, comment, deprecationMessage, indent string) {
|
|
|
|
if comment == "" && deprecationMessage == "" {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
lines := strings.Split(sanitizeComment(comment), "\n")
|
|
|
|
for len(lines) > 0 && lines[len(lines)-1] == "" {
|
|
|
|
lines = lines[:len(lines)-1]
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "%s/**\n", indent)
|
|
|
|
for _, l := range lines {
|
2020-02-11 22:34:22 +00:00
|
|
|
if l == "" {
|
|
|
|
fmt.Fprintf(w, "%s *\n", indent)
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, "%s * %s\n", indent, l)
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2020-02-06 17:29:06 +00:00
|
|
|
if deprecationMessage != "" {
|
|
|
|
if len(lines) > 0 {
|
2020-02-11 22:34:22 +00:00
|
|
|
fmt.Fprintf(w, "%s *\n", indent)
|
2020-02-06 17:29:06 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "%s * @deprecated %s\n", indent, deprecationMessage)
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "%s */\n", indent)
|
|
|
|
}
|
|
|
|
|
2021-11-18 20:23:30 +00:00
|
|
|
// Generates a plain interface type.
|
|
|
|
//
|
|
|
|
// We use this to represent both argument and plain object types.
|
|
|
|
func (mod *modContext) genPlainType(w io.Writer, name, comment string,
|
2023-03-03 16:36:39 +00:00
|
|
|
properties []*schema.Property, input, readonly bool, level int,
|
|
|
|
) error {
|
2020-01-21 22:45:48 +00:00
|
|
|
indent := strings.Repeat(" ", level)
|
|
|
|
|
2020-02-06 17:29:06 +00:00
|
|
|
printComment(w, comment, "", indent)
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "%sexport interface %s {\n", indent, name)
|
|
|
|
for _, p := range properties {
|
2020-02-06 17:29:06 +00:00
|
|
|
printComment(w, p.Comment, p.DeprecationMessage, indent+" ")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
prefix := ""
|
|
|
|
if readonly {
|
|
|
|
prefix = "readonly "
|
|
|
|
}
|
|
|
|
|
2021-06-24 16:17:55 +00:00
|
|
|
sigil, propertyType := "", p.Type
|
|
|
|
if !p.IsRequired() {
|
|
|
|
sigil, propertyType = "?", codegen.RequiredType(p)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-06-24 16:17:55 +00:00
|
|
|
typ := mod.typeString(propertyType, input, p.ConstValue)
|
2021-03-10 15:08:08 +00:00
|
|
|
fmt.Fprintf(w, "%s %s%s%s: %s;\n", indent, prefix, p.Name, sigil, typ)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "%s}\n", indent)
|
2021-11-18 20:23:30 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate a provide defaults function for an associated plain object.
|
2021-11-23 23:10:15 +00:00
|
|
|
func (mod *modContext) genPlainObjectDefaultFunc(w io.Writer, name string,
|
2023-03-03 16:36:39 +00:00
|
|
|
properties []*schema.Property, input, readonly bool, level int,
|
|
|
|
) error {
|
2021-11-18 20:23:30 +00:00
|
|
|
indent := strings.Repeat(" ", level)
|
|
|
|
defaults := []string{}
|
|
|
|
for _, p := range properties {
|
|
|
|
if p.DefaultValue != nil {
|
|
|
|
dv, err := mod.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defaults = append(defaults, fmt.Sprintf("%s: (val.%s) ?? %s", p.Name, p.Name, dv))
|
|
|
|
} else if funcName := mod.provideDefaultsFuncName(p.Type, input); funcName != "" {
|
|
|
|
// ProvideDefaults functions have the form `(Input<shape> | undefined) ->
|
|
|
|
// Output<shape> | undefined`. We need to disallow the undefined. This is safe
|
|
|
|
// because val.%arg existed in the input (type system enforced).
|
|
|
|
var compositeObject string
|
|
|
|
if codegen.IsNOptionalInput(p.Type) {
|
|
|
|
compositeObject = fmt.Sprintf("pulumi.output(val.%s).apply(%s)", p.Name, funcName)
|
|
|
|
} else {
|
|
|
|
compositeObject = fmt.Sprintf("%s(val.%s)", funcName, p.Name)
|
|
|
|
}
|
|
|
|
if !p.IsRequired() {
|
|
|
|
compositeObject = fmt.Sprintf("(val.%s ? %s : undefined)", p.Name, compositeObject)
|
|
|
|
}
|
|
|
|
defaults = append(defaults, fmt.Sprintf("%s: %s", p.Name, compositeObject))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// There are no defaults, so don't generate a default function.
|
|
|
|
if len(defaults) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
// Generates a function header that looks like this:
|
|
|
|
// export function %sProvideDefaults(val: pulumi.Input<%s> | undefined): pulumi.Output<%s> | undefined {
|
|
|
|
// const def = (val: LayeredTypeArgs) => ({
|
|
|
|
// ...val,
|
|
|
|
defaultProvderName := provideDefaultsFuncNameFromName(name)
|
|
|
|
printComment(w, fmt.Sprintf("%s sets the appropriate defaults for %s",
|
|
|
|
defaultProvderName, name), "", indent)
|
|
|
|
fmt.Fprintf(w, "%sexport function %s(val: %s): "+
|
|
|
|
"%s {\n", indent, defaultProvderName, name, name)
|
|
|
|
fmt.Fprintf(w, "%s return {\n", indent)
|
|
|
|
fmt.Fprintf(w, "%s ...val,\n", indent)
|
|
|
|
|
|
|
|
// Fields look as follows
|
|
|
|
// %s: (val.%s) ?? devValue,
|
|
|
|
for _, val := range defaults {
|
|
|
|
fmt.Fprintf(w, "%s %s,\n", indent, val)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "%s };\n", indent)
|
|
|
|
fmt.Fprintf(w, "%s}\n", indent)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// The name of the helper function used to provide default values to plain
|
|
|
|
// types, derived purely from the name of the enclosing type. Prefer to use
|
|
|
|
// provideDefaultsFuncName when full type information is available.
|
|
|
|
func provideDefaultsFuncNameFromName(typeName string) string {
|
|
|
|
var i int
|
|
|
|
if in := strings.LastIndex(typeName, "."); in != -1 {
|
|
|
|
i = in
|
|
|
|
}
|
|
|
|
// path + camel(name) + ProvideDefaults suffix
|
|
|
|
return typeName[:i] + camel(typeName[i:]) + "ProvideDefaults"
|
|
|
|
}
|
|
|
|
|
|
|
|
// The name of the function used to set defaults on the plain type.
|
|
|
|
//
|
|
|
|
// `type` is the type which the function applies to.
|
|
|
|
// `input` indicates whither `type` is an input type.
|
|
|
|
func (mod *modContext) provideDefaultsFuncName(typ schema.Type, input bool) string {
|
2021-11-23 23:10:15 +00:00
|
|
|
if !codegen.IsProvideDefaultsFuncRequired(typ) {
|
2021-11-18 20:23:30 +00:00
|
|
|
return ""
|
|
|
|
}
|
|
|
|
requiredType := codegen.UnwrapType(typ)
|
|
|
|
typeName := mod.typeString(requiredType, input, nil)
|
|
|
|
return provideDefaultsFuncNameFromName(typeName)
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
func tsPrimitiveValue(value interface{}) (string, error) {
|
|
|
|
v := reflect.ValueOf(value)
|
|
|
|
if v.Kind() == reflect.Interface {
|
|
|
|
v = v.Elem()
|
|
|
|
}
|
|
|
|
|
turn on the golangci-lint exhaustive linter (#15028)
Turn on the golangci-lint exhaustive linter. This is the first step
towards catching more missing cases during development rather than
in tests, or in production.
This might be best reviewed commit-by-commit, as the first commit turns
on the linter with the `default-signifies-exhaustive: true` option set,
which requires a lot less changes in the current codebase.
I think it's probably worth doing the second commit as well, as that
will get us the real benefits, even though we end up with a little bit
more churn. However it means all the `switch` statements are covered,
which isn't the case after the first commit, since we do have a lot of
`default` statements that just call `assert.Fail`.
Fixes #14601
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [x] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-01-17 16:50:41 +00:00
|
|
|
//nolint:exhaustive // Only a subset of types has default values.
|
2020-01-21 22:45:48 +00:00
|
|
|
switch v.Kind() {
|
|
|
|
case reflect.Bool:
|
|
|
|
if v.Bool() {
|
|
|
|
return "true", nil
|
|
|
|
}
|
|
|
|
return "false", nil
|
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32:
|
|
|
|
return strconv.FormatInt(v.Int(), 10), nil
|
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
|
|
|
return strconv.FormatUint(v.Uint(), 10), nil
|
|
|
|
case reflect.Float32, reflect.Float64:
|
|
|
|
return strconv.FormatFloat(v.Float(), 'f', -1, 64), nil
|
|
|
|
case reflect.String:
|
|
|
|
return fmt.Sprintf("%q", v.String()), nil
|
|
|
|
default:
|
2021-11-13 02:37:17 +00:00
|
|
|
return "", fmt.Errorf("unsupported default value of type %T", value)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-13 17:55:37 +00:00
|
|
|
func (mod *modContext) getConstValue(cv interface{}) (string, error) {
|
|
|
|
if cv == nil {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
return tsPrimitiveValue(cv)
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
func (mod *modContext) getDefaultValue(dv *schema.DefaultValue, t schema.Type) (string, error) {
|
|
|
|
var val string
|
|
|
|
if dv.Value != nil {
|
|
|
|
v, err := tsPrimitiveValue(dv.Value)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
val = v
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(dv.Environment) != 0 {
|
|
|
|
getType := ""
|
|
|
|
switch t {
|
|
|
|
case schema.BoolType:
|
|
|
|
getType = "Boolean"
|
|
|
|
case schema.IntType, schema.NumberType:
|
|
|
|
getType = "Number"
|
|
|
|
}
|
|
|
|
|
|
|
|
envVars := fmt.Sprintf("%q", dv.Environment[0])
|
|
|
|
for _, e := range dv.Environment[1:] {
|
|
|
|
envVars += fmt.Sprintf(", %q", e)
|
|
|
|
}
|
|
|
|
|
|
|
|
cast := ""
|
2021-11-18 20:23:30 +00:00
|
|
|
if t != schema.StringType && getType == "" {
|
2020-01-21 22:45:48 +00:00
|
|
|
cast = "<any>"
|
|
|
|
}
|
|
|
|
|
|
|
|
getEnv := fmt.Sprintf("%sutilities.getEnv%s(%s)", cast, getType, envVars)
|
|
|
|
if val != "" {
|
|
|
|
val = fmt.Sprintf("(%s || %s)", getEnv, val)
|
|
|
|
} else {
|
|
|
|
val = getEnv
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return val, nil
|
|
|
|
}
|
|
|
|
|
2022-09-01 22:42:44 +00:00
|
|
|
func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFileInfo, error) {
|
|
|
|
info := resourceFileInfo{}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
// Create a resource module file into which all of this resource's types will go.
|
|
|
|
name := resourceName(r)
|
2022-09-01 22:42:44 +00:00
|
|
|
info.resourceClassName = name
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// Write the TypeDoc/JSDoc for the resource class
|
2020-06-18 19:32:15 +00:00
|
|
|
printComment(w, codegen.FilterExamples(r.Comment, "typescript"), r.DeprecationMessage, "")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
var baseType, optionsType string
|
|
|
|
switch {
|
|
|
|
case r.IsComponent:
|
|
|
|
baseType, optionsType = "ComponentResource", "ComponentResourceOptions"
|
|
|
|
case r.IsProvider:
|
|
|
|
baseType, optionsType = "ProviderResource", "ResourceOptions"
|
|
|
|
default:
|
|
|
|
baseType, optionsType = "CustomResource", "CustomResourceOptions"
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Begin defining the class.
|
2022-09-01 22:42:44 +00:00
|
|
|
fmt.Fprintf(w, "export class %s extends pulumi.%s {\n", info.resourceClassName, baseType)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
// Emit a static factory to read instances of this resource unless this is a provider resource or ComponentResource.
|
2020-01-21 22:45:48 +00:00
|
|
|
stateType := name + "State"
|
2020-09-25 19:35:27 +00:00
|
|
|
if !r.IsProvider && !r.IsComponent {
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, " /**\n")
|
|
|
|
fmt.Fprintf(w, " * Get an existing %s resource's state with the given name, ID, and optional extra\n", name)
|
|
|
|
fmt.Fprintf(w, " * properties used to qualify the lookup.\n")
|
|
|
|
fmt.Fprintf(w, " *\n")
|
|
|
|
fmt.Fprintf(w, " * @param name The _unique_ name of the resulting resource.\n")
|
|
|
|
fmt.Fprintf(w, " * @param id The _unique_ provider ID of the resource to lookup.\n")
|
2020-06-05 17:11:18 +00:00
|
|
|
// TODO: Document id format: https://github.com/pulumi/pulumi/issues/4754
|
|
|
|
if r.StateInputs != nil {
|
|
|
|
fmt.Fprintf(w, " * @param state Any extra arguments used during the lookup.\n")
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, " * @param opts Optional settings to control the behavior of the CustomResource.\n")
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, " */\n")
|
|
|
|
|
2020-09-02 15:09:41 +00:00
|
|
|
stateParam, stateRef := "", "undefined as any, "
|
2020-01-21 22:45:48 +00:00
|
|
|
if r.StateInputs != nil {
|
|
|
|
stateParam, stateRef = fmt.Sprintf("state?: %s, ", stateType), "<any>state, "
|
|
|
|
}
|
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
fmt.Fprintf(w, " public static get(name: string, id: pulumi.Input<pulumi.ID>, %sopts?: pulumi.%s): %s {\n",
|
|
|
|
stateParam, optionsType, name)
|
2020-07-01 19:50:26 +00:00
|
|
|
if r.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
|
2022-04-08 15:40:11 +00:00
|
|
|
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, escape(r.DeprecationMessage))
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, " return new %s(name, %s{ ...opts, id: id });\n", name, stateRef)
|
|
|
|
fmt.Fprintf(w, " }\n")
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
pulumiType := r.Token
|
|
|
|
if r.IsProvider {
|
2022-12-08 13:36:44 +00:00
|
|
|
pulumiType = mod.pkg.Name()
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, " /** @internal */\n")
|
|
|
|
fmt.Fprintf(w, " public static readonly __pulumiType = '%s';\n", pulumiType)
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
fmt.Fprintf(w, " /**\n")
|
|
|
|
fmt.Fprintf(w, " * Returns true if the given object is an instance of %s. This is designed to work even\n", name)
|
|
|
|
fmt.Fprintf(w, " * when multiple copies of the Pulumi SDK have been loaded into the same process.\n")
|
|
|
|
fmt.Fprintf(w, " */\n")
|
|
|
|
fmt.Fprintf(w, " public static isInstance(obj: any): obj is %s {\n", name)
|
|
|
|
fmt.Fprintf(w, " if (obj === undefined || obj === null) {\n")
|
|
|
|
fmt.Fprintf(w, " return false;\n")
|
|
|
|
fmt.Fprintf(w, " }\n")
|
2023-06-23 21:32:03 +00:00
|
|
|
|
2023-12-12 12:19:42 +00:00
|
|
|
typeExpression := name + ".__pulumiType"
|
2023-06-23 21:32:03 +00:00
|
|
|
if r.IsProvider {
|
|
|
|
// We pass __pulumiType to the ProviderResource constructor as the "type" for this provider, the
|
|
|
|
// ProviderResource constructor in the SDK then prefixes "pulumi:providers:" to that token and passes that
|
|
|
|
// down to the CustomResource constructor, which then assigns that type token to the newly constructed
|
|
|
|
// objects __pulumiType field. As such we also need to prefix "pulumi:providers:" when doing the equality
|
|
|
|
// check here.
|
|
|
|
typeExpression = "\"pulumi:providers:\" + " + typeExpression
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, " return obj['__pulumiType'] === %s;\n", typeExpression)
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, " }\n")
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
|
|
|
|
// Emit all properties (using their output types).
|
|
|
|
// TODO[pulumi/pulumi#397]: represent sensitive types using a Secret<T> type.
|
2020-05-28 23:22:50 +00:00
|
|
|
ins := codegen.NewStringSet()
|
2020-01-21 22:45:48 +00:00
|
|
|
allOptionalInputs := true
|
|
|
|
for _, prop := range r.InputProperties {
|
2020-05-28 23:22:50 +00:00
|
|
|
ins.Add(prop.Name)
|
2021-06-24 16:17:55 +00:00
|
|
|
allOptionalInputs = allOptionalInputs && !prop.IsRequired()
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
for _, prop := range r.Properties {
|
2020-02-06 17:29:06 +00:00
|
|
|
printComment(w, prop.Comment, prop.DeprecationMessage, " ")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// Make a little comment in the code so it's easy to pick out output properties.
|
|
|
|
var outcomment string
|
2020-05-28 23:22:50 +00:00
|
|
|
if !ins.Has(prop.Name) {
|
2020-01-21 22:45:48 +00:00
|
|
|
outcomment = "/*out*/ "
|
|
|
|
}
|
|
|
|
|
2021-06-24 16:17:55 +00:00
|
|
|
propertyType := prop.Type
|
2020-05-29 19:39:29 +00:00
|
|
|
if mod.compatibility == kubernetes20 {
|
2021-06-24 16:17:55 +00:00
|
|
|
propertyType = codegen.RequiredType(prop)
|
2020-05-29 19:39:29 +00:00
|
|
|
}
|
2021-06-24 16:17:55 +00:00
|
|
|
fmt.Fprintf(w, " public %sreadonly %s!: pulumi.Output<%s>;\n", outcomment, prop.Name, mod.typeString(propertyType, false, prop.ConstValue))
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
|
|
|
|
// Now create a constructor that chains supercalls and stores into properties.
|
|
|
|
fmt.Fprintf(w, " /**\n")
|
|
|
|
fmt.Fprintf(w, " * Create a %s resource with the given unique name, arguments, and options.\n", name)
|
|
|
|
fmt.Fprintf(w, " *\n")
|
|
|
|
fmt.Fprintf(w, " * @param name The _unique_ name of the resource.\n")
|
|
|
|
fmt.Fprintf(w, " * @param args The arguments to use to populate this resource's properties.\n")
|
|
|
|
fmt.Fprintf(w, " * @param opts A bag of options that control this resource's behavior.\n")
|
|
|
|
fmt.Fprintf(w, " */\n")
|
|
|
|
|
2020-05-29 22:35:42 +00:00
|
|
|
// k8s provider "get" methods don't require args, so make args optional.
|
|
|
|
if mod.compatibility == kubernetes20 {
|
|
|
|
allOptionalInputs = true
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
// Write out callable constructor: We only emit a single public constructor, even though we use a private signature
|
|
|
|
// as well as part of the implementation of `.get`. This is complicated slightly by the fact that, if there is no
|
|
|
|
// args type, we will emit a constructor lacking that parameter.
|
|
|
|
var argsFlags string
|
2020-05-29 22:35:42 +00:00
|
|
|
if allOptionalInputs {
|
2020-01-21 22:45:48 +00:00
|
|
|
// If the number of required input properties was zero, we can make the args object optional.
|
|
|
|
argsFlags = "?"
|
|
|
|
}
|
|
|
|
argsType := name + "Args"
|
2020-09-25 19:35:27 +00:00
|
|
|
var trailingBrace string
|
|
|
|
switch {
|
|
|
|
case r.IsProvider, r.StateInputs == nil:
|
2020-09-02 15:09:41 +00:00
|
|
|
trailingBrace = " {"
|
2020-09-25 19:35:27 +00:00
|
|
|
default:
|
|
|
|
trailingBrace = ""
|
2020-09-02 15:09:41 +00:00
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
if r.DeprecationMessage != "" {
|
|
|
|
fmt.Fprintf(w, " /** @deprecated %s */\n", r.DeprecationMessage)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, " constructor(name: string, args%s: %s, opts?: pulumi.%s)%s\n", argsFlags, argsType,
|
|
|
|
optionsType, trailingBrace)
|
|
|
|
|
2020-09-01 22:37:03 +00:00
|
|
|
genInputProps := func() error {
|
|
|
|
for _, prop := range r.InputProperties {
|
2021-06-24 16:17:55 +00:00
|
|
|
if prop.IsRequired() {
|
2021-02-12 18:10:59 +00:00
|
|
|
fmt.Fprintf(w, " if ((!args || args.%s === undefined) && !opts.urn) {\n", prop.Name)
|
2020-09-01 22:37:03 +00:00
|
|
|
fmt.Fprintf(w, " throw new Error(\"Missing required property '%s'\");\n", prop.Name)
|
|
|
|
fmt.Fprintf(w, " }\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, prop := range r.InputProperties {
|
2021-05-26 22:00:51 +00:00
|
|
|
var arg string
|
2021-11-18 20:23:30 +00:00
|
|
|
applyDefaults := func(arg string) string {
|
|
|
|
if name := mod.provideDefaultsFuncName(prop.Type, true /*input*/); name != "" {
|
|
|
|
var body string
|
|
|
|
if codegen.IsNOptionalInput(prop.Type) {
|
|
|
|
body = fmt.Sprintf("pulumi.output(%[2]s).apply(%[1]s)", name, arg)
|
|
|
|
} else {
|
|
|
|
body = fmt.Sprintf("%s(%s)", name, arg)
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("(%s ? %s : undefined)", arg, body)
|
|
|
|
}
|
|
|
|
return arg
|
|
|
|
}
|
|
|
|
|
2023-12-12 12:19:42 +00:00
|
|
|
argValue := applyDefaults("args." + prop.Name)
|
2021-05-26 22:00:51 +00:00
|
|
|
if prop.Secret {
|
2021-11-18 20:23:30 +00:00
|
|
|
arg = fmt.Sprintf("args?.%[1]s ? pulumi.secret(%[2]s) : undefined", prop.Name, argValue)
|
2021-05-26 22:00:51 +00:00
|
|
|
} else {
|
2021-11-18 20:23:30 +00:00
|
|
|
arg = fmt.Sprintf("args ? %[1]s : undefined", argValue)
|
2021-05-26 22:00:51 +00:00
|
|
|
}
|
2020-09-01 22:37:03 +00:00
|
|
|
|
|
|
|
prefix := " "
|
|
|
|
if prop.ConstValue != nil {
|
|
|
|
cv, err := mod.getConstValue(prop.ConstValue)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
arg = cv
|
|
|
|
} else {
|
|
|
|
if prop.DefaultValue != nil {
|
2021-06-24 16:17:55 +00:00
|
|
|
dv, err := mod.getDefaultValue(prop.DefaultValue, codegen.UnwrapType(prop.Type))
|
2020-09-01 22:37:03 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-03-10 21:16:18 +00:00
|
|
|
|
|
|
|
arg = fmt.Sprintf("(%s) ?? %s", arg, dv)
|
2020-09-01 22:37:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// provider properties must be marshaled as JSON strings.
|
|
|
|
if r.IsProvider && !isStringType(prop.Type) {
|
|
|
|
arg = fmt.Sprintf("pulumi.output(%s).apply(JSON.stringify)", arg)
|
|
|
|
}
|
|
|
|
}
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, "%sresourceInputs[\"%s\"] = %s;\n", prefix, prop.Name, arg)
|
2020-09-01 22:37:03 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 23:56:38 +00:00
|
|
|
for _, prop := range r.Properties {
|
|
|
|
prefix := " "
|
|
|
|
if !ins.Has(prop.Name) {
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, "%sresourceInputs[\"%s\"] = undefined /*out*/;\n", prefix, prop.Name)
|
2020-09-01 23:56:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-01 22:37:03 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
if !r.IsProvider {
|
2020-05-13 17:55:37 +00:00
|
|
|
if r.StateInputs != nil {
|
|
|
|
if r.DeprecationMessage != "" {
|
|
|
|
fmt.Fprintf(w, " /** @deprecated %s */\n", r.DeprecationMessage)
|
|
|
|
}
|
2020-09-25 19:35:27 +00:00
|
|
|
|
2020-05-13 17:55:37 +00:00
|
|
|
// Now write out a general purpose constructor implementation that can handle the public signature as well as the
|
|
|
|
// signature to support construction via `.get`. And then emit the body preamble which will pluck out the
|
|
|
|
// conditional state into sensible variables using dynamic type tests.
|
2020-09-25 19:35:27 +00:00
|
|
|
fmt.Fprintf(w, " constructor(name: string, argsOrState?: %s | %s, opts?: pulumi.%s) {\n",
|
|
|
|
argsType, stateType, optionsType)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2020-07-01 19:50:26 +00:00
|
|
|
if r.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
|
2022-04-08 15:40:11 +00:00
|
|
|
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, escape(r.DeprecationMessage))
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, " let resourceInputs: pulumi.Inputs = {};\n")
|
2021-02-12 18:10:59 +00:00
|
|
|
fmt.Fprintf(w, " opts = opts || {};\n")
|
2020-07-10 18:23:31 +00:00
|
|
|
|
2020-05-13 17:55:37 +00:00
|
|
|
if r.StateInputs != nil {
|
|
|
|
// The lookup case:
|
2021-02-12 18:10:59 +00:00
|
|
|
fmt.Fprintf(w, " if (opts.id) {\n")
|
2020-05-13 17:55:37 +00:00
|
|
|
fmt.Fprintf(w, " const state = argsOrState as %[1]s | undefined;\n", stateType)
|
2020-07-10 18:23:31 +00:00
|
|
|
for _, prop := range r.StateInputs.Properties {
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, " resourceInputs[\"%[1]s\"] = state ? state.%[1]s : undefined;\n", prop.Name)
|
2020-05-13 17:55:37 +00:00
|
|
|
}
|
|
|
|
// The creation case (with args):
|
|
|
|
fmt.Fprintf(w, " } else {\n")
|
2020-09-01 22:37:03 +00:00
|
|
|
fmt.Fprintf(w, " const args = argsOrState as %s | undefined;\n", argsType)
|
|
|
|
err := genInputProps()
|
|
|
|
if err != nil {
|
2022-09-01 22:42:44 +00:00
|
|
|
return resourceFileInfo{}, err
|
2020-09-01 22:37:03 +00:00
|
|
|
}
|
2020-07-10 18:23:31 +00:00
|
|
|
} else {
|
|
|
|
// The creation case:
|
2021-02-12 18:10:59 +00:00
|
|
|
fmt.Fprintf(w, " if (!opts.id) {\n")
|
2020-09-01 22:37:03 +00:00
|
|
|
err := genInputProps()
|
2020-01-21 22:45:48 +00:00
|
|
|
if err != nil {
|
2022-09-01 22:42:44 +00:00
|
|
|
return resourceFileInfo{}, err
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2020-09-01 22:37:03 +00:00
|
|
|
// The get case:
|
|
|
|
fmt.Fprintf(w, " } else {\n")
|
|
|
|
for _, prop := range r.Properties {
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, " resourceInputs[\"%[1]s\"] = undefined /*out*/;\n", prop.Name)
|
2020-05-13 17:55:37 +00:00
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2020-09-01 22:37:03 +00:00
|
|
|
} else {
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, " let resourceInputs: pulumi.Inputs = {};\n")
|
2021-02-12 18:10:59 +00:00
|
|
|
fmt.Fprintf(w, " opts = opts || {};\n")
|
2020-09-01 22:37:03 +00:00
|
|
|
fmt.Fprintf(w, " {\n")
|
|
|
|
err := genInputProps()
|
|
|
|
if err != nil {
|
2022-09-01 22:42:44 +00:00
|
|
|
return resourceFileInfo{}, err
|
2020-09-01 22:37:03 +00:00
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2020-07-02 19:30:10 +00:00
|
|
|
var secretProps []string
|
2020-01-21 22:45:48 +00:00
|
|
|
for _, prop := range r.Properties {
|
2020-07-02 19:30:10 +00:00
|
|
|
if prop.Secret {
|
|
|
|
secretProps = append(secretProps, prop.Name)
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2020-07-10 18:23:31 +00:00
|
|
|
fmt.Fprintf(w, " }\n")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// If the caller didn't request a specific version, supply one using the version of this library.
|
2022-01-10 23:54:41 +00:00
|
|
|
// If a `pluginDownloadURL` was supplied by the generating schema, we supply a default facility
|
|
|
|
// much like for version. Both operations are handled in the utilities library.
|
|
|
|
fmt.Fprint(w, " opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts);\n")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// Now invoke the super constructor with the type, name, and a property map.
|
|
|
|
if len(r.Aliases) > 0 {
|
|
|
|
fmt.Fprintf(w, " const aliasOpts = { aliases: [")
|
|
|
|
for i, alias := range r.Aliases {
|
2023-11-21 22:40:14 +00:00
|
|
|
if alias.Type != nil {
|
|
|
|
fmt.Fprintf(w, "{ type: \"%v\" }", *alias.Type)
|
|
|
|
if i != len(r.Aliases)-1 {
|
|
|
|
fmt.Fprintf(w, ", ")
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "] };\n")
|
2021-02-12 18:10:59 +00:00
|
|
|
fmt.Fprintf(w, " opts = pulumi.mergeOptions(opts, aliasOpts);\n")
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2020-07-02 19:30:10 +00:00
|
|
|
if len(secretProps) > 0 {
|
2021-05-26 22:00:51 +00:00
|
|
|
fmt.Fprintf(w, ` const secretOpts = { additionalSecretOutputs: ["%s"] };`, strings.Join(secretProps, `", "`))
|
|
|
|
fmt.Fprintf(w, "\n opts = pulumi.mergeOptions(opts, secretOpts);\n")
|
2020-07-02 19:30:10 +00:00
|
|
|
}
|
|
|
|
|
2021-09-08 05:23:30 +00:00
|
|
|
replaceOnChanges, errList := r.ReplaceOnChanges()
|
|
|
|
for _, err := range errList {
|
|
|
|
cmdutil.Diag().Warningf(&diag.Diag{Message: err.Error()})
|
|
|
|
}
|
|
|
|
replaceOnChangesStrings := schema.PropertyListJoinToString(replaceOnChanges,
|
|
|
|
func(x string) string { return x })
|
|
|
|
if len(replaceOnChanges) > 0 {
|
|
|
|
fmt.Fprintf(w, ` const replaceOnChanges = { replaceOnChanges: ["%s"] };`, strings.Join(replaceOnChangesStrings, `", "`))
|
|
|
|
fmt.Fprintf(w, "\n opts = pulumi.mergeOptions(opts, replaceOnChanges);\n")
|
|
|
|
}
|
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
// If it's a ComponentResource, set the remote option.
|
|
|
|
if r.IsComponent {
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, " super(%s.__pulumiType, name, resourceInputs, opts, true /*remote*/);\n", name)
|
2020-09-25 19:35:27 +00:00
|
|
|
} else {
|
2021-11-18 20:23:30 +00:00
|
|
|
fmt.Fprintf(w, " super(%s.__pulumiType, name, resourceInputs, opts);\n", name)
|
2020-09-25 19:35:27 +00:00
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
fmt.Fprintf(w, " }\n")
|
2021-07-08 03:16:42 +00:00
|
|
|
|
|
|
|
// Generate methods.
|
|
|
|
genMethod := func(method *schema.Method) {
|
|
|
|
methodName := camel(method.Name)
|
|
|
|
fun := method.Function
|
|
|
|
|
2023-01-11 22:17:14 +00:00
|
|
|
var objectReturnType *schema.ObjectType
|
|
|
|
if fun.ReturnType != nil {
|
|
|
|
if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && objectType != nil {
|
|
|
|
objectReturnType = objectType
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
} else if !fun.ReturnTypePlain {
|
|
|
|
// Currently the code only knows how to generate code for methods returning an
|
|
|
|
// ObjectType or methods returning a plain resource All other methods are simply
|
|
|
|
// skipped; bail here.
|
2023-01-11 22:17:14 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
liftReturn := mod.liftSingleValueMethodReturns && objectReturnType != nil && len(objectReturnType.Properties) == 1
|
2021-10-01 18:33:02 +00:00
|
|
|
|
2021-07-08 03:16:42 +00:00
|
|
|
// Write the TypeDoc/JSDoc for the data source function.
|
|
|
|
fmt.Fprint(w, "\n")
|
|
|
|
printComment(w, codegen.FilterExamples(fun.Comment, "typescript"), fun.DeprecationMessage, " ")
|
|
|
|
|
|
|
|
// Now, emit the method signature.
|
|
|
|
var args []*schema.Property
|
|
|
|
var argsig string
|
|
|
|
argsOptional := true
|
|
|
|
if fun.Inputs != nil {
|
|
|
|
// Filter out the __self__ argument from the inputs.
|
2023-06-28 16:02:04 +00:00
|
|
|
args = slice.Prealloc[*schema.Property](len(fun.Inputs.InputShape.Properties))
|
2021-07-08 03:16:42 +00:00
|
|
|
for _, arg := range fun.Inputs.InputShape.Properties {
|
|
|
|
if arg.Name == "__self__" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if arg.IsRequired() {
|
|
|
|
argsOptional = false
|
|
|
|
}
|
|
|
|
args = append(args, arg)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(args) > 0 {
|
|
|
|
optFlag := ""
|
|
|
|
if argsOptional {
|
|
|
|
optFlag = "?"
|
|
|
|
}
|
|
|
|
argsig = fmt.Sprintf("args%s: %s.%sArgs", optFlag, name, title(method.Name))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var retty string
|
2023-01-11 22:17:14 +00:00
|
|
|
if fun.ReturnType == nil {
|
2021-07-08 03:16:42 +00:00
|
|
|
retty = "void"
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
} else if fun.ReturnTypePlain {
|
|
|
|
var innerType string
|
|
|
|
if objectReturnType == nil {
|
|
|
|
innerType = mod.typeString(fun.ReturnType, false, nil)
|
|
|
|
} else {
|
|
|
|
innerType = fmt.Sprintf("%s.%sResult", name, title(method.Name))
|
|
|
|
}
|
|
|
|
retty = fmt.Sprintf("Promise<%s>", innerType)
|
2023-01-11 22:17:14 +00:00
|
|
|
} else if liftReturn {
|
|
|
|
retty = fmt.Sprintf("pulumi.Output<%s>", mod.typeString(objectReturnType.Properties[0].Type, false, nil))
|
2021-07-08 03:16:42 +00:00
|
|
|
} else {
|
|
|
|
retty = fmt.Sprintf("pulumi.Output<%s.%sResult>", name, title(method.Name))
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, " %s(%s): %s {\n", methodName, argsig, retty)
|
|
|
|
if fun.DeprecationMessage != "" {
|
|
|
|
fmt.Fprintf(w, " pulumi.log.warn(\"%s.%s is deprecated: %s\")\n", name, methodName,
|
2022-04-08 15:40:11 +00:00
|
|
|
escape(fun.DeprecationMessage))
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Zero initialize the args if empty and necessary.
|
|
|
|
if len(args) > 0 && argsOptional {
|
|
|
|
fmt.Fprintf(w, " args = args || {};\n")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now simply call the runtime function with the arguments, returning the results.
|
|
|
|
var ret string
|
2023-01-11 22:17:14 +00:00
|
|
|
if fun.ReturnType != nil {
|
|
|
|
if liftReturn {
|
2021-10-01 18:33:02 +00:00
|
|
|
ret = fmt.Sprintf("const result: pulumi.Output<%s.%sResult> = ", name, title(method.Name))
|
|
|
|
} else {
|
|
|
|
ret = "return "
|
|
|
|
}
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
|
|
|
|
if fun.ReturnTypePlain {
|
|
|
|
fmt.Fprintf(w, " %sutilities.callAsync(\"%s\", {\n", ret, fun.Token)
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, " %spulumi.runtime.call(\"%s\", {\n", ret, fun.Token)
|
|
|
|
}
|
|
|
|
|
2021-07-08 03:16:42 +00:00
|
|
|
if fun.Inputs != nil {
|
|
|
|
for _, p := range fun.Inputs.InputShape.Properties {
|
|
|
|
// Pass the argument to the invocation.
|
|
|
|
if p.Name == "__self__" {
|
|
|
|
fmt.Fprintf(w, " \"%s\": this,\n", p.Name)
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, " \"%[1]s\": args.%[1]s,\n", p.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
fmt.Fprintf(w, " }, this")
|
|
|
|
|
|
|
|
if fun.ReturnTypePlain {
|
|
|
|
// Unwrap magic property "res" for methods that return a plain non-object-type.
|
|
|
|
if objectReturnType == nil {
|
|
|
|
fmt.Fprintf(w, `, {property: "res"});`)
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, `, {});`)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, ");\n")
|
|
|
|
}
|
|
|
|
|
2023-01-11 22:17:14 +00:00
|
|
|
if liftReturn {
|
|
|
|
fmt.Fprintf(w, " return result.%s;\n", camel(objectReturnType.Properties[0].Name))
|
2021-10-01 18:33:02 +00:00
|
|
|
}
|
2021-07-08 03:16:42 +00:00
|
|
|
fmt.Fprintf(w, " }\n")
|
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
|
2021-07-08 03:16:42 +00:00
|
|
|
for _, method := range r.Methods {
|
|
|
|
genMethod(method)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finish the class.
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "}\n")
|
|
|
|
|
|
|
|
// Emit the state type for get methods.
|
|
|
|
if r.StateInputs != nil {
|
|
|
|
fmt.Fprintf(w, "\n")
|
2021-11-18 20:23:30 +00:00
|
|
|
if err := mod.genPlainType(w, stateType, r.StateInputs.Comment, r.StateInputs.Properties, true, false, 0); err != nil {
|
2022-09-01 22:42:44 +00:00
|
|
|
return resourceFileInfo{}, err
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
info.stateInterfaceName = stateType
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Emit the argument type for construction.
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
argsComment := fmt.Sprintf("The set of arguments for constructing a %s resource.", name)
|
2021-11-18 20:23:30 +00:00
|
|
|
if err := mod.genPlainType(w, argsType, argsComment, r.InputProperties, true, false, 0); err != nil {
|
2022-09-01 22:42:44 +00:00
|
|
|
return resourceFileInfo{}, err
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
info.resourceArgsInterfaceName = argsType
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2021-07-08 03:16:42 +00:00
|
|
|
// Emit any method types inside a namespace merged with the class, to represent types nested in the class.
|
|
|
|
// https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-namespaces-with-classes
|
2021-11-18 20:23:30 +00:00
|
|
|
genMethodTypes := func(w io.Writer, method *schema.Method) error {
|
2021-07-08 03:16:42 +00:00
|
|
|
fun := method.Function
|
|
|
|
methodName := title(method.Name)
|
|
|
|
if fun.Inputs != nil {
|
2023-06-28 16:02:04 +00:00
|
|
|
args := slice.Prealloc[*schema.Property](len(fun.Inputs.InputShape.Properties))
|
2021-07-08 03:16:42 +00:00
|
|
|
for _, arg := range fun.Inputs.InputShape.Properties {
|
|
|
|
if arg.Name == "__self__" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
args = append(args, arg)
|
|
|
|
}
|
|
|
|
if len(args) > 0 {
|
|
|
|
comment := fun.Inputs.Comment
|
|
|
|
if comment == "" {
|
|
|
|
comment = fmt.Sprintf("The set of arguments for the %s.%s method.", name, method.Name)
|
|
|
|
}
|
2021-11-18 20:23:30 +00:00
|
|
|
if err := mod.genPlainType(w, methodName+"Args", comment, args, true, false, 1); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-07-08 03:16:42 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
|
|
|
|
if fun.ReturnType != nil {
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
genReturnType := func(properties []*schema.Property) error {
|
2023-01-11 22:17:14 +00:00
|
|
|
comment := fun.Inputs.Comment
|
|
|
|
if comment == "" {
|
|
|
|
comment = fmt.Sprintf("The results of the %s.%s method.", name, method.Name)
|
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
if err := mod.genPlainType(w, methodName+"Result", comment, properties, false, true, 1); err != nil {
|
2023-01-11 22:17:14 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && objectType != nil {
|
|
|
|
if err := genReturnType(objectType.Properties); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
// For non-object types with fun.ReturnTypePlain return type is not needed.
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
2021-11-18 20:23:30 +00:00
|
|
|
return nil
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
|
|
|
types := &bytes.Buffer{}
|
|
|
|
for _, method := range r.Methods {
|
2021-11-18 20:23:30 +00:00
|
|
|
if err := genMethodTypes(types, method); err != nil {
|
2022-09-01 22:42:44 +00:00
|
|
|
return resourceFileInfo{}, err
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
|
|
|
typesString := types.String()
|
|
|
|
if typesString != "" {
|
|
|
|
fmt.Fprintf(w, "\nexport namespace %s {\n", name)
|
2023-01-13 18:56:53 +00:00
|
|
|
fmt.Fprint(w, typesString)
|
|
|
|
fmt.Fprint(w, "}\n")
|
2022-09-01 22:42:44 +00:00
|
|
|
info.methodsNamespaceName = name
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
return info, nil
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2023-01-11 22:17:14 +00:00
|
|
|
func (mod *modContext) functionReturnType(fun *schema.Function) string {
|
|
|
|
name := tokenToFunctionName(fun.Token)
|
|
|
|
if fun.ReturnType == nil {
|
|
|
|
return "void"
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, isObject := fun.ReturnType.(*schema.ObjectType); isObject && fun.InlineObjectAsReturnType {
|
|
|
|
return title(name) + "Result"
|
|
|
|
}
|
|
|
|
|
|
|
|
return mod.typeString(fun.ReturnType, false, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// runtimeInvokeFunction returns the name of the Invoke function to use at runtime
|
|
|
|
// from the SDK for the given provider function. This is necessary because some
|
|
|
|
// functions have simple return types such as number, string, array<string> etc.
|
|
|
|
// and the SDK's invoke function cannot handle these types since the engine expects
|
|
|
|
// the result of invokes to be a dictionary.
|
|
|
|
//
|
|
|
|
// We use invoke for functions with object return types and invokeSingle for everything else.
|
|
|
|
func runtimeInvokeFunction(fun *schema.Function) string {
|
|
|
|
switch fun.ReturnType.(type) {
|
|
|
|
// If the function has no return type, it is a void function.
|
|
|
|
case nil:
|
|
|
|
return "invoke"
|
|
|
|
// If the function has an object return type, it is a normal invoke function.
|
|
|
|
case *schema.ObjectType:
|
|
|
|
return "invoke"
|
|
|
|
// If the function has an object return type, it is also a normal invoke function.
|
|
|
|
// because the deserialization can handle it
|
|
|
|
case *schema.MapType:
|
|
|
|
return "invoke"
|
|
|
|
default:
|
|
|
|
// Anything else needs to be handled by InvokeSingle
|
|
|
|
// which expects an object with a single property to be returned
|
|
|
|
// then unwraps the value from that property
|
|
|
|
return "invokeSingle"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-01 22:42:44 +00:00
|
|
|
func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) (functionFileInfo, error) {
|
2020-04-28 00:47:01 +00:00
|
|
|
name := tokenToFunctionName(fun.Token)
|
2022-09-01 22:42:44 +00:00
|
|
|
info := functionFileInfo{functionName: name}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// Write the TypeDoc/JSDoc for the data source function.
|
2020-06-18 19:32:15 +00:00
|
|
|
printComment(w, codegen.FilterExamples(fun.Comment, "typescript"), "", "")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
if fun.DeprecationMessage != "" {
|
|
|
|
fmt.Fprintf(w, "/** @deprecated %s */\n", fun.DeprecationMessage)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now, emit the function signature.
|
|
|
|
var argsig string
|
2021-10-07 19:39:19 +00:00
|
|
|
argsOptional := functionArgsOptional(fun)
|
2020-01-21 22:45:48 +00:00
|
|
|
if fun.Inputs != nil {
|
|
|
|
optFlag := ""
|
|
|
|
if argsOptional {
|
|
|
|
optFlag = "?"
|
|
|
|
}
|
|
|
|
argsig = fmt.Sprintf("args%s: %sArgs, ", optFlag, title(name))
|
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
|
|
|
|
funReturnType := mod.functionReturnType(fun)
|
|
|
|
|
|
|
|
fmt.Fprintf(w, "export function %s(", name)
|
|
|
|
if fun.MultiArgumentInputs {
|
|
|
|
for _, prop := range fun.Inputs.Properties {
|
|
|
|
if prop.IsRequired() {
|
|
|
|
fmt.Fprintf(w, "%s: ", prop.Name)
|
|
|
|
fmt.Fprintf(w, "%s, ", mod.typeString(prop.Type, false, nil))
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, "%s?: ", prop.Name)
|
|
|
|
// since we already applied the '?' to the type, we can simplify
|
|
|
|
// the optional-ness of the type
|
|
|
|
propType := prop.Type.(*schema.OptionalType)
|
|
|
|
fmt.Fprintf(w, "%s, ", mod.typeString(propType.ElementType, false, nil))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, "%s", argsig)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, "opts?: pulumi.InvokeOptions): Promise<%s> {\n", funReturnType)
|
2020-07-01 19:50:26 +00:00
|
|
|
if fun.DeprecationMessage != "" && mod.compatibility != kubernetes20 {
|
2022-04-08 15:40:11 +00:00
|
|
|
fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, escape(fun.DeprecationMessage))
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Zero initialize the args if empty and necessary.
|
2023-01-11 22:17:14 +00:00
|
|
|
if fun.Inputs != nil && argsOptional && !fun.MultiArgumentInputs {
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, " args = args || {};\n")
|
|
|
|
}
|
|
|
|
|
2023-01-11 22:17:14 +00:00
|
|
|
fmt.Fprint(w, "\n")
|
2020-01-21 22:45:48 +00:00
|
|
|
// If the caller didn't request a specific version, supply one using the version of this library.
|
2022-11-14 13:58:16 +00:00
|
|
|
fmt.Fprintf(w, " opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {});\n")
|
2023-01-11 22:17:14 +00:00
|
|
|
invokeCall := runtimeInvokeFunction(fun)
|
2020-01-21 22:45:48 +00:00
|
|
|
// Now simply invoke the runtime function with the arguments, returning the results.
|
2023-01-11 22:17:14 +00:00
|
|
|
fmt.Fprintf(w, " return pulumi.runtime.%s(\"%s\", {\n", invokeCall, fun.Token)
|
2020-01-21 22:45:48 +00:00
|
|
|
if fun.Inputs != nil {
|
|
|
|
for _, p := range fun.Inputs.Properties {
|
|
|
|
// Pass the argument to the invocation.
|
2023-12-12 12:19:42 +00:00
|
|
|
body := "args." + p.Name
|
2023-01-11 22:17:14 +00:00
|
|
|
if fun.MultiArgumentInputs {
|
|
|
|
body = p.Name
|
|
|
|
}
|
|
|
|
|
2021-11-18 20:23:30 +00:00
|
|
|
if name := mod.provideDefaultsFuncName(p.Type, true /*input*/); name != "" {
|
|
|
|
if codegen.IsNOptionalInput(p.Type) {
|
|
|
|
body = fmt.Sprintf("pulumi.output(%s).apply(%s)", body, name)
|
|
|
|
} else {
|
|
|
|
body = fmt.Sprintf("%s(%s)", name, body)
|
|
|
|
}
|
|
|
|
body = fmt.Sprintf("args.%s ? %s : undefined", p.Name, body)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, " \"%[1]s\": %[2]s,\n", p.Name, body)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
|
|
|
|
fmt.Fprint(w, " }, opts);\n")
|
|
|
|
fmt.Fprint(w, "}\n")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// If there are argument and/or return types, emit them.
|
2023-01-11 22:17:14 +00:00
|
|
|
if fun.Inputs != nil && !fun.MultiArgumentInputs {
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
2022-09-01 22:42:44 +00:00
|
|
|
argsInterfaceName := title(name) + "Args"
|
|
|
|
if err := mod.genPlainType(w, argsInterfaceName, fun.Inputs.Comment, fun.Inputs.Properties, true, false, 0); err != nil {
|
|
|
|
return info, err
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
info.functionArgsInterfaceName = argsInterfaceName
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
|
|
|
|
// if the return type is an inline object definition (not a reference), emit it.
|
|
|
|
if fun.ReturnType != nil {
|
|
|
|
if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && fun.InlineObjectAsReturnType {
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
resultInterfaceName := title(name) + "Result"
|
|
|
|
if err := mod.genPlainType(w, resultInterfaceName,
|
|
|
|
objectType.Comment, objectType.Properties, false, true, 0); err != nil {
|
|
|
|
return info, err
|
|
|
|
}
|
|
|
|
info.functionResultInterfaceName = resultInterfaceName
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2021-10-07 19:39:19 +00:00
|
|
|
|
2022-09-01 22:42:44 +00:00
|
|
|
return mod.genFunctionOutputVersion(w, fun, info)
|
2021-10-07 19:39:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func functionArgsOptional(fun *schema.Function) bool {
|
|
|
|
if fun.Inputs != nil {
|
|
|
|
for _, p := range fun.Inputs.Properties {
|
|
|
|
if p.IsRequired() {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generates `function ${fn}Output(..)` version lifted to work on
|
|
|
|
// `Input`-warpped arguments and producing an `Output`-wrapped result.
|
2022-09-01 22:42:44 +00:00
|
|
|
func (mod *modContext) genFunctionOutputVersion(
|
|
|
|
w io.Writer,
|
|
|
|
fun *schema.Function,
|
2023-03-03 16:36:39 +00:00
|
|
|
info functionFileInfo,
|
|
|
|
) (functionFileInfo, error) {
|
2023-08-08 18:09:37 +00:00
|
|
|
if fun.ReturnType == nil {
|
2022-09-01 22:42:44 +00:00
|
|
|
return info, nil
|
2021-10-07 19:39:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
originalName := tokenToFunctionName(fun.Token)
|
2023-12-12 12:19:42 +00:00
|
|
|
fnOutput := originalName + "Output"
|
2023-01-11 22:17:14 +00:00
|
|
|
returnType := mod.functionReturnType(fun)
|
2022-09-01 22:42:44 +00:00
|
|
|
info.functionOutputVersionName = fnOutput
|
2023-12-12 12:19:42 +00:00
|
|
|
argTypeName := title(fnOutput) + "Args"
|
2021-10-07 19:39:19 +00:00
|
|
|
|
2023-08-08 18:09:37 +00:00
|
|
|
argsig := ""
|
|
|
|
if fun.Inputs != nil && len(fun.Inputs.Properties) > 0 {
|
|
|
|
argsOptional := functionArgsOptional(fun)
|
|
|
|
optFlag := ""
|
|
|
|
if argsOptional {
|
|
|
|
optFlag = "?"
|
|
|
|
}
|
|
|
|
argsig = fmt.Sprintf("args%s: %s, ", optFlag, argTypeName)
|
2021-10-07 19:39:19 +00:00
|
|
|
}
|
|
|
|
|
2023-01-11 22:17:14 +00:00
|
|
|
// Write the TypeDoc/JSDoc for the data source function.
|
|
|
|
printComment(w, codegen.FilterExamples(fun.Comment, "typescript"), "", "")
|
|
|
|
|
|
|
|
if fun.DeprecationMessage != "" {
|
|
|
|
fmt.Fprintf(w, "/** @deprecated %s */\n", fun.DeprecationMessage)
|
|
|
|
}
|
|
|
|
if !fun.MultiArgumentInputs {
|
2023-08-08 18:09:37 +00:00
|
|
|
if argsig != "" {
|
|
|
|
fmt.Fprintf(w, `export function %s(%sopts?: pulumi.InvokeOptions): pulumi.Output<%s> {
|
2022-12-05 11:57:05 +00:00
|
|
|
return pulumi.output(args).apply((a: any) => %s(a, opts))
|
2021-10-07 19:39:19 +00:00
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
`, fnOutput, argsig, returnType, originalName)
|
2023-08-08 18:09:37 +00:00
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, `export function %s(opts?: pulumi.InvokeOptions): pulumi.Output<%s> {
|
|
|
|
return pulumi.output(%s(opts))
|
|
|
|
}
|
|
|
|
`, fnOutput, returnType, originalName)
|
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
} else {
|
|
|
|
fmt.Fprintf(w, "export function %s(", fnOutput)
|
2023-08-08 18:09:37 +00:00
|
|
|
var properties []*schema.Property
|
|
|
|
if fun.Inputs != nil {
|
|
|
|
properties = fun.Inputs.Properties
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, prop := range properties {
|
2023-01-11 22:17:14 +00:00
|
|
|
paramDeclaration := ""
|
|
|
|
propertyType := &schema.InputType{ElementType: prop.Type}
|
|
|
|
argumentType := mod.typeString(propertyType, true /* input */, nil)
|
|
|
|
if prop.IsRequired() {
|
|
|
|
paramDeclaration = fmt.Sprintf("%s: %s", prop.Name, argumentType)
|
|
|
|
} else {
|
|
|
|
paramDeclaration = fmt.Sprintf("%s?: %s", prop.Name, argumentType)
|
|
|
|
}
|
2022-12-16 12:39:03 +00:00
|
|
|
|
2023-01-11 22:17:14 +00:00
|
|
|
fmt.Fprintf(w, "%s, ", paramDeclaration)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, "opts?: pulumi.InvokeOptions): pulumi.Output<%s> {\n", returnType)
|
|
|
|
fmt.Fprint(w, " var args = {\n")
|
2023-08-08 18:09:37 +00:00
|
|
|
for _, p := range properties {
|
2023-01-11 22:17:14 +00:00
|
|
|
fmt.Fprintf(w, " \"%s\": %s,\n", p.Name, p.Name)
|
|
|
|
}
|
|
|
|
fmt.Fprint(w, " };\n")
|
|
|
|
fmt.Fprintf(w, " return pulumi.output(args).apply((resolvedArgs: any) => %s(", originalName)
|
2023-08-08 18:09:37 +00:00
|
|
|
for _, p := range properties {
|
2023-01-11 22:17:14 +00:00
|
|
|
// Pass the argument to the invocation.
|
|
|
|
fmt.Fprintf(w, "resolvedArgs.%s, ", p.Name)
|
|
|
|
}
|
|
|
|
fmt.Fprint(w, "opts))\n")
|
|
|
|
fmt.Fprint(w, "}\n")
|
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
|
2023-08-08 18:09:37 +00:00
|
|
|
if !fun.MultiArgumentInputs && fun.Inputs != nil && len(fun.Inputs.Properties) > 0 {
|
2023-01-11 22:17:14 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
info.functionOutputVersionArgsInterfaceName = argTypeName
|
|
|
|
if err := mod.genPlainType(w,
|
|
|
|
argTypeName,
|
|
|
|
fun.Inputs.Comment,
|
|
|
|
fun.Inputs.InputShape.Properties,
|
|
|
|
true, /* input */
|
|
|
|
false, /* readonly */
|
|
|
|
0 /* level */); err != nil {
|
|
|
|
return info, err
|
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return info, nil
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-06-24 16:17:55 +00:00
|
|
|
func visitObjectTypes(properties []*schema.Property, visitor func(*schema.ObjectType)) {
|
|
|
|
codegen.VisitTypeClosure(properties, func(t schema.Type) {
|
|
|
|
if o, ok := t.(*schema.ObjectType); ok {
|
|
|
|
visitor(o)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2021-04-19 23:40:39 +00:00
|
|
|
})
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-11-18 20:23:30 +00:00
|
|
|
func (mod *modContext) genType(w io.Writer, obj *schema.ObjectType, input bool, level int) error {
|
2020-06-01 18:50:10 +00:00
|
|
|
properties := obj.Properties
|
|
|
|
info, hasInfo := obj.Language["nodejs"]
|
|
|
|
if hasInfo {
|
|
|
|
var requiredProperties []string
|
|
|
|
if input {
|
|
|
|
requiredProperties = info.(NodeObjectInfo).RequiredInputs
|
|
|
|
} else {
|
|
|
|
requiredProperties = info.(NodeObjectInfo).RequiredOutputs
|
|
|
|
}
|
|
|
|
|
|
|
|
if requiredProperties != nil {
|
|
|
|
required := codegen.StringSet{}
|
|
|
|
for _, name := range requiredProperties {
|
|
|
|
required.Add(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
properties = make([]*schema.Property, len(obj.Properties))
|
|
|
|
for i, p := range obj.Properties {
|
all: Fix revive issues
Fixes the following issues found by revive
included in the latest release of golangci-lint.
Full list of issues:
**pkg**
```
backend/display/object_diff.go:47:10: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
backend/display/object_diff.go:716:12: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:742:14: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:983:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (revive)
backend/httpstate/backend.go:1814:4: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/backend.go:1824:5: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/client/client.go:444:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
backend/httpstate/client/client.go:455:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/org.go:113:4: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/util.go:216:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
codegen/docs/gen.go:428:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/hcl2/model/expression.go:2151:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:151:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:329:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:381:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/nodejs/gen.go:1367:5: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/python/gen_program_expressions.go:136:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/python/gen_program_expressions.go:142:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/report/report.go:126:6: redefines-builtin-id: redefinition of the built-in function panic (revive)
codegen/schema/docs_test.go:210:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
codegen/schema/schema.go:790:2: redefines-builtin-id: redefinition of the built-in type any (revive)
codegen/schema/schema.go:793:4: redefines-builtin-id: redefinition of the built-in type any (revive)
resource/deploy/plan.go:506:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
resource/deploy/snapshot_test.go:59:3: redefines-builtin-id: redefinition of the built-in function copy (revive)
resource/deploy/state_builder.go:108:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
```
**sdk**
```
go/common/resource/plugin/context.go:142:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/resource/plugin/plugin.go:142:12: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (revive)
go/common/resource/properties_diff.go:114:2: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:117:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:122:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:127:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:132:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/util/deepcopy/copy.go:30:1: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/workspace/creds.go:242:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:569:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:706:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi/run_test.go:925:2: redefines-builtin-id: redefinition of the built-in type any (revive)
go/pulumi/run_test.go:933:3: redefines-builtin-id: redefinition of the built-in type any (revive)
nodejs/cmd/pulumi-language-nodejs/main.go:778:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:1011:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:863:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/python.go:230:2: redefines-builtin-id: redefinition of the built-in function print (revive)
```
**tests**
```
integration/integration_util_test.go:282:11: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
```
2023-03-20 23:48:02 +00:00
|
|
|
newp := *p
|
2021-07-13 16:39:58 +00:00
|
|
|
if required.Has(p.Name) {
|
all: Fix revive issues
Fixes the following issues found by revive
included in the latest release of golangci-lint.
Full list of issues:
**pkg**
```
backend/display/object_diff.go:47:10: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
backend/display/object_diff.go:716:12: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:742:14: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:983:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (revive)
backend/httpstate/backend.go:1814:4: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/backend.go:1824:5: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/client/client.go:444:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
backend/httpstate/client/client.go:455:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/org.go:113:4: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/util.go:216:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
codegen/docs/gen.go:428:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/hcl2/model/expression.go:2151:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:151:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:329:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:381:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/nodejs/gen.go:1367:5: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/python/gen_program_expressions.go:136:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/python/gen_program_expressions.go:142:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/report/report.go:126:6: redefines-builtin-id: redefinition of the built-in function panic (revive)
codegen/schema/docs_test.go:210:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
codegen/schema/schema.go:790:2: redefines-builtin-id: redefinition of the built-in type any (revive)
codegen/schema/schema.go:793:4: redefines-builtin-id: redefinition of the built-in type any (revive)
resource/deploy/plan.go:506:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
resource/deploy/snapshot_test.go:59:3: redefines-builtin-id: redefinition of the built-in function copy (revive)
resource/deploy/state_builder.go:108:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
```
**sdk**
```
go/common/resource/plugin/context.go:142:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/resource/plugin/plugin.go:142:12: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (revive)
go/common/resource/properties_diff.go:114:2: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:117:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:122:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:127:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:132:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/util/deepcopy/copy.go:30:1: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/workspace/creds.go:242:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:569:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:706:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi/run_test.go:925:2: redefines-builtin-id: redefinition of the built-in type any (revive)
go/pulumi/run_test.go:933:3: redefines-builtin-id: redefinition of the built-in type any (revive)
nodejs/cmd/pulumi-language-nodejs/main.go:778:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:1011:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:863:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/python.go:230:2: redefines-builtin-id: redefinition of the built-in function print (revive)
```
**tests**
```
integration/integration_util_test.go:282:11: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
```
2023-03-20 23:48:02 +00:00
|
|
|
newp.Type = codegen.RequiredType(&newp)
|
2021-07-13 16:39:58 +00:00
|
|
|
} else {
|
all: Fix revive issues
Fixes the following issues found by revive
included in the latest release of golangci-lint.
Full list of issues:
**pkg**
```
backend/display/object_diff.go:47:10: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
backend/display/object_diff.go:716:12: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:742:14: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:983:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (revive)
backend/httpstate/backend.go:1814:4: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/backend.go:1824:5: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/client/client.go:444:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
backend/httpstate/client/client.go:455:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/org.go:113:4: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/util.go:216:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
codegen/docs/gen.go:428:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/hcl2/model/expression.go:2151:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:151:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:329:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:381:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/nodejs/gen.go:1367:5: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/python/gen_program_expressions.go:136:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/python/gen_program_expressions.go:142:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/report/report.go:126:6: redefines-builtin-id: redefinition of the built-in function panic (revive)
codegen/schema/docs_test.go:210:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
codegen/schema/schema.go:790:2: redefines-builtin-id: redefinition of the built-in type any (revive)
codegen/schema/schema.go:793:4: redefines-builtin-id: redefinition of the built-in type any (revive)
resource/deploy/plan.go:506:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
resource/deploy/snapshot_test.go:59:3: redefines-builtin-id: redefinition of the built-in function copy (revive)
resource/deploy/state_builder.go:108:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
```
**sdk**
```
go/common/resource/plugin/context.go:142:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/resource/plugin/plugin.go:142:12: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (revive)
go/common/resource/properties_diff.go:114:2: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:117:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:122:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:127:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:132:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/util/deepcopy/copy.go:30:1: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/workspace/creds.go:242:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:569:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:706:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi/run_test.go:925:2: redefines-builtin-id: redefinition of the built-in type any (revive)
go/pulumi/run_test.go:933:3: redefines-builtin-id: redefinition of the built-in type any (revive)
nodejs/cmd/pulumi-language-nodejs/main.go:778:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:1011:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:863:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/python.go:230:2: redefines-builtin-id: redefinition of the built-in function print (revive)
```
**tests**
```
integration/integration_util_test.go:282:11: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
```
2023-03-20 23:48:02 +00:00
|
|
|
newp.Type = codegen.OptionalType(&newp)
|
2021-06-24 16:17:55 +00:00
|
|
|
}
|
all: Fix revive issues
Fixes the following issues found by revive
included in the latest release of golangci-lint.
Full list of issues:
**pkg**
```
backend/display/object_diff.go:47:10: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
backend/display/object_diff.go:716:12: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:742:14: redefines-builtin-id: redefinition of the built-in function delete (revive)
backend/display/object_diff.go:983:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (revive)
backend/httpstate/backend.go:1814:4: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/backend.go:1824:5: redefines-builtin-id: redefinition of the built-in function cap (revive)
backend/httpstate/client/client.go:444:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
backend/httpstate/client/client.go:455:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/org.go:113:4: if-return: redundant if ...; err != nil check, just return error instead. (revive)
cmd/pulumi/util.go:216:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
codegen/docs/gen.go:428:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/hcl2/model/expression.go:2151:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:151:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:329:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/hcl2/syntax/comments.go:381:5: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/nodejs/gen.go:1367:5: redefines-builtin-id: redefinition of the built-in function copy (revive)
codegen/python/gen_program_expressions.go:136:2: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/python/gen_program_expressions.go:142:3: redefines-builtin-id: redefinition of the built-in function close (revive)
codegen/report/report.go:126:6: redefines-builtin-id: redefinition of the built-in function panic (revive)
codegen/schema/docs_test.go:210:10: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
codegen/schema/schema.go:790:2: redefines-builtin-id: redefinition of the built-in type any (revive)
codegen/schema/schema.go:793:4: redefines-builtin-id: redefinition of the built-in type any (revive)
resource/deploy/plan.go:506:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
resource/deploy/snapshot_test.go:59:3: redefines-builtin-id: redefinition of the built-in function copy (revive)
resource/deploy/state_builder.go:108:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
```
**sdk**
```
go/common/resource/plugin/context.go:142:2: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/resource/plugin/plugin.go:142:12: superfluous-else: if block ends with a break statement, so drop this else and outdent its block (revive)
go/common/resource/properties_diff.go:114:2: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:117:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:122:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:127:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/resource/properties_diff.go:132:4: redefines-builtin-id: redefinition of the built-in function len (revive)
go/common/util/deepcopy/copy.go:30:1: redefines-builtin-id: redefinition of the built-in function copy (revive)
go/common/workspace/creds.go:242:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:569:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi-language-go/main.go:706:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
go/pulumi/run_test.go:925:2: redefines-builtin-id: redefinition of the built-in type any (revive)
go/pulumi/run_test.go:933:3: redefines-builtin-id: redefinition of the built-in type any (revive)
nodejs/cmd/pulumi-language-nodejs/main.go:778:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:1011:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/cmd/pulumi-language-python/main.go:863:2: if-return: redundant if ...; err != nil check, just return error instead. (revive)
python/python.go:230:2: redefines-builtin-id: redefinition of the built-in function print (revive)
```
**tests**
```
integration/integration_util_test.go:282:11: superfluous-else: if block ends with a continue statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary) (revive)
```
2023-03-20 23:48:02 +00:00
|
|
|
properties[i] = &newp
|
2020-06-01 18:50:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-18 20:23:30 +00:00
|
|
|
name := mod.getObjectName(obj, input)
|
|
|
|
err := mod.genPlainType(w, name, obj.Comment, properties, input, false, level)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-11-23 23:10:15 +00:00
|
|
|
return mod.genPlainObjectDefaultFunc(w, name, properties, input, false, level)
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// getObjectName recovers the name of `obj` as a type.
|
|
|
|
func (mod *modContext) getObjectName(obj *schema.ObjectType, input bool) string {
|
2021-04-16 02:03:28 +00:00
|
|
|
name := tokenToName(obj.Token)
|
2021-10-07 19:39:19 +00:00
|
|
|
|
|
|
|
details := mod.details(obj)
|
|
|
|
|
|
|
|
if obj.IsInputShape() && input && details != nil && details.usedInFunctionOutputVersionInputs {
|
|
|
|
name += "Args"
|
|
|
|
} else if obj.IsInputShape() && mod.compatibility != tfbridge20 && mod.compatibility != kubernetes20 {
|
2021-06-24 16:17:55 +00:00
|
|
|
name += "Args"
|
2021-04-16 02:03:28 +00:00
|
|
|
}
|
2021-11-18 20:23:30 +00:00
|
|
|
return name
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
func (mod *modContext) getTypeImports(t schema.Type, recurse bool, externalImports codegen.StringSet, imports map[string]codegen.StringSet, seen codegen.Set) bool {
|
2021-07-08 03:16:42 +00:00
|
|
|
return mod.getTypeImportsForResource(t, recurse, externalImports, imports, seen, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mod *modContext) getTypeImportsForResource(t schema.Type, recurse bool, externalImports codegen.StringSet, imports map[string]codegen.StringSet, seen codegen.Set, res *schema.Resource) bool {
|
2020-05-28 22:37:39 +00:00
|
|
|
if seen.Has(t) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
seen.Add(t)
|
2020-09-25 19:35:27 +00:00
|
|
|
|
|
|
|
resourceOrTokenImport := func(tok string) bool {
|
|
|
|
modName, name, modPath := mod.pkg.TokenToModule(tok), tokenToName(tok), "./index"
|
2020-06-05 17:11:18 +00:00
|
|
|
if override, ok := mod.modToPkg[modName]; ok {
|
|
|
|
modName = override
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
if modName != mod.mod {
|
|
|
|
mp, err := filepath.Rel(mod.mod, modName)
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "cannot make %q relative to %q", modName, mod.mod)
|
2020-01-21 22:45:48 +00:00
|
|
|
if path.Base(mp) == "." {
|
|
|
|
mp = path.Dir(mp)
|
|
|
|
}
|
|
|
|
modPath = filepath.ToSlash(mp)
|
|
|
|
}
|
|
|
|
if imports[modPath] == nil {
|
2020-05-28 23:22:50 +00:00
|
|
|
imports[modPath] = codegen.NewStringSet()
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2020-05-28 23:22:50 +00:00
|
|
|
imports[modPath].Add(name)
|
2020-01-21 22:45:48 +00:00
|
|
|
return false
|
2020-09-25 19:35:27 +00:00
|
|
|
}
|
|
|
|
|
2021-07-16 17:27:20 +00:00
|
|
|
var nodePackageInfo NodePackageInfo
|
2022-12-08 13:36:44 +00:00
|
|
|
def, err := mod.pkg.Definition()
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "error loading definition for package %v", mod.pkg.Name())
|
2022-12-08 13:36:44 +00:00
|
|
|
if languageInfo, hasLanguageInfo := def.Language["nodejs"]; hasLanguageInfo {
|
2021-07-16 17:27:20 +00:00
|
|
|
nodePackageInfo = languageInfo.(NodePackageInfo)
|
|
|
|
}
|
|
|
|
|
2021-09-20 17:11:44 +00:00
|
|
|
writeImports := func(pkg string) {
|
|
|
|
if imp, ok := nodePackageInfo.ProviderNameToModuleName[pkg]; ok {
|
|
|
|
externalImports.Add(fmt.Sprintf("import * as %s from \"%s\";", externalModuleName(pkg), imp))
|
|
|
|
} else {
|
|
|
|
externalImports.Add(fmt.Sprintf("import * as %s from \"@pulumi/%s\";", externalModuleName(pkg), pkg))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
switch t := t.(type) {
|
2021-06-24 16:17:55 +00:00
|
|
|
case *schema.OptionalType:
|
|
|
|
return mod.getTypeImports(t.ElementType, recurse, externalImports, imports, seen)
|
|
|
|
case *schema.InputType:
|
|
|
|
return mod.getTypeImports(t.ElementType, recurse, externalImports, imports, seen)
|
2020-09-25 19:35:27 +00:00
|
|
|
case *schema.ArrayType:
|
2021-01-30 00:52:00 +00:00
|
|
|
return mod.getTypeImports(t.ElementType, recurse, externalImports, imports, seen)
|
2020-09-25 19:35:27 +00:00
|
|
|
case *schema.MapType:
|
2021-01-30 00:52:00 +00:00
|
|
|
return mod.getTypeImports(t.ElementType, recurse, externalImports, imports, seen)
|
2020-11-06 17:29:49 +00:00
|
|
|
case *schema.EnumType:
|
2022-07-29 15:07:27 +00:00
|
|
|
// If the enum is from another package, add an import for the external package.
|
2022-12-08 13:36:44 +00:00
|
|
|
if t.PackageReference != nil && !codegen.PkgEquals(t.PackageReference, mod.pkg) {
|
|
|
|
pkg := t.PackageReference.Name()
|
2022-07-29 15:07:27 +00:00
|
|
|
writeImports(pkg)
|
|
|
|
return false
|
|
|
|
}
|
2020-11-06 17:29:49 +00:00
|
|
|
return true
|
2020-09-25 19:35:27 +00:00
|
|
|
case *schema.ObjectType:
|
2021-01-30 00:52:00 +00:00
|
|
|
// If it's from another package, add an import for the external package.
|
2022-12-08 13:36:44 +00:00
|
|
|
if t.PackageReference != nil && !codegen.PkgEquals(t.PackageReference, mod.pkg) {
|
|
|
|
pkg := t.PackageReference.Name()
|
2021-09-20 17:11:44 +00:00
|
|
|
writeImports(pkg)
|
2021-01-30 00:52:00 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
for _, p := range t.Properties {
|
2021-01-30 00:52:00 +00:00
|
|
|
mod.getTypeImports(p.Type, recurse, externalImports, imports, seen)
|
2020-09-25 19:35:27 +00:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
case *schema.ResourceType:
|
2021-01-30 00:52:00 +00:00
|
|
|
// If it's from another package, add an import for the external package.
|
2022-12-08 13:36:44 +00:00
|
|
|
if t.Resource != nil && !codegen.PkgEquals(t.Resource.PackageReference, mod.pkg) {
|
|
|
|
pkg := t.Resource.PackageReference.Name()
|
2021-09-20 17:11:44 +00:00
|
|
|
writeImports(pkg)
|
2021-01-30 00:52:00 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2021-07-08 03:16:42 +00:00
|
|
|
// Don't import itself.
|
|
|
|
if t.Resource == res {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-09-25 19:35:27 +00:00
|
|
|
return resourceOrTokenImport(t.Token)
|
|
|
|
case *schema.TokenType:
|
|
|
|
return resourceOrTokenImport(t.Token)
|
2020-01-21 22:45:48 +00:00
|
|
|
case *schema.UnionType:
|
|
|
|
needsTypes := false
|
|
|
|
for _, e := range t.ElementTypes {
|
2021-01-30 00:52:00 +00:00
|
|
|
needsTypes = mod.getTypeImports(e, recurse, externalImports, imports, seen) || needsTypes
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
return needsTypes
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
func (mod *modContext) getImports(member interface{}, externalImports codegen.StringSet, imports map[string]codegen.StringSet) bool {
|
2021-07-08 03:16:42 +00:00
|
|
|
return mod.getImportsForResource(member, externalImports, imports, nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mod *modContext) getImportsForResource(member interface{}, externalImports codegen.StringSet, imports map[string]codegen.StringSet, res *schema.Resource) bool {
|
2020-05-28 22:37:39 +00:00
|
|
|
seen := codegen.Set{}
|
2020-01-21 22:45:48 +00:00
|
|
|
switch member := member.(type) {
|
|
|
|
case *schema.ObjectType:
|
|
|
|
needsTypes := false
|
|
|
|
for _, p := range member.Properties {
|
2021-01-30 00:52:00 +00:00
|
|
|
needsTypes = mod.getTypeImports(p.Type, true, externalImports, imports, seen) || needsTypes
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
return needsTypes
|
2020-09-25 19:35:27 +00:00
|
|
|
case *schema.ResourceType:
|
2021-01-30 00:52:00 +00:00
|
|
|
mod.getTypeImports(member, true, externalImports, imports, seen)
|
2020-09-25 19:35:27 +00:00
|
|
|
return false
|
2020-01-21 22:45:48 +00:00
|
|
|
case *schema.Resource:
|
|
|
|
needsTypes := false
|
|
|
|
for _, p := range member.Properties {
|
2021-07-08 03:16:42 +00:00
|
|
|
needsTypes = mod.getTypeImportsForResource(p.Type, false, externalImports, imports, seen, res) || needsTypes
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
for _, p := range member.InputProperties {
|
2021-07-08 03:16:42 +00:00
|
|
|
needsTypes = mod.getTypeImportsForResource(p.Type, false, externalImports, imports, seen, res) || needsTypes
|
|
|
|
}
|
|
|
|
for _, method := range member.Methods {
|
|
|
|
if method.Function.Inputs != nil {
|
|
|
|
for _, p := range method.Function.Inputs.Properties {
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
if p.Name == "__self__" {
|
|
|
|
continue
|
|
|
|
}
|
2023-03-03 16:36:39 +00:00
|
|
|
needsTypes = mod.getTypeImportsForResource(p.Type, false, externalImports, imports, seen, res) || needsTypes
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
|
|
|
|
if method.Function.ReturnType != nil {
|
|
|
|
if objectType, ok := method.Function.ReturnType.(*schema.ObjectType); ok && objectType != nil {
|
|
|
|
for _, p := range objectType.Properties {
|
2023-03-03 16:36:39 +00:00
|
|
|
needsTypes = mod.getTypeImportsForResource(p.Type, false, externalImports, imports, seen, res) || needsTypes
|
2023-01-11 22:17:14 +00:00
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
} else if method.Function.ReturnTypePlain {
|
|
|
|
needsTypes = mod.getTypeImportsForResource(
|
|
|
|
method.Function.ReturnType, false, externalImports,
|
|
|
|
imports, seen, res) || needsTypes
|
2021-07-08 03:16:42 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
return needsTypes
|
|
|
|
case *schema.Function:
|
|
|
|
needsTypes := false
|
|
|
|
if member.Inputs != nil {
|
2021-09-23 17:12:27 +00:00
|
|
|
for _, p := range member.Inputs.Properties {
|
|
|
|
needsTypes = mod.getTypeImports(p.Type, false, externalImports, imports, seen) || needsTypes
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
if member.ReturnType != nil {
|
|
|
|
// for object return types that are defined inline,
|
|
|
|
// look through the properties to see if any of them need imports
|
|
|
|
if objectType, ok := member.ReturnType.(*schema.ObjectType); ok && member.InlineObjectAsReturnType {
|
|
|
|
for _, p := range objectType.Properties {
|
|
|
|
needsTypes = mod.getTypeImports(p.Type, false, externalImports, imports, seen) || needsTypes
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// all other cases mean we have a more generic type like a reference to other types
|
|
|
|
needsTypes = mod.getTypeImports(member.ReturnType, false, externalImports, imports, seen) || needsTypes
|
2021-09-23 17:12:27 +00:00
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
return needsTypes
|
|
|
|
case []*schema.Property:
|
|
|
|
needsTypes := false
|
|
|
|
for _, p := range member {
|
2021-01-30 00:52:00 +00:00
|
|
|
needsTypes = mod.getTypeImports(p.Type, false, externalImports, imports, seen) || needsTypes
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
return needsTypes
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
func (mod *modContext) genHeader(w io.Writer, imports []string, externalImports codegen.StringSet, importedTypes map[string]codegen.StringSet) {
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "// *** WARNING: this file was generated by %v. ***\n", mod.tool)
|
|
|
|
fmt.Fprintf(w, "// *** Do not edit by hand unless you're certain you know what you are doing! ***\n\n")
|
|
|
|
|
|
|
|
if len(imports) > 0 {
|
|
|
|
for _, i := range imports {
|
|
|
|
fmt.Fprintf(w, "%s\n", i)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
if externalImports.Any() {
|
|
|
|
for _, i := range externalImports.SortedValues() {
|
|
|
|
fmt.Fprintf(w, "%s\n", i)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
if len(importedTypes) > 0 {
|
|
|
|
var modules []string
|
|
|
|
for module := range importedTypes {
|
|
|
|
modules = append(modules, module)
|
|
|
|
}
|
|
|
|
sort.Strings(modules)
|
|
|
|
|
|
|
|
for _, module := range modules {
|
2022-11-09 12:52:28 +00:00
|
|
|
fmt.Fprintf(w, "import {")
|
2021-01-30 00:52:00 +00:00
|
|
|
for i, name := range importedTypes[module].SortedValues() {
|
2020-01-21 22:45:48 +00:00
|
|
|
if i > 0 {
|
|
|
|
fmt.Fprint(w, ", ")
|
|
|
|
}
|
|
|
|
fmt.Fprint(w, name)
|
|
|
|
}
|
2022-11-09 12:52:28 +00:00
|
|
|
fmt.Fprintf(w, "} from \"%s\";\n", module)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-04 21:51:21 +00:00
|
|
|
// configGetter returns the name of the config.get* method used for a configuration variable and the cast necessary
|
|
|
|
// for the result of the call, if any.
|
|
|
|
func (mod *modContext) configGetter(v *schema.Property) (string, string) {
|
2021-06-24 16:17:55 +00:00
|
|
|
typ := codegen.RequiredType(v)
|
|
|
|
|
|
|
|
if typ == schema.StringType {
|
2020-06-04 21:51:21 +00:00
|
|
|
return "get", ""
|
|
|
|
}
|
|
|
|
|
2021-06-24 16:17:55 +00:00
|
|
|
if tok, ok := typ.(*schema.TokenType); ok && tok.UnderlyingType == schema.StringType {
|
|
|
|
return "get", fmt.Sprintf("<%s>", mod.typeString(typ, false, nil))
|
2020-06-04 21:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Only try to parse a JSON object if the config isn't a straight string.
|
2021-06-24 16:17:55 +00:00
|
|
|
return fmt.Sprintf("getObject<%s>", mod.typeString(typ, false, nil)), ""
|
2020-06-04 21:51:21 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
func (mod *modContext) genConfig(w io.Writer, variables []*schema.Property) error {
|
2021-01-30 00:52:00 +00:00
|
|
|
externalImports, imports := codegen.NewStringSet(), map[string]codegen.StringSet{}
|
|
|
|
referencesNestedTypes := mod.getImports(variables, externalImports, imports)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2022-10-06 15:32:08 +00:00
|
|
|
mod.genHeader(w, mod.sdkImports(referencesNestedTypes, true), externalImports, imports)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2021-07-16 16:52:45 +00:00
|
|
|
fmt.Fprintf(w, "declare var exports: any;\n")
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
// Create a config bag for the variables to pull from.
|
2022-12-08 13:36:44 +00:00
|
|
|
fmt.Fprintf(w, "const __config = new pulumi.Config(\"%v\");\n", mod.pkg.Name())
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
|
|
|
|
// Emit an entry for all config variables.
|
|
|
|
for _, p := range variables {
|
2020-06-04 21:51:21 +00:00
|
|
|
getfunc, cast := mod.configGetter(p)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-02-06 17:29:06 +00:00
|
|
|
printComment(w, p.Comment, "", "")
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-06-04 21:51:21 +00:00
|
|
|
configFetch := fmt.Sprintf("%s__config.%s(\"%s\")", cast, getfunc, p.Name)
|
2020-06-05 17:11:18 +00:00
|
|
|
// TODO: handle ConstValues https://github.com/pulumi/pulumi/issues/4755
|
2020-01-21 22:45:48 +00:00
|
|
|
if p.DefaultValue != nil {
|
2021-06-24 16:17:55 +00:00
|
|
|
v, err := mod.getDefaultValue(p.DefaultValue, codegen.UnwrapType(p.Type))
|
2020-01-21 22:45:48 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-07-16 16:52:45 +00:00
|
|
|
configFetch += " ?? " + v
|
|
|
|
}
|
|
|
|
optType := codegen.OptionalType(p)
|
|
|
|
if p.DefaultValue != nil && p.DefaultValue.Value != nil {
|
|
|
|
optType = codegen.RequiredType(p)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-07-16 16:52:45 +00:00
|
|
|
fmt.Fprintf(w, "export declare const %s: %s;\n", p.Name, mod.typeString(optType, false, nil))
|
|
|
|
fmt.Fprintf(w, "Object.defineProperty(exports, %q, {\n", p.Name)
|
|
|
|
fmt.Fprintf(w, " get() {\n")
|
|
|
|
fmt.Fprintf(w, " return %s;\n", configFetch)
|
|
|
|
fmt.Fprintf(w, " },\n")
|
|
|
|
fmt.Fprintf(w, " enumerable: true,\n")
|
|
|
|
fmt.Fprintf(w, "});\n\n")
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-12-05 18:19:41 +00:00
|
|
|
func (mod *modContext) getRelativePath() string {
|
|
|
|
rel, err := filepath.Rel(mod.mod, "")
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "could not turn %q into a relative path", mod.mod)
|
2020-10-08 01:13:10 +00:00
|
|
|
return path.Dir(filepath.ToSlash(rel))
|
|
|
|
}
|
|
|
|
|
2022-10-06 15:32:08 +00:00
|
|
|
func (mod *modContext) sdkImports(nested, utilities bool) []string {
|
2022-12-05 18:19:41 +00:00
|
|
|
imports := []string{"import * as pulumi from \"@pulumi/pulumi\";"}
|
|
|
|
|
|
|
|
relRoot := mod.getRelativePath()
|
2020-01-21 22:45:48 +00:00
|
|
|
if nested {
|
2022-12-05 18:19:41 +00:00
|
|
|
imports = append(imports, []string{
|
|
|
|
fmt.Sprintf(`import * as inputs from "%s/types/input";`, relRoot),
|
|
|
|
fmt.Sprintf(`import * as outputs from "%s/types/output";`, relRoot),
|
|
|
|
}...)
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
def, err := mod.pkg.Definition()
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "error loading package definition for %q", mod.pkg.Name())
|
2022-12-08 13:36:44 +00:00
|
|
|
if def.Language["nodejs"].(NodePackageInfo).ContainsEnums {
|
2022-12-05 18:19:41 +00:00
|
|
|
code := `import * as enums from "%s/types/enums";`
|
2022-12-08 13:36:44 +00:00
|
|
|
if lookupNodePackageInfo(def).UseTypeOnlyReferences {
|
2022-12-05 18:19:41 +00:00
|
|
|
code = `import type * as enums from "%s/types/enums";`
|
|
|
|
}
|
|
|
|
imports = append(imports, fmt.Sprintf(code, relRoot))
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2022-12-05 18:19:41 +00:00
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
if utilities {
|
2022-12-05 18:19:41 +00:00
|
|
|
imports = append(imports, mod.utilitiesImport())
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return imports
|
|
|
|
}
|
|
|
|
|
2022-12-05 18:19:41 +00:00
|
|
|
func (mod *modContext) utilitiesImport() string {
|
|
|
|
relRoot := mod.getRelativePath()
|
2022-09-01 22:42:44 +00:00
|
|
|
return fmt.Sprintf("import * as utilities from \"%s/utilities\";", relRoot)
|
|
|
|
}
|
|
|
|
|
2022-12-05 18:19:41 +00:00
|
|
|
func (mod *modContext) genTypes() (string, string, error) {
|
|
|
|
externalImports, imports := codegen.NewStringSet(), map[string]codegen.StringSet{}
|
|
|
|
var hasDefaultObjects bool
|
2020-01-21 22:45:48 +00:00
|
|
|
for _, t := range mod.types {
|
2021-11-12 00:00:03 +00:00
|
|
|
if t.IsOverlay {
|
|
|
|
// This type is generated by the provider, so no further action is required.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
mod.getImports(t, externalImports, imports)
|
2022-12-05 18:19:41 +00:00
|
|
|
if codegen.IsProvideDefaultsFuncRequired(t) {
|
|
|
|
hasDefaultObjects = true
|
2022-11-09 12:52:28 +00:00
|
|
|
}
|
2022-11-09 03:21:40 +00:00
|
|
|
}
|
2022-12-05 18:19:41 +00:00
|
|
|
// Instantiating the default might require an environmental variable. This
|
|
|
|
// uses utilities.
|
|
|
|
if hasDefaultObjects {
|
|
|
|
externalImports.Add(fmt.Sprintf("import * as utilities from \"%s/utilities\";", mod.getRelativePath()))
|
2022-10-06 15:32:08 +00:00
|
|
|
}
|
2022-12-05 18:19:41 +00:00
|
|
|
|
|
|
|
inputs, outputs := &bytes.Buffer{}, &bytes.Buffer{}
|
|
|
|
mod.genHeader(inputs, mod.sdkImports(true, false), externalImports, imports)
|
|
|
|
mod.genHeader(outputs, mod.sdkImports(true, false), externalImports, imports)
|
|
|
|
|
|
|
|
// Build a namespace tree out of the types, then emit them.
|
|
|
|
namespaces := mod.getNamespaces()
|
|
|
|
if err := mod.genNamespace(inputs, namespaces[""], true, 0); err != nil {
|
|
|
|
return "", "", err
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
2022-12-05 18:19:41 +00:00
|
|
|
if err := mod.genNamespace(outputs, namespaces[""], false, 0); err != nil {
|
|
|
|
return "", "", err
|
2021-11-18 20:23:30 +00:00
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2022-12-05 18:19:41 +00:00
|
|
|
return inputs.String(), outputs.String(), nil
|
2020-08-01 01:29:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type namespace struct {
|
|
|
|
name string
|
|
|
|
types []*schema.ObjectType
|
2020-10-08 01:13:10 +00:00
|
|
|
enums []*schema.EnumType
|
2020-08-01 01:29:00 +00:00
|
|
|
children []*namespace
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-08-01 01:29:00 +00:00
|
|
|
func (mod *modContext) getNamespaces() map[string]*namespace {
|
2020-01-21 22:45:48 +00:00
|
|
|
namespaces := map[string]*namespace{}
|
|
|
|
var getNamespace func(string) *namespace
|
|
|
|
getNamespace = func(mod string) *namespace {
|
|
|
|
ns, ok := namespaces[mod]
|
|
|
|
if !ok {
|
|
|
|
name := mod
|
|
|
|
if mod != "" {
|
|
|
|
name = path.Base(mod)
|
|
|
|
}
|
|
|
|
|
|
|
|
ns = &namespace{name: name}
|
|
|
|
if mod != "" {
|
|
|
|
parentMod := path.Dir(mod)
|
|
|
|
if parentMod == "." {
|
|
|
|
parentMod = ""
|
|
|
|
}
|
|
|
|
parent := getNamespace(parentMod)
|
|
|
|
parent.children = append(parent.children, ns)
|
|
|
|
}
|
|
|
|
|
|
|
|
namespaces[mod] = ns
|
|
|
|
}
|
|
|
|
return ns
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, t := range mod.types {
|
2021-11-12 00:00:03 +00:00
|
|
|
if t.IsOverlay {
|
|
|
|
// This type is generated by the provider, so no further action is required.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-06-05 17:11:18 +00:00
|
|
|
modName := mod.pkg.TokenToModule(t.Token)
|
|
|
|
if override, ok := mod.modToPkg[modName]; ok {
|
|
|
|
modName = override
|
|
|
|
}
|
|
|
|
ns := getNamespace(modName)
|
2020-01-21 22:45:48 +00:00
|
|
|
ns.types = append(ns.types, t)
|
|
|
|
}
|
|
|
|
|
2020-08-01 01:29:00 +00:00
|
|
|
return namespaces
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2021-11-18 20:23:30 +00:00
|
|
|
func (mod *modContext) genNamespace(w io.Writer, ns *namespace, input bool, level int) error {
|
2020-08-01 01:29:00 +00:00
|
|
|
indent := strings.Repeat(" ", level)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2022-07-29 15:07:27 +00:00
|
|
|
// We generate the input and output namespaces when there are enums, regardless of if
|
|
|
|
// they are empty.
|
|
|
|
if ns == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-08-01 01:29:00 +00:00
|
|
|
sort.Slice(ns.types, func(i, j int) bool {
|
2022-09-28 14:46:44 +00:00
|
|
|
return objectTypeLessThan(ns.types[i], ns.types[j])
|
2020-08-01 01:29:00 +00:00
|
|
|
})
|
2020-10-08 01:13:10 +00:00
|
|
|
sort.Slice(ns.enums, func(i, j int) bool {
|
|
|
|
return tokenToName(ns.enums[i].Token) < tokenToName(ns.enums[j].Token)
|
|
|
|
})
|
2020-08-01 01:29:00 +00:00
|
|
|
for i, t := range ns.types {
|
|
|
|
if input && mod.details(t).inputType || !input && mod.details(t).outputType {
|
2021-11-18 20:23:30 +00:00
|
|
|
if err := mod.genType(w, t, input, level); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-01 01:29:00 +00:00
|
|
|
if i != len(ns.types)-1 {
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-01 01:29:00 +00:00
|
|
|
sort.Slice(ns.children, func(i, j int) bool {
|
|
|
|
return ns.children[i].name < ns.children[j].name
|
|
|
|
})
|
2020-08-27 21:50:34 +00:00
|
|
|
for i, child := range ns.children {
|
|
|
|
fmt.Fprintf(w, "%sexport namespace %s {\n", indent, child.name)
|
2021-11-18 20:23:30 +00:00
|
|
|
if err := mod.genNamespace(w, child, input, level+1); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-01 01:29:00 +00:00
|
|
|
fmt.Fprintf(w, "%s}\n", indent)
|
|
|
|
if i != len(ns.children)-1 {
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
}
|
2021-11-18 20:23:30 +00:00
|
|
|
return nil
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2022-05-02 18:16:21 +00:00
|
|
|
func enumMemberName(typeName string, member *schema.Enum) (string, error) {
|
|
|
|
if member.Name == "" {
|
|
|
|
member.Name = fmt.Sprintf("%v", member.Value)
|
2022-04-18 09:03:42 +00:00
|
|
|
}
|
2022-05-02 18:16:21 +00:00
|
|
|
return makeSafeEnumName(member.Name, typeName)
|
2022-04-18 09:03:42 +00:00
|
|
|
}
|
|
|
|
|
2020-11-09 19:33:22 +00:00
|
|
|
func (mod *modContext) genEnum(w io.Writer, enum *schema.EnumType) error {
|
2020-10-09 15:27:01 +00:00
|
|
|
indent := " "
|
2020-10-08 01:13:10 +00:00
|
|
|
enumName := tokenToName(enum.Token)
|
2020-10-09 15:27:01 +00:00
|
|
|
fmt.Fprintf(w, "export const %s = {\n", enumName)
|
2020-10-08 01:13:10 +00:00
|
|
|
for _, e := range enum.Elements {
|
2020-11-09 19:33:22 +00:00
|
|
|
// If the enum doesn't have a name, set the value as the name.
|
2022-05-02 18:16:21 +00:00
|
|
|
safeName, err := enumMemberName(enumName, e)
|
2020-11-09 19:33:22 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
e.Name = safeName
|
|
|
|
|
2020-10-09 15:27:01 +00:00
|
|
|
printComment(w, e.Comment, e.DeprecationMessage, indent)
|
|
|
|
fmt.Fprintf(w, "%s%s: ", indent, e.Name)
|
2020-10-08 01:13:10 +00:00
|
|
|
if val, ok := e.Value.(string); ok {
|
2020-10-09 15:27:01 +00:00
|
|
|
fmt.Fprintf(w, "%q,\n", val)
|
2020-10-08 01:13:10 +00:00
|
|
|
} else {
|
2020-10-09 15:27:01 +00:00
|
|
|
fmt.Fprintf(w, "%v,\n", e.Value)
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
|
|
|
}
|
2020-10-09 15:27:01 +00:00
|
|
|
fmt.Fprintf(w, "} as const;\n")
|
2020-10-08 01:13:10 +00:00
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
|
|
|
|
printComment(w, enum.Comment, "", "")
|
2020-10-09 15:27:01 +00:00
|
|
|
fmt.Fprintf(w, "export type %[1]s = (typeof %[1]s)[keyof typeof %[1]s];\n", enumName)
|
2020-11-09 19:33:22 +00:00
|
|
|
return nil
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-06-01 23:24:21 +00:00
|
|
|
func (mod *modContext) isReservedSourceFileName(name string) bool {
|
|
|
|
switch name {
|
|
|
|
case "index.ts":
|
|
|
|
return true
|
|
|
|
case "input.ts", "output.ts":
|
|
|
|
return len(mod.types) != 0
|
|
|
|
case "utilities.ts":
|
|
|
|
return mod.mod == ""
|
|
|
|
case "vars.ts":
|
2022-12-08 13:36:44 +00:00
|
|
|
config, err := mod.pkg.Config()
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "failed to get config for package %q", mod.pkg.Name())
|
2022-12-08 13:36:44 +00:00
|
|
|
return len(config) > 0
|
2020-06-01 23:24:21 +00:00
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-09 19:49:59 +00:00
|
|
|
func (mod *modContext) gen(fs codegen.Fs) error {
|
2023-06-28 16:02:04 +00:00
|
|
|
files := slice.Prealloc[fileInfo](len(mod.extraSourceFiles))
|
2022-09-01 22:42:44 +00:00
|
|
|
for _, path := range mod.extraSourceFiles {
|
|
|
|
files = append(files, fileInfo{
|
|
|
|
fileType: otherFileType,
|
|
|
|
pathToNodeModule: path,
|
|
|
|
})
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-07-14 17:58:29 +00:00
|
|
|
modDir := strings.ToLower(mod.mod)
|
|
|
|
|
2022-09-01 22:42:44 +00:00
|
|
|
addFile := func(fileType fileType, name, contents string) {
|
2020-07-14 17:58:29 +00:00
|
|
|
p := path.Join(modDir, name)
|
2022-09-01 22:42:44 +00:00
|
|
|
files = append(files, fileInfo{
|
|
|
|
fileType: fileType,
|
|
|
|
pathToNodeModule: p,
|
|
|
|
})
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add(p, []byte(contents))
|
2022-09-01 22:42:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
addResourceFile := func(resourceFileInfo resourceFileInfo, name, contents string) {
|
|
|
|
p := path.Join(modDir, name)
|
|
|
|
files = append(files, fileInfo{
|
|
|
|
fileType: resourceFileType,
|
|
|
|
resourceFileInfo: resourceFileInfo,
|
|
|
|
pathToNodeModule: p,
|
|
|
|
})
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add(p, []byte(contents))
|
2022-09-01 22:42:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
addFunctionFile := func(info functionFileInfo, name, contents string) {
|
|
|
|
p := path.Join(modDir, name)
|
|
|
|
files = append(files, fileInfo{
|
|
|
|
fileType: functionFileType,
|
|
|
|
functionFileInfo: info,
|
|
|
|
pathToNodeModule: p,
|
|
|
|
})
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add(p, []byte(contents))
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
def, err := mod.pkg.Definition()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-06-05 17:11:18 +00:00
|
|
|
// Utilities, config, readme
|
|
|
|
switch mod.mod {
|
|
|
|
case "":
|
|
|
|
buffer := &bytes.Buffer{}
|
2021-01-30 00:52:00 +00:00
|
|
|
mod.genHeader(buffer, nil, nil, nil)
|
2022-12-08 13:36:44 +00:00
|
|
|
err := mod.genUtilitiesFile(buffer)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add(path.Join(modDir, "utilities.ts"), buffer.Bytes())
|
2020-06-05 17:11:18 +00:00
|
|
|
|
|
|
|
// Ensure that the top-level (provider) module directory contains a README.md file.
|
2022-12-08 13:36:44 +00:00
|
|
|
readme := def.Language["nodejs"].(NodePackageInfo).Readme
|
2020-05-29 19:36:16 +00:00
|
|
|
if readme == "" {
|
2022-12-08 13:36:44 +00:00
|
|
|
readme = def.Description
|
2020-05-29 19:36:16 +00:00
|
|
|
if readme != "" && readme[len(readme)-1] != '\n' {
|
2020-05-13 17:55:37 +00:00
|
|
|
readme += "\n"
|
|
|
|
}
|
2022-12-08 13:36:44 +00:00
|
|
|
if def.Attribution != "" {
|
2020-05-29 19:36:16 +00:00
|
|
|
if len(readme) != 0 {
|
|
|
|
readme += "\n"
|
|
|
|
}
|
2022-12-08 13:36:44 +00:00
|
|
|
readme += def.Attribution
|
2020-05-29 19:36:16 +00:00
|
|
|
}
|
2020-05-13 17:55:37 +00:00
|
|
|
}
|
2020-05-29 19:36:16 +00:00
|
|
|
if readme != "" && readme[len(readme)-1] != '\n' {
|
|
|
|
readme += "\n"
|
|
|
|
}
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add(path.Join(modDir, "README.md"), []byte(readme))
|
2020-01-21 22:45:48 +00:00
|
|
|
case "config":
|
2022-12-08 13:36:44 +00:00
|
|
|
if len(def.Config) > 0 {
|
2020-01-21 22:45:48 +00:00
|
|
|
buffer := &bytes.Buffer{}
|
2022-12-08 13:36:44 +00:00
|
|
|
if err := mod.genConfig(buffer, def.Config); err != nil {
|
2020-01-21 22:45:48 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
addFile(otherFileType, "vars.ts", buffer.String())
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Resources
|
|
|
|
for _, r := range mod.resources {
|
2021-11-12 00:00:03 +00:00
|
|
|
if r.IsOverlay {
|
|
|
|
// This resource code is generated by the provider, so no further action is required.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
externalImports, imports := codegen.NewStringSet(), map[string]codegen.StringSet{}
|
2021-07-08 03:16:42 +00:00
|
|
|
referencesNestedTypes := mod.getImportsForResource(r, externalImports, imports, r)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
buffer := &bytes.Buffer{}
|
2022-10-06 15:32:08 +00:00
|
|
|
mod.genHeader(buffer, mod.sdkImports(referencesNestedTypes, true), externalImports, imports)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2022-09-01 22:42:44 +00:00
|
|
|
rinfo, err := mod.genResource(buffer, r)
|
|
|
|
if err != nil {
|
2020-01-21 22:45:48 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-12-02 21:45:25 +00:00
|
|
|
fileName := mod.resourceFileName(r)
|
2022-09-01 22:42:44 +00:00
|
|
|
addResourceFile(rinfo, fileName, buffer.String())
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Functions
|
|
|
|
for _, f := range mod.functions {
|
2021-11-12 00:00:03 +00:00
|
|
|
if f.IsOverlay {
|
|
|
|
// This function code is generated by the provider, so no further action is required.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-01-30 00:52:00 +00:00
|
|
|
externalImports, imports := codegen.NewStringSet(), map[string]codegen.StringSet{}
|
|
|
|
referencesNestedTypes := mod.getImports(f, externalImports, imports)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
buffer := &bytes.Buffer{}
|
2022-10-06 15:32:08 +00:00
|
|
|
mod.genHeader(buffer, mod.sdkImports(referencesNestedTypes, true), externalImports, imports)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2022-09-01 22:42:44 +00:00
|
|
|
funInfo, err := mod.genFunction(buffer, f)
|
|
|
|
if err != nil {
|
2021-11-18 20:23:30 +00:00
|
|
|
return err
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2020-06-01 23:24:21 +00:00
|
|
|
fileName := camel(tokenToName(f.Token)) + ".ts"
|
|
|
|
if mod.isReservedSourceFileName(fileName) {
|
|
|
|
fileName = camel(tokenToName(f.Token)) + "_.ts"
|
|
|
|
}
|
2022-09-01 22:42:44 +00:00
|
|
|
addFunctionFile(funInfo, fileName, buffer.String())
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2020-10-08 01:13:10 +00:00
|
|
|
if mod.hasEnums() {
|
|
|
|
buffer := &bytes.Buffer{}
|
2021-01-30 00:52:00 +00:00
|
|
|
mod.genHeader(buffer, []string{}, nil, nil)
|
2020-10-08 01:13:10 +00:00
|
|
|
|
2020-11-09 19:33:22 +00:00
|
|
|
err := mod.genEnums(buffer, mod.enums)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-10-08 01:13:10 +00:00
|
|
|
|
|
|
|
var fileName string
|
|
|
|
if modDir == "" {
|
|
|
|
fileName = "index.ts"
|
|
|
|
} else {
|
|
|
|
fileName = path.Join(modDir, "index.ts")
|
|
|
|
}
|
|
|
|
fileName = path.Join("types", "enums", fileName)
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add(fileName, buffer.Bytes())
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
// Nested types
|
2022-07-29 15:07:27 +00:00
|
|
|
// Importing enums always imports inputs and outputs, so if we have enums we generate inputs and outputs
|
2022-12-08 13:36:44 +00:00
|
|
|
if len(mod.types) > 0 || (def.Language["nodejs"].(NodePackageInfo).ContainsEnums && mod.mod == "types") {
|
2022-12-05 18:19:41 +00:00
|
|
|
input, output, err := mod.genTypes()
|
2021-11-18 20:23:30 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-12-05 18:19:41 +00:00
|
|
|
fs.Add(path.Join(modDir, "input.ts"), []byte(input))
|
|
|
|
fs.Add(path.Join(modDir, "output.ts"), []byte(output))
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Index
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add(path.Join(modDir, "index.ts"), []byte(mod.genIndex(files)))
|
2020-01-21 22:45:48 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-10-08 01:13:10 +00:00
|
|
|
func getChildMod(modName string) string {
|
|
|
|
child := strings.ToLower(modName)
|
|
|
|
// Extract version suffix from child modules. Nested versions will have their own index.ts file.
|
|
|
|
// Example: apps/v1beta1 -> v1beta1
|
|
|
|
parts := strings.SplitN(child, "/", 2)
|
|
|
|
if len(parts) == 2 {
|
|
|
|
child = parts[1]
|
|
|
|
}
|
|
|
|
return child
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
// genIndex emits an index module, optionally re-exporting other members or submodules.
|
2022-09-01 22:42:44 +00:00
|
|
|
func (mod *modContext) genIndex(exports []fileInfo) string {
|
|
|
|
children := codegen.NewStringSet()
|
|
|
|
|
|
|
|
for _, mod := range mod.children {
|
|
|
|
child := getChildMod(mod.mod)
|
|
|
|
children.Add(child)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(mod.types) > 0 {
|
|
|
|
children.Add("input")
|
|
|
|
children.Add("output")
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
w := &bytes.Buffer{}
|
2020-12-02 21:45:25 +00:00
|
|
|
|
|
|
|
var imports []string
|
|
|
|
// Include the SDK import if we'll be registering module resources.
|
|
|
|
if len(mod.resources) != 0 {
|
2022-12-05 18:19:41 +00:00
|
|
|
imports = mod.sdkImports(false /*nested*/, true /*utilities*/)
|
2022-09-01 22:42:44 +00:00
|
|
|
} else if len(children) > 0 || len(mod.functions) > 0 {
|
|
|
|
// Even if there are no resources, exports ref utilities.
|
2022-12-05 18:19:41 +00:00
|
|
|
imports = append(imports, mod.utilitiesImport())
|
2020-12-02 21:45:25 +00:00
|
|
|
}
|
2021-01-30 00:52:00 +00:00
|
|
|
mod.genHeader(w, imports, nil, nil)
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// Export anything flatly that is a direct export rather than sub-module.
|
|
|
|
if len(exports) > 0 {
|
|
|
|
fmt.Fprintf(w, "// Export members:\n")
|
2022-09-01 22:42:44 +00:00
|
|
|
sort.SliceStable(exports, func(i, j int) bool {
|
|
|
|
return exports[i].pathToNodeModule < exports[j].pathToNodeModule
|
|
|
|
})
|
|
|
|
|
|
|
|
ll := newLazyLoadGen()
|
|
|
|
modDir := strings.ToLower(mod.mod)
|
2020-01-21 22:45:48 +00:00
|
|
|
for _, exp := range exports {
|
2022-09-01 22:42:44 +00:00
|
|
|
rel, err := filepath.Rel(modDir, exp.pathToNodeModule)
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "cannot make %q relative to %q", exp.pathToNodeModule, modDir)
|
2020-01-21 22:45:48 +00:00
|
|
|
if path.Base(rel) == "." {
|
|
|
|
rel = path.Dir(rel)
|
|
|
|
}
|
2023-12-12 12:19:42 +00:00
|
|
|
importPath := "./" + strings.TrimSuffix(rel, ".ts")
|
2022-09-01 22:42:44 +00:00
|
|
|
ll.genReexport(w, exp, importPath)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
def, err := mod.pkg.Definition()
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "error loading package definition for %q", mod.pkg.Name())
|
2022-12-08 13:36:44 +00:00
|
|
|
|
|
|
|
info, _ := def.Language["nodejs"].(NodePackageInfo)
|
2020-10-08 01:13:10 +00:00
|
|
|
if info.ContainsEnums {
|
|
|
|
if mod.mod == "types" {
|
|
|
|
children.Add("enums")
|
2022-07-29 15:07:27 +00:00
|
|
|
// input & output might be empty, but they will be imported with enums, so we
|
|
|
|
// need to have them.
|
|
|
|
children.Add("input")
|
|
|
|
children.Add("output")
|
2020-10-08 01:13:10 +00:00
|
|
|
} else if len(mod.enums) > 0 {
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
fmt.Fprintf(w, "// Export enums:\n")
|
2022-10-06 15:32:08 +00:00
|
|
|
rel := mod.getRelativePath()
|
2020-10-08 01:13:10 +00:00
|
|
|
var filePath string
|
|
|
|
if mod.mod == "" {
|
|
|
|
filePath = ""
|
|
|
|
} else {
|
2023-12-12 12:19:42 +00:00
|
|
|
filePath = "/" + mod.mod
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "export * from \"%s/types/enums%s\";\n", rel, filePath)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-02 21:45:25 +00:00
|
|
|
// If there are submodules, export them.
|
2020-01-21 22:45:48 +00:00
|
|
|
if len(children) > 0 {
|
|
|
|
if len(exports) > 0 {
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "// Export sub-modules:\n")
|
|
|
|
|
2021-07-14 22:12:15 +00:00
|
|
|
directChildren := codegen.NewStringSet()
|
|
|
|
for _, child := range children.SortedValues() {
|
|
|
|
directChildren.Add(path.Base(child))
|
|
|
|
}
|
|
|
|
sorted := directChildren.SortedValues()
|
|
|
|
|
2020-06-05 17:11:18 +00:00
|
|
|
for _, mod := range sorted {
|
2020-01-21 22:45:48 +00:00
|
|
|
fmt.Fprintf(w, "import * as %[1]s from \"./%[1]s\";\n", mod)
|
|
|
|
}
|
|
|
|
|
2020-11-06 17:29:49 +00:00
|
|
|
printExports(w, sorted)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2020-12-02 21:45:25 +00:00
|
|
|
// If there are resources in this module, register the module with the runtime.
|
|
|
|
if len(mod.resources) != 0 {
|
|
|
|
mod.genResourceModule(w)
|
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
return w.String()
|
|
|
|
}
|
|
|
|
|
2020-12-02 21:45:25 +00:00
|
|
|
// genResourceModule generates a ResourceModule definition and the code to register an instance thereof with the
|
|
|
|
// Pulumi runtime. The generated ResourceModule supports the deserialization of resource references into fully-
|
|
|
|
// hydrated Resource instances. If this is the root module, this function also generates a ResourcePackage
|
|
|
|
// definition and its registration to support rehydrating providers.
|
|
|
|
func (mod *modContext) genResourceModule(w io.Writer) {
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.Assertf(len(mod.resources) != 0, "module %v has no resources", mod.mod)
|
2020-12-02 21:45:25 +00:00
|
|
|
|
|
|
|
// Check for provider-only modules.
|
|
|
|
var provider *schema.Resource
|
|
|
|
if providerOnly := len(mod.resources) == 1 && mod.resources[0].IsProvider; providerOnly {
|
|
|
|
provider = mod.resources[0]
|
|
|
|
} else {
|
2022-09-01 22:42:44 +00:00
|
|
|
registrations := codegen.StringSet{}
|
2020-12-02 21:45:25 +00:00
|
|
|
for _, r := range mod.resources {
|
2021-11-12 00:00:03 +00:00
|
|
|
if r.IsOverlay {
|
|
|
|
// This resource code is generated by the provider, so no further action is required.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-12-02 21:45:25 +00:00
|
|
|
if r.IsProvider {
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.Assertf(provider == nil, "module %v has multiple providers", mod.mod)
|
2020-12-02 21:45:25 +00:00
|
|
|
provider = r
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
registrations.Add(schema.TokenToRuntimeModule(r.Token))
|
2020-12-02 21:45:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, "\nconst _module = {\n")
|
|
|
|
fmt.Fprintf(w, " version: utilities.getVersion(),\n")
|
|
|
|
fmt.Fprintf(w, " construct: (name: string, type: string, urn: string): pulumi.Resource => {\n")
|
|
|
|
fmt.Fprintf(w, " switch (type) {\n")
|
|
|
|
|
|
|
|
for _, r := range mod.resources {
|
2021-11-12 00:00:03 +00:00
|
|
|
if r.IsOverlay {
|
|
|
|
// This resource code is generated by the provider, so no further action is required.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2020-12-02 21:45:25 +00:00
|
|
|
if r.IsProvider {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, " case \"%v\":\n", r.Token)
|
|
|
|
fmt.Fprintf(w, " return new %v(name, <any>undefined, { urn })\n", resourceName(r))
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, " default:\n")
|
|
|
|
fmt.Fprintf(w, " throw new Error(`unknown resource type ${type}`);\n")
|
|
|
|
fmt.Fprintf(w, " }\n")
|
|
|
|
fmt.Fprintf(w, " },\n")
|
|
|
|
fmt.Fprintf(w, "};\n")
|
|
|
|
for _, name := range registrations.SortedValues() {
|
2022-12-08 13:36:44 +00:00
|
|
|
fmt.Fprintf(w, "pulumi.runtime.registerResourceModule(\"%v\", \"%v\", _module)\n", mod.pkg.Name(), name)
|
2020-12-02 21:45:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if provider != nil {
|
2022-12-08 13:36:44 +00:00
|
|
|
fmt.Fprintf(w, "pulumi.runtime.registerResourcePackage(\"%v\", {\n", mod.pkg.Name())
|
2020-12-02 21:45:25 +00:00
|
|
|
fmt.Fprintf(w, " version: utilities.getVersion(),\n")
|
|
|
|
fmt.Fprintf(w, " constructProvider: (name: string, type: string, urn: string): pulumi.ProviderResource => {\n")
|
|
|
|
fmt.Fprintf(w, " if (type !== \"%v\") {\n", provider.Token)
|
|
|
|
fmt.Fprintf(w, " throw new Error(`unknown provider type ${type}`);\n")
|
|
|
|
fmt.Fprintf(w, " }\n")
|
|
|
|
fmt.Fprintf(w, " return new Provider(name, <any>undefined, { urn });\n")
|
|
|
|
fmt.Fprintf(w, " },\n")
|
|
|
|
fmt.Fprintf(w, "});\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-06 17:29:49 +00:00
|
|
|
func printExports(w io.Writer, exports []string) {
|
|
|
|
fmt.Fprintf(w, "\n")
|
|
|
|
fmt.Fprintf(w, "export {\n")
|
|
|
|
for _, mod := range exports {
|
|
|
|
fmt.Fprintf(w, " %s,\n", mod)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, "};\n")
|
|
|
|
}
|
|
|
|
|
2020-10-08 01:13:10 +00:00
|
|
|
func (mod *modContext) hasEnums() bool {
|
|
|
|
if mod.mod == "types" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if len(mod.enums) > 0 {
|
|
|
|
return true
|
|
|
|
}
|
2022-07-29 15:07:27 +00:00
|
|
|
for _, mod := range mod.children {
|
|
|
|
if mod.hasEnums() {
|
|
|
|
return true
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2020-11-09 19:33:22 +00:00
|
|
|
func (mod *modContext) genEnums(buffer *bytes.Buffer, enums []*schema.EnumType) error {
|
2020-10-08 01:13:10 +00:00
|
|
|
if len(mod.children) > 0 {
|
|
|
|
children := codegen.NewStringSet()
|
|
|
|
|
|
|
|
for _, mod := range mod.children {
|
|
|
|
child := getChildMod(mod.mod)
|
|
|
|
if mod.hasEnums() {
|
|
|
|
children.Add(child)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(children) > 0 {
|
|
|
|
fmt.Fprintf(buffer, "// Export sub-modules:\n")
|
|
|
|
|
2021-07-14 22:12:15 +00:00
|
|
|
directChildren := codegen.NewStringSet()
|
|
|
|
for _, child := range children.SortedValues() {
|
|
|
|
directChildren.Add(path.Base(child))
|
|
|
|
}
|
|
|
|
sorted := directChildren.SortedValues()
|
|
|
|
|
2020-10-08 01:13:10 +00:00
|
|
|
for _, mod := range sorted {
|
|
|
|
fmt.Fprintf(buffer, "import * as %[1]s from \"./%[1]s\";\n", mod)
|
|
|
|
}
|
2020-11-06 17:29:49 +00:00
|
|
|
printExports(buffer, sorted)
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(enums) > 0 {
|
|
|
|
fmt.Fprintf(buffer, "\n")
|
|
|
|
for i, enum := range enums {
|
2020-11-09 19:33:22 +00:00
|
|
|
err := mod.genEnum(buffer, enum)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-10-08 01:13:10 +00:00
|
|
|
if i != len(enums)-1 {
|
|
|
|
fmt.Fprintf(buffer, "\n")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-09 19:33:22 +00:00
|
|
|
return nil
|
2020-10-08 01:13:10 +00:00
|
|
|
}
|
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
// genPackageMetadata generates all the non-code metadata required by a Pulumi package.
|
2024-03-26 13:10:34 +00:00
|
|
|
func genPackageMetadata(pkg *schema.Package, info NodePackageInfo, fs codegen.Fs, localDependencies map[string]string) error {
|
2022-01-19 22:21:09 +00:00
|
|
|
// The generator already emitted Pulumi.yaml, so that leaves three more files to write out:
|
2020-01-21 22:45:48 +00:00
|
|
|
// 1) package.json: minimal NPM package metadata
|
|
|
|
// 2) tsconfig.json: instructions for TypeScript compilation
|
2024-03-26 13:10:34 +00:00
|
|
|
packageJSON, err := genNPMPackageMetadata(pkg, info, localDependencies)
|
Add SupportPack to schemas to write out in the new style (#15713)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This adds a new flag to the schema metadata to tell codegen to use the
new proposed style of SDKs where we fill in versions and write go.mods
etc.
I've reworked pack to operate on packages assuming they're in this new
style. That is pack no longer has the responsibility to fill in any
version information.
This updates python and node codegen to write out SDKs in this new
style, and fixes their core libraries to still be buildable via pack.
There are two approaches to fixing those, I've chosen option 1 below but
could pretty easily rework for option 2.
1) Write the version information directly to the SDKs at the same time
as we edit the .version file. To simplify this I've added a new
'set-version.py' script that takes a version string an writes it to all
the relevant places (.version, package.json, etc).
2) Write "pack" in the language host to search up the directory tree for
the ".version" file and then fill in the version information as we we're
doing before with envvar tricks and copying and editing package.json.
I think 1 is simpler long term, but does force some amount of cleanup in
unrelated bits of the system right now (release makefiles need a small
edit). 2 is much more localised but keeps this complexity that
sdk/nodejs sdk/python aren't actually valid source modules.
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [x] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-03-22 09:25:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
fs.Add("package.json", []byte(packageJSON))
|
2022-11-09 19:49:59 +00:00
|
|
|
fs.Add("tsconfig.json", []byte(genTypeScriptProjectFile(info, fs)))
|
2022-01-19 22:21:09 +00:00
|
|
|
return nil
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type npmPackage struct {
|
2022-05-24 19:28:06 +00:00
|
|
|
Name string `json:"name"`
|
|
|
|
Version string `json:"version"`
|
|
|
|
Description string `json:"description,omitempty"`
|
|
|
|
Keywords []string `json:"keywords,omitempty"`
|
|
|
|
Homepage string `json:"homepage,omitempty"`
|
|
|
|
Repository string `json:"repository,omitempty"`
|
|
|
|
License string `json:"license,omitempty"`
|
|
|
|
Scripts map[string]string `json:"scripts,omitempty"`
|
|
|
|
Dependencies map[string]string `json:"dependencies,omitempty"`
|
|
|
|
DevDependencies map[string]string `json:"devDependencies,omitempty"`
|
|
|
|
PeerDependencies map[string]string `json:"peerDependencies,omitempty"`
|
|
|
|
Resolutions map[string]string `json:"resolutions,omitempty"`
|
|
|
|
Pulumi plugin.PulumiPluginJSON `json:"pulumi,omitempty"`
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2024-03-26 13:10:34 +00:00
|
|
|
func genNPMPackageMetadata(pkg *schema.Package, info NodePackageInfo, localDependencies map[string]string) (string, error) {
|
2020-01-21 22:45:48 +00:00
|
|
|
packageName := info.PackageName
|
|
|
|
if packageName == "" {
|
2023-12-12 12:19:42 +00:00
|
|
|
packageName = "@pulumi/" + pkg.Name
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
devDependencies := map[string]string{}
|
|
|
|
if info.TypeScriptVersion != "" {
|
|
|
|
devDependencies["typescript"] = info.TypeScriptVersion
|
2021-07-16 16:52:45 +00:00
|
|
|
} else {
|
2022-11-09 22:04:48 +00:00
|
|
|
devDependencies["typescript"] = MinimumTypescriptVersion
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2022-11-09 22:04:48 +00:00
|
|
|
devDependencies["@types/node"] = MinimumNodeTypesVersion
|
2020-01-21 22:45:48 +00:00
|
|
|
|
2022-02-03 16:07:13 +00:00
|
|
|
version := "${VERSION}"
|
2023-08-03 17:04:54 +00:00
|
|
|
pluginVersion := ""
|
|
|
|
if pkg.Version != nil && info.RespectSchemaVersion {
|
2022-02-03 16:07:13 +00:00
|
|
|
version = pkg.Version.String()
|
|
|
|
pluginVersion = version
|
|
|
|
}
|
Add SupportPack to schemas to write out in the new style (#15713)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This adds a new flag to the schema metadata to tell codegen to use the
new proposed style of SDKs where we fill in versions and write go.mods
etc.
I've reworked pack to operate on packages assuming they're in this new
style. That is pack no longer has the responsibility to fill in any
version information.
This updates python and node codegen to write out SDKs in this new
style, and fixes their core libraries to still be buildable via pack.
There are two approaches to fixing those, I've chosen option 1 below but
could pretty easily rework for option 2.
1) Write the version information directly to the SDKs at the same time
as we edit the .version file. To simplify this I've added a new
'set-version.py' script that takes a version string an writes it to all
the relevant places (.version, package.json, etc).
2) Write "pack" in the language host to search up the directory tree for
the ".version" file and then fill in the version information as we we're
doing before with envvar tricks and copying and editing package.json.
I think 1 is simpler long term, but does force some amount of cleanup in
unrelated bits of the system right now (release makefiles need a small
edit). 2 is much more localised but keeps this complexity that
sdk/nodejs sdk/python aren't actually valid source modules.
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [x] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-03-22 09:25:46 +00:00
|
|
|
if pkg.SupportPack {
|
|
|
|
if pkg.Version == nil {
|
|
|
|
return "", errors.New("package version is required")
|
|
|
|
}
|
|
|
|
pluginVersion = pkg.Version.String()
|
|
|
|
version = pluginVersion
|
|
|
|
}
|
2022-02-03 16:07:13 +00:00
|
|
|
|
2020-01-21 22:45:48 +00:00
|
|
|
// Create info that will get serialized into an NPM package.json.
|
|
|
|
npminfo := npmPackage{
|
|
|
|
Name: packageName,
|
2022-02-03 16:07:13 +00:00
|
|
|
Version: version,
|
2020-01-21 22:45:48 +00:00
|
|
|
Description: info.PackageDescription,
|
|
|
|
Keywords: pkg.Keywords,
|
|
|
|
Homepage: pkg.Homepage,
|
|
|
|
Repository: pkg.Repository,
|
|
|
|
License: pkg.License,
|
|
|
|
Scripts: map[string]string{
|
2023-08-30 08:05:34 +00:00
|
|
|
"build": "tsc",
|
2020-01-21 22:45:48 +00:00
|
|
|
},
|
|
|
|
DevDependencies: devDependencies,
|
2022-05-24 19:28:06 +00:00
|
|
|
Pulumi: plugin.PulumiPluginJSON{
|
|
|
|
Resource: true,
|
|
|
|
Server: pkg.PluginDownloadURL,
|
2023-08-03 17:04:54 +00:00
|
|
|
Name: pkg.Name,
|
2022-05-24 19:28:06 +00:00
|
|
|
Version: pluginVersion,
|
2020-01-21 22:45:48 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the overlay dependencies, if any.
|
|
|
|
for depk, depv := range info.Dependencies {
|
|
|
|
if npminfo.Dependencies == nil {
|
|
|
|
npminfo.Dependencies = make(map[string]string)
|
|
|
|
}
|
2024-03-26 13:10:34 +00:00
|
|
|
if path, ok := localDependencies[depk]; ok {
|
|
|
|
npminfo.Dependencies[depk] = path
|
|
|
|
} else {
|
|
|
|
npminfo.Dependencies[depk] = depv
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
for depk, depv := range info.DevDependencies {
|
|
|
|
if npminfo.DevDependencies == nil {
|
|
|
|
npminfo.DevDependencies = make(map[string]string)
|
|
|
|
}
|
|
|
|
npminfo.DevDependencies[depk] = depv
|
|
|
|
}
|
|
|
|
for depk, depv := range info.PeerDependencies {
|
|
|
|
if npminfo.PeerDependencies == nil {
|
|
|
|
npminfo.PeerDependencies = make(map[string]string)
|
|
|
|
}
|
|
|
|
npminfo.PeerDependencies[depk] = depv
|
|
|
|
}
|
2020-05-02 21:17:31 +00:00
|
|
|
for resk, resv := range info.Resolutions {
|
|
|
|
if npminfo.Resolutions == nil {
|
|
|
|
npminfo.Resolutions = make(map[string]string)
|
|
|
|
}
|
|
|
|
npminfo.Resolutions[resk] = resv
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// If there is no @pulumi/pulumi, add "latest" as a peer dependency (for npm linking style usage).
|
|
|
|
sdkPack := "@pulumi/pulumi"
|
|
|
|
if npminfo.Dependencies[sdkPack] == "" &&
|
|
|
|
npminfo.DevDependencies[sdkPack] == "" &&
|
|
|
|
npminfo.PeerDependencies[sdkPack] == "" {
|
2022-11-09 22:04:48 +00:00
|
|
|
if npminfo.Dependencies == nil {
|
|
|
|
npminfo.Dependencies = make(map[string]string)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2024-03-26 13:10:34 +00:00
|
|
|
if path, ok := localDependencies["pulumi"]; ok {
|
|
|
|
npminfo.Dependencies[sdkPack] = path
|
|
|
|
} else {
|
|
|
|
npminfo.Dependencies[sdkPack] = MinimumValidSDKVersion
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now write out the serialized form.
|
|
|
|
npmjson, err := json.MarshalIndent(npminfo, "", " ")
|
2023-02-23 20:46:42 +00:00
|
|
|
contract.AssertNoErrorf(err, "error serializing package.json")
|
Add SupportPack to schemas to write out in the new style (#15713)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This adds a new flag to the schema metadata to tell codegen to use the
new proposed style of SDKs where we fill in versions and write go.mods
etc.
I've reworked pack to operate on packages assuming they're in this new
style. That is pack no longer has the responsibility to fill in any
version information.
This updates python and node codegen to write out SDKs in this new
style, and fixes their core libraries to still be buildable via pack.
There are two approaches to fixing those, I've chosen option 1 below but
could pretty easily rework for option 2.
1) Write the version information directly to the SDKs at the same time
as we edit the .version file. To simplify this I've added a new
'set-version.py' script that takes a version string an writes it to all
the relevant places (.version, package.json, etc).
2) Write "pack" in the language host to search up the directory tree for
the ".version" file and then fill in the version information as we we're
doing before with envvar tricks and copying and editing package.json.
I think 1 is simpler long term, but does force some amount of cleanup in
unrelated bits of the system right now (release makefiles need a small
edit). 2 is much more localised but keeps this complexity that
sdk/nodejs sdk/python aren't actually valid source modules.
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [x] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-03-22 09:25:46 +00:00
|
|
|
return string(npmjson) + "\n", nil
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2022-11-09 19:49:59 +00:00
|
|
|
func genTypeScriptProjectFile(info NodePackageInfo, files codegen.Fs) string {
|
2020-01-21 22:45:48 +00:00
|
|
|
w := &bytes.Buffer{}
|
|
|
|
|
|
|
|
fmt.Fprintf(w, `{
|
|
|
|
"compilerOptions": {
|
|
|
|
"outDir": "bin",
|
|
|
|
"target": "es2016",
|
|
|
|
"module": "commonjs",
|
|
|
|
"moduleResolution": "node",
|
|
|
|
"declaration": true,
|
|
|
|
"sourceMap": true,
|
|
|
|
"stripInternal": true,
|
|
|
|
"experimentalDecorators": true,
|
|
|
|
"noFallthroughCasesInSwitch": true,
|
|
|
|
"forceConsistentCasingInFileNames": true,
|
|
|
|
"strict": true
|
|
|
|
},
|
|
|
|
"files": [
|
|
|
|
`)
|
|
|
|
|
|
|
|
var tsFiles []string
|
|
|
|
for f := range files {
|
|
|
|
if path.Ext(f) == ".ts" {
|
|
|
|
tsFiles = append(tsFiles, f)
|
|
|
|
}
|
|
|
|
}
|
2021-10-04 21:26:49 +00:00
|
|
|
|
|
|
|
tsFiles = append(tsFiles, info.ExtraTypeScriptFiles...)
|
2020-01-21 22:45:48 +00:00
|
|
|
sort.Strings(tsFiles)
|
|
|
|
|
|
|
|
for i, file := range tsFiles {
|
|
|
|
var suffix string
|
|
|
|
if i != len(tsFiles)-1 {
|
|
|
|
suffix = ","
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, " \"%s\"%s\n", file, suffix)
|
|
|
|
}
|
|
|
|
fmt.Fprintf(w, ` ]
|
|
|
|
}
|
|
|
|
`)
|
|
|
|
return w.String()
|
|
|
|
}
|
|
|
|
|
2020-06-04 01:20:32 +00:00
|
|
|
// generateModuleContextMap groups resources, types, and functions into NodeJS packages.
|
2021-07-09 15:52:30 +00:00
|
|
|
func generateModuleContextMap(tool string, pkg *schema.Package, extraFiles map[string][]byte,
|
|
|
|
) (map[string]*modContext, NodePackageInfo, error) {
|
|
|
|
if err := pkg.ImportLanguages(map[string]schema.Language{"nodejs": Importer}); err != nil {
|
|
|
|
return nil, NodePackageInfo{}, err
|
|
|
|
}
|
|
|
|
info, _ := pkg.Language["nodejs"].(NodePackageInfo)
|
2020-06-07 16:21:09 +00:00
|
|
|
|
2020-06-04 01:20:32 +00:00
|
|
|
// group resources, types, and functions into NodeJS packages
|
2020-01-21 22:45:48 +00:00
|
|
|
modules := map[string]*modContext{}
|
|
|
|
|
2020-06-03 01:15:21 +00:00
|
|
|
var getMod func(modName string) *modContext
|
|
|
|
getMod = func(modName string) *modContext {
|
2020-06-04 01:20:32 +00:00
|
|
|
if override, ok := info.ModuleToPackage[modName]; ok {
|
|
|
|
modName = override
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
mod, ok := modules[modName]
|
|
|
|
if !ok {
|
|
|
|
mod = &modContext{
|
2022-12-08 13:36:44 +00:00
|
|
|
pkg: pkg.Reference(),
|
2021-10-01 18:33:02 +00:00
|
|
|
mod: modName,
|
|
|
|
tool: tool,
|
|
|
|
compatibility: info.Compatibility,
|
|
|
|
modToPkg: info.ModuleToPackage,
|
|
|
|
disableUnionOutputTypes: info.DisableUnionOutputTypes,
|
|
|
|
liftSingleValueMethodReturns: info.LiftSingleValueMethodReturns,
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if modName != "" {
|
|
|
|
parentName := path.Dir(modName)
|
2020-06-03 01:15:21 +00:00
|
|
|
if parentName == "." {
|
|
|
|
parentName = ""
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
parent := getMod(parentName)
|
|
|
|
parent.children = append(parent.children, mod)
|
|
|
|
}
|
|
|
|
|
|
|
|
modules[modName] = mod
|
|
|
|
}
|
|
|
|
return mod
|
|
|
|
}
|
|
|
|
|
2020-06-03 01:15:21 +00:00
|
|
|
getModFromToken := func(token string) *modContext {
|
|
|
|
return getMod(pkg.TokenToModule(token))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a temporary module for type information.
|
|
|
|
types := &modContext{}
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
// Create the config module if necessary.
|
2020-05-29 19:39:29 +00:00
|
|
|
if len(pkg.Config) > 0 &&
|
2020-06-22 15:38:20 +00:00
|
|
|
info.Compatibility != kubernetes20 { // k8s SDK doesn't use config.
|
2020-06-03 01:15:21 +00:00
|
|
|
_ = getMod("config")
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2021-06-24 16:17:55 +00:00
|
|
|
visitObjectTypes(pkg.Config, func(t *schema.ObjectType) {
|
2021-04-19 23:40:39 +00:00
|
|
|
types.details(t).outputType = true
|
|
|
|
})
|
2020-01-21 22:45:48 +00:00
|
|
|
|
|
|
|
scanResource := func(r *schema.Resource) {
|
2021-11-12 00:00:03 +00:00
|
|
|
if r.IsOverlay {
|
|
|
|
// This resource code is generated by the provider, so no further action is required.
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-03 01:15:21 +00:00
|
|
|
mod := getModFromToken(r.Token)
|
2020-01-21 22:45:48 +00:00
|
|
|
mod.resources = append(mod.resources, r)
|
2021-06-24 16:17:55 +00:00
|
|
|
visitObjectTypes(r.Properties, func(t *schema.ObjectType) {
|
2021-04-19 23:40:39 +00:00
|
|
|
types.details(t).outputType = true
|
|
|
|
})
|
2021-06-24 16:17:55 +00:00
|
|
|
visitObjectTypes(r.InputProperties, func(t *schema.ObjectType) {
|
2021-04-19 23:40:39 +00:00
|
|
|
types.details(t).inputType = true
|
|
|
|
})
|
2020-01-21 22:45:48 +00:00
|
|
|
if r.StateInputs != nil {
|
2021-06-24 16:17:55 +00:00
|
|
|
visitObjectTypes(r.StateInputs.Properties, func(t *schema.ObjectType) {
|
2021-04-16 02:03:28 +00:00
|
|
|
types.details(t).inputType = true
|
2021-04-19 23:40:39 +00:00
|
|
|
})
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scanResource(pkg.Provider)
|
|
|
|
for _, r := range pkg.Resources {
|
|
|
|
scanResource(r)
|
|
|
|
}
|
|
|
|
|
2021-04-16 02:03:28 +00:00
|
|
|
// Clear the input and outputs sets: we want the visitors below to touch the transitive closure of types reachable
|
|
|
|
// from function inputs and outputs, including types that have already been visited.
|
2020-01-21 22:45:48 +00:00
|
|
|
for _, f := range pkg.Functions {
|
2020-06-03 01:15:21 +00:00
|
|
|
mod := getModFromToken(f.Token)
|
2021-07-08 03:16:42 +00:00
|
|
|
if !f.IsMethod {
|
|
|
|
mod.functions = append(mod.functions, f)
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
if f.Inputs != nil {
|
2021-06-24 16:17:55 +00:00
|
|
|
visitObjectTypes(f.Inputs.Properties, func(t *schema.ObjectType) {
|
2020-01-21 22:45:48 +00:00
|
|
|
types.details(t).inputType = true
|
2021-04-19 23:40:39 +00:00
|
|
|
})
|
2021-10-07 19:39:19 +00:00
|
|
|
|
|
|
|
if f.NeedsOutputVersion() {
|
|
|
|
visitObjectTypes(f.Inputs.InputShape.Properties, func(t *schema.ObjectType) {
|
|
|
|
for _, mod := range []*modContext{types, getModFromToken(t.Token)} {
|
|
|
|
det := mod.details(t)
|
|
|
|
det.inputType = true
|
|
|
|
det.usedInFunctionOutputVersionInputs = true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
2023-01-11 22:17:14 +00:00
|
|
|
if f.ReturnType != nil {
|
|
|
|
// special case where the return type is defined inline with the function
|
|
|
|
if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && f.InlineObjectAsReturnType {
|
|
|
|
visitObjectTypes(objectType.Properties, func(t *schema.ObjectType) {
|
|
|
|
types.details(t).outputType = true
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
// otherwise, the return type is or has a reference to a type defined elsewhere
|
|
|
|
codegen.VisitType(f.ReturnType, func(schemaType schema.Type) {
|
|
|
|
if t, ok := schemaType.(*schema.ObjectType); ok {
|
|
|
|
types.details(t).outputType = true
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := modules["types"]; ok {
|
2020-10-08 01:13:10 +00:00
|
|
|
return nil, info, errors.New("this provider has a `types` module which is reserved for input/output types")
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the types module.
|
|
|
|
for _, t := range pkg.Types {
|
2020-10-08 01:13:10 +00:00
|
|
|
switch typ := t.(type) {
|
|
|
|
case *schema.ObjectType:
|
|
|
|
types.types = append(types.types, typ)
|
|
|
|
case *schema.EnumType:
|
2021-11-16 23:53:28 +00:00
|
|
|
if !typ.IsOverlay {
|
|
|
|
info.ContainsEnums = true
|
|
|
|
mod := getModFromToken(typ.Token)
|
|
|
|
mod.enums = append(mod.enums, typ)
|
|
|
|
}
|
2020-10-08 01:13:10 +00:00
|
|
|
default:
|
|
|
|
continue
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-29 15:07:27 +00:00
|
|
|
if len(types.types) > 0 || info.ContainsEnums {
|
2020-06-03 01:15:21 +00:00
|
|
|
typeDetails, typeList := types.typeDetails, types.types
|
|
|
|
types = getMod("types")
|
|
|
|
types.typeDetails, types.types = typeDetails, typeList
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
|
2020-06-07 16:21:09 +00:00
|
|
|
// Add Typescript source files to the corresponding modules. Note that we only add the file names; the contents are
|
|
|
|
// still laid out manually in GeneratePackage.
|
|
|
|
for p := range extraFiles {
|
|
|
|
if path.Ext(p) != ".ts" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
modName := path.Dir(p)
|
|
|
|
if modName == "/" || modName == "." {
|
|
|
|
modName = ""
|
|
|
|
}
|
|
|
|
mod := getMod(modName)
|
|
|
|
mod.extraSourceFiles = append(mod.extraSourceFiles, p)
|
|
|
|
}
|
|
|
|
|
2020-10-08 01:13:10 +00:00
|
|
|
return modules, info, nil
|
2020-06-04 01:20:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// LanguageResource holds information about a resource to be used by downstream codegen.
|
|
|
|
type LanguageResource struct {
|
|
|
|
*schema.Resource
|
|
|
|
|
|
|
|
Name string // The resource name (e.g., "FlowSchema")
|
|
|
|
Package string // The name of the package containing the resource definition (e.g., "flowcontrol.v1alpha1")
|
|
|
|
Properties []LanguageProperty // Properties of the resource
|
|
|
|
}
|
|
|
|
|
|
|
|
// LanguageProperty holds information about a resource property to be used by downstream codegen.
|
|
|
|
type LanguageProperty struct {
|
|
|
|
ConstValue string // If set, the constant value of the property (e.g., "flowcontrol.apiserver.k8s.io/v1alpha1")
|
|
|
|
Name string // The name of the property (e.g., "FlowSchemaSpec")
|
|
|
|
Package string // The package path containing the property definition (e.g., "outputs.flowcontrol.v1alpha1")
|
|
|
|
}
|
|
|
|
|
|
|
|
// LanguageResources returns a map of resources that can be used by downstream codegen. The map
|
|
|
|
// key is the resource schema token.
|
|
|
|
func LanguageResources(pkg *schema.Package) (map[string]LanguageResource, error) {
|
|
|
|
resources := map[string]LanguageResource{}
|
|
|
|
|
2021-07-09 15:52:30 +00:00
|
|
|
modules, _, err := generateModuleContextMap("", pkg, nil)
|
2020-06-04 01:20:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for modName, mod := range modules {
|
|
|
|
for _, r := range mod.resources {
|
2021-11-12 00:00:03 +00:00
|
|
|
if r.IsOverlay {
|
|
|
|
// This resource code is generated by the provider, so no further action is required.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2023-02-23 20:51:11 +00:00
|
|
|
packagePath := strings.ReplaceAll(modName, "/", ".")
|
2020-06-04 01:20:32 +00:00
|
|
|
lr := LanguageResource{
|
|
|
|
Resource: r,
|
|
|
|
Name: resourceName(r),
|
|
|
|
Package: packagePath,
|
|
|
|
}
|
|
|
|
for _, p := range r.Properties {
|
|
|
|
lp := LanguageProperty{
|
|
|
|
Name: p.Name,
|
|
|
|
}
|
|
|
|
if p.ConstValue != nil {
|
2021-06-24 16:17:55 +00:00
|
|
|
lp.ConstValue = mod.typeString(p.Type, false, p.ConstValue)
|
2020-06-04 01:20:32 +00:00
|
|
|
} else {
|
2021-06-24 16:17:55 +00:00
|
|
|
lp.Package = mod.typeString(p.Type, false, nil)
|
2020-06-04 01:20:32 +00:00
|
|
|
}
|
|
|
|
lr.Properties = append(lr.Properties, lp)
|
|
|
|
}
|
|
|
|
resources[r.Token] = lr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return resources, nil
|
|
|
|
}
|
|
|
|
|
2024-03-26 13:10:34 +00:00
|
|
|
func GeneratePackage(tool string, pkg *schema.Package,
|
|
|
|
extraFiles map[string][]byte, localDependencies map[string]string,
|
|
|
|
) (map[string][]byte, error) {
|
2021-07-09 15:52:30 +00:00
|
|
|
modules, info, err := generateModuleContextMap(tool, pkg, extraFiles)
|
2020-06-04 01:20:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-10-08 01:13:10 +00:00
|
|
|
pkg.Language["nodejs"] = info
|
2020-06-04 01:20:32 +00:00
|
|
|
|
2022-11-09 19:49:59 +00:00
|
|
|
files := codegen.Fs{}
|
2020-01-21 22:45:48 +00:00
|
|
|
for p, f := range extraFiles {
|
2022-11-09 19:49:59 +00:00
|
|
|
files.Add(p, f)
|
2020-01-21 22:45:48 +00:00
|
|
|
}
|
|
|
|
for _, mod := range modules {
|
|
|
|
if err := mod.gen(files); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Finally emit the package metadata (NPM, TypeScript, and so on).
|
2024-03-26 13:10:34 +00:00
|
|
|
if err = genPackageMetadata(pkg, info, files, localDependencies); err != nil {
|
2022-01-19 22:21:09 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-21 22:45:48 +00:00
|
|
|
return files, nil
|
|
|
|
}
|
|
|
|
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
//go:embed utilities.ts
|
|
|
|
var utilitiesFile string
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
func (mod *modContext) genUtilitiesFile(w io.Writer) error {
|
|
|
|
def, err := mod.pkg.Definition()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
code := utilitiesFile
|
|
|
|
|
2022-12-08 13:36:44 +00:00
|
|
|
if url := def.PluginDownloadURL; url != "" {
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
code = strings.ReplaceAll(code, "/*pluginDownloadURL*/",
|
|
|
|
fmt.Sprintf(", pluginDownloadURL: %q", url))
|
|
|
|
} else {
|
|
|
|
code = strings.ReplaceAll(code, "/*pluginDownloadURL*/", "")
|
2022-01-10 23:54:41 +00:00
|
|
|
}
|
Support returning plain values from methods (#13592)
Support returning plain values from methods.
Implements Node, Python and Go support.
Remaining:
- [x] test receiving unknowns
- [x] acceptance tests written and passing locally for Node, Python, Go
clients against a Go server
- [x] acceptance tests passing in CI
- [x] tickets filed for remaining languages
- [x] https://github.com/pulumi/pulumi-yaml/issues/499
- [x] https://github.com/pulumi/pulumi-java/issues/1193
- [x] https://github.com/pulumi/pulumi-dotnet/issues/170
Known limitations:
- this is technically a breaking change in case there is code out there
that already uses methods that return Plain: true
- struct-wrapping limitation: the provider for the component resource
needs to still wrap the plain-returning Method response with a 1-arg
struct; by convention the field is named "res", and this is how it
travels through the plumbing
- resources cannot return plain values yet
- the provider for the component resource cannot have unknown
configuration, if it does, the methods will not be called
- Per Luke https://github.com/pulumi/pulumi/issues/11520 this might not
be supported/realizable yet
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
Fixes https://github.com/pulumi/pulumi/issues/12709
## Checklist
- [ ] I have run `make tidy` to update any new dependencies
- [ ] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-11-18 06:02:06 +00:00
|
|
|
|
|
|
|
_, err = fmt.Fprintf(w, "%s", code)
|
2022-12-08 13:36:44 +00:00
|
|
|
return err
|
2022-01-10 23:54:41 +00:00
|
|
|
}
|
2022-01-19 22:21:09 +00:00
|
|
|
|
2022-09-28 14:46:44 +00:00
|
|
|
// Used to sort ObjectType values.
|
|
|
|
func objectTypeLessThan(a, b *schema.ObjectType) bool {
|
|
|
|
switch strings.Compare(tokenToName(a.Token), tokenToName(b.Token)) {
|
|
|
|
case -1:
|
|
|
|
return true
|
|
|
|
case 0:
|
|
|
|
tIsInput := a.PlainShape != nil
|
|
|
|
otherIsInput := b.PlainShape != nil
|
|
|
|
if !tIsInput && otherIsInput {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|