// Copyright 2016-2020, Pulumi Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package pcl import ( "github.com/hashicorp/hcl/v2" "github.com/pulumi/pulumi/pkg/v3/codegen/hcl2/model" ) func getEntriesSignature( args []model.Expression, options bindOptions, ) (model.StaticFunctionSignature, hcl.Diagnostics) { var diagnostics hcl.Diagnostics keyType, valueType := model.Type(model.DynamicType), model.Type(model.DynamicType) signature := model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "collection", Type: model.DynamicType, }}, } if len(args) == 1 { strictCollectionTypechecking := !options.skipRangeTypecheck keyT, valueT, diags := model.GetCollectionTypes( model.ResolveOutputs(args[0].Type()), args[0].SyntaxNode().Range(), strictCollectionTypechecking) keyType, valueType, diagnostics = keyT, valueT, append(diagnostics, diags...) } elementType := model.NewObjectType(map[string]model.Type{ "key": keyType, "value": valueType, }) signature.ReturnType = model.NewListType(elementType) return signature, diagnostics } func pulumiBuiltins(options bindOptions) map[string]*model.Function { return map[string]*model.Function{ "element": model.NewFunction(model.GenericFunctionSignature( func(args []model.Expression) (model.StaticFunctionSignature, hcl.Diagnostics) { var diagnostics hcl.Diagnostics listType, returnType := model.Type(model.DynamicType), model.Type(model.DynamicType) if len(args) > 0 { switch t := model.ResolveOutputs(args[0].Type()).(type) { case *model.ListType: listType, returnType = args[0].Type(), t.ElementType case *model.TupleType: _, elementType := model.UnifyTypes(t.ElementTypes...) listType, returnType = args[0].Type(), elementType default: rng := args[0].SyntaxNode().Range() diagnostics = hcl.Diagnostics{&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "the first argument to 'element' must be a list or tuple", Subject: &rng, }} } } return model.StaticFunctionSignature{ Parameters: []model.Parameter{ { Name: "list", Type: listType, }, { Name: "index", Type: model.NumberType, }, }, ReturnType: returnType, }, diagnostics })), "entries": model.NewFunction(model.GenericFunctionSignature( func(arguments []model.Expression) (model.StaticFunctionSignature, hcl.Diagnostics) { return getEntriesSignature(arguments, options) })), "fileArchive": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "path", Type: model.StringType, }}, ReturnType: ArchiveType, }), "remoteArchive": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "uri", Type: model.StringType, }}, ReturnType: ArchiveType, }), "assetArchive": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "assets", Type: model.NewMapType(AssetOrArchiveType), }}, ReturnType: ArchiveType, }), "fileAsset": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "path", Type: model.StringType, }}, ReturnType: AssetType, }), "stringAsset": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: model.StringType, }}, ReturnType: AssetType, }), "remoteAsset": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "uri", Type: model.StringType, }}, ReturnType: AssetType, }), "join": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{ { Name: "separator", Type: model.StringType, }, { Name: "strings", Type: model.NewListType(model.StringType), }, }, ReturnType: model.StringType, }), "length": model.NewFunction(model.GenericFunctionSignature( func(args []model.Expression) (model.StaticFunctionSignature, hcl.Diagnostics) { var diagnostics hcl.Diagnostics valueType := model.Type(model.DynamicType) if len(args) > 0 { valueType = args[0].Type() elementType := UnwrapOption(model.ResolveOutputs(valueType)) switch valueType := elementType.(type) { case *model.ListType, *model.MapType, *model.ObjectType, *model.TupleType: // OK default: if model.StringType.ConversionFrom(valueType) == model.NoConversion { rng := args[0].SyntaxNode().Range() diagnostics = hcl.Diagnostics{&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "the first argument to 'length' must be a list, map, object, tuple, or string", Subject: &rng, }} } } } return model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: valueType, }}, ReturnType: model.IntType, }, diagnostics })), "lookup": model.NewFunction(model.GenericFunctionSignature( func(args []model.Expression) (model.StaticFunctionSignature, hcl.Diagnostics) { var diagnostics hcl.Diagnostics mapType, elementType := model.Type(model.DynamicType), model.Type(model.DynamicType) if len(args) > 0 { switch t := model.ResolveOutputs(args[0].Type()).(type) { case *model.MapType: mapType, elementType = args[0].Type(), t.ElementType case *model.ObjectType: var unifiedType model.Type for _, t := range t.Properties { _, unifiedType = model.UnifyTypes(unifiedType, t) } mapType, elementType = args[0].Type(), unifiedType default: rng := args[0].SyntaxNode().Range() diagnostics = hcl.Diagnostics{&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "the first argument to 'lookup' must be a map", Subject: &rng, }} } } return model.StaticFunctionSignature{ Parameters: []model.Parameter{ { Name: "map", Type: mapType, }, { Name: "key", Type: model.StringType, }, { Name: "default", Type: model.NewOptionalType(elementType), }, }, ReturnType: elementType, }, diagnostics })), "mimeType": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "path", Type: model.StringType, }}, ReturnType: model.StringType, }), "range": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{ { Name: "fromOrTo", Type: model.NumberType, }, { Name: "to", Type: model.NewOptionalType(model.NumberType), }, }, ReturnType: model.NewListType(model.IntType), }), "readDir": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "path", Type: model.StringType, }}, ReturnType: model.NewListType(model.StringType), }), "readFile": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "path", Type: model.StringType, }}, ReturnType: model.StringType, }), "filebase64": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "path", Type: model.StringType, }}, ReturnType: model.StringType, }), "filebase64sha256": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "path", Type: model.StringType, }}, ReturnType: model.StringType, }), "secret": model.NewFunction(model.GenericFunctionSignature( func(args []model.Expression) (model.StaticFunctionSignature, hcl.Diagnostics) { valueType := model.Type(model.DynamicType) if len(args) == 1 { valueType = args[0].Type() } return model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: valueType, }}, ReturnType: model.NewOutputType(valueType), }, nil })), "unsecret": model.NewFunction(model.GenericFunctionSignature( func(args []model.Expression) (model.StaticFunctionSignature, hcl.Diagnostics) { valueType := model.Type(model.DynamicType) if len(args) == 1 { valueType = args[0].Type() } return model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: valueType, }}, ReturnType: model.NewOutputType(valueType), }, nil })), "sha1": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "input", Type: model.StringType, }}, ReturnType: model.StringType, }), "split": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{ { Name: "separator", Type: model.StringType, }, { Name: "string", Type: model.StringType, }, }, ReturnType: model.NewListType(model.StringType), }), "toBase64": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: model.StringType, }}, ReturnType: model.StringType, }), "fromBase64": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: model.StringType, }}, ReturnType: model.StringType, }), "toJSON": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: model.DynamicType, }}, ReturnType: model.StringType, }), // Returns the name of the current stack "stack": model.NewFunction(model.StaticFunctionSignature{ ReturnType: model.StringType, }), // Returns the name of the current project "project": model.NewFunction(model.StaticFunctionSignature{ ReturnType: model.StringType, }), // Returns the directory from which pulumi was run "cwd": model.NewFunction(model.StaticFunctionSignature{ ReturnType: model.StringType, }), "notImplemented": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "errorMessage", Type: model.StringType, }}, ReturnType: model.DynamicType, }), // Returns either the single item in a list, none if the list is empty or errors. "singleOrNone": model.NewFunction(model.GenericFunctionSignature( func(args []model.Expression) (model.StaticFunctionSignature, hcl.Diagnostics) { var diagnostics hcl.Diagnostics valueType := model.Type(model.DynamicType) if len(args) == 1 { valueType = args[0].Type() } else { diagnostics = hcl.Diagnostics{&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "'singleOrNone' only expects one argument", }} } elementType := model.Type(model.DynamicType) switch valueType := model.ResolveOutputs(valueType).(type) { case *model.ListType: elementType = valueType.ElementType case *model.TupleType: if len(valueType.ElementTypes) > 0 { elementType = valueType.ElementTypes[0] } default: if valueType != model.DynamicType { rng := args[0].SyntaxNode().Range() diagnostics = hcl.Diagnostics{&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "the first argument to 'singleOrNone' must be a list or tuple", Subject: &rng, }} } } return model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "value", Type: valueType, }}, ReturnType: model.NewOptionalType(elementType), }, diagnostics })), "getOutput": model.NewFunction(model.StaticFunctionSignature{ Parameters: []model.Parameter{{ Name: "stackReference", // TODO: should be StackReference resource type but I'm not sure how to define that Type: model.DynamicType, }, { Name: "outputName", Type: model.StringType, }}, ReturnType: model.NewOutputType(model.DynamicType), }), } }