diff --git a/changelog/pending/20230102--sdkgen-dotnet-nodejs--initial-implementation-of-simplified-invokes-for-dotnet-and-nodejs.yaml b/changelog/pending/20230102--sdkgen-dotnet-nodejs--initial-implementation-of-simplified-invokes-for-dotnet-and-nodejs.yaml new file mode 100644 index 000000000000..af16c98ab81c --- /dev/null +++ b/changelog/pending/20230102--sdkgen-dotnet-nodejs--initial-implementation-of-simplified-invokes-for-dotnet-and-nodejs.yaml @@ -0,0 +1,4 @@ +changes: +- type: feat + scope: sdkgen/dotnet,nodejs + description: Initial implementation of simplified invokes for dotnet and nodejs. diff --git a/pkg/codegen/docs/gen.go b/pkg/codegen/docs/gen.go index 3eb67d2ee0b6..a5145712abb0 100644 --- a/pkg/codegen/docs/gen.go +++ b/pkg/codegen/docs/gen.go @@ -1722,11 +1722,14 @@ func (mod *modContext) getTypes(member interface{}, types nestedTypeUsageInfo) { mod.getTypes(m.Function, types) } case *schema.Function: - if t.Inputs != nil { + if t.Inputs != nil && !t.MultiArgumentInputs { mod.getNestedTypes(t.Inputs, types, true) } - if t.Outputs != nil { - mod.getNestedTypes(t.Outputs, types, false) + + if t.ReturnType != nil { + if objectType, ok := t.ReturnType.(*schema.ObjectType); ok && objectType != nil { + mod.getNestedTypes(objectType, types, false) + } } } } diff --git a/pkg/codegen/docs/gen_function.go b/pkg/codegen/docs/gen_function.go index 7862bf18b22c..3af366df93ee 100644 --- a/pkg/codegen/docs/gen_function.go +++ b/pkg/codegen/docs/gen_function.go @@ -443,8 +443,11 @@ func (mod *modContext) genFunction(f *schema.Function) functionDocArgs { if f.Inputs != nil { inputProps[lang] = mod.getProperties(f.Inputs.Properties, lang, true, false, false) } - if f.Outputs != nil { - outputProps[lang] = mod.getProperties(f.Outputs.Properties, lang, false, false, false) + if f.ReturnType != nil { + if objectObject, ok := f.ReturnType.(*schema.ObjectType); ok { + outputProps[lang] = mod.getProperties(objectObject.Properties, + lang, false, false, false) + } } } diff --git a/pkg/codegen/docs/gen_method.go b/pkg/codegen/docs/gen_method.go index c51b6ff6af1a..3e8810f0a5d8 100644 --- a/pkg/codegen/docs/gen_method.go +++ b/pkg/codegen/docs/gen_method.go @@ -78,9 +78,11 @@ func (mod *modContext) genMethod(r *schema.Resource, m *schema.Method) methodDoc inputProps[lang] = props } } - if f.Outputs != nil { - outputProps[lang] = mod.getPropertiesWithIDPrefixAndExclude(f.Outputs.Properties, lang, false, false, false, - fmt.Sprintf("%s_result_", m.Name), nil) + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + outputProps[lang] = mod.getPropertiesWithIDPrefixAndExclude(objectType.Properties, lang, false, false, false, + fmt.Sprintf("%s_result_", m.Name), nil) + } } } @@ -324,7 +326,7 @@ func (mod *modContext) getMethodResult(r *schema.Resource, m *schema.Method) map var resultTypeName string for _, lang := range dctx.supportedLanguages { - if m.Function.Outputs != nil && len(m.Function.Outputs.Properties) > 0 { + if m.Function.ReturnType != nil { def, err := mod.pkg.Definition() contract.AssertNoError(err) resultTypeName = dctx.getLanguageDocHelper(lang).GetMethodResultName(def, mod.mod, r, m) diff --git a/pkg/codegen/dotnet/doc.go b/pkg/codegen/dotnet/doc.go index e3d9d7f0e0ad..a5fa0d3086d6 100644 --- a/pkg/codegen/dotnet/doc.go +++ b/pkg/codegen/dotnet/doc.go @@ -110,8 +110,24 @@ func (d DocLanguageHelper) GetMethodName(m *schema.Method) string { func (d DocLanguageHelper) GetMethodResultName(pkg *schema.Package, modName string, r *schema.Resource, m *schema.Method) string { + var returnType *schema.ObjectType + if m.Function.ReturnType != nil { + if objectType, ok := m.Function.ReturnType.(*schema.ObjectType); ok { + returnType = objectType + } else { + typeDetails := map[*schema.ObjectType]*typeDetails{} + mod := &modContext{ + pkg: pkg.Reference(), + mod: modName, + typeDetails: typeDetails, + namespaces: d.Namespaces, + } + return mod.typeString(m.Function.ReturnType, "", false, false, false) + } + } + if info, ok := pkg.Language["csharp"].(CSharpPackageInfo); ok { - if info.LiftSingleValueMethodReturns && m.Function.Outputs != nil && len(m.Function.Outputs.Properties) == 1 { + if info.LiftSingleValueMethodReturns && returnType != nil && len(returnType.Properties) == 1 { typeDetails := map[*schema.ObjectType]*typeDetails{} mod := &modContext{ pkg: pkg.Reference(), @@ -120,7 +136,7 @@ func (d DocLanguageHelper) GetMethodResultName(pkg *schema.Package, modName stri namespaces: d.Namespaces, rootNamespace: info.GetRootNamespace(), } - return mod.typeString(m.Function.Outputs.Properties[0].Type, "", false, false, false) + return mod.typeString(returnType.Properties[0].Type, "", false, false, false) } } return fmt.Sprintf("%s.%sResult", resourceName(r), d.GetMethodName(m)) diff --git a/pkg/codegen/dotnet/gen.go b/pkg/codegen/dotnet/gen.go index 219fa18fdd8c..26f293abb7e9 100644 --- a/pkg/codegen/dotnet/gen.go +++ b/pkg/codegen/dotnet/gen.go @@ -1127,18 +1127,26 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error { methodName := Title(method.Name) fun := method.Function - shouldLiftReturn := mod.liftSingleValueMethodReturns && fun.Outputs != nil && len(fun.Outputs.Properties) == 1 + var objectReturnType *schema.ObjectType + + if fun.ReturnType != nil { + if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && fun.InlineObjectAsReturnType { + objectReturnType = objectType + } + } + + liftReturn := mod.liftSingleValueMethodReturns && objectReturnType != nil && len(objectReturnType.Properties) == 1 fmt.Fprintf(w, "\n") returnType, typeParameter, lift := "void", "", "" - if fun.Outputs != nil { + if fun.ReturnType != nil { typeParameter = fmt.Sprintf("<%s%sResult>", className, methodName) - if shouldLiftReturn { + if liftReturn { returnType = fmt.Sprintf("global::Pulumi.Output<%s>", - mod.typeString(fun.Outputs.Properties[0].Type, "", false, false, false)) + mod.typeString(objectReturnType.Properties[0].Type, "", false, false, false)) - fieldName := mod.propertyName(fun.Outputs.Properties[0]) + fieldName := mod.propertyName(objectReturnType.Properties[0]) lift = fmt.Sprintf(".Apply(v => v.%s)", fieldName) } else { returnType = fmt.Sprintf("global::Pulumi.Output%s", typeParameter) @@ -1266,9 +1274,16 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error { } } + var objectReturnType *schema.ObjectType + if fun.ReturnType != nil { + if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && objectType != nil { + objectReturnType = objectType + } + } + // Generate result type. - if fun.Outputs != nil { - shouldLiftReturn := mod.liftSingleValueMethodReturns && len(fun.Outputs.Properties) == 1 + if objectReturnType != nil { + shouldLiftReturn := mod.liftSingleValueMethodReturns && len(objectReturnType.Properties) == 1 comment, escape := fun.Inputs.Comment, true if comment == "" { @@ -1281,7 +1296,7 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) error { unescapeComment: !escape, name: fmt.Sprintf("%s%sResult", className, methodName), propertyTypeQualifier: "Outputs", - properties: fun.Outputs.Properties, + properties: objectReturnType.Properties, internal: shouldLiftReturn, } resultType.genOutputType(w, 1) @@ -1335,16 +1350,64 @@ func allOptionalInputs(fun *schema.Function) bool { return true } +func typeParamOrEmpty(typeParamName string) string { + if typeParamName != "" { + return fmt.Sprintf("<%s>", typeParamName) + } + + return "" +} + +func (mod *modContext) functionReturnType(fun *schema.Function) string { + className := tokenToFunctionName(fun.Token) + if fun.ReturnType != nil { + if _, ok := fun.ReturnType.(*schema.ObjectType); ok && fun.InlineObjectAsReturnType { + // for object return types, assume a Result type is generated in the same class as it's function + // and reference it from here directly + return fmt.Sprintf("%sResult", className) + } + + // otherwise, the object type is a reference to an output type + return mod.typeString(fun.ReturnType, "Outputs", false, false, true) + } + + return "" +} + +// 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 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" + } +} + func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) error { className := tokenToFunctionName(fun.Token) fmt.Fprintf(w, "namespace %s\n", mod.tokenToNamespace(fun.Token, "")) fmt.Fprintf(w, "{\n") - var typeParameter string - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { - typeParameter = fmt.Sprintf("<%sResult>", className) - } + typeParameter := mod.functionReturnType(fun) var argsParamDef string argsParamRef := "InvokeArgs.Empty" @@ -1362,18 +1425,65 @@ func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) error { if fun.DeprecationMessage != "" { fmt.Fprintf(w, " [Obsolete(@\"%s\")]\n", strings.Replace(fun.DeprecationMessage, `"`, `""`, -1)) } - // Open the class we'll use for datasources. + + // Open the class we'll use for data sources. fmt.Fprintf(w, " public static class %s\n", className) fmt.Fprintf(w, " {\n") // Emit the doc comment, if any. printComment(w, fun.Comment, " ") + invokeCall := runtimeInvokeFunction(fun) + if !fun.MultiArgumentInputs { + // Emit the datasource method. + // this is default behavior for all functions. + fmt.Fprintf(w, " public static Task%s InvokeAsync(%sInvokeOptions? options = null)\n", + typeParamOrEmpty(typeParameter), argsParamDef) + // new line and indent + fmt.Fprint(w, " ") + fmt.Fprintf(w, "=> global::Pulumi.Deployment.Instance.%sAsync%s", invokeCall, typeParamOrEmpty(typeParameter)) + fmt.Fprintf(w, "(\"%s\", %s, options.WithDefaults());\n", fun.Token, argsParamRef) + } else { + // multi-argument inputs and output property bag + // first generate the function definition + fmt.Fprintf(w, " public static async Task%s InvokeAsync(", typeParamOrEmpty(typeParameter)) + for _, prop := range fun.Inputs.Properties { + argumentName := LowerCamelCase(prop.Name) + argumentType := mod.typeString(prop.Type, "", false, false, true) + paramDeclaration := fmt.Sprintf("%s %s", argumentType, argumentName) + if !prop.IsRequired() { + paramDeclaration += " = null" + } + + fmt.Fprintf(w, "%s", paramDeclaration) + fmt.Fprint(w, ", ") + } - // Emit the datasource method. - fmt.Fprintf(w, " public static Task%s InvokeAsync(%sInvokeOptions? options = null)\n", - typeParameter, argsParamDef) - fmt.Fprintf(w, " => global::Pulumi.Deployment.Instance.InvokeAsync%s(\"%s\", %s, options.WithDefaults());\n", - typeParameter, fun.Token, argsParamRef) + fmt.Fprint(w, "InvokeOptions? invokeOptions = null)\n") + + funcBodyIndent := func() { + fmt.Fprintf(w, " ") + } + + // now the function body + fmt.Fprint(w, " {\n") + // generate a dictionary where each entry is a key-value pair made out of the inputs of the function + funcBodyIndent() + fmt.Fprint(w, "var builder = ImmutableDictionary.CreateBuilder();\n") + for _, prop := range fun.Inputs.Properties { + argumentName := LowerCamelCase(prop.Name) + funcBodyIndent() + fmt.Fprintf(w, "builder[\"%s\"] = %s;\n", prop.Name, argumentName) + } + + funcBodyIndent() + fmt.Fprint(w, "var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary());\n") + funcBodyIndent() + // full invoke call + fmt.Fprint(w, "return await global::Pulumi.Deployment.Instance.") + fmt.Fprintf(w, "%sAsync%s", invokeCall, typeParamOrEmpty(typeParameter)) + fmt.Fprintf(w, "(\"%s\", args, invokeOptions.WithDefaults());\n", fun.Token) + fmt.Fprint(w, " }\n") + } // Emit the Output method if needed. err := mod.genFunctionOutputVersion(w, fun) @@ -1385,7 +1495,7 @@ func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) error { fmt.Fprintf(w, " }\n") // Emit the args and result types, if any. - if fun.Inputs != nil { + if fun.Inputs != nil && !fun.MultiArgumentInputs { fmt.Fprintf(w, "\n") args := &plainType{ @@ -1405,16 +1515,19 @@ func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) error { return err } - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { - fmt.Fprintf(w, "\n") + if fun.ReturnType != nil { + if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && fun.InlineObjectAsReturnType { - res := &plainType{ - mod: mod, - name: className + "Result", - propertyTypeQualifier: "Outputs", - properties: fun.Outputs.Properties, + fmt.Fprintf(w, "\n") + + res := &plainType{ + mod: mod, + name: className + "Result", + propertyTypeQualifier: "Outputs", + properties: objectType.Properties, + } + res.genOutputType(w, 1) } - res.genOutputType(w, 1) } // Close the namespace. @@ -1433,26 +1546,59 @@ func (mod *modContext) genFunctionOutputVersion(w io.Writer, fun *schema.Functio if !fun.NeedsOutputVersion() { return nil } - className := tokenToFunctionName(fun.Token) - var argsDefault, sigil string if allOptionalInputs(fun) { // If the number of required input properties was zero, we can make the args object optional. argsDefault, sigil = " = null", "?" } + typeParameter := mod.functionReturnType(fun) + invokeCall := runtimeInvokeFunction(fun) argsTypeName := functionOutputVersionArgsTypeName(fun) outputArgsParamDef := fmt.Sprintf("%s%s args%s, ", argsTypeName, sigil, argsDefault) outputArgsParamRef := fmt.Sprintf("args ?? new %s()", argsTypeName) fmt.Fprintf(w, "\n") - // Emit the doc comment, if any. printComment(w, fun.Comment, " ") - fmt.Fprintf(w, " public static Output<%sResult> Invoke(%sInvokeOptions? options = null)\n", - className, outputArgsParamDef) - fmt.Fprintf(w, " => global::Pulumi.Deployment.Instance.Invoke<%sResult>(\"%s\", %s, options.WithDefaults());\n", - className, fun.Token, outputArgsParamRef) + + if !fun.MultiArgumentInputs { + fmt.Fprintf(w, " public static Output%s Invoke(%sInvokeOptions? options = null)\n", + typeParamOrEmpty(typeParameter), outputArgsParamDef) + fmt.Fprintf(w, " => global::Pulumi.Deployment.Instance.%s%s(\"%s\", %s, options.WithDefaults());\n", + invokeCall, typeParamOrEmpty(typeParameter), fun.Token, outputArgsParamRef) + } else { + fmt.Fprintf(w, " public static Output%s Invoke(", typeParamOrEmpty(typeParameter)) + for _, prop := range fun.Inputs.Properties { + var paramDeclaration string + argumentName := LowerCamelCase(prop.Name) + propertyType := &schema.InputType{ElementType: prop.Type} + argumentType := mod.typeString(propertyType, "", true /* input */, false, true) + if prop.IsRequired() { + paramDeclaration = fmt.Sprintf("%s %s", argumentType, argumentName) + } else { + paramDeclaration = fmt.Sprintf("%s? %s = null", argumentType, argumentName) + } + + fmt.Fprintf(w, "%s", paramDeclaration) + fmt.Fprint(w, ", ") + } + + fmt.Fprint(w, "InvokeOptions? invokeOptions = null)\n") + + // now the function body + fmt.Fprint(w, " {\n") + fmt.Fprint(w, " var builder = ImmutableDictionary.CreateBuilder();\n") + for _, prop := range fun.Inputs.Properties { + argumentName := LowerCamelCase(prop.Name) + fmt.Fprintf(w, " builder[\"%s\"] = %s;\n", prop.Name, argumentName) + } + fmt.Fprint(w, " var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary());\n") + fmt.Fprintf(w, " return global::Pulumi.Deployment.Instance.%s%s(\"%s\", args, invokeOptions.WithDefaults());\n", + invokeCall, typeParamOrEmpty(typeParameter), fun.Token) + fmt.Fprint(w, " }\n") + } + return nil } @@ -1462,18 +1608,21 @@ func (mod *modContext) genFunctionOutputVersionTypes(w io.Writer, fun *schema.Fu return nil } - applyArgs := &plainType{ - mod: mod, - name: functionOutputVersionArgsTypeName(fun), - propertyTypeQualifier: "Inputs", - baseClass: "InvokeArgs", - properties: fun.Inputs.InputShape.Properties, - args: true, - } + if !fun.MultiArgumentInputs { + applyArgs := &plainType{ + mod: mod, + name: functionOutputVersionArgsTypeName(fun), + propertyTypeQualifier: "Inputs", + baseClass: "InvokeArgs", + properties: fun.Inputs.InputShape.Properties, + args: true, + } - if err := applyArgs.genInputTypeWithFlags(w, 1, true /* generateInputAttributes */); err != nil { - return err + if err := applyArgs.genInputTypeWithFlags(w, 1, true /* generateInputAttributes */); err != nil { + return err + } } + return nil } @@ -2169,10 +2318,13 @@ func generateModuleContextMap(tool string, pkg *schema.Package) (map[string]*mod if f.Inputs != nil { computePropertyNames(f.Inputs.Properties, propertyNames) } - if f.Outputs != nil { - computePropertyNames(f.Outputs.Properties, propertyNames) + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + computePropertyNames(objectType.Properties, propertyNames) + } } } + for _, t := range pkg.Types { if obj, ok := t.(*schema.ObjectType); ok { computePropertyNames(obj.Properties, propertyNames) @@ -2286,12 +2438,24 @@ func generateModuleContextMap(tool string, pkg *schema.Package) (map[string]*mod }) } } - if f.Outputs != nil { - visitObjectTypes(f.Outputs.Properties, func(t *schema.ObjectType) { - details := getModFromToken(t.Token, t.PackageReference).details(t) - details.outputType = true - details.plainType = true - }) + 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) { + details := getModFromToken(t.Token, t.PackageReference).details(t) + details.outputType = true + details.plainType = true + }) + } else { + // otherwise, the return type is a reference to a type defined elsewhere + codegen.VisitType(f.ReturnType, func(schemaType schema.Type) { + if t, ok := schemaType.(*schema.ObjectType); ok { + details := getModFromToken(t.Token, t.PackageReference).details(t) + details.outputType = true + details.plainType = true + } + }) + } } } diff --git a/pkg/codegen/dotnet/gen_program_expressions.go b/pkg/codegen/dotnet/gen_program_expressions.go index 2d9c0a3b3a48..07dd5cd623d9 100644 --- a/pkg/codegen/dotnet/gen_program_expressions.go +++ b/pkg/codegen/dotnet/gen_program_expressions.go @@ -411,7 +411,8 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC useImplicitTypeName := g.generateOptions.implicitResourceArgsTypeName inputTypeName := functionName + "InvokeArgs" destTypeName := strings.ReplaceAll(fullFunctionName, functionName, inputTypeName) - g.genObjectConsExpressionWithTypeName(w, arg, destTypeName, useImplicitTypeName) + g.genObjectConsExpressionWithTypeName(w, arg, destTypeName, useImplicitTypeName, + pcl.SortedFunctionParameters(funcExpr)) }) default: g.genIntrensic(w, funcExpr.Args[0], expr.Signature.ReturnType) @@ -422,7 +423,8 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC useImplicitTypeName := g.generateOptions.implicitResourceArgsTypeName inputTypeName := functionName + "InvokeArgs" destTypeName := strings.ReplaceAll(fullFunctionName, functionName, inputTypeName) - g.genObjectConsExpressionWithTypeName(w, objectExpr, destTypeName, useImplicitTypeName) + g.genObjectConsExpressionWithTypeName(w, objectExpr, destTypeName, useImplicitTypeName, + pcl.SortedFunctionParameters(funcExpr)) }) } else { g.Fgenf(w, "%v", funcExpr.Args[1]) @@ -492,7 +494,8 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC } destTypeName := strings.ReplaceAll(fullFunctionName, functionName, inputTypeName) - g.genObjectConsExpressionWithTypeName(w, arg, destTypeName, useImplicitTypeName) + g.genObjectConsExpressionWithTypeName(w, arg, destTypeName, useImplicitTypeName, + pcl.SortedFunctionParameters(expr)) }) default: g.genIntrensic(w, expr.Args[0], expr.Signature.ReturnType) @@ -503,7 +506,8 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC case *model.ObjectConsExpression: useImplicitTypeName := true destTypeName := "Irrelevant" - g.genObjectConsExpressionWithTypeName(w, arg, destTypeName, useImplicitTypeName) + g.genObjectConsExpressionWithTypeName(w, arg, destTypeName, useImplicitTypeName, + pcl.SortedFunctionParameters(expr)) default: g.genIntrensic(w, expr.Args[0], expr.Signature.ReturnType) } @@ -665,7 +669,7 @@ func (g *generator) genObjectConsExpression(w io.Writer, expr *model.ObjectConsE } destTypeName := g.argumentTypeName(expr, destType) - g.genObjectConsExpressionWithTypeName(w, expr, destTypeName, false) + g.genObjectConsExpressionWithTypeName(w, expr, destTypeName, false, nil) } func propertyNameOverrides(exprType model.Type) map[string]string { @@ -705,12 +709,21 @@ func resolvePropertyName(property string, overrides map[string]string) string { } func (g *generator) genObjectConsExpressionWithTypeName( - w io.Writer, expr *model.ObjectConsExpression, destTypeName string, implicitTypeName bool) { + w io.Writer, + expr *model.ObjectConsExpression, + destTypeName string, + implicitTypeName bool, + multiArguments []*schema.Property) { if len(expr.Items) == 0 { return } + if len(multiArguments) > 0 { + pcl.GenerateMultiArguments(g.Formatter, w, "null", expr, multiArguments) + return + } + typeName := destTypeName if typeName != "" { if implicitTypeName { @@ -813,10 +826,17 @@ func (g *generator) GenScopeTraversalExpression(w io.Writer, expr *model.ScopeTr invokedFunctionSchema, isFunctionInvoke := g.functionInvokes[rootName] - if isFunctionInvoke && !g.asyncInit { - lambdaArg := LowerCamelCase(g.schemaTypeName(invokedFunctionSchema.Outputs)) + if isFunctionInvoke && !g.asyncInit && len(expr.Parts) > 1 { + lambdaArg := "invoke" + if invokedFunctionSchema.ReturnType != nil { + if objectType, ok := invokedFunctionSchema.ReturnType.(*schema.ObjectType); ok && objectType != nil { + lambdaArg = LowerCamelCase(g.schemaTypeName(objectType)) + } + } + // Assume invokes are returning Output instead of Task g.Fgenf(w, ".Apply(%s => %s", lambdaArg, lambdaArg) + } var objType *schema.ObjectType @@ -827,7 +847,7 @@ func (g *generator) GenScopeTraversalExpression(w io.Writer, expr *model.ScopeTr } g.genRelativeTraversal(w, expr.Traversal.SimpleSplit().Rel, expr.Parts, objType) - if isFunctionInvoke && !g.asyncInit { + if isFunctionInvoke && !g.asyncInit && len(expr.Parts) > 1 { g.Fgenf(w, ")") } } diff --git a/pkg/codegen/go/doc.go b/pkg/codegen/go/doc.go index bf24fb8768ca..5aab3e2872a0 100644 --- a/pkg/codegen/go/doc.go +++ b/pkg/codegen/go/doc.go @@ -146,8 +146,15 @@ func (d DocLanguageHelper) GetMethodResultName(pkg *schema.Package, modName stri m *schema.Method) string { if info, ok := pkg.Language["go"].(GoPackageInfo); ok { - if info.LiftSingleValueMethodReturns && m.Function.Outputs != nil && len(m.Function.Outputs.Properties) == 1 { - t := m.Function.Outputs.Properties[0].Type + var objectReturnType *schema.ObjectType + if m.Function.ReturnType != nil { + if objectType, ok := m.Function.ReturnType.(*schema.ObjectType); ok && objectType != nil { + objectReturnType = objectType + } + } + + if info.LiftSingleValueMethodReturns && objectReturnType != nil && len(objectReturnType.Properties) == 1 { + t := objectReturnType.Properties[0].Type modPkg, ok := d.packages[modName] if !ok { glog.Errorf("cannot calculate type string for type %q. could not find a package for module %q", diff --git a/pkg/codegen/go/gen.go b/pkg/codegen/go/gen.go index f08470873a16..0f753235a64d 100644 --- a/pkg/codegen/go/gen.go +++ b/pkg/codegen/go/gen.go @@ -1884,7 +1884,14 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso methodName := Title(method.Name) f := method.Function - shouldLiftReturn := pkg.liftSingleValueMethodReturns && f.Outputs != nil && len(f.Outputs.Properties) == 1 + var objectReturnType *schema.ObjectType + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + objectReturnType = objectType + } + } + + liftReturn := pkg.liftSingleValueMethodReturns && objectReturnType != nil && len(objectReturnType.Properties) == 1 var args []*schema.Property if f.Inputs != nil { @@ -1902,10 +1909,10 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso argsig = fmt.Sprintf("%s, args *%s%sArgs", argsig, name, methodName) } var retty string - if f.Outputs == nil { + if objectReturnType == nil { retty = "error" - } else if shouldLiftReturn { - retty = fmt.Sprintf("(%s, error)", pkg.outputType(f.Outputs.Properties[0].Type)) + } else if liftReturn { + retty = fmt.Sprintf("(%s, error)", pkg.outputType(objectReturnType.Properties[0].Type)) } else { retty = fmt.Sprintf("(%s%sResultOutput, error)", name, methodName) } @@ -1914,7 +1921,7 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso fmt.Fprintf(w, "func (r *%s) %s(%s) %s {\n", name, methodName, argsig, retty) resultVar := "_" - if f.Outputs != nil { + if objectReturnType != nil { resultVar = "out" } @@ -1926,24 +1933,24 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso // Now simply invoke the runtime function with the arguments. outputsType := "pulumi.AnyOutput" - if f.Outputs != nil { - if shouldLiftReturn { + if objectReturnType != nil { + if liftReturn { outputsType = fmt.Sprintf("%s%sResultOutput", cgstrings.Camel(name), methodName) } else { outputsType = fmt.Sprintf("%s%sResultOutput", name, methodName) } } fmt.Fprintf(w, "\t%s, err := ctx.Call(%q, %s, %s{}, r)\n", resultVar, f.Token, inputsVar, outputsType) - if f.Outputs == nil { + if objectReturnType == nil { fmt.Fprintf(w, "\treturn err\n") - } else if shouldLiftReturn { + } else if liftReturn { // Check the error before proceeding. fmt.Fprintf(w, "\tif err != nil {\n") - fmt.Fprintf(w, "\t\treturn %s{}, err\n", pkg.outputType(f.Outputs.Properties[0].Type)) + fmt.Fprintf(w, "\t\treturn %s{}, err\n", pkg.outputType(objectReturnType.Properties[0].Type)) fmt.Fprintf(w, "\t}\n") // Get the name of the method to return the output - fmt.Fprintf(w, "\treturn %s.(%s).%s(), nil\n", resultVar, cgstrings.Camel(outputsType), Title(f.Outputs.Properties[0].Name)) + fmt.Fprintf(w, "\treturn %s.(%s).%s(), nil\n", resultVar, cgstrings.Camel(outputsType), Title(objectReturnType.Properties[0].Name)) } else { // Check the error before proceeding. fmt.Fprintf(w, "\tif err != nil {\n") @@ -1978,17 +1985,17 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso fmt.Fprintf(w, "\treturn reflect.TypeOf((*%s%sArgs)(nil)).Elem()\n", cgstrings.Camel(name), methodName) fmt.Fprintf(w, "}\n\n") } - if f.Outputs != nil { + if objectReturnType != nil { outputStructName := name // Don't export the result struct if we're lifting the value - if shouldLiftReturn { + if liftReturn { outputStructName = cgstrings.Camel(name) } fmt.Fprintf(w, "\n") - pkg.genPlainType(w, fmt.Sprintf("%s%sResult", outputStructName, methodName), f.Outputs.Comment, "", - f.Outputs.Properties) + pkg.genPlainType(w, fmt.Sprintf("%s%sResult", outputStructName, methodName), objectReturnType.Comment, "", + objectReturnType.Properties) fmt.Fprintf(w, "\n") fmt.Fprintf(w, "type %s%sResultOutput struct{ *pulumi.OutputState }\n\n", outputStructName, methodName) @@ -1997,7 +2004,7 @@ func (pkg *pkgContext) genResource(w io.Writer, r *schema.Resource, generateReso fmt.Fprintf(w, "\treturn reflect.TypeOf((*%s%sResult)(nil)).Elem()\n", outputStructName, methodName) fmt.Fprintf(w, "}\n") - for _, p := range f.Outputs.Properties { + for _, p := range objectReturnType.Properties { fmt.Fprintf(w, "\n") printCommentWithDeprecationMessage(w, p.Comment, p.DeprecationMessage, false) fmt.Fprintf(w, "func (o %s%sResultOutput) %s() %s {\n", outputStructName, methodName, Title(p.Name), @@ -2102,6 +2109,21 @@ func (pkg *pkgContext) genFunctionCodeFile(f *schema.Function) (string, error) { func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error { name := pkg.functionName(f) + + if f.MultiArgumentInputs { + return fmt.Errorf("go SDK-gen does not implement MultiArgumentInputs for function '%s'", f.Token) + } + + var objectReturnType *schema.ObjectType + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok { + objectReturnType = objectType + } else { + // TODO: remove when we add support for generalized return type for go + return fmt.Errorf("go sdk-gen doesn't support non-Object return types for function %s", f.Token) + } + } + printCommentWithDeprecationMessage(w, f.Comment, f.DeprecationMessage, false) // Now, emit the function signature. @@ -2110,7 +2132,7 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error { argsig = fmt.Sprintf("%s, args *%sArgs", argsig, name) } var retty string - if f.Outputs == nil || len(f.Outputs.Properties) == 0 { + if objectReturnType == nil { retty = "error" } else { retty = fmt.Sprintf("(*%sResult, error)", name) @@ -2129,7 +2151,7 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error { // Now simply invoke the runtime function with the arguments. var outputsType string - if f.Outputs == nil || len(f.Outputs.Properties) == 0 { + if objectReturnType == nil { outputsType = "struct{}" } else { outputsType = name + "Result" @@ -2143,7 +2165,7 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error { fmt.Fprintf(w, "\tvar rv %s\n", outputsType) fmt.Fprintf(w, "\terr := ctx.Invoke(\"%s\", %s, &rv, opts...)\n", f.Token, inputsVar) - if f.Outputs == nil || len(f.Outputs.Properties) == 0 { + if objectReturnType == nil { fmt.Fprintf(w, "\treturn err\n") } else { // Check the error before proceeding. @@ -2153,7 +2175,7 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error { // Return the result. var retValue string - if codegen.IsProvideDefaultsFuncRequired(f.Outputs) && !pkg.disableObjectDefaults { + if codegen.IsProvideDefaultsFuncRequired(objectReturnType) && !pkg.disableObjectDefaults { retValue = "rv.Defaults()" } else { retValue = "&rv" @@ -2173,12 +2195,12 @@ func (pkg *pkgContext) genFunction(w io.Writer, f *schema.Function) error { } } } - if f.Outputs != nil && len(f.Outputs.Properties) > 0 { + if objectReturnType != nil { fmt.Fprintf(w, "\n") fnOutputsName := pkg.functionResultTypeName(f) - pkg.genPlainType(w, fnOutputsName, f.Outputs.Comment, "", f.Outputs.Properties) - if codegen.IsProvideDefaultsFuncRequired(f.Outputs) && !pkg.disableObjectDefaults { - if err := pkg.genObjectDefaultFunc(w, fnOutputsName, f.Outputs.Properties); err != nil { + pkg.genPlainType(w, fnOutputsName, objectReturnType.Comment, "", objectReturnType.Properties) + if codegen.IsProvideDefaultsFuncRequired(objectReturnType) && !pkg.disableObjectDefaults { + if err := pkg.genObjectDefaultFunc(w, fnOutputsName, objectReturnType.Properties); err != nil { return err } } @@ -2245,10 +2267,14 @@ func ${fn}Output(ctx *pulumi.Context, args ${fn}OutputArgs, opts ...pulumi.Invok elementType: pkg.functionArgsTypeName(f), }) - pkg.genOutputTypes(w, genOutputTypesArgs{ - t: f.Outputs, - name: originalResultTypeName, - }) + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + pkg.genOutputTypes(w, genOutputTypesArgs{ + t: objectType, + name: originalResultTypeName, + }) + } + } // Assuming the file represented by `w` only has one function, // generate an `init()` for Output type init. @@ -2655,8 +2681,16 @@ func (pkg *pkgContext) genResourceRegistrations(w io.Writer, r *schema.Resource, // Register all output types fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%sOutput{})\n", name) for _, method := range r.Methods { - if method.Function.Outputs != nil { - if pkg.liftSingleValueMethodReturns && len(method.Function.Outputs.Properties) == 1 { + + var objectReturnType *schema.ObjectType + if method.Function.ReturnType != nil { + if objectType, ok := method.Function.ReturnType.(*schema.ObjectType); ok && objectType != nil { + objectReturnType = objectType + } + } + + if objectReturnType != nil { + if pkg.liftSingleValueMethodReturns && len(objectReturnType.Properties) == 1 { fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%s%sResultOutput{})\n", cgstrings.Camel(name), Title(method.Name)) } else { fmt.Fprintf(w, "\tpulumi.RegisterOutputType(%s%sResultOutput{})\n", name, Title(method.Name)) @@ -2780,8 +2814,16 @@ func (pkg *pkgContext) getImports(member interface{}, importsAndAliases map[stri pkg.getTypeImports(p.Type, false, importsAndAliases, seen) } } - if method.Function.Outputs != nil { - for _, p := range method.Function.Outputs.Properties { + + var returnType *schema.ObjectType + if method.Function.ReturnType != nil { + if objectType, ok := method.Function.ReturnType.(*schema.ObjectType); ok && objectType != nil { + returnType = objectType + } + } + + if returnType != nil { + for _, p := range returnType.Properties { pkg.getTypeImports(p.Type, false, importsAndAliases, seen) } } @@ -2790,8 +2832,16 @@ func (pkg *pkgContext) getImports(member interface{}, importsAndAliases map[stri if member.Inputs != nil { pkg.getTypeImports(member.Inputs, true, importsAndAliases, seen) } - if member.Outputs != nil { - pkg.getTypeImports(member.Outputs, true, importsAndAliases, seen) + + var returnType *schema.ObjectType + if member.ReturnType != nil { + if objectType, ok := member.ReturnType.(*schema.ObjectType); ok && objectType != nil { + returnType = objectType + } + } + + if returnType != nil { + pkg.getTypeImports(returnType, true, importsAndAliases, seen) } case []*schema.Property: for _, p := range member { @@ -3311,8 +3361,10 @@ func generatePackageContextMap(tool string, pkg schema.PackageReference, goInfo if method.Function.Inputs != nil { pkg.names.Add(rawResourceName(r) + Title(method.Name) + "Args") } - if method.Function.Outputs != nil { - pkg.names.Add(rawResourceName(r) + Title(method.Name) + "Result") + if method.Function.ReturnType != nil { + if _, ok := method.Function.ReturnType.(*schema.ObjectType); ok { + pkg.names.Add(rawResourceName(r) + Title(method.Name) + "Result") + } } } } @@ -3440,8 +3492,8 @@ func generatePackageContextMap(tool string, pkg schema.PackageReference, goInfo if f.Inputs != nil { populateDetailsForPropertyTypes(seenMap, f.Inputs.InputShape.Properties, optional, false, false) } - if f.Outputs != nil { - populateDetailsForTypes(seenMap, f.Outputs, optional, false, true) + if f.ReturnType != nil { + populateDetailsForTypes(seenMap, f.ReturnType, optional, false, true) } } } @@ -3470,11 +3522,14 @@ func generatePackageContextMap(tool string, pkg schema.PackageReference, goInfo pkg.names.Add(name) pkg.functionNames[f] = name - if f.Inputs != nil { + if f.Inputs != nil && !f.MultiArgumentInputs { pkg.names.Add(name + "Args") } - if f.Outputs != nil { - pkg.names.Add(name + "Result") + + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + pkg.names.Add(name + "Result") + } } } diff --git a/pkg/codegen/go/gen_program_expressions.go b/pkg/codegen/go/gen_program_expressions.go index 9b0c641f21fe..e0d31c8e5f26 100644 --- a/pkg/codegen/go/gen_program_expressions.go +++ b/pkg/codegen/go/gen_program_expressions.go @@ -264,6 +264,10 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC // Assuming the existence of the following helper method g.Fgenf(w, "filebase64sha256OrPanic(%v)", expr.Args[0]) case pcl.Invoke: + if expr.Signature.MultiArgumentInputs { + panic(fmt.Errorf("go program-gen does not implement MultiArgumentInputs for function '%v'", + expr.Args[0])) + } pkg, module, fn, diags := g.functionName(expr.Args[0]) contract.Assertf(len(diags) == 0, "We don't allow problems getting the function name") diff --git a/pkg/codegen/hcl2/model/functions.go b/pkg/codegen/hcl2/model/functions.go index 1bde2154d1b5..0e39a141ffca 100644 --- a/pkg/codegen/hcl2/model/functions.go +++ b/pkg/codegen/hcl2/model/functions.go @@ -41,6 +41,8 @@ type StaticFunctionSignature struct { VarargsParameter *Parameter // The return type of the function. ReturnType Type + // Determines whether the input bag should be treated as a single argument or as multiple arguments. + MultiArgumentInputs bool } // GetSignature returns the static signature itself. diff --git a/pkg/codegen/nodejs/doc.go b/pkg/codegen/nodejs/doc.go index d6cda06383ef..a9bfc3afc39e 100644 --- a/pkg/codegen/nodejs/doc.go +++ b/pkg/codegen/nodejs/doc.go @@ -111,13 +111,26 @@ func (d DocLanguageHelper) GetMethodName(m *schema.Method) string { func (d DocLanguageHelper) GetMethodResultName(pkg *schema.Package, modName string, r *schema.Resource, m *schema.Method) string { + var objectReturnType *schema.ObjectType + if m.Function.ReturnType != nil { + if objectType, ok := m.Function.ReturnType.(*schema.ObjectType); ok && objectType != nil { + objectReturnType = objectType + } else { + modCtx := &modContext{ + pkg: pkg.Reference(), + mod: modName, + } + return modCtx.typeString(m.Function.ReturnType, false, nil) + } + } + if info, ok := pkg.Language["nodejs"].(NodePackageInfo); ok { - if info.LiftSingleValueMethodReturns && m.Function.Outputs != nil && len(m.Function.Outputs.Properties) == 1 { + if info.LiftSingleValueMethodReturns && objectReturnType != nil && len(objectReturnType.Properties) == 1 { modCtx := &modContext{ pkg: pkg.Reference(), mod: modName, } - return modCtx.typeString(m.Function.Outputs.Properties[0].Type, false, nil) + return modCtx.typeString(objectReturnType.Properties[0].Type, false, nil) } } return fmt.Sprintf("%s.%sResult", resourceName(r), title(d.GetMethodName(m))) diff --git a/pkg/codegen/nodejs/gen.go b/pkg/codegen/nodejs/gen.go index 1952d8f34627..13bd027c9cf8 100644 --- a/pkg/codegen/nodejs/gen.go +++ b/pkg/codegen/nodejs/gen.go @@ -929,7 +929,16 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFil methodName := camel(method.Name) fun := method.Function - shouldLiftReturn := mod.liftSingleValueMethodReturns && fun.Outputs != nil && len(fun.Outputs.Properties) == 1 + var objectReturnType *schema.ObjectType + if fun.ReturnType != nil { + if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && objectType != nil { + objectReturnType = objectType + } else { + return + } + } + + liftReturn := mod.liftSingleValueMethodReturns && objectReturnType != nil && len(objectReturnType.Properties) == 1 // Write the TypeDoc/JSDoc for the data source function. fmt.Fprint(w, "\n") @@ -961,10 +970,10 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFil } } var retty string - if fun.Outputs == nil { + if fun.ReturnType == nil { retty = "void" - } else if shouldLiftReturn { - retty = fmt.Sprintf("pulumi.Output<%s>", mod.typeString(fun.Outputs.Properties[0].Type, false, nil)) + } else if liftReturn { + retty = fmt.Sprintf("pulumi.Output<%s>", mod.typeString(objectReturnType.Properties[0].Type, false, nil)) } else { retty = fmt.Sprintf("pulumi.Output<%s.%sResult>", name, title(method.Name)) } @@ -981,8 +990,8 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFil // Now simply call the runtime function with the arguments, returning the results. var ret string - if fun.Outputs != nil { - if shouldLiftReturn { + if fun.ReturnType != nil { + if liftReturn { ret = fmt.Sprintf("const result: pulumi.Output<%s.%sResult> = ", name, title(method.Name)) } else { ret = "return " @@ -1000,8 +1009,8 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFil } } fmt.Fprintf(w, " }, this);\n") - if shouldLiftReturn { - fmt.Fprintf(w, " return result.%s;\n", camel(fun.Outputs.Properties[0].Name)) + if liftReturn { + fmt.Fprintf(w, " return result.%s;\n", camel(objectReturnType.Properties[0].Name)) } fmt.Fprintf(w, " }\n") } @@ -1053,15 +1062,18 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFil fmt.Fprintf(w, "\n") } } - if fun.Outputs != nil { - comment := fun.Inputs.Comment - if comment == "" { - comment = fmt.Sprintf("The results of the %s.%s method.", name, method.Name) - } - if err := mod.genPlainType(w, methodName+"Result", comment, fun.Outputs.Properties, false, true, 1); err != nil { - return err + + if fun.ReturnType != nil { + if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && objectType != nil { + comment := fun.Inputs.Comment + if comment == "" { + comment = fmt.Sprintf("The results of the %s.%s method.", name, method.Name) + } + if err := mod.genPlainType(w, methodName+"Result", comment, objectType.Properties, false, true, 1); err != nil { + return err + } + fmt.Fprintf(w, "\n") } - fmt.Fprintf(w, "\n") } return nil } @@ -1081,6 +1093,46 @@ func (mod *modContext) genResource(w io.Writer, r *schema.Resource) (resourceFil return info, nil } +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 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" + } +} + func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) (functionFileInfo, error) { name := tokenToFunctionName(fun.Token) info := functionFileInfo{functionName: name} @@ -1102,27 +1154,51 @@ func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) (functionF } argsig = fmt.Sprintf("args%s: %sArgs, ", optFlag, title(name)) } - fmt.Fprintf(w, "export function %s(%sopts?: pulumi.InvokeOptions): Promise<%s> {\n", - name, argsig, functionReturnType(fun)) + + 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) if fun.DeprecationMessage != "" && mod.compatibility != kubernetes20 { fmt.Fprintf(w, " pulumi.log.warn(\"%s is deprecated: %s\")\n", name, escape(fun.DeprecationMessage)) } // Zero initialize the args if empty and necessary. - if fun.Inputs != nil && argsOptional { + if fun.Inputs != nil && argsOptional && !fun.MultiArgumentInputs { fmt.Fprintf(w, " args = args || {};\n") } + fmt.Fprint(w, "\n") // If the caller didn't request a specific version, supply one using the version of this library. - fmt.Fprintf(w, "\n") fmt.Fprintf(w, " opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {});\n") - + invokeCall := runtimeInvokeFunction(fun) // Now simply invoke the runtime function with the arguments, returning the results. - fmt.Fprintf(w, " return pulumi.runtime.invoke(\"%s\", {\n", fun.Token) + fmt.Fprintf(w, " return pulumi.runtime.%s(\"%s\", {\n", invokeCall, fun.Token) if fun.Inputs != nil { for _, p := range fun.Inputs.Properties { // Pass the argument to the invocation. body := fmt.Sprintf("args.%s", p.Name) + if fun.MultiArgumentInputs { + body = p.Name + } + if name := mod.provideDefaultsFuncName(p.Type, true /*input*/); name != "" { if codegen.IsNOptionalInput(p.Type) { body = fmt.Sprintf("pulumi.output(%s).apply(%s)", body, name) @@ -1134,11 +1210,12 @@ func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) (functionF fmt.Fprintf(w, " \"%[1]s\": %[2]s,\n", p.Name, body) } } - fmt.Fprintf(w, " }, opts);\n") - fmt.Fprintf(w, "}\n") + + fmt.Fprint(w, " }, opts);\n") + fmt.Fprint(w, "}\n") // If there are argument and/or return types, emit them. - if fun.Inputs != nil { + if fun.Inputs != nil && !fun.MultiArgumentInputs { fmt.Fprintf(w, "\n") argsInterfaceName := title(name) + "Args" if err := mod.genPlainType(w, argsInterfaceName, fun.Inputs.Comment, fun.Inputs.Properties, true, false, 0); err != nil { @@ -1146,13 +1223,18 @@ func (mod *modContext) genFunction(w io.Writer, fun *schema.Function) (functionF } info.functionArgsInterfaceName = argsInterfaceName } - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { - fmt.Fprintf(w, "\n") - resultInterfaceName := title(name) + "Result" - if err := mod.genPlainType(w, resultInterfaceName, fun.Outputs.Comment, fun.Outputs.Properties, false, true, 0); err != nil { - return info, err + + // 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 } - info.functionResultInterfaceName = resultInterfaceName } return mod.genFunctionOutputVersion(w, fun, info) @@ -1169,13 +1251,6 @@ func functionArgsOptional(fun *schema.Function) bool { return true } -func functionReturnType(fun *schema.Function) string { - if fun.Outputs == nil || len(fun.Outputs.Properties) == 0 { - return "void" - } - return title(tokenToFunctionName(fun.Token)) + "Result" -} - // Generates `function ${fn}Output(..)` version lifted to work on // `Input`-warpped arguments and producing an `Output`-wrapped result. func (mod *modContext) genFunctionOutputVersion( @@ -1186,15 +1261,9 @@ func (mod *modContext) genFunctionOutputVersion( return info, nil } - // 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) - } - originalName := tokenToFunctionName(fun.Token) fnOutput := fmt.Sprintf("%sOutput", originalName) + returnType := mod.functionReturnType(fun) info.functionOutputVersionName = fnOutput argTypeName := fmt.Sprintf("%sArgs", title(fnOutput)) @@ -1206,22 +1275,59 @@ func (mod *modContext) genFunctionOutputVersion( } argsig = fmt.Sprintf("args%s: %s, ", optFlag, argTypeName) - fmt.Fprintf(w, `export function %s(%sopts?: pulumi.InvokeOptions): pulumi.Output<%s> { + // 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 { + fmt.Fprintf(w, `export function %s(%sopts?: pulumi.InvokeOptions): pulumi.Output<%s> { return pulumi.output(args).apply((a: any) => %s(a, opts)) } -`, fnOutput, argsig, functionReturnType(fun), originalName) - fmt.Fprintf(w, "\n") +`, fnOutput, argsig, returnType, originalName) + } else { + fmt.Fprintf(w, "export function %s(", fnOutput) + for _, prop := range fun.Inputs.Properties { + 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) + } - info.functionOutputVersionArgsInterfaceName = argTypeName + fmt.Fprintf(w, "%s, ", paramDeclaration) + } + + fmt.Fprintf(w, "opts?: pulumi.InvokeOptions): pulumi.Output<%s> {\n", returnType) + fmt.Fprint(w, " var args = {\n") + for _, p := range fun.Inputs.Properties { + 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) + for _, p := range fun.Inputs.Properties { + // Pass the argument to the invocation. + fmt.Fprintf(w, "resolvedArgs.%s, ", p.Name) + } + fmt.Fprint(w, "opts))\n") + fmt.Fprint(w, "}\n") + } - if err := mod.genPlainType(w, - argTypeName, - fun.Inputs.Comment, - fun.Inputs.InputShape.Properties, - true, /* input */ - false, /* readonly */ - 0 /* level */); err != nil { - return info, err + if !fun.MultiArgumentInputs { + 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 + } } return info, nil @@ -1419,10 +1525,13 @@ func (mod *modContext) getImportsForResource(member interface{}, externalImports mod.getTypeImportsForResource(p.Type, false, externalImports, imports, seen, res) || needsTypes } } - if method.Function.Outputs != nil { - for _, p := range method.Function.Outputs.Properties { - needsTypes = - mod.getTypeImportsForResource(p.Type, false, externalImports, imports, seen, res) || needsTypes + + if method.Function.ReturnType != nil { + if objectType, ok := method.Function.ReturnType.(*schema.ObjectType); ok && objectType != nil { + for _, p := range objectType.Properties { + needsTypes = + mod.getTypeImportsForResource(p.Type, false, externalImports, imports, seen, res) || needsTypes + } } } } @@ -1434,9 +1543,16 @@ func (mod *modContext) getImportsForResource(member interface{}, externalImports needsTypes = mod.getTypeImports(p.Type, false, externalImports, imports, seen) || needsTypes } } - if member.Outputs != nil { - for _, p := range member.Outputs.Properties { - needsTypes = mod.getTypeImports(p.Type, false, externalImports, imports, seen) || needsTypes + 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 } } return needsTypes @@ -2461,10 +2577,20 @@ func generateModuleContextMap(tool string, pkg *schema.Package, extraFiles map[s }) } } - if f.Outputs != nil { - visitObjectTypes(f.Outputs.Properties, func(t *schema.ObjectType) { - types.details(t).outputType = true - }) + 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 + } + }) + } } } diff --git a/pkg/codegen/nodejs/gen_program_expressions.go b/pkg/codegen/nodejs/gen_program_expressions.go index c5daeb8bd5eb..ad848e6df262 100644 --- a/pkg/codegen/nodejs/gen_program_expressions.go +++ b/pkg/codegen/nodejs/gen_program_expressions.go @@ -416,7 +416,20 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC } g.Fprintf(w, "%s(", name) if len(expr.Args) >= 2 { - g.Fgenf(w, "%.v", expr.Args[1]) + if expr.Signature.MultiArgumentInputs { + var invokeArgs *model.ObjectConsExpression + // extract invoke args in case we have the form invoke("token", __convert(args)) + if converted, objectArgs, _ := pcl.RecognizeTypedObjectCons(expr.Args[1]); converted { + invokeArgs = objectArgs + } else { + // otherwise, we have the form invoke("token", args) + invokeArgs = expr.Args[1].(*model.ObjectConsExpression) + } + + pcl.GenerateMultiArguments(g.Formatter, w, "undefined", invokeArgs, pcl.SortedFunctionParameters(expr)) + } else { + g.Fgenf(w, "%.v", expr.Args[1]) + } } if len(expr.Args) == 3 { g.Fgenf(w, ", %.v", expr.Args[2]) diff --git a/pkg/codegen/pcl/invoke.go b/pkg/codegen/pcl/invoke.go index 8725d1f7d01f..9f7d68dc76e6 100644 --- a/pkg/codegen/pcl/invoke.go +++ b/pkg/codegen/pcl/invoke.go @@ -155,6 +155,7 @@ func (b *binder) bindInvokeSignature(args []model.Expression) (model.StaticFunct } } + sig.MultiArgumentInputs = fn.MultiArgumentInputs return sig, nil } @@ -221,10 +222,10 @@ func (b *binder) regularSignature(fn *schema.Function) model.StaticFunctionSigna } var returnType model.Type - if fn.Outputs == nil { + if fn.ReturnType == nil { returnType = model.NewObjectType(map[string]model.Type{}) } else { - returnType = b.schemaTypeToType(fn.Outputs) + returnType = b.schemaTypeToType(fn.ReturnType) } return b.makeSignature(argsType, model.NewPromiseType(returnType)) @@ -235,9 +236,9 @@ func (b *binder) outputVersionSignature(fn *schema.Function) (model.StaticFuncti return model.StaticFunctionSignature{}, fmt.Errorf("Function %s does not have an Output version", fn.Token) } - // Given `fn.NeedsOutputVersion()==true`, can assume `fn.Inputs != nil`, `fn.Outputs != nil`. + // Given `fn.NeedsOutputVersion()==true`, can assume `fn.Inputs != nil`, `fn.ReturnType != nil`. argsType := b.schemaTypeToType(fn.Inputs.InputShape) - returnType := b.schemaTypeToType(fn.Outputs) + returnType := b.schemaTypeToType(fn.ReturnType) return b.makeSignature(argsType, model.NewOutputType(returnType)), nil } diff --git a/pkg/codegen/pcl/utilities.go b/pkg/codegen/pcl/utilities.go index b5645f01cd74..9fa1c44927cf 100644 --- a/pkg/codegen/pcl/utilities.go +++ b/pkg/codegen/pcl/utilities.go @@ -15,6 +15,7 @@ package pcl import ( + "io" "sort" "strings" "unicode" @@ -23,6 +24,8 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/pulumi/pulumi/pkg/v3/codegen" "github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/model" + "github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/model/format" + "github.com/pulumi/pulumi/pkg/v3/codegen/schema" ) // titleCase replaces the first character in the given string with its upper-case equivalent. @@ -162,3 +165,76 @@ func FixupPulumiPackageTokens(r *Resource) { r.Token = "pulumi::" + name } } + +// SortedFunctionParameters returns a list of properties of the input type from the schema +// for an invoke function call which has multi argument inputs. We assume here +// that the expression is an invoke which has it's args (2nd parameter) annotated +// with the original schema type. The original schema type has properties sorted. +// This is important because model.ObjectType has no guarantee of property order. +func SortedFunctionParameters(expr *model.FunctionCallExpression) []*schema.Property { + if !expr.Signature.MultiArgumentInputs { + return []*schema.Property{} + } + + switch args := expr.Signature.Parameters[1].Type.(type) { + case *model.ObjectType: + if len(args.Annotations) == 0 { + return []*schema.Property{} + } + + originalSchemaType, ok := args.Annotations[0].(*schema.ObjectType) + if !ok { + return []*schema.Property{} + } + + return originalSchemaType.Properties + default: + return []*schema.Property{} + } +} + +// GenerateMultiArguments takes the input bag (object) of a function invoke and spreads the values of that object +// into multi-argument function call. +// For example, { a: 1, b: 2 } with multiInputArguments: ["a", "b"] would become: 1, 2 +// +// However, when optional parameters are omitted, then is used where they should be. +// Take for example { a: 1, c: 3 } with multiInputArguments: ["a", "b", "c"], it becomes 1, , 3 +// because b was omitted and c was provided so b had to be the provided +func GenerateMultiArguments( + f *format.Formatter, + w io.Writer, + undefinedLiteral string, + expr *model.ObjectConsExpression, + multiArguments []*schema.Property) { + items := make(map[string]model.Expression) + for _, item := range expr.Items { + lit := item.Key.(*model.LiteralValueExpression) + propertyKey := lit.Value.AsString() + items[propertyKey] = item.Value + } + + hasMoreArgs := func(index int) bool { + for _, arg := range multiArguments[index:] { + if _, ok := items[arg.Name]; ok { + return true + } + } + + return false + } + + for index, arg := range multiArguments { + value, ok := items[arg.Name] + if ok { + f.Fgenf(w, "%.v", value) + } else if hasMoreArgs(index) { + // a positional argument was not provided in the input bag + // assume it is optional + f.Fgen(w, undefinedLiteral) + } + + if hasMoreArgs(index + 1) { + f.Fgen(w, ", ") + } + } +} diff --git a/pkg/codegen/python/doc.go b/pkg/codegen/python/doc.go index 843bbd31605f..5da50aa83d50 100644 --- a/pkg/codegen/python/doc.go +++ b/pkg/codegen/python/doc.go @@ -110,15 +110,22 @@ func (d DocLanguageHelper) GetMethodName(m *schema.Method) string { func (d DocLanguageHelper) GetMethodResultName(pkg *schema.Package, modName string, r *schema.Resource, m *schema.Method) string { + var returnType *schema.ObjectType + if m.Function.ReturnType != nil { + if objectType, ok := m.Function.ReturnType.(*schema.ObjectType); ok && objectType != nil { + returnType = objectType + } + } + if info, ok := pkg.Language["python"].(PackageInfo); ok { - if info.LiftSingleValueMethodReturns && m.Function.Outputs != nil && len(m.Function.Outputs.Properties) == 1 { + if info.LiftSingleValueMethodReturns && returnType != nil && len(returnType.Properties) == 1 { typeDetails := map[*schema.ObjectType]*typeDetails{} mod := &modContext{ pkg: pkg.Reference(), mod: modName, typeDetails: typeDetails, } - return mod.typeString(m.Function.Outputs.Properties[0].Type, false, false) + return mod.typeString(returnType.Properties[0].Type, false, false) } } return fmt.Sprintf("%s.%sResult", resourceName(r), title(d.GetMethodName(m))) diff --git a/pkg/codegen/python/gen.go b/pkg/codegen/python/gen.go index bdde452331f7..b85fe1c631a8 100644 --- a/pkg/codegen/python/gen.go +++ b/pkg/codegen/python/gen.go @@ -561,6 +561,11 @@ func (mod *modContext) gen(fs codegen.Fs) error { continue } + if f.MultiArgumentInputs { + return fmt.Errorf("python SDK-gen does not implement MultiArgumentInputs for function '%s'", + f.Token) + } + fun, err := mod.genFunction(f) if err != nil { return err @@ -1151,8 +1156,9 @@ func (mod *modContext) genResource(res *schema.Resource) (string, error) { if method.Function.Inputs != nil { mod.collectImportsForResource(method.Function.Inputs.Properties, imports, true /*input*/, res) } - if method.Function.Outputs != nil { - mod.collectImportsForResource(method.Function.Outputs.Properties, imports, false /*input*/, res) + returnType := returnTypeObject(method.Function) + if returnType != nil { + mod.collectImportsForResource(returnType.Properties, imports, false /*input*/, res) } } @@ -1526,7 +1532,7 @@ func (mod *modContext) genProperties(w io.Writer, properties []*schema.Property, func (mod *modContext) genMethods(w io.Writer, res *schema.Resource) { genReturnType := func(method *schema.Method) string { - obj := method.Function.Outputs + obj := returnTypeObject(method.Function) name := pyClassName(title(method.Name)) + "Result" // Produce a class definition with optional """ comment. @@ -1570,18 +1576,19 @@ func (mod *modContext) genMethods(w io.Writer, res *schema.Resource) { genMethod := func(method *schema.Method) { methodName := PyName(method.Name) fun := method.Function + returnType := returnTypeObject(fun) - shouldLiftReturn := mod.liftSingleValueMethodReturns && method.Function.Outputs != nil && len(method.Function.Outputs.Properties) == 1 + shouldLiftReturn := mod.liftSingleValueMethodReturns && returnType != nil && len(returnType.Properties) == 1 // If there is a return type, emit it. var retTypeName, retTypeNameQualified, retTypeNameQualifiedOutput, methodRetType string - if fun.Outputs != nil { + if returnType != nil { retTypeName = genReturnType(method) retTypeNameQualified = fmt.Sprintf("%s.%s", resourceName(res), retTypeName) retTypeNameQualifiedOutput = fmt.Sprintf("pulumi.Output['%s']", retTypeNameQualified) if shouldLiftReturn { - methodRetType = fmt.Sprintf("pulumi.Output['%s']", mod.pyType(fun.Outputs.Properties[0].Type)) + methodRetType = fmt.Sprintf("pulumi.Output['%s']", mod.pyType(returnType.Properties[0].Type)) } else { methodRetType = retTypeNameQualifiedOutput } @@ -1669,12 +1676,12 @@ func (mod *modContext) genMethods(w io.Writer, res *schema.Resource) { typ = fmt.Sprintf(", typ=%s", retTypeNameQualified) } - if method.Function.Outputs == nil { + if returnType == nil { fmt.Fprintf(w, " pulumi.runtime.call('%s', __args__, res=__self__%s)\n", fun.Token, typ) } else if shouldLiftReturn { // Store the return in a variable and return the property output fmt.Fprintf(w, " __result__ = pulumi.runtime.call('%s', __args__, res=__self__%s)\n", fun.Token, typ) - fmt.Fprintf(w, " return __result__.%s\n", PyName(fun.Outputs.Properties[0].Name)) + fmt.Fprintf(w, " return __result__.%s\n", PyName(returnType.Properties[0].Name)) } else { // Otherwise return the call directly fmt.Fprintf(w, " return pulumi.runtime.call('%s', __args__, res=__self__%s)\n", fun.Token, typ) @@ -1717,21 +1724,32 @@ func (mod *modContext) genFunction(fun *schema.Function) (string, error) { if fun.Inputs != nil { mod.collectImports(fun.Inputs.Properties, imports, true) } - if fun.Outputs != nil { - mod.collectImports(fun.Outputs.Properties, imports, false) + + var returnType *schema.ObjectType + if fun.ReturnType != nil { + if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok { + returnType = objectType + } else { + // TODO: remove when we add support for generalized return type for python + return "", fmt.Errorf("python sdk-gen doesn't support non-Object return types for function %s", fun.Token) + } + } + + if returnType != nil { + mod.collectImports(returnType.Properties, imports, false) } mod.genFunctionHeader(w, fun, imports) var baseName, awaitableName string - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { - baseName, awaitableName = awaitableTypeNames(fun.Outputs.Token) + if returnType != nil { + baseName, awaitableName = awaitableTypeNames(returnType.Token) } name := PyName(tokenToName(fun.Token)) // Export only the symbols we want exported. fmt.Fprintf(w, "__all__ = [\n") - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { + if returnType != nil { fmt.Fprintf(w, " '%s',\n", baseName) fmt.Fprintf(w, " '%s',\n", awaitableName) } @@ -1749,8 +1767,8 @@ func (mod *modContext) genFunction(fun *schema.Function) (string, error) { // If there is a return type, emit it. retTypeName := "" var rets []*schema.Property - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { - retTypeName, rets = mod.genAwaitableType(w, fun.Outputs), fun.Outputs.Properties + if returnType != nil { + retTypeName, rets = mod.genAwaitableType(w, returnType), returnType.Properties fmt.Fprintf(w, "\n\n") } else { retTypeName = "Awaitable[None]" @@ -1777,7 +1795,7 @@ func (mod *modContext) genFunction(fun *schema.Function) (string, error) { // Now simply invoke the runtime function with the arguments. var typ string - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { + if returnType != nil { // Pass along the private output_type we generated, so any nested outputs classes are instantiated by // the call to invoke. typ = fmt.Sprintf(", typ=%s", baseName) @@ -1786,7 +1804,7 @@ func (mod *modContext) genFunction(fun *schema.Function) (string, error) { fmt.Fprintf(w, "\n") // And copy the results to an object, if there are indeed any expected returns. - if fun.Outputs != nil && len(fun.Outputs.Properties) > 0 { + if returnType != nil { fmt.Fprintf(w, " return %s(", retTypeName) for i, ret := range rets { if i > 0 { @@ -1870,6 +1888,15 @@ func (mod *modContext) genFunDef(w io.Writer, name, retTypeName string, args []* } } +func returnTypeObject(fun *schema.Function) *schema.ObjectType { + if fun.ReturnType != nil { + if objectType, ok := fun.ReturnType.(*schema.ObjectType); ok && objectType != nil { + return objectType + } + } + return nil +} + // Generates `def ${fn}_output(..) version lifted to work on // `Input`-wrapped arguments and producing an `Output`-wrapped result. func (mod *modContext) genFunctionOutputVersion(w io.Writer, fun *schema.Function) { @@ -1877,9 +1904,11 @@ func (mod *modContext) genFunctionOutputVersion(w io.Writer, fun *schema.Functio return } + returnType := returnTypeObject(fun) + var retTypeName string - if fun.Outputs != nil { - originalOutputTypeName, _ := awaitableTypeNames(fun.Outputs.Token) + if returnType != nil { + originalOutputTypeName, _ := awaitableTypeNames(returnType.Token) retTypeName = fmt.Sprintf("pulumi.Output[%s]", originalOutputTypeName) } else { retTypeName = "pulumi.Output[void]" @@ -2788,8 +2817,16 @@ func generateModuleContextMap(tool string, pkg *schema.Package, info PackageInfo } }) } - if f.Outputs != nil { - visitObjectTypes(f.Outputs.Properties, func(t schema.Type) { + + var returnType *schema.ObjectType + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + returnType = objectType + } + } + + if returnType != nil { + visitObjectTypes(returnType.Properties, func(t schema.Type) { switch T := t.(type) { case *schema.ObjectType: getModFromToken(T.Token, T.PackageReference).details(T).outputType = true diff --git a/pkg/codegen/python/gen_program_expressions.go b/pkg/codegen/python/gen_program_expressions.go index da1c13cfb675..0510b5502780 100644 --- a/pkg/codegen/python/gen_program_expressions.go +++ b/pkg/codegen/python/gen_program_expressions.go @@ -298,6 +298,12 @@ func (g *generator) GenFunctionCallExpression(w io.Writer, expr *model.FunctionC // Assuming the existence of the following helper method g.Fgenf(w, "computeFilebase64sha256(%v)", expr.Args[0]) case pcl.Invoke: + if expr.Signature.MultiArgumentInputs { + err := fmt.Errorf("python program-gen does not implement MultiArgumentInputs for function '%v'", + expr.Args[0]) + panic(err) + } + pkg, module, fn, diags := functionName(expr.Args[0]) contract.Assert(len(diags) == 0) if module != "" { diff --git a/pkg/codegen/schema/bind.go b/pkg/codegen/schema/bind.go index 6e70a88389fa..472bf163a38e 100644 --- a/pkg/codegen/schema/bind.go +++ b/pkg/codegen/schema/bind.go @@ -1476,6 +1476,13 @@ func (t *types) bindFunctionDef(token string) (*Function, hcl.Diagnostics, error path := memberPath("functions", token) + // Check that spec.MultiArgumentInputs => spec.Inputs + if len(spec.MultiArgumentInputs) > 0 && spec.Inputs == nil { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "cannot specify multi-argument inputs without specifying inputs", + }) + } var inputs *ObjectType if spec.Inputs != nil { ins, inDiags, err := t.bindAnonymousObjectType(path+"/inputs", token+"Args", *spec.Inputs) @@ -1483,33 +1490,111 @@ func (t *types) bindFunctionDef(token string) (*Function, hcl.Diagnostics, error if err != nil { return nil, diags, fmt.Errorf("error binding inputs for function %v: %w", token, err) } + + if len(spec.MultiArgumentInputs) > 0 { + idx := make(map[string]int, len(spec.MultiArgumentInputs)) + for i, k := range spec.MultiArgumentInputs { + idx[k] = i + } + // Check that MultiArgumentInputs matches up 1:1 with the input properties + for k, i := range idx { + if _, ok := spec.Inputs.Properties[k]; !ok { + diags = diags.Append(&hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("multiArgumentInputs[%d] refers to non-existent property %#v", i, k), + }) + } + } + var detailGiven bool + for k := range spec.Inputs.Properties { + if _, ok := idx[k]; !ok { + diag := hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: fmt.Sprintf("Property %#v not specified by multiArgumentInputs", k), + } + if !detailGiven { + detailGiven = true + diag.Detail = "If multiArgumentInputs is given, all properties must be specified" + } + diags = diags.Append(&diag) + } + } + + // Order output properties as specified by MultiArgumentInputs + sortProps := func(props []*Property) { + sort.Slice(props, func(i, j int) bool { + return idx[props[i].Name] < idx[props[j].Name] + }) + } + sortProps(ins.Properties) + if ins.InputShape != nil { + sortProps(ins.InputShape.Properties) + } + if ins.PlainShape != nil { + sortProps(ins.PlainShape.Properties) + } + } + inputs = ins } var outputs *ObjectType - if spec.Outputs != nil { + + language := make(map[string]interface{}) + for name, raw := range spec.Language { + language[name] = json.RawMessage(raw) + } + + var inlineObjectAsReturnType bool + var returnType Type + if spec.ReturnType != nil && spec.Outputs == nil { + // compute the return type from the spec + if spec.ReturnType.ObjectTypeSpec != nil { + // bind as an object type + outs, outDiags, err := t.bindAnonymousObjectType(path+"/outputs", token+"Result", *spec.ReturnType.ObjectTypeSpec) + diags = diags.Extend(outDiags) + if err != nil { + return nil, diags, fmt.Errorf("error binding outputs for function %v: %w", token, err) + } + returnType = outs + outputs = outs + inlineObjectAsReturnType = true + } else if spec.ReturnType.TypeSpec != nil { + out, outDiags, err := t.bindTypeSpec(path+"/outputs", *spec.ReturnType.TypeSpec, false) + diags = diags.Extend(outDiags) + if err != nil { + return nil, diags, fmt.Errorf("error binding outputs for function %v: %w", token, err) + } + returnType = out + } else { + // Setting `spec.ReturnType` to a value without setting either `TypeSpec` or `ObjectTypeSpec` + // indicates a logical bug in our marshaling code. + return nil, diags, fmt.Errorf("error binding outputs for function %v: invalid return type", token) + } + } else if spec.Outputs != nil { + // bind the outputs when the specs don't rely on the new ReturnType field outs, outDiags, err := t.bindAnonymousObjectType(path+"/outputs", token+"Result", *spec.Outputs) diags = diags.Extend(outDiags) if err != nil { return nil, diags, fmt.Errorf("error binding outputs for function %v: %w", token, err) } outputs = outs - } - - language := make(map[string]interface{}) - for name, raw := range spec.Language { - language[name] = json.RawMessage(raw) + returnType = outs + inlineObjectAsReturnType = true } fn := &Function{ - PackageReference: t.externalPackage(), - Token: token, - Comment: spec.Description, - Inputs: inputs, - Outputs: outputs, - DeprecationMessage: spec.DeprecationMessage, - Language: language, - IsOverlay: spec.IsOverlay, + PackageReference: t.externalPackage(), + Token: token, + Comment: spec.Description, + Inputs: inputs, + MultiArgumentInputs: len(spec.MultiArgumentInputs) > 0, + InlineObjectAsReturnType: inlineObjectAsReturnType, + Outputs: outputs, + ReturnType: returnType, + DeprecationMessage: spec.DeprecationMessage, + Language: language, + IsOverlay: spec.IsOverlay, } t.functionDefs[token] = fn diff --git a/pkg/codegen/schema/docs_test.go b/pkg/codegen/schema/docs_test.go index 91987139c48c..f2ac0bfb94bd 100644 --- a/pkg/codegen/schema/docs_test.go +++ b/pkg/codegen/schema/docs_test.go @@ -71,7 +71,13 @@ func getDocsForFunction(f *Function) []doc { {entity: entity + "/deprecationMessage", content: f.DeprecationMessage}, } docs = append(docs, getDocsForObjectType(entity+"/inputs/properties", f.Inputs)...) - docs = append(docs, getDocsForObjectType(entity+"/outputs/properties", f.Outputs)...) + + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*ObjectType); ok && objectType != nil { + docs = append(docs, getDocsForObjectType(entity+"/outputs/properties", objectType)...) + } + } + return docs } diff --git a/pkg/codegen/schema/pulumi.json b/pkg/codegen/schema/pulumi.json index 99a02dec8e32..ff5d408870c9 100644 --- a/pkg/codegen/schema/pulumi.json +++ b/pkg/codegen/schema/pulumi.json @@ -521,9 +521,19 @@ "description": "The bag of input values for the function, if any.", "$ref": "#/$defs/objectTypeSpec" }, + "multiArgumentInputs": { + "description": "A list of parameter names that determines whether the input bag should be treated as a single argument or as multiple arguments. The list corresponds to the order in which the parameters should be passed to the function.", + "type": "array", + "items": { + "type": "string" + } + }, "outputs": { - "description": "The bag of output values for the function, if any.", - "$ref": "#/$defs/objectTypeSpec" + "description": "Specifies the return type of the function definition.", + "anyOf": [ + { "$ref": "#/$defs/typeSpec" }, + { "$ref": "#/$defs/objectTypeSpec" } + ] }, "deprecationMessage": { "description": "Indicates whether the function is deprecated", diff --git a/pkg/codegen/schema/schema.go b/pkg/codegen/schema/schema.go index 9b9a030a2260..306f1c30c86b 100644 --- a/pkg/codegen/schema/schema.go +++ b/pkg/codegen/schema/schema.go @@ -529,8 +529,16 @@ type Function struct { Comment string // Inputs is the bag of input values for the function, if any. Inputs *ObjectType + // Determines whether the input bag should be treated as a single argument or as multiple arguments. + MultiArgumentInputs bool // Outputs is the bag of output values for the function, if any. Outputs *ObjectType + // The return type of the function, if any. + ReturnType Type + // When InlineObjectAsReturnType is true, it means that the return type definition is defined inline + // as an object type that should be generated as a separate type and it is not + // a reference to a existing type in the schema. + InlineObjectAsReturnType bool // DeprecationMessage indicates whether or not the function is deprecated. DeprecationMessage string // Language specifies additional language-specific data about the function. @@ -542,14 +550,14 @@ type Function struct { IsOverlay bool } -// Determines if codegen should emit a ${fn}Output version that -// automatically accepts Inputs and returns Outputs. +// NeedsOutputVersion determines if codegen should emit a ${fn}Output version that +// automatically accepts Inputs and returns ReturnType. func (fun *Function) NeedsOutputVersion() bool { // Skip functions that return no value. Arguably we could // support them and return `Task`, but there are no such // functions in `pulumi-azure-native` or `pulumi-aws` so we // omit to simplify. - if fun.Outputs == nil || len(fun.Outputs.Properties) == 0 { + if fun.ReturnType == nil { return false } @@ -752,9 +760,11 @@ func importFunctionLanguages(function *Function, languages map[string]Language) return fmt.Errorf("importing inputs: %w", err) } } - if function.Outputs != nil { - if err := importObjectTypeLanguages(function.Outputs, languages); err != nil { - return fmt.Errorf("importing outputs: %w", err) + if function.ReturnType != nil { + if objectType, ok := function.ReturnType.(*ObjectType); ok && objectType != nil { + if err := importObjectTypeLanguages(objectType, languages); err != nil { + return fmt.Errorf("importing outputs: %w", err) + } } } @@ -1136,6 +1146,13 @@ func (pkg *Package) marshalFunction(f *Function) (FunctionSpec, error) { } inputs = &ins.ObjectTypeSpec } + var multiArgumentInputs []string + if f.MultiArgumentInputs { + multiArgumentInputs = make([]string, len(f.Inputs.Properties)) + for i, prop := range f.Inputs.Properties { + multiArgumentInputs[i] = prop.Name + } + } var outputs *ObjectTypeSpec if f.Outputs != nil { @@ -1146,16 +1163,35 @@ func (pkg *Package) marshalFunction(f *Function) (FunctionSpec, error) { outputs = &outs.ObjectTypeSpec } + var returnType *ReturnTypeSpec + if f.ReturnType != nil { + returnType = &ReturnTypeSpec{} + if objectType, ok := f.ReturnType.(*ObjectType); ok { + ret, err := pkg.marshalObject(objectType, true) + if err != nil { + return FunctionSpec{}, fmt.Errorf("marshaling object spec: %w", err) + } + returnType.ObjectTypeSpec = &ret.ObjectTypeSpec + } else { + typeSpec := pkg.marshalType(f.ReturnType, true) + returnType.TypeSpec = &typeSpec + } + } + lang, err := marshalLanguage(f.Language) if err != nil { return FunctionSpec{}, err } return FunctionSpec{ - Description: f.Comment, - Inputs: inputs, - Outputs: outputs, - Language: lang, + Description: f.Comment, + DeprecationMessage: f.DeprecationMessage, + IsOverlay: f.IsOverlay, + Inputs: inputs, + MultiArgumentInputs: multiArgumentInputs, + Outputs: outputs, + ReturnType: returnType, + Language: lang, }, nil } @@ -1510,15 +1546,69 @@ type ResourceSpec struct { Methods map[string]string `json:"methods,omitempty" yaml:"methods,omitempty"` } +// ReturnTypeSpec is either ObjectTypeSpec or TypeSpec +type ReturnTypeSpec struct { + ObjectTypeSpec *ObjectTypeSpec + TypeSpec *TypeSpec +} + +// Decoder is an alias for a function that takes (in []byte, out interface{}) and potentially returns an error +// it is used to abstract json.Unmarshal and yaml.Unmarshal which satisfy this function signature +type Decoder func([]byte, interface{}) error + +func (returnTypeSpec *ReturnTypeSpec) UnmarshalReturnTypeSpec(data []byte, decode Decoder) error { + var objectMap map[string]interface{} + if err := decode(data, &objectMap); err != nil { + return err + } + + if len(objectMap) == 0 { + return nil + } + + var objectSpec *ObjectTypeSpec + var typeSpec *TypeSpec + if _, hasProperties := objectMap["properties"]; hasProperties { + if err := decode(data, &objectSpec); err != nil { + return err + } + } else { + if err := decode(data, &typeSpec); err != nil { + return err + } + } + + returnTypeSpec.TypeSpec = typeSpec + returnTypeSpec.ObjectTypeSpec = objectSpec + return nil +} + +func (returnTypeSpec *ReturnTypeSpec) UnmarshalJSON(inputJSON []byte) error { + return returnTypeSpec.UnmarshalReturnTypeSpec(inputJSON, json.Unmarshal) +} + +func (returnTypeSpec *ReturnTypeSpec) UnmarshalYAML(inputYAML []byte) error { + return returnTypeSpec.UnmarshalReturnTypeSpec(inputYAML, yaml.Unmarshal) +} + // FunctionSpec is the serializable form of a function description. type FunctionSpec struct { // Description is the description of the function, if any. Description string `json:"description,omitempty" yaml:"description,omitempty"` // Inputs is the bag of input values for the function, if any. Inputs *ObjectTypeSpec `json:"inputs,omitempty" yaml:"inputs,omitempty"` + // Determines whether the input bag should be treated as a single argument or as multiple arguments. + // When MultiArgumentInputs is non-empty, it must match up 1:1 with the property names in of the Inputs object. + // The order in which the properties are listed in MultiArgumentInputs determines the order in which the + // arguments are passed to the function. + MultiArgumentInputs []string `json:"multiArgumentInputs,omitempty" yaml:"multiArgumentInputs,omitempty"` // Outputs is the bag of output values for the function, if any. + // This field is DEPRECATED. Use ReturnType instead where it allows for more flexible types + // to describe the outputs of the function definition. It is invalid to specify both Outputs and ReturnType. Outputs *ObjectTypeSpec `json:"outputs,omitempty" yaml:"outputs,omitempty"` - // DeprecationMessage indicates whether or not the function is deprecated. + // Specified the return type of the function definition + ReturnType *ReturnTypeSpec + // DeprecationMessage indicates whether the function is deprecated. DeprecationMessage string `json:"deprecationMessage,omitempty" yaml:"deprecationMessage,omitempty"` // Language specifies additional language-specific data about the function. Language map[string]RawMessage `json:"language,omitempty" yaml:"language,omitempty"` @@ -1527,6 +1617,157 @@ type FunctionSpec struct { IsOverlay bool `json:"isOverlay,omitempty" yaml:"isOverlay,omitempty"` } +func emptyObject(data RawMessage) (bool, error) { + var objectData *map[string]RawMessage + if err := json.Unmarshal(data, &objectData); err != nil { + return false, err + } + + if objectData == nil { + return true, nil + } + + return len(*objectData) == 0, nil +} + +func unmarshalFunctionSpec(funcSpec *FunctionSpec, data map[string]RawMessage) error { + if description, ok := data["description"]; ok { + if err := json.Unmarshal(description, &funcSpec.Description); err != nil { + return err + } + } + + if inputs, ok := data["inputs"]; ok { + if err := json.Unmarshal(inputs, &funcSpec.Inputs); err != nil { + return err + } + } + + if multiArgumentInputs, ok := data["multiArgumentInputs"]; ok { + if err := json.Unmarshal(multiArgumentInputs, &funcSpec.MultiArgumentInputs); err != nil { + return err + } + } + + if returnType, ok := data["outputs"]; ok { + isEmpty, err := emptyObject(returnType) + if err != nil { + return err + } + + if !isEmpty { + if err := json.Unmarshal(returnType, &funcSpec.ReturnType); err != nil { + return err + } + } else { + funcSpec.ReturnType = nil + } + } + + if deprecationMessage, ok := data["deprecationMessage"]; ok { + if err := json.Unmarshal(deprecationMessage, &funcSpec.DeprecationMessage); err != nil { + return err + } + } + + if language, ok := data["language"]; ok { + if err := json.Unmarshal(language, &funcSpec.Language); err != nil { + return err + } + } + + if isOverlay, ok := data["isOverlay"]; ok { + if err := json.Unmarshal(isOverlay, &funcSpec.IsOverlay); err != nil { + return err + } + } + + return nil +} + +// UnmarshalJSON is custom unmarshalling logic for FunctionSpec so that we can derive Outputs from ReturnType +// which otherwise isn't possible when both are retrieved from the same JSON field +func (funcSpec *FunctionSpec) UnmarshalJSON(inputJSON []byte) error { + var data map[string]RawMessage + if err := json.Unmarshal(inputJSON, &data); err != nil { + return err + } + return unmarshalFunctionSpec(funcSpec, data) +} + +// UnmarshalYAML is custom unmarshalling logic for FunctionSpec so that we can derive Outputs from ReturnType +// which otherwise isn't possible when both are retrieved from the same JSON field +func (funcSpec *FunctionSpec) UnmarshalYAML(node *yaml.Node) error { + var data map[string]RawMessage + if err := node.Decode(&data); err != nil { + return err + } + return unmarshalFunctionSpec(funcSpec, data) +} + +func (funcSpec FunctionSpec) marshalFunctionSpec() (map[string]interface{}, error) { + data := make(map[string]interface{}) + if funcSpec.Description != "" { + data["description"] = funcSpec.Description + } + + if funcSpec.Inputs != nil { + data["inputs"] = funcSpec.Inputs + } + + if len(funcSpec.MultiArgumentInputs) > 0 { + data["multiArgumentInputs"] = funcSpec.MultiArgumentInputs + } + + if funcSpec.ReturnType != nil && funcSpec.Outputs != nil { + return nil, fmt.Errorf("cannot specify both Outputs and ReturnType when marshalling FunctionSpec" + + " because they are mutually exclusive") + } + + if funcSpec.ReturnType != nil { + if funcSpec.ReturnType.ObjectTypeSpec != nil { + data["outputs"] = funcSpec.ReturnType.ObjectTypeSpec + } + + if funcSpec.ReturnType.TypeSpec != nil { + data["outputs"] = funcSpec.ReturnType.TypeSpec + } + } + + // for backward-compat when we only specify the outputs object of the function + if funcSpec.ReturnType == nil && funcSpec.Outputs != nil { + data["outputs"] = funcSpec.Outputs + } + + if funcSpec.DeprecationMessage != "" { + data["deprecationMessage"] = funcSpec.DeprecationMessage + } + + if funcSpec.IsOverlay { + // the default is false, so only write the property when it is true + data["isOverlay"] = true + } + + if funcSpec.Language != nil && len(funcSpec.Language) > 0 { + data["language"] = funcSpec.Language + } + + return data, nil +} + +func (funcSpec FunctionSpec) MarshalJSON() ([]byte, error) { + data, err := funcSpec.marshalFunctionSpec() + if err != nil { + return nil, err + } + + return json.Marshal(data) +} + +func (funcSpec FunctionSpec) MarshalYAML() (interface{}, error) { + return funcSpec.marshalFunctionSpec() +} + // ConfigSpec is the serializable description of a package's configuration variables. type ConfigSpec struct { // Variables is a map from variable name to PropertySpec that describes a package's configuration variables. diff --git a/pkg/codegen/schema/schema_test.go b/pkg/codegen/schema/schema_test.go index b98c7474180f..9c58389364d2 100644 --- a/pkg/codegen/schema/schema_test.go +++ b/pkg/codegen/schema/schema_test.go @@ -17,6 +17,7 @@ package schema import ( "encoding/json" + "fmt" "net/url" "os" "path/filepath" @@ -27,6 +28,7 @@ import ( "github.com/blang/semver" "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" ) func readSchemaFile(file string) (pkgSpec PackageSpec) { @@ -36,8 +38,16 @@ func readSchemaFile(file string) (pkgSpec PackageSpec) { panic(err) } - if err = json.Unmarshal(schemaBytes, &pkgSpec); err != nil { - panic(err) + if strings.HasSuffix(file, ".json") { + if err = json.Unmarshal(schemaBytes, &pkgSpec); err != nil { + panic(err) + } + } else if strings.HasSuffix(file, ".yaml") || strings.HasSuffix(file, ".yml") { + if err = yaml.Unmarshal(schemaBytes, &pkgSpec); err != nil { + panic(err) + } + } else { + panic(fmt.Sprintf("unknown schema file extension while parsing %s", file)) } return pkgSpec @@ -109,6 +119,113 @@ var enumTests = []struct { }}, } +func TestUnmarshalYAMLFunctionSpec(t *testing.T) { + t.Parallel() + var functionSpec *FunctionSpec + fnYaml := ` +description: Test function +outputs: + type: number` + + err := yaml.Unmarshal([]byte(fnYaml), &functionSpec) + assert.Nil(t, err, "Unmarshalling should work") + assert.Equal(t, "Test function", functionSpec.Description) + assert.NotNil(t, functionSpec.ReturnType, "Return type is not nil") + assert.NotNil(t, functionSpec.ReturnType.TypeSpec, "Return type is a type spec") + assert.Equal(t, "number", functionSpec.ReturnType.TypeSpec.Type, "Return type is a number") +} + +func TestUnmarshalJSONFunctionSpec(t *testing.T) { + t.Parallel() + var functionSpec *FunctionSpec + fnJSON := `{"description":"Test function", "outputs": { "type": "number" } }` + err := json.Unmarshal([]byte(fnJSON), &functionSpec) + assert.Nil(t, err, "Unmarshalling should work") + assert.Equal(t, "Test function", functionSpec.Description) + assert.NotNil(t, functionSpec.ReturnType, "Return type is not nil") + assert.NotNil(t, functionSpec.ReturnType.TypeSpec, "Return type is a type spec") + assert.Equal(t, "number", functionSpec.ReturnType.TypeSpec.Type, "Return type is a number") +} + +func TestMarshalJSONFunctionSpec(t *testing.T) { + t.Parallel() + functionSpec := &FunctionSpec{ + Description: "Test function", + ReturnType: &ReturnTypeSpec{ + TypeSpec: &TypeSpec{Type: "number"}, + }, + } + + dataJSON, err := json.Marshal(functionSpec) + data := string(dataJSON) + expectedJSON := `{"description":"Test function","outputs":{"type":"number"}}` + assert.Nil(t, err, "Unmarshalling should work") + assert.Equal(t, expectedJSON, data) +} + +func TestMarshalJSONFunctionSpecWithOutputs(t *testing.T) { + t.Parallel() + functionSpec := &FunctionSpec{ + Description: "Test function", + Outputs: &ObjectTypeSpec{ + Type: "object", + Properties: map[string]PropertySpec{ + "foo": { + TypeSpec: TypeSpec{Type: "string"}, + }, + }, + }, + } + + dataJSON, err := json.Marshal(functionSpec) + data := string(dataJSON) + expectedJSON := `{"description":"Test function","outputs":{"properties":{"foo":{"type":"string"}},"type":"object"}}` + assert.Nil(t, err, "Unmarshalling should work") + assert.Equal(t, expectedJSON, data) +} + +func TestMarshalFunctionSpecErrorsWhenBothOutputsAndReturnTypePopulated(t *testing.T) { + t.Parallel() + functionSpec := &FunctionSpec{ + Description: "Test function", + ReturnType: &ReturnTypeSpec{ + TypeSpec: &TypeSpec{Type: "number"}, + }, + Outputs: &ObjectTypeSpec{ + Type: "object", + Properties: map[string]PropertySpec{ + "foo": { + TypeSpec: TypeSpec{Type: "string"}, + }, + }, + }, + } + + _, err := json.Marshal(functionSpec) + assert.NotNil(t, err, "Unmarshalling should fail") + assert.True(t, strings.Contains(err.Error(), "cannot specify both Outputs and ReturnType")) +} + +func TestMarshalYAMLFunctionSpec(t *testing.T) { + t.Parallel() + functionSpec := &FunctionSpec{ + Description: "Test function", + ReturnType: &ReturnTypeSpec{ + TypeSpec: &TypeSpec{Type: "number"}, + }, + } + + dataYAML, err := yaml.Marshal(functionSpec) + data := string(dataYAML) + expectedYAML := `description: Test function +outputs: + type: number +` + + assert.Nil(t, err, "Unmarshalling should work") + assert.Equal(t, expectedYAML, data) +} + func TestEnums(t *testing.T) { t.Parallel() @@ -378,9 +495,14 @@ func TestMethods(t *testing.T) { Resource: pkg.Resources[0], }, inputs[0].Type) - assert.NotNil(t, pkg.Resources[0].Methods[0].Function.Outputs) - assert.Len(t, pkg.Resources[0].Methods[0].Function.Outputs.Properties, 1) - outputs := pkg.Resources[0].Methods[0].Function.Outputs.Properties + var objectReturnType *ObjectType + if objectType, ok := pkg.Resources[0].Methods[0].Function.ReturnType.(*ObjectType); ok && objectType != nil { + objectReturnType = objectType + } + + assert.NotNil(t, objectReturnType) + assert.Len(t, objectReturnType.Properties, 1) + outputs := objectReturnType.Properties assert.Equal(t, "someValue", outputs[0].Name) assert.Equal(t, StringType, outputs[0].Type) @@ -389,6 +511,22 @@ func TestMethods(t *testing.T) { assert.Same(t, pkg.Resources[0].Methods[0].Function, pkg.Functions[0]) }, }, + { + filename: "good-simplified-methods.json", + validator: func(pkg *Package) { + assert.Len(t, pkg.Functions, 1) + assert.NotNil(t, pkg.Functions[0].ReturnType, "There should be a return type") + assert.Equal(t, pkg.Functions[0].ReturnType, NumberType) + }, + }, + { + filename: "good-simplified-methods.yml", + validator: func(pkg *Package) { + assert.Len(t, pkg.Functions, 1) + assert.NotNil(t, pkg.Functions[0].ReturnType, "There should be a return type") + assert.Equal(t, pkg.Functions[0].ReturnType, NumberType) + }, + }, { filename: "bad-methods-1.json", expectedError: "unknown function xyz:index:Foo/bar", @@ -476,6 +614,50 @@ func TestIsOverlay(t *testing.T) { }) } +func TestBindingOutputsPopulatesReturnType(t *testing.T) { + t.Parallel() + + // Test that using Outputs in PackageSpec correctly populates the return type of the function. + pkgSpec := PackageSpec{ + Name: "xyz", + Version: "0.0.1", + Functions: map[string]FunctionSpec{ + "xyz:index:abs": { + MultiArgumentInputs: []string{"value"}, + Inputs: &ObjectTypeSpec{ + Properties: map[string]PropertySpec{ + "value": { + TypeSpec: TypeSpec{ + Type: "number", + }, + }, + }, + }, + Outputs: &ObjectTypeSpec{ + Required: []string{"result"}, + Properties: map[string]PropertySpec{ + "result": { + TypeSpec: TypeSpec{ + Type: "number", + }, + }, + }, + }, + }, + }, + } + + pkg, err := ImportSpec(pkgSpec, nil) + if err != nil { + t.Error(err) + } + + assert.NotNil(t, pkg.Functions[0].ReturnType) + objectType, ok := pkg.Functions[0].ReturnType.(*ObjectType) + assert.True(t, ok) + assert.Equal(t, NumberType, objectType.Properties[0].Type) +} + // Tests that the method ReplaceOnChanges works as expected. Does not test // codegen. func TestReplaceOnChanges(t *testing.T) { diff --git a/pkg/codegen/testing/test/program_driver.go b/pkg/codegen/testing/test/program_driver.go index 35bbf68a7442..f43cbd1f089d 100644 --- a/pkg/codegen/testing/test/program_driver.go +++ b/pkg/codegen/testing/test/program_driver.go @@ -97,6 +97,12 @@ var PulumiPulumiProgramTests = []ProgramTest{ Description: "Python regression test for #10914", Skip: allProgLanguages.Except("python"), }, + { + Directory: "simplified-invokes", + Description: "Simplified invokes", + Skip: codegen.NewStringSet("python", "go"), + SkipCompile: codegen.NewStringSet("dotnet", "nodejs"), + }, { Directory: "aws-optionals", Description: "AWS get invoke with nested object constructor that takes an optional string", diff --git a/pkg/codegen/testing/test/sdk_driver.go b/pkg/codegen/testing/test/sdk_driver.go index ee31e0530a40..af8987716ff3 100644 --- a/pkg/codegen/testing/test/sdk_driver.go +++ b/pkg/codegen/testing/test/sdk_driver.go @@ -100,6 +100,11 @@ var PulumiPulumiSDKTests = []*SDKTest{ Description: "Nested module", SkipCompileCheck: codegen.NewStringSet(dotnet), }, + { + Directory: "simplified-invokes", + Description: "Simplified invokes", + Skip: codegen.NewStringSet("python/any", "go/any"), + }, { Directory: "nested-module-thirdparty", Description: "Third-party nested module", diff --git a/pkg/codegen/testing/test/testdata/output-funcs/docs/funcwithemptyoutputs/_index.md b/pkg/codegen/testing/test/testdata/output-funcs/docs/funcwithemptyoutputs/_index.md index f8be5fb64f71..1fb0e5cb482a 100644 --- a/pkg/codegen/testing/test/testdata/output-funcs/docs/funcwithemptyoutputs/_index.md +++ b/pkg/codegen/testing/test/testdata/output-funcs/docs/funcwithemptyoutputs/_index.md @@ -188,42 +188,6 @@ The following output properties are available: -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- diff --git a/pkg/codegen/testing/test/testdata/schema/good-simplified-methods.json b/pkg/codegen/testing/test/testdata/schema/good-simplified-methods.json new file mode 100644 index 000000000000..312c10d2416e --- /dev/null +++ b/pkg/codegen/testing/test/testdata/schema/good-simplified-methods.json @@ -0,0 +1,20 @@ +{ + "name": "xyz", + "version": "0.0.1", + "functions": { + "xyz:index:basic": { + "multiArgumentInputs": ["value"], + "inputs": { + "properties": { + "value": { + "type": "number" + } + }, + "required": ["value"] + }, + "outputs": { + "type": "number" + } + } + } +} diff --git a/pkg/codegen/testing/test/testdata/schema/good-simplified-methods.yml b/pkg/codegen/testing/test/testdata/schema/good-simplified-methods.yml new file mode 100644 index 000000000000..31892c950390 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/schema/good-simplified-methods.yml @@ -0,0 +1,14 @@ +name: xyz +version: 0.0.1 +functions: + xyz:index:basic: + multiArgumentInputs: + - value + inputs: + properties: + value: + type: number + required: + - value + outputs: + type: number diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes-pp/dotnet/simplified-invokes.cs b/pkg/codegen/testing/test/testdata/simplified-invokes-pp/dotnet/simplified-invokes.cs new file mode 100644 index 000000000000..a97f40f30155 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes-pp/dotnet/simplified-invokes.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Pulumi; +using Std = Pulumi.Std; + +return await Deployment.RunAsync(() => +{ + var everyArg = Std.AbsMultiArgs.Invoke(10, 20, 30); + + var onlyRequiredArgs = Std.AbsMultiArgs.Invoke(10); + + var optionalArgs = Std.AbsMultiArgs.Invoke(10, null, 30); + + var nestedUse = Std.AbsMultiArgs.Invoke(everyArg, Std.AbsMultiArgs.Invoke(42)); + + return new Dictionary + { + ["result"] = nestedUse, + }; +}); + diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes-pp/nodejs/simplified-invokes.ts b/pkg/codegen/testing/test/testdata/simplified-invokes-pp/nodejs/simplified-invokes.ts new file mode 100644 index 000000000000..284776d5dca9 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes-pp/nodejs/simplified-invokes.ts @@ -0,0 +1,8 @@ +import * as pulumi from "@pulumi/pulumi"; +import * as std from "@pulumi/std"; + +const everyArg = std.AbsMultiArgs(10, 20, 30); +const onlyRequiredArgs = std.AbsMultiArgs(10); +const optionalArgs = std.AbsMultiArgs(10, undefined, 30); +const nestedUse = Promise.all([everyArg, std.AbsMultiArgs(42)]).then(([everyArg, invoke]) => std.AbsMultiArgs(everyArg, invoke)); +export const result = nestedUse; diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes-pp/simplified-invokes.pp b/pkg/codegen/testing/test/testdata/simplified-invokes-pp/simplified-invokes.pp new file mode 100644 index 000000000000..cd5a60cf9de0 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes-pp/simplified-invokes.pp @@ -0,0 +1,23 @@ +everyArg = invoke("std:index:AbsMultiArgs", { + a: 10 + b: 20 + c: 30 +}) + +onlyRequiredArgs = invoke("std:index:AbsMultiArgs", { + a: 10 +}) + +optionalArgs = invoke("std:index:AbsMultiArgs", { + a: 10 + c: 30 +}) + +nestedUse = invoke("std:index:AbsMultiArgs", { + a: everyArg + b: invoke("std:index:AbsMultiArgs", { a: 42 }) +}) + +output result { + value = nestedUse +} \ No newline at end of file diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/_index.md new file mode 100644 index 000000000000..1867c134b148 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/_index.md @@ -0,0 +1,42 @@ +--- +title: "StandardLibrary" +title_tag: "std.StandardLibrary" +meta_desc: "Standard library functions" +layout: api +no_edit_this_page: true +--- + + + + +Standard library functions + +

Resources

+ + +

Functions

+ + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
Version
+
1.0.0
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/abs/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/abs/_index.md new file mode 100644 index 000000000000..8ab2772c7129 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/abs/_index.md @@ -0,0 +1,342 @@ + +--- +title: "Abs" +title_tag: "std.Abs" +meta_desc: "Documentation for the std.Abs function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + +Returns the absolute value of a given float. +Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + + + + +## Using Abs {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function abs(args: AbsArgs, opts?: InvokeOptions): Promise<AbsResult>
+function absOutput(args: AbsOutputArgs, opts?: InvokeOptions): Output<AbsResult>
+
+
+ + +
+ +
def abs(a: Optional[float] = None,
+        b: Optional[float] = None,
+        opts: Optional[InvokeOptions] = None) -> AbsResult
+def abs_output(a: Optional[pulumi.Input[float]] = None,
+        b: Optional[pulumi.Input[float]] = None,
+        opts: Optional[InvokeOptions] = None) -> Output[AbsResult]
+
+
+ + +
+ +
func Abs(ctx *Context, args *AbsArgs, opts ...InvokeOption) (*AbsResult, error)
+func AbsOutput(ctx *Context, args *AbsOutputArgs, opts ...InvokeOption) AbsResultOutput
+ +
+
+ + +
+ +
public static class Abs 
+{
+    public static Task<AbsResult> InvokeAsync(AbsArgs args, InvokeOptions? opts = null)
+    public static Output<AbsResult> Invoke(AbsInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<AbsResult> abs(AbsArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:Abs
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+ +B + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+ +B + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+ +b + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+ +b + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+ +b + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+ +b + + + Number +
+
+
+
+ + + + +## Abs Result {#result} + +The following output properties are available: + + + +
+ +
+ +Result + + + double +
+
+
+
+ +
+ +
+ +Result + + + float64 +
+
+
+
+ +
+ +
+ +result + + + Double +
+
+
+
+ +
+ +
+ +result + + + number +
+
+
+
+ +
+ +
+ +result + + + float +
+
+
+
+ +
+ +
+ +result + + + Number +
+
+
+
+ + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargs/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargs/_index.md new file mode 100644 index 000000000000..c0befa297523 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargs/_index.md @@ -0,0 +1,342 @@ + +--- +title: "AbsMultiArgs" +title_tag: "std.AbsMultiArgs" +meta_desc: "Documentation for the std.AbsMultiArgs function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + +Returns the absolute value of a given float. +Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + + + + +## Using AbsMultiArgs {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function absMultiArgs(args: AbsMultiArgsArgs, opts?: InvokeOptions): Promise<AbsMultiArgsResult>
+function absMultiArgsOutput(args: AbsMultiArgsOutputArgs, opts?: InvokeOptions): Output<AbsMultiArgsResult>
+
+
+ + +
+ +
def abs_multi_args(a: Optional[float] = None,
+                   b: Optional[float] = None,
+                   opts: Optional[InvokeOptions] = None) -> AbsMultiArgsResult
+def abs_multi_args_output(a: Optional[pulumi.Input[float]] = None,
+                   b: Optional[pulumi.Input[float]] = None,
+                   opts: Optional[InvokeOptions] = None) -> Output[AbsMultiArgsResult]
+
+
+ + +
+ +
func AbsMultiArgs(ctx *Context, args *AbsMultiArgsArgs, opts ...InvokeOption) (*AbsMultiArgsResult, error)
+func AbsMultiArgsOutput(ctx *Context, args *AbsMultiArgsOutputArgs, opts ...InvokeOption) AbsMultiArgsResultOutput
+ +
+
+ + +
+ +
public static class AbsMultiArgs 
+{
+    public static Task<AbsMultiArgsResult> InvokeAsync(AbsMultiArgsArgs args, InvokeOptions? opts = null)
+    public static Output<AbsMultiArgsResult> Invoke(AbsMultiArgsInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<AbsMultiArgsResult> absMultiArgs(AbsMultiArgsArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:AbsMultiArgs
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+ +B + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+ +B + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+ +b + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+ +b + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+ +b + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+ +b + + + Number +
+
+
+
+ + + + +## AbsMultiArgs Result {#result} + +The following output properties are available: + + + +
+ +
+ +Result + + + double +
+
+
+
+ +
+ +
+ +Result + + + float64 +
+
+
+
+ +
+ +
+ +result + + + Double +
+
+
+
+ +
+ +
+ +result + + + number +
+
+
+
+ +
+ +
+ +result + + + float +
+
+
+
+ +
+ +
+ +result + + + Number +
+
+
+
+ + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargsreducedoutput/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargsreducedoutput/_index.md new file mode 100644 index 000000000000..ca31850fa4f2 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargsreducedoutput/_index.md @@ -0,0 +1,258 @@ + +--- +title: "AbsMultiArgsReducedOutput" +title_tag: "std.AbsMultiArgsReducedOutput" +meta_desc: "Documentation for the std.AbsMultiArgsReducedOutput function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + +Returns the absolute value of a given float. +Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + + + + +## Using AbsMultiArgsReducedOutput {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function absMultiArgsReducedOutput(args: AbsMultiArgsReducedOutputArgs, opts?: InvokeOptions): Promise<AbsMultiArgsReducedOutputResult>
+function absMultiArgsReducedOutputOutput(args: AbsMultiArgsReducedOutputOutputArgs, opts?: InvokeOptions): Output<AbsMultiArgsReducedOutputResult>
+
+
+ + +
+ +
def abs_multi_args_reduced_output(a: Optional[float] = None,
+                                  b: Optional[float] = None,
+                                  opts: Optional[InvokeOptions] = None) -> AbsMultiArgsReducedOutputResult
+def abs_multi_args_reduced_output_output(a: Optional[pulumi.Input[float]] = None,
+                                  b: Optional[pulumi.Input[float]] = None,
+                                  opts: Optional[InvokeOptions] = None) -> Output[AbsMultiArgsReducedOutputResult]
+
+
+ + +
+ +
func AbsMultiArgsReducedOutput(ctx *Context, args *AbsMultiArgsReducedOutputArgs, opts ...InvokeOption) (*AbsMultiArgsReducedOutputResult, error)
+func AbsMultiArgsReducedOutputOutput(ctx *Context, args *AbsMultiArgsReducedOutputOutputArgs, opts ...InvokeOption) AbsMultiArgsReducedOutputResultOutput
+ +
+
+ + +
+ +
public static class AbsMultiArgsReducedOutput 
+{
+    public static Task<AbsMultiArgsReducedOutputResult> InvokeAsync(AbsMultiArgsReducedOutputArgs args, InvokeOptions? opts = null)
+    public static Output<AbsMultiArgsReducedOutputResult> Invoke(AbsMultiArgsReducedOutputInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<AbsMultiArgsReducedOutputResult> absMultiArgsReducedOutput(AbsMultiArgsReducedOutputArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:AbsMultiArgsReducedOutput
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+ +B + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+ +B + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+ +b + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+ +b + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+ +b + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+ +b + + + Number +
+
+
+
+ + + + +## AbsMultiArgsReducedOutput Result {#result} + +The following output properties are available: + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargsreducedoutputswapped/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargsreducedoutputswapped/_index.md new file mode 100644 index 000000000000..6694b1b61ae6 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absmultiargsreducedoutputswapped/_index.md @@ -0,0 +1,258 @@ + +--- +title: "AbsMultiArgsReducedOutputSwapped" +title_tag: "std.AbsMultiArgsReducedOutputSwapped" +meta_desc: "Documentation for the std.AbsMultiArgsReducedOutputSwapped function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + +Returns the absolute value of a given float. +Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + + + + +## Using AbsMultiArgsReducedOutputSwapped {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function absMultiArgsReducedOutputSwapped(args: AbsMultiArgsReducedOutputSwappedArgs, opts?: InvokeOptions): Promise<AbsMultiArgsReducedOutputSwappedResult>
+function absMultiArgsReducedOutputSwappedOutput(args: AbsMultiArgsReducedOutputSwappedOutputArgs, opts?: InvokeOptions): Output<AbsMultiArgsReducedOutputSwappedResult>
+
+
+ + +
+ +
def abs_multi_args_reduced_output_swapped(b: Optional[float] = None,
+                                          a: Optional[float] = None,
+                                          opts: Optional[InvokeOptions] = None) -> AbsMultiArgsReducedOutputSwappedResult
+def abs_multi_args_reduced_output_swapped_output(b: Optional[pulumi.Input[float]] = None,
+                                          a: Optional[pulumi.Input[float]] = None,
+                                          opts: Optional[InvokeOptions] = None) -> Output[AbsMultiArgsReducedOutputSwappedResult]
+
+
+ + +
+ +
func AbsMultiArgsReducedOutputSwapped(ctx *Context, args *AbsMultiArgsReducedOutputSwappedArgs, opts ...InvokeOption) (*AbsMultiArgsReducedOutputSwappedResult, error)
+func AbsMultiArgsReducedOutputSwappedOutput(ctx *Context, args *AbsMultiArgsReducedOutputSwappedOutputArgs, opts ...InvokeOption) AbsMultiArgsReducedOutputSwappedResultOutput
+ +
+
+ + +
+ +
public static class AbsMultiArgsReducedOutputSwapped 
+{
+    public static Task<AbsMultiArgsReducedOutputSwappedResult> InvokeAsync(AbsMultiArgsReducedOutputSwappedArgs args, InvokeOptions? opts = null)
+    public static Output<AbsMultiArgsReducedOutputSwappedResult> Invoke(AbsMultiArgsReducedOutputSwappedInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<AbsMultiArgsReducedOutputSwappedResult> absMultiArgsReducedOutputSwapped(AbsMultiArgsReducedOutputSwappedArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:AbsMultiArgsReducedOutputSwapped
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+ +B + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+ +B + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+ +b + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+ +b + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+ +b + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+ +b + + + Number +
+
+
+
+ + + + +## AbsMultiArgsReducedOutputSwapped Result {#result} + +The following output properties are available: + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absreducedoutput/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absreducedoutput/_index.md new file mode 100644 index 000000000000..dd4cecb9e426 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/absreducedoutput/_index.md @@ -0,0 +1,258 @@ + +--- +title: "AbsReducedOutput" +title_tag: "std.AbsReducedOutput" +meta_desc: "Documentation for the std.AbsReducedOutput function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + +Returns the absolute value of a given float. +Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + + + + +## Using AbsReducedOutput {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function absReducedOutput(args: AbsReducedOutputArgs, opts?: InvokeOptions): Promise<AbsReducedOutputResult>
+function absReducedOutputOutput(args: AbsReducedOutputOutputArgs, opts?: InvokeOptions): Output<AbsReducedOutputResult>
+
+
+ + +
+ +
def abs_reduced_output(a: Optional[float] = None,
+                       b: Optional[float] = None,
+                       opts: Optional[InvokeOptions] = None) -> AbsReducedOutputResult
+def abs_reduced_output_output(a: Optional[pulumi.Input[float]] = None,
+                       b: Optional[pulumi.Input[float]] = None,
+                       opts: Optional[InvokeOptions] = None) -> Output[AbsReducedOutputResult]
+
+
+ + +
+ +
func AbsReducedOutput(ctx *Context, args *AbsReducedOutputArgs, opts ...InvokeOption) (*AbsReducedOutputResult, error)
+func AbsReducedOutputOutput(ctx *Context, args *AbsReducedOutputOutputArgs, opts ...InvokeOption) AbsReducedOutputResultOutput
+ +
+
+ + +
+ +
public static class AbsReducedOutput 
+{
+    public static Task<AbsReducedOutputResult> InvokeAsync(AbsReducedOutputArgs args, InvokeOptions? opts = null)
+    public static Output<AbsReducedOutputResult> Invoke(AbsReducedOutputInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<AbsReducedOutputResult> absReducedOutput(AbsReducedOutputArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:AbsReducedOutput
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+ +B + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+ +B + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+ +b + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+ +b + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+ +b + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+ +b + + + Number +
+
+
+
+ + + + +## AbsReducedOutput Result {#result} + +The following output properties are available: + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/codegen-manifest.json b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/codegen-manifest.json new file mode 100644 index 000000000000..7235c303b788 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/codegen-manifest.json @@ -0,0 +1,16 @@ +{ + "emittedFiles": [ + "_index.md", + "abs/_index.md", + "absmultiargs/_index.md", + "absmultiargsreducedoutput/_index.md", + "absmultiargsreducedoutputswapped/_index.md", + "absreducedoutput/_index.md", + "getarchive/_index.md", + "getarraycustomresult/_index.md", + "getasset/_index.md", + "getcustomresult/_index.md", + "getdictionary/_index.md", + "provider/_index.md" + ] +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getarchive/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getarchive/_index.md new file mode 100644 index 000000000000..358d4061c3b3 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getarchive/_index.md @@ -0,0 +1,205 @@ + +--- +title: "GetArchive" +title_tag: "std.GetArchive" +meta_desc: "Documentation for the std.GetArchive function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + + + + +## Using GetArchive {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function getArchive(args: GetArchiveArgs, opts?: InvokeOptions): Promise<GetArchiveResult>
+function getArchiveOutput(args: GetArchiveOutputArgs, opts?: InvokeOptions): Output<GetArchiveResult>
+
+
+ + +
+ +
def get_archive(a: Optional[float] = None,
+                opts: Optional[InvokeOptions] = None) -> GetArchiveResult
+def get_archive_output(a: Optional[pulumi.Input[float]] = None,
+                opts: Optional[InvokeOptions] = None) -> Output[GetArchiveResult]
+
+
+ + +
+ +
func GetArchive(ctx *Context, args *GetArchiveArgs, opts ...InvokeOption) (*GetArchiveResult, error)
+func GetArchiveOutput(ctx *Context, args *GetArchiveOutputArgs, opts ...InvokeOption) GetArchiveResultOutput
+ +
+
+ + +
+ +
public static class GetArchive 
+{
+    public static Task<GetArchiveResult> InvokeAsync(GetArchiveArgs args, InvokeOptions? opts = null)
+    public static Output<GetArchiveResult> Invoke(GetArchiveInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<GetArchiveResult> getArchive(GetArchiveArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:GetArchive
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+
+
+ + + + +## GetArchive Result {#result} + +The following output properties are available: + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getarraycustomresult/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getarraycustomresult/_index.md new file mode 100644 index 000000000000..74ebdf9149d0 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getarraycustomresult/_index.md @@ -0,0 +1,205 @@ + +--- +title: "GetArrayCustomResult" +title_tag: "std.GetArrayCustomResult" +meta_desc: "Documentation for the std.GetArrayCustomResult function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + + + + +## Using GetArrayCustomResult {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function getArrayCustomResult(args: GetArrayCustomResultArgs, opts?: InvokeOptions): Promise<GetArrayCustomResultResult>
+function getArrayCustomResultOutput(args: GetArrayCustomResultOutputArgs, opts?: InvokeOptions): Output<GetArrayCustomResultResult>
+
+
+ + +
+ +
def get_array_custom_result(a: Optional[float] = None,
+                            opts: Optional[InvokeOptions] = None) -> GetArrayCustomResultResult
+def get_array_custom_result_output(a: Optional[pulumi.Input[float]] = None,
+                            opts: Optional[InvokeOptions] = None) -> Output[GetArrayCustomResultResult]
+
+
+ + +
+ +
func GetArrayCustomResult(ctx *Context, args *GetArrayCustomResultArgs, opts ...InvokeOption) (*GetArrayCustomResultResult, error)
+func GetArrayCustomResultOutput(ctx *Context, args *GetArrayCustomResultOutputArgs, opts ...InvokeOption) GetArrayCustomResultResultOutput
+ +
+
+ + +
+ +
public static class GetArrayCustomResult 
+{
+    public static Task<GetArrayCustomResultResult> InvokeAsync(GetArrayCustomResultArgs args, InvokeOptions? opts = null)
+    public static Output<GetArrayCustomResultResult> Invoke(GetArrayCustomResultInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<GetArrayCustomResultResult> getArrayCustomResult(GetArrayCustomResultArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:GetArrayCustomResult
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+
+
+ + + + +## GetArrayCustomResult Result {#result} + +The following output properties are available: + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getasset/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getasset/_index.md new file mode 100644 index 000000000000..27bf334f0e76 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getasset/_index.md @@ -0,0 +1,205 @@ + +--- +title: "GetAsset" +title_tag: "std.GetAsset" +meta_desc: "Documentation for the std.GetAsset function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + + + + +## Using GetAsset {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function getAsset(args: GetAssetArgs, opts?: InvokeOptions): Promise<GetAssetResult>
+function getAssetOutput(args: GetAssetOutputArgs, opts?: InvokeOptions): Output<GetAssetResult>
+
+
+ + +
+ +
def get_asset(a: Optional[float] = None,
+              opts: Optional[InvokeOptions] = None) -> GetAssetResult
+def get_asset_output(a: Optional[pulumi.Input[float]] = None,
+              opts: Optional[InvokeOptions] = None) -> Output[GetAssetResult]
+
+
+ + +
+ +
func GetAsset(ctx *Context, args *GetAssetArgs, opts ...InvokeOption) (*GetAssetResult, error)
+func GetAssetOutput(ctx *Context, args *GetAssetOutputArgs, opts ...InvokeOption) GetAssetResultOutput
+ +
+
+ + +
+ +
public static class GetAsset 
+{
+    public static Task<GetAssetResult> InvokeAsync(GetAssetArgs args, InvokeOptions? opts = null)
+    public static Output<GetAssetResult> Invoke(GetAssetInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<GetAssetResult> getAsset(GetAssetArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:GetAsset
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+
+
+ + + + +## GetAsset Result {#result} + +The following output properties are available: + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getcustomresult/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getcustomresult/_index.md new file mode 100644 index 000000000000..e948684044f1 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getcustomresult/_index.md @@ -0,0 +1,383 @@ + +--- +title: "GetCustomResult" +title_tag: "std.GetCustomResult" +meta_desc: "Documentation for the std.GetCustomResult function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + + + + +## Using GetCustomResult {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function getCustomResult(args: GetCustomResultArgs, opts?: InvokeOptions): Promise<GetCustomResultResult>
+function getCustomResultOutput(args: GetCustomResultOutputArgs, opts?: InvokeOptions): Output<GetCustomResultResult>
+
+
+ + +
+ +
def get_custom_result(a: Optional[float] = None,
+                      opts: Optional[InvokeOptions] = None) -> GetCustomResultResult
+def get_custom_result_output(a: Optional[pulumi.Input[float]] = None,
+                      opts: Optional[InvokeOptions] = None) -> Output[GetCustomResultResult]
+
+
+ + +
+ +
func GetCustomResult(ctx *Context, args *GetCustomResultArgs, opts ...InvokeOption) (*GetCustomResultResult, error)
+func GetCustomResultOutput(ctx *Context, args *GetCustomResultOutputArgs, opts ...InvokeOption) GetCustomResultResultOutput
+ +
+
+ + +
+ +
public static class GetCustomResult 
+{
+    public static Task<GetCustomResultResult> InvokeAsync(GetCustomResultArgs args, InvokeOptions? opts = null)
+    public static Output<GetCustomResultResult> Invoke(GetCustomResultInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<GetCustomResultResult> getCustomResult(GetCustomResultArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:GetCustomResult
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+
+
+ + + + +## GetCustomResult Result {#result} + +The following output properties are available: + + + +
+ +
+ +Value + + + string +
+
+
+
+ +
+ +
+ +Value + + + string +
+
+
+
+ +
+ +
+ +value + + + String +
+
+
+
+ +
+ +
+ +value + + + string +
+
+
+
+ +
+ +
+ +value + + + str +
+
+
+
+ +
+ +
+ +value + + + String +
+
+
+
+ + + + +## Supporting Types + + +

CustomResult

+ + + +
+ +
+ +Value + + + string +
+
+
+
+ +
+ +
+ +Value + + + string +
+
+
+
+ +
+ +
+ +value + + + String +
+
+
+
+ +
+ +
+ +value + + + string +
+
+
+
+ +
+ +
+ +value + + + str +
+
+
+
+ +
+ +
+ +value + + + String +
+
+
+
+ + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getdictionary/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getdictionary/_index.md new file mode 100644 index 000000000000..c0f4ffc8cab4 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/getdictionary/_index.md @@ -0,0 +1,205 @@ + +--- +title: "GetDictionary" +title_tag: "std.GetDictionary" +meta_desc: "Documentation for the std.GetDictionary function with examples, input properties, output properties, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + + + + +## Using GetDictionary {#using} + +Two invocation forms are available. The direct form accepts plain +arguments and either blocks until the result value is available, or +returns a Promise-wrapped result. The output form accepts +Input-wrapped arguments and returns an Output-wrapped result. + +
+ +
+ + +
+ +
function getDictionary(args: GetDictionaryArgs, opts?: InvokeOptions): Promise<GetDictionaryResult>
+function getDictionaryOutput(args: GetDictionaryOutputArgs, opts?: InvokeOptions): Output<GetDictionaryResult>
+
+
+ + +
+ +
def get_dictionary(a: Optional[float] = None,
+                   opts: Optional[InvokeOptions] = None) -> GetDictionaryResult
+def get_dictionary_output(a: Optional[pulumi.Input[float]] = None,
+                   opts: Optional[InvokeOptions] = None) -> Output[GetDictionaryResult]
+
+
+ + +
+ +
func GetDictionary(ctx *Context, args *GetDictionaryArgs, opts ...InvokeOption) (*GetDictionaryResult, error)
+func GetDictionaryOutput(ctx *Context, args *GetDictionaryOutputArgs, opts ...InvokeOption) GetDictionaryResultOutput
+ +
+
+ + +
+ +
public static class GetDictionary 
+{
+    public static Task<GetDictionaryResult> InvokeAsync(GetDictionaryArgs args, InvokeOptions? opts = null)
+    public static Output<GetDictionaryResult> Invoke(GetDictionaryInvokeArgs args, InvokeOptions? opts = null)
+}
+
+
+ + +
+ +
public static CompletableFuture<GetDictionaryResult> getDictionary(GetDictionaryArgs args, InvokeOptions options)
+// Output-based functions aren't available in Java yet
+
+
+
+ + +
+ +
fn::invoke:
+  function: std:GetDictionary
+  arguments:
+    # arguments dictionary
+
+
+ + + +The following arguments are supported: + + +
+ +
+ +A + + + double +
+
+
+
+ +
+ +
+ +A + + + float64 +
+
+
+
+ +
+ +
+ +a + + + Double +
+
+
+
+ +
+ +
+ +a + + + number +
+
+
+
+ +
+ +
+ +a + + + float +
+
+
+
+ +
+ +
+ +a + + + Number +
+
+
+
+ + + + +## GetDictionary Result {#result} + +The following output properties are available: + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/docs/provider/_index.md b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/provider/_index.md new file mode 100644 index 000000000000..a0d59b9442ae --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/docs/provider/_index.md @@ -0,0 +1,366 @@ + +--- +title: "Provider" +title_tag: "std.Provider" +meta_desc: "Documentation for the std.Provider resource with examples, input properties, output properties, lookup functions, and supporting types." +layout: api +no_edit_this_page: true +--- + + + + + + + + + +## Create Provider Resource {#create} +
+ +
+ + +
+ +
new Provider(name: string, args?: ProviderArgs, opts?: CustomResourceOptions);
+
+
+ +
+ +
@overload
+def Provider(resource_name: str,
+             opts: Optional[ResourceOptions] = None)
+@overload
+def Provider(resource_name: str,
+             args: Optional[ProviderArgs] = None,
+             opts: Optional[ResourceOptions] = None)
+
+
+ +
+ +
func NewProvider(ctx *Context, name string, args *ProviderArgs, opts ...ResourceOption) (*Provider, error)
+
+
+ +
+ +
public Provider(string name, ProviderArgs? args = null, CustomResourceOptions? opts = null)
+
+
+ +
+ +
+public Provider(String name, ProviderArgs args)
+public Provider(String name, ProviderArgs args, CustomResourceOptions options)
+
+
+
+ +
+ +
type: pulumi:providers:std
+properties: # The arguments to resource properties.
+options: # Bag of options to control resource's behavior.
+
+
+
+
+ +
+ + +
+ name + + string +
+
The unique name of the resource.
+ args + + ProviderArgs +
+
The arguments to resource properties.
+ opts + + CustomResourceOptions +
+
Bag of options to control resource's behavior.
+ +
+
+ +
+ + +
+ resource_name + + str +
+
The unique name of the resource.
+ args + + ProviderArgs +
+
The arguments to resource properties.
+ opts + + ResourceOptions +
+
Bag of options to control resource's behavior.
+ +
+
+ +
+ + +
+ ctx + + Context +
+
Context object for the current deployment.
+ name + + string +
+
The unique name of the resource.
+ args + + ProviderArgs +
+
The arguments to resource properties.
+ opts + + ResourceOption +
+
Bag of options to control resource's behavior.
+ +
+
+ +
+ + +
+ name + + string +
+
The unique name of the resource.
+ args + + ProviderArgs +
+
The arguments to resource properties.
+ opts + + CustomResourceOptions +
+
Bag of options to control resource's behavior.
+ +
+
+ +
+ + +
+ name + + String +
+
The unique name of the resource.
+ args + + ProviderArgs +
+
The arguments to resource properties.
+ options + + CustomResourceOptions +
+
Bag of options to control resource's behavior.
+ +
+
+ +## Provider Resource Properties {#properties} + +To learn more about resource properties and how to use them, see [Inputs and Outputs](/docs/intro/concepts/inputs-outputs) in the Architecture and Concepts docs. + +### Inputs + +The Provider resource accepts the following [input](/docs/intro/concepts/inputs-outputs) properties: + + + +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ + +### Outputs + +All [input](#inputs) properties are implicitly available as output properties. Additionally, the Provider resource produces the following output properties: + + + +
+ +
+ +Id + + + string +
+

The provider-assigned unique ID for this managed resource.

+
+
+
+ +
+ +
+ +Id + + + string +
+

The provider-assigned unique ID for this managed resource.

+
+
+
+ +
+ +
+ +id + + + String +
+

The provider-assigned unique ID for this managed resource.

+
+
+
+ +
+ +
+ +id + + + string +
+

The provider-assigned unique ID for this managed resource.

+
+
+
+ +
+ +
+ +id + + + str +
+

The provider-assigned unique ID for this managed resource.

+
+
+
+ +
+ +
+ +id + + + String +
+

The provider-assigned unique ID for this managed resource.

+
+
+
+ + + + + + + + +

Package Details

+
+
Repository
+
https://github.com/pulumi/pulumi-std
+
License
+
+
+ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Abs.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Abs.cs new file mode 100644 index 000000000000..d6f143093f08 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Abs.cs @@ -0,0 +1,70 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class Abs + { + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static Task InvokeAsync(AbsArgs args, InvokeOptions? options = null) + => global::Pulumi.Deployment.Instance.InvokeAsync("std:index:Abs", args ?? new AbsArgs(), options.WithDefaults()); + + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static Output Invoke(AbsInvokeArgs args, InvokeOptions? options = null) + => global::Pulumi.Deployment.Instance.Invoke("std:index:Abs", args ?? new AbsInvokeArgs(), options.WithDefaults()); + } + + + public sealed class AbsArgs : global::Pulumi.InvokeArgs + { + [Input("a", required: true)] + public double A { get; set; } + + [Input("b", required: true)] + public double B { get; set; } + + public AbsArgs() + { + } + public static new AbsArgs Empty => new AbsArgs(); + } + + public sealed class AbsInvokeArgs : global::Pulumi.InvokeArgs + { + [Input("a", required: true)] + public Input A { get; set; } = null!; + + [Input("b", required: true)] + public Input B { get; set; } = null!; + + public AbsInvokeArgs() + { + } + public static new AbsInvokeArgs Empty => new AbsInvokeArgs(); + } + + + [OutputType] + public sealed class AbsResult + { + public readonly double Result; + + [OutputConstructor] + private AbsResult(double result) + { + Result = result; + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgs.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgs.cs new file mode 100644 index 000000000000..2c68a6d71e0b --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgs.cs @@ -0,0 +1,53 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class AbsMultiArgs + { + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static async Task InvokeAsync(double a, double? b = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + builder["b"] = b; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeAsync("std:index:AbsMultiArgs", args, invokeOptions.WithDefaults()); + } + + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static Output Invoke(Input a, Input? b = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + builder["b"] = b; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.Invoke("std:index:AbsMultiArgs", args, invokeOptions.WithDefaults()); + } + } + + + [OutputType] + public sealed class AbsMultiArgsResult + { + public readonly double Result; + + [OutputConstructor] + private AbsMultiArgsResult(double result) + { + Result = result; + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgsReducedOutput.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgsReducedOutput.cs new file mode 100644 index 000000000000..cccbfad8e85d --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgsReducedOutput.cs @@ -0,0 +1,40 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class AbsMultiArgsReducedOutput + { + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static async Task InvokeAsync(double a, double? b = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + builder["b"] = b; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeSingleAsync("std:index:AbsMultiArgsReducedOutput", args, invokeOptions.WithDefaults()); + } + + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static Output Invoke(Input a, Input? b = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + builder["b"] = b; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.InvokeSingle("std:index:AbsMultiArgsReducedOutput", args, invokeOptions.WithDefaults()); + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgsReducedOutputSwapped.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgsReducedOutputSwapped.cs new file mode 100644 index 000000000000..a5d676d9e984 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsMultiArgsReducedOutputSwapped.cs @@ -0,0 +1,40 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class AbsMultiArgsReducedOutputSwapped + { + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static async Task InvokeAsync(double b, double a, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["b"] = b; + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeSingleAsync("std:index:AbsMultiArgsReducedOutputSwapped", args, invokeOptions.WithDefaults()); + } + + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static Output Invoke(Input b, Input a, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["b"] = b; + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.InvokeSingle("std:index:AbsMultiArgsReducedOutputSwapped", args, invokeOptions.WithDefaults()); + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsReducedOutput.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsReducedOutput.cs new file mode 100644 index 000000000000..4516717068c2 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/AbsReducedOutput.cs @@ -0,0 +1,57 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class AbsReducedOutput + { + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static Task InvokeAsync(AbsReducedOutputArgs args, InvokeOptions? options = null) + => global::Pulumi.Deployment.Instance.InvokeSingleAsync("std:index:AbsReducedOutput", args ?? new AbsReducedOutputArgs(), options.WithDefaults()); + + /// + /// Returns the absolute value of a given float. + /// Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + /// + public static Output Invoke(AbsReducedOutputInvokeArgs args, InvokeOptions? options = null) + => global::Pulumi.Deployment.Instance.InvokeSingle("std:index:AbsReducedOutput", args ?? new AbsReducedOutputInvokeArgs(), options.WithDefaults()); + } + + + public sealed class AbsReducedOutputArgs : global::Pulumi.InvokeArgs + { + [Input("a", required: true)] + public double A { get; set; } + + [Input("b")] + public double? B { get; set; } + + public AbsReducedOutputArgs() + { + } + public static new AbsReducedOutputArgs Empty => new AbsReducedOutputArgs(); + } + + public sealed class AbsReducedOutputInvokeArgs : global::Pulumi.InvokeArgs + { + [Input("a", required: true)] + public Input A { get; set; } = null!; + + [Input("b")] + public Input? B { get; set; } + + public AbsReducedOutputInvokeArgs() + { + } + public static new AbsReducedOutputInvokeArgs Empty => new AbsReducedOutputInvokeArgs(); + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetArchive.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetArchive.cs new file mode 100644 index 000000000000..03a93fb26ecb --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetArchive.cs @@ -0,0 +1,30 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class GetArchive + { + public static async Task InvokeAsync(double? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeSingleAsync("std:index:GetArchive", args, invokeOptions.WithDefaults()); + } + + public static Output Invoke(Input? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.InvokeSingle("std:index:GetArchive", args, invokeOptions.WithDefaults()); + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetArrayCustomResult.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetArrayCustomResult.cs new file mode 100644 index 000000000000..25b46315acf9 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetArrayCustomResult.cs @@ -0,0 +1,30 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class GetArrayCustomResult + { + public static async Task> InvokeAsync(double? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeSingleAsync>("std:index:GetArrayCustomResult", args, invokeOptions.WithDefaults()); + } + + public static Output> Invoke(Input? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.InvokeSingle>("std:index:GetArrayCustomResult", args, invokeOptions.WithDefaults()); + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetAsset.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetAsset.cs new file mode 100644 index 000000000000..6dfba26c6c2c --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetAsset.cs @@ -0,0 +1,30 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class GetAsset + { + public static async Task InvokeAsync(double? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeSingleAsync("std:index:GetAsset", args, invokeOptions.WithDefaults()); + } + + public static Output Invoke(Input? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.InvokeSingle("std:index:GetAsset", args, invokeOptions.WithDefaults()); + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetCustomResult.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetCustomResult.cs new file mode 100644 index 000000000000..b21a19901605 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetCustomResult.cs @@ -0,0 +1,30 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class GetCustomResult + { + public static async Task InvokeAsync(double? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeAsync("std:index:GetCustomResult", args, invokeOptions.WithDefaults()); + } + + public static Output Invoke(Input? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.Invoke("std:index:GetCustomResult", args, invokeOptions.WithDefaults()); + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetDictionary.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetDictionary.cs new file mode 100644 index 000000000000..e979e5117793 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/GetDictionary.cs @@ -0,0 +1,30 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + public static class GetDictionary + { + public static async Task> InvokeAsync(double? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return await global::Pulumi.Deployment.Instance.InvokeAsync>("std:index:GetDictionary", args, invokeOptions.WithDefaults()); + } + + public static Output> Invoke(Input? a = null, InvokeOptions? invokeOptions = null) + { + var builder = ImmutableDictionary.CreateBuilder(); + builder["a"] = a; + var args = new global::Pulumi.DictionaryInvokeArgs(builder.ToImmutableDictionary()); + return global::Pulumi.Deployment.Instance.Invoke>("std:index:GetDictionary", args, invokeOptions.WithDefaults()); + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Outputs/AnotherCustomResult.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Outputs/AnotherCustomResult.cs new file mode 100644 index 000000000000..fbfc7c08e90f --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Outputs/AnotherCustomResult.cs @@ -0,0 +1,24 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std.Outputs +{ + + [OutputType] + public sealed class AnotherCustomResult + { + public readonly string? Value; + + [OutputConstructor] + private AnotherCustomResult(string? value) + { + Value = value; + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Outputs/CustomResult.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Outputs/CustomResult.cs new file mode 100644 index 000000000000..ac3282d679c5 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Outputs/CustomResult.cs @@ -0,0 +1,24 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std.Outputs +{ + + [OutputType] + public sealed class CustomResult + { + public readonly string? Value; + + [OutputConstructor] + private CustomResult(string? value) + { + Value = value; + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Provider.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Provider.cs new file mode 100644 index 000000000000..1cc2227234e8 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Provider.cs @@ -0,0 +1,47 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.Std +{ + [StdResourceType("pulumi:providers:std")] + public partial class Provider : global::Pulumi.ProviderResource + { + /// + /// Create a Provider resource with the given unique name, arguments, and options. + /// + /// + /// The unique name of the resource + /// The arguments used to populate this resource's properties + /// A bag of options that control this resource's behavior + public Provider(string name, ProviderArgs? args = null, CustomResourceOptions? options = null) + : base("std", name, args ?? new ProviderArgs(), MakeResourceOptions(options, "")) + { + } + + private static CustomResourceOptions MakeResourceOptions(CustomResourceOptions? options, Input? id) + { + var defaultOptions = new CustomResourceOptions + { + Version = Utilities.Version, + }; + var merged = CustomResourceOptions.Merge(defaultOptions, options); + // Override the ID if one was specified for consistency with other language SDKs. + merged.Id = id ?? merged.Id; + return merged; + } + } + + public sealed class ProviderArgs : global::Pulumi.ResourceArgs + { + public ProviderArgs() + { + } + public static new ProviderArgs Empty => new ProviderArgs(); + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Pulumi.Std.csproj b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Pulumi.Std.csproj new file mode 100644 index 000000000000..e2af4d2751c5 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Pulumi.Std.csproj @@ -0,0 +1,61 @@ + + + + true + Pulumi + Pulumi + Standard library functions + + https://github.com/pulumi/pulumi-std + https://github.com/pulumi/pulumi-std + logo.png + + netcoreapp3.1 + enable + false + + + + true + 1701;1702;1591 + + + + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + true + true + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + + + diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/README.md b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/README.md new file mode 100644 index 000000000000..1aa6474ef295 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/README.md @@ -0,0 +1 @@ +Standard library functions diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Utilities.cs b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Utilities.cs new file mode 100644 index 000000000000..d23c96dd71f8 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/Utilities.cs @@ -0,0 +1,83 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +namespace Pulumi.Std +{ + static class Utilities + { + public static string? GetEnv(params string[] names) + { + foreach (var n in names) + { + var value = global::System.Environment.GetEnvironmentVariable(n); + if (value != null) + { + return value; + } + } + return null; + } + + static string[] trueValues = { "1", "t", "T", "true", "TRUE", "True" }; + static string[] falseValues = { "0", "f", "F", "false", "FALSE", "False" }; + public static bool? GetEnvBoolean(params string[] names) + { + var s = GetEnv(names); + if (s != null) + { + if (global::System.Array.IndexOf(trueValues, s) != -1) + { + return true; + } + if (global::System.Array.IndexOf(falseValues, s) != -1) + { + return false; + } + } + return null; + } + + public static int? GetEnvInt32(params string[] names) => int.TryParse(GetEnv(names), out int v) ? (int?)v : null; + + public static double? GetEnvDouble(params string[] names) => double.TryParse(GetEnv(names), out double v) ? (double?)v : null; + + [global::System.Obsolete("Please use WithDefaults instead")] + public static global::Pulumi.InvokeOptions WithVersion(this global::Pulumi.InvokeOptions? options) + { + var dst = options ?? new global::Pulumi.InvokeOptions{}; + dst.Version = options?.Version ?? Version; + return dst; + } + + public static global::Pulumi.InvokeOptions WithDefaults(this global::Pulumi.InvokeOptions? src) + { + var dst = src ?? new global::Pulumi.InvokeOptions{}; + dst.Version = src?.Version ?? Version; + return dst; + } + + private readonly static string version; + public static string Version => version; + + static Utilities() + { + var assembly = global::System.Reflection.IntrospectionExtensions.GetTypeInfo(typeof(Utilities)).Assembly; + using var stream = assembly.GetManifestResourceStream("Pulumi.Std.version.txt"); + using var reader = new global::System.IO.StreamReader(stream ?? throw new global::System.NotSupportedException("Missing embedded version.txt file")); + version = reader.ReadToEnd().Trim(); + var parts = version.Split("\n"); + if (parts.Length == 2) + { + // The first part is the provider name. + version = parts[1].Trim(); + } + } + } + + internal sealed class StdResourceTypeAttribute : global::Pulumi.ResourceTypeAttribute + { + public StdResourceTypeAttribute(string type) : base(type, Utilities.Version) + { + } + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/codegen-manifest.json b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/codegen-manifest.json new file mode 100644 index 000000000000..40b663c4633b --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/codegen-manifest.json @@ -0,0 +1,22 @@ +{ + "emittedFiles": [ + "Abs.cs", + "AbsMultiArgs.cs", + "AbsMultiArgsReducedOutput.cs", + "AbsMultiArgsReducedOutputSwapped.cs", + "AbsReducedOutput.cs", + "GetArchive.cs", + "GetArrayCustomResult.cs", + "GetAsset.cs", + "GetCustomResult.cs", + "GetDictionary.cs", + "Outputs/AnotherCustomResult.cs", + "Outputs/CustomResult.cs", + "Provider.cs", + "Pulumi.Std.csproj", + "README.md", + "Utilities.cs", + "logo.png", + "pulumi-plugin.json" + ] +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/logo.png b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/logo.png new file mode 100644 index 000000000000..181f421e9156 Binary files /dev/null and b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/logo.png differ diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/pulumi-plugin.json b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/pulumi-plugin.json new file mode 100644 index 000000000000..2d1ffe3b6235 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/pulumi-plugin.json @@ -0,0 +1,4 @@ +{ + "resource": true, + "name": "std" +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/version.txt b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/version.txt new file mode 100644 index 000000000000..77d6f4ca2371 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/dotnet/version.txt @@ -0,0 +1 @@ +0.0.0 diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/README.md b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/README.md new file mode 100644 index 000000000000..1aa6474ef295 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/README.md @@ -0,0 +1 @@ +Standard library functions diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/abs.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/abs.ts new file mode 100644 index 000000000000..b4de1a210d24 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/abs.ts @@ -0,0 +1,39 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function abs(args: AbsArgs, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invoke("std:index:Abs", { + "a": args.a, + "b": args.b, + }, opts); +} + +export interface AbsArgs { + a: number; + b: number; +} + +export interface AbsResult { + readonly result: number; +} +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absOutput(args: AbsOutputArgs, opts?: pulumi.InvokeOptions): pulumi.Output { + return pulumi.output(args).apply((a: any) => abs(a, opts)) +} + +export interface AbsOutputArgs { + a: pulumi.Input; + b: pulumi.Input; +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgs.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgs.ts new file mode 100644 index 000000000000..ef96c732f2ef --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgs.ts @@ -0,0 +1,33 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absMultiArgs(a: number, b?: number, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invoke("std:index:AbsMultiArgs", { + "a": a, + "b": b, + }, opts); +} + +export interface AbsMultiArgsResult { + readonly result: number; +} +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absMultiArgsOutput(a: pulumi.Input, b?: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output { + var args = { + "a": a, + "b": b, + }; + return pulumi.output(args).apply((resolvedArgs: any) => absMultiArgs(resolvedArgs.a, resolvedArgs.b, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgsReducedOutput.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgsReducedOutput.ts new file mode 100644 index 000000000000..43911870ea7d --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgsReducedOutput.ts @@ -0,0 +1,29 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absMultiArgsReducedOutput(a: number, b?: number, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invokeSingle("std:index:AbsMultiArgsReducedOutput", { + "a": a, + "b": b, + }, opts); +} +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absMultiArgsReducedOutputOutput(a: pulumi.Input, b?: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output { + var args = { + "a": a, + "b": b, + }; + return pulumi.output(args).apply((resolvedArgs: any) => absMultiArgsReducedOutput(resolvedArgs.a, resolvedArgs.b, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgsReducedOutputSwapped.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgsReducedOutputSwapped.ts new file mode 100644 index 000000000000..d7cad23e374c --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absMultiArgsReducedOutputSwapped.ts @@ -0,0 +1,29 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absMultiArgsReducedOutputSwapped(b: number, a: number, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invokeSingle("std:index:AbsMultiArgsReducedOutputSwapped", { + "b": b, + "a": a, + }, opts); +} +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absMultiArgsReducedOutputSwappedOutput(b: pulumi.Input, a: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output { + var args = { + "b": b, + "a": a, + }; + return pulumi.output(args).apply((resolvedArgs: any) => absMultiArgsReducedOutputSwapped(resolvedArgs.b, resolvedArgs.a, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absReducedOutput.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absReducedOutput.ts new file mode 100644 index 000000000000..2188ba553c53 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/absReducedOutput.ts @@ -0,0 +1,35 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absReducedOutput(args: AbsReducedOutputArgs, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invokeSingle("std:index:AbsReducedOutput", { + "a": args.a, + "b": args.b, + }, opts); +} + +export interface AbsReducedOutputArgs { + a: number; + b?: number; +} +/** + * Returns the absolute value of a given float. + * Example: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14. + */ +export function absReducedOutputOutput(args: AbsReducedOutputOutputArgs, opts?: pulumi.InvokeOptions): pulumi.Output { + return pulumi.output(args).apply((a: any) => absReducedOutput(a, opts)) +} + +export interface AbsReducedOutputOutputArgs { + a: pulumi.Input; + b?: pulumi.Input; +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/codegen-manifest.json b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/codegen-manifest.json new file mode 100644 index 000000000000..f46dd6570fa3 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/codegen-manifest.json @@ -0,0 +1,24 @@ +{ + "emittedFiles": [ + "README.md", + "abs.ts", + "absMultiArgs.ts", + "absMultiArgsReducedOutput.ts", + "absMultiArgsReducedOutputSwapped.ts", + "absReducedOutput.ts", + "getArchive.ts", + "getArrayCustomResult.ts", + "getAsset.ts", + "getCustomResult.ts", + "getDictionary.ts", + "index.ts", + "package.json", + "provider.ts", + "scripts/install-pulumi-plugin.js", + "tsconfig.json", + "types/index.ts", + "types/input.ts", + "types/output.ts", + "utilities.ts" + ] +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getArchive.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getArchive.ts new file mode 100644 index 000000000000..d8263e48df4f --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getArchive.ts @@ -0,0 +1,19 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +export function getArchive(a?: number, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invokeSingle("std:index:GetArchive", { + "a": a, + }, opts); +} +export function getArchiveOutput(a?: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output { + var args = { + "a": a, + }; + return pulumi.output(args).apply((resolvedArgs: any) => getArchive(resolvedArgs.a, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getArrayCustomResult.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getArrayCustomResult.ts new file mode 100644 index 000000000000..4e8f0be74758 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getArrayCustomResult.ts @@ -0,0 +1,21 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as inputs from "./types/input"; +import * as outputs from "./types/output"; +import * as utilities from "./utilities"; + +export function getArrayCustomResult(a?: number, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invokeSingle("std:index:GetArrayCustomResult", { + "a": a, + }, opts); +} +export function getArrayCustomResultOutput(a?: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output { + var args = { + "a": a, + }; + return pulumi.output(args).apply((resolvedArgs: any) => getArrayCustomResult(resolvedArgs.a, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getAsset.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getAsset.ts new file mode 100644 index 000000000000..427bccf39294 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getAsset.ts @@ -0,0 +1,19 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +export function getAsset(a?: number, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invokeSingle("std:index:GetAsset", { + "a": a, + }, opts); +} +export function getAssetOutput(a?: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output { + var args = { + "a": a, + }; + return pulumi.output(args).apply((resolvedArgs: any) => getAsset(resolvedArgs.a, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getCustomResult.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getCustomResult.ts new file mode 100644 index 000000000000..a20a1b95ab7e --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getCustomResult.ts @@ -0,0 +1,21 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as inputs from "./types/input"; +import * as outputs from "./types/output"; +import * as utilities from "./utilities"; + +export function getCustomResult(a?: number, opts?: pulumi.InvokeOptions): Promise { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invoke("std:index:GetCustomResult", { + "a": a, + }, opts); +} +export function getCustomResultOutput(a?: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output { + var args = { + "a": a, + }; + return pulumi.output(args).apply((resolvedArgs: any) => getCustomResult(resolvedArgs.a, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getDictionary.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getDictionary.ts new file mode 100644 index 000000000000..e64a374c2947 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/getDictionary.ts @@ -0,0 +1,21 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as inputs from "./types/input"; +import * as outputs from "./types/output"; +import * as utilities from "./utilities"; + +export function getDictionary(a?: number, opts?: pulumi.InvokeOptions): Promise<{[key: string]: outputs.AnotherCustomResult}> { + + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts || {}); + return pulumi.runtime.invoke("std:index:GetDictionary", { + "a": a, + }, opts); +} +export function getDictionaryOutput(a?: pulumi.Input, opts?: pulumi.InvokeOptions): pulumi.Output<{[key: string]: outputs.AnotherCustomResult}> { + var args = { + "a": a, + }; + return pulumi.output(args).apply((resolvedArgs: any) => getDictionary(resolvedArgs.a, opts)) +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/index.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/index.ts new file mode 100644 index 000000000000..aa9bda881d27 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/index.ts @@ -0,0 +1,71 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +// Export members: +export { AbsArgs, AbsResult, AbsOutputArgs } from "./abs"; +export const abs: typeof import("./abs").abs = null as any; +export const absOutput: typeof import("./abs").absOutput = null as any; +utilities.lazyLoad(exports, ["abs","absOutput"], () => require("./abs")); + +export { AbsMultiArgsResult } from "./absMultiArgs"; +export const absMultiArgs: typeof import("./absMultiArgs").absMultiArgs = null as any; +export const absMultiArgsOutput: typeof import("./absMultiArgs").absMultiArgsOutput = null as any; +utilities.lazyLoad(exports, ["absMultiArgs","absMultiArgsOutput"], () => require("./absMultiArgs")); + +export const absMultiArgsReducedOutput: typeof import("./absMultiArgsReducedOutput").absMultiArgsReducedOutput = null as any; +export const absMultiArgsReducedOutputOutput: typeof import("./absMultiArgsReducedOutput").absMultiArgsReducedOutputOutput = null as any; +utilities.lazyLoad(exports, ["absMultiArgsReducedOutput","absMultiArgsReducedOutputOutput"], () => require("./absMultiArgsReducedOutput")); + +export const absMultiArgsReducedOutputSwapped: typeof import("./absMultiArgsReducedOutputSwapped").absMultiArgsReducedOutputSwapped = null as any; +export const absMultiArgsReducedOutputSwappedOutput: typeof import("./absMultiArgsReducedOutputSwapped").absMultiArgsReducedOutputSwappedOutput = null as any; +utilities.lazyLoad(exports, ["absMultiArgsReducedOutputSwapped","absMultiArgsReducedOutputSwappedOutput"], () => require("./absMultiArgsReducedOutputSwapped")); + +export { AbsReducedOutputArgs, AbsReducedOutputOutputArgs } from "./absReducedOutput"; +export const absReducedOutput: typeof import("./absReducedOutput").absReducedOutput = null as any; +export const absReducedOutputOutput: typeof import("./absReducedOutput").absReducedOutputOutput = null as any; +utilities.lazyLoad(exports, ["absReducedOutput","absReducedOutputOutput"], () => require("./absReducedOutput")); + +export const getArchive: typeof import("./getArchive").getArchive = null as any; +export const getArchiveOutput: typeof import("./getArchive").getArchiveOutput = null as any; +utilities.lazyLoad(exports, ["getArchive","getArchiveOutput"], () => require("./getArchive")); + +export const getArrayCustomResult: typeof import("./getArrayCustomResult").getArrayCustomResult = null as any; +export const getArrayCustomResultOutput: typeof import("./getArrayCustomResult").getArrayCustomResultOutput = null as any; +utilities.lazyLoad(exports, ["getArrayCustomResult","getArrayCustomResultOutput"], () => require("./getArrayCustomResult")); + +export const getAsset: typeof import("./getAsset").getAsset = null as any; +export const getAssetOutput: typeof import("./getAsset").getAssetOutput = null as any; +utilities.lazyLoad(exports, ["getAsset","getAssetOutput"], () => require("./getAsset")); + +export const getCustomResult: typeof import("./getCustomResult").getCustomResult = null as any; +export const getCustomResultOutput: typeof import("./getCustomResult").getCustomResultOutput = null as any; +utilities.lazyLoad(exports, ["getCustomResult","getCustomResultOutput"], () => require("./getCustomResult")); + +export const getDictionary: typeof import("./getDictionary").getDictionary = null as any; +export const getDictionaryOutput: typeof import("./getDictionary").getDictionaryOutput = null as any; +utilities.lazyLoad(exports, ["getDictionary","getDictionaryOutput"], () => require("./getDictionary")); + +export { ProviderArgs } from "./provider"; +export type Provider = import("./provider").Provider; +export const Provider: typeof import("./provider").Provider = null as any; +utilities.lazyLoad(exports, ["Provider"], () => require("./provider")); + + +// Export sub-modules: +import * as types from "./types"; + +export { + types, +}; +pulumi.runtime.registerResourcePackage("std", { + version: utilities.getVersion(), + constructProvider: (name: string, type: string, urn: string): pulumi.ProviderResource => { + if (type !== "pulumi:providers:std") { + throw new Error(`unknown provider type ${type}`); + } + return new Provider(name, undefined, { urn }); + }, +}); diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/package.json b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/package.json new file mode 100644 index 000000000000..6013d1d494f8 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/package.json @@ -0,0 +1,22 @@ +{ + "name": "@pulumi/std", + "version": "1.0.0", + "homepage": "https://github.com/pulumi/pulumi-std", + "repository": "https://github.com/pulumi/pulumi-std", + "scripts": { + "build": "tsc", + "install": "node scripts/install-pulumi-plugin.js resource std 1.0.0" + }, + "dependencies": { + "@pulumi/pulumi": "^3.0.0" + }, + "devDependencies": { + "@types/node": "^14", + "typescript": "^4.3.5" + }, + "pulumi": { + "resource": true, + "name": "std", + "version": "1.0.0" + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/provider.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/provider.ts new file mode 100644 index 000000000000..65d5ece37d11 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/provider.ts @@ -0,0 +1,44 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +export class Provider extends pulumi.ProviderResource { + /** @internal */ + public static readonly __pulumiType = 'std'; + + /** + * Returns true if the given object is an instance of Provider. This is designed to work even + * when multiple copies of the Pulumi SDK have been loaded into the same process. + */ + public static isInstance(obj: any): obj is Provider { + if (obj === undefined || obj === null) { + return false; + } + return obj['__pulumiType'] === Provider.__pulumiType; + } + + + /** + * Create a Provider resource with the given unique name, arguments, and options. + * + * @param name The _unique_ name of the resource. + * @param args The arguments to use to populate this resource's properties. + * @param opts A bag of options that control this resource's behavior. + */ + constructor(name: string, args?: ProviderArgs, opts?: pulumi.ResourceOptions) { + let resourceInputs: pulumi.Inputs = {}; + opts = opts || {}; + { + } + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts); + super(Provider.__pulumiType, name, resourceInputs, opts); + } +} + +/** + * The set of arguments for constructing a Provider resource. + */ +export interface ProviderArgs { +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/scripts/install-pulumi-plugin.js b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/scripts/install-pulumi-plugin.js new file mode 100644 index 000000000000..fefc6e0eb097 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/scripts/install-pulumi-plugin.js @@ -0,0 +1,26 @@ +"use strict"; +var childProcess = require("child_process"); + +var args = process.argv.slice(2); + +if (args.indexOf("${VERSION}") !== -1) { + process.exit(0); +} + +var res = childProcess.spawnSync("pulumi", ["plugin", "install"].concat(args), { + stdio: ["ignore", "inherit", "inherit"] +}); + +if (res.error && res.error.code === "ENOENT") { + console.error("\nThere was an error installing the resource provider plugin. " + + "It looks like `pulumi` is not installed on your system. " + + "Please visit https://pulumi.com/ to install the Pulumi CLI.\n" + + "You may try manually installing the plugin by running " + + "`pulumi plugin install " + args.join(" ") + "`"); +} else if (res.error || res.status !== 0) { + console.error("\nThere was an error installing the resource provider plugin. " + + "You may try to manually installing the plugin by running " + + "`pulumi plugin install " + args.join(" ") + "`"); +} + +process.exit(0); diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/tsconfig.json b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/tsconfig.json new file mode 100644 index 000000000000..5f1eab2e85ed --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "outDir": "bin", + "target": "es2016", + "module": "commonjs", + "moduleResolution": "node", + "declaration": true, + "sourceMap": true, + "stripInternal": true, + "experimentalDecorators": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, + "strict": true + }, + "files": [ + "abs.ts", + "absMultiArgs.ts", + "absMultiArgsReducedOutput.ts", + "absMultiArgsReducedOutputSwapped.ts", + "absReducedOutput.ts", + "getArchive.ts", + "getArrayCustomResult.ts", + "getAsset.ts", + "getCustomResult.ts", + "getDictionary.ts", + "index.ts", + "provider.ts", + "types/index.ts", + "types/input.ts", + "types/output.ts", + "utilities.ts" + ] +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/index.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/index.ts new file mode 100644 index 000000000000..d1f303f60379 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/index.ts @@ -0,0 +1,13 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as utilities from "../utilities"; + +// Export sub-modules: +import * as input from "./input"; +import * as output from "./output"; + +export { + input, + output, +}; diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/input.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/input.ts new file mode 100644 index 000000000000..a277306fc819 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/input.ts @@ -0,0 +1,7 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as inputs from "../types/input"; +import * as outputs from "../types/output"; + diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/output.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/output.ts new file mode 100644 index 000000000000..594af5f40b40 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/types/output.ts @@ -0,0 +1,15 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as inputs from "../types/input"; +import * as outputs from "../types/output"; + +export interface AnotherCustomResult { + value?: string; +} + +export interface CustomResult { + value?: string; +} + diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/utilities.ts b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/utilities.ts new file mode 100644 index 000000000000..fae1054b6bab --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/nodejs/utilities.ts @@ -0,0 +1,66 @@ +// *** WARNING: this file was generated by test. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + + +export function getEnv(...vars: string[]): string | undefined { + for (const v of vars) { + const value = process.env[v]; + if (value) { + return value; + } + } + return undefined; +} + +export function getEnvBoolean(...vars: string[]): boolean | undefined { + const s = getEnv(...vars); + if (s !== undefined) { + // NOTE: these values are taken from https://golang.org/src/strconv/atob.go?s=351:391#L1, which is what + // Terraform uses internally when parsing boolean values. + if (["1", "t", "T", "true", "TRUE", "True"].find(v => v === s) !== undefined) { + return true; + } + if (["0", "f", "F", "false", "FALSE", "False"].find(v => v === s) !== undefined) { + return false; + } + } + return undefined; +} + +export function getEnvNumber(...vars: string[]): number | undefined { + const s = getEnv(...vars); + if (s !== undefined) { + const f = parseFloat(s); + if (!isNaN(f)) { + return f; + } + } + return undefined; +} + +export function getVersion(): string { + let version = require('./package.json').version; + // Node allows for the version to be prefixed by a "v", while semver doesn't. + // If there is a v, strip it off. + if (version.indexOf('v') === 0) { + version = version.slice(1); + } + return version; +} + +/** @internal */ +export function resourceOptsDefaults(): any { + return { version: getVersion() }; +} + +/** @internal */ +export function lazyLoad(exports: any, props: string[], loadModule: any) { + for (let property of props) { + Object.defineProperty(exports, property, { + enumerable: true, + get: function() { + return loadModule()[property]; + }, + }); + } +} diff --git a/pkg/codegen/testing/test/testdata/simplified-invokes/schema.json b/pkg/codegen/testing/test/testdata/simplified-invokes/schema.json new file mode 100644 index 000000000000..aa69ce8a6ce4 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/simplified-invokes/schema.json @@ -0,0 +1,252 @@ +{ + "name": "std", + "displayName": "StandardLibrary", + "version": "1.0.0", + "description": "Standard library functions", + "homepage": "https://github.com/pulumi/pulumi-std", + "repository": "https://github.com/pulumi/pulumi-std", + "publisher": "Pulumi", + "meta": { + "moduleFormat": "(.*)" + }, + "language": { + "csharp": { + "packageReferences": { + "Pulumi": "3.50.0" + } + }, + "nodejs": { + "dependencies": { + "@pulumi/pulumi": "^3.0.0" + }, + "respectSchemaVersion": true + } + }, + "config": {}, + "provider": { + "type": "object" + }, + "functions": { + "std:index:Abs": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a", + "b" + ] + }, + "outputs": { + "properties": { + "result": { + "type": "number" + } + }, + "type": "object", + "required": [ + "result" + ] + } + }, + "std:index:AbsMultiArgs": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "multiArgumentInputs": ["a", "b"], + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a" + ] + }, + "outputs": { + "properties": { + "result": { + "type": "number" + } + }, + "type": "object", + "required": [ + "result" + ] + } + }, + "std:index:AbsReducedOutput": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a" + ] + }, + "outputs": { + "type": "number" + } + }, + "std:index:AbsMultiArgsReducedOutput": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "multiArgumentInputs": ["a", "b"], + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a" + ] + }, + "outputs": { + "type": "number" + } + }, + "std:index:AbsMultiArgsReducedOutputSwapped": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "multiArgumentInputs": ["b", "a"], + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a", + "b" + ] + }, + "outputs": { + "type": "number" + } + }, + + "std:index:GetCustomResult": { + "multiArgumentInputs": ["a"], + "inputs": { + "type": "object", + "properties": { + "a": { + "type": "number" + } + } + }, + "outputs": { + "$ref": "#/types/std::CustomResult" + } + }, + + "std:index:GetArrayCustomResult": { + "multiArgumentInputs": ["a"], + "inputs": { + "type": "object", + "properties": { + "a": { + "type": "number" + } + } + }, + "outputs": { + "type": "array", + "items": { + "$ref": "#/types/std::CustomResult" + } + } + }, + + "std:index:GetDictionary": { + "multiArgumentInputs": ["a"], + "inputs": { + "type": "object", + "properties": { + "a": { + "type": "number" + } + } + }, + "outputs": { + "type": "object", + "additionalProperties": { + "$ref": "#/types/std::AnotherCustomResult" + } + } + }, + + "std:index:GetAsset": { + "multiArgumentInputs": ["a"], + "inputs": { + "type": "object", + "properties": { + "a": { + "type": "number" + } + } + }, + "outputs": { + "$ref": "pulumi.json#/Asset" + } + }, + + "std:index:GetArchive": { + "multiArgumentInputs": ["a"], + "inputs": { + "type": "object", + "properties": { + "a": { + "type": "number" + } + } + }, + "outputs": { + "$ref": "pulumi.json#/Archive" + } + } + }, + + "types": { + "std::CustomResult": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + }, + "std::AnotherCustomResult": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/pkg/codegen/testing/test/testdata/std-1.0.0.json b/pkg/codegen/testing/test/testdata/std-1.0.0.json new file mode 100644 index 000000000000..60b048e1b8d0 --- /dev/null +++ b/pkg/codegen/testing/test/testdata/std-1.0.0.json @@ -0,0 +1,147 @@ +{ + "name": "std", + "displayName": "StandardLibrary", + "version": "1.0.0", + "description": "Standard library functions", + "homepage": "https://github.com/pulumi/pulumi-std", + "repository": "https://github.com/pulumi/pulumi-std", + "publisher": "Pulumi", + "meta": { + "moduleFormat": "(.*)" + }, + "language": { + "csharp": { + "packageReferences": { + "Pulumi": "3.50.0" + } + }, + "nodejs": { + "dependencies": { + "@pulumi/pulumi": "^3.0.0" + }, + "respectSchemaVersion": true + } + }, + "config": {}, + "provider": { + "type": "object" + }, + "functions": { + "std:index:Abs": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a", + "b" + ] + }, + "outputs": { + "properties": { + "result": { + "type": "number" + } + }, + "type": "object", + "required": [ + "result" + ] + } + }, + "std:index:AbsMultiArgs": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "multiArgumentInputs": ["a", "b", "c"], + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + }, + "c": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a" + ] + }, + "outputs": { + "type": "number" + } + }, + "std:index:AbsReducedOutput": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a" + ] + }, + "outputs": { + "type": "number" + } + }, + "std:index:AbsMultiArgsReducedOutput": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "multiArgumentInputs": ["a", "b"], + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a" + ] + }, + "outputs": { + "type": "number" + } + }, + "std:index:AbsMultiArgsReducedOutputSwapped": { + "description": "Returns the absolute value of a given float. \nExample: abs(1) returns 1, and abs(-1) would also return 1, whereas abs(-3.14) would return 3.14.", + "multiArgumentInputs": ["b", "a"], + "inputs": { + "properties": { + "a": { + "type": "number" + }, + "b": { + "type": "number" + } + }, + "type": "object", + "required": [ + "a", + "b" + ] + }, + "outputs": { + "type": "number" + } + } + } +} \ No newline at end of file diff --git a/pkg/codegen/testing/test/type_driver.go b/pkg/codegen/testing/test/type_driver.go index 793d54347af4..03145641352e 100644 --- a/pkg/codegen/testing/test/type_driver.go +++ b/pkg/codegen/testing/test/type_driver.go @@ -124,8 +124,10 @@ func TestTypeNameCodegen(t *testing.T, language string, newTypeNameGenerator New if f.Inputs != nil { runTests("/functions/"+f.Token+"/inputs/properties", f.Inputs.Properties, false) } - if f.Outputs != nil { - runTests("/functions/"+f.Token+"/outputs/properties", f.Outputs.Properties, false) + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + runTests("/functions/"+f.Token+"/outputs/properties", objectType.Properties, false) + } } } return @@ -185,8 +187,10 @@ func TestTypeNameCodegen(t *testing.T, language string, newTypeNameGenerator New if f.Inputs != nil { updateTests(f.Inputs.Properties) } - if f.Outputs != nil { - updateTests(f.Outputs.Properties) + if f.ReturnType != nil { + if objectType, ok := f.ReturnType.(*schema.ObjectType); ok && objectType != nil { + updateTests(objectType.Properties) + } } } diff --git a/pkg/codegen/testing/utils/host.go b/pkg/codegen/testing/utils/host.go index a3968e022fe1..b001aee8f718 100644 --- a/pkg/codegen/testing/utils/host.go +++ b/pkg/codegen/testing/utils/host.go @@ -65,6 +65,7 @@ func NewHost(schemaDirectoryPath string) plugin.Host { SchemaProvider{"google-native", "0.18.2"}, SchemaProvider{"aws-native", "0.13.0"}, SchemaProvider{"docker", "3.1.0"}, + SchemaProvider{"std", "1.0.0"}, // PCL examples in 'testing/test/testdata/transpiled_examples require these versions SchemaProvider{"aws", "5.4.0"}, SchemaProvider{"azure-native", "1.56.0"}, diff --git a/pkg/codegen/utilities_types.go b/pkg/codegen/utilities_types.go index 5606f2e8ed3c..783a4437bcd3 100644 --- a/pkg/codegen/utilities_types.go +++ b/pkg/codegen/utilities_types.go @@ -32,6 +32,11 @@ func visitTypeClosure(t schema.Type, visitor func(t schema.Type), seen Set) { } } +func VisitType(schemaType schema.Type, visitor func(t schema.Type)) { + seen := Set{} + visitTypeClosure(schemaType, visitor, seen) +} + func VisitTypeClosure(properties []*schema.Property, visitor func(t schema.Type)) { seen := Set{} for _, p := range properties {