From ea8526c3ec6e6d7d89d5b843e72178e70727e7d3 Mon Sep 17 00:00:00 2001 From: Anthony Martin Date: Mon, 15 Mar 2021 14:20:37 -0400 Subject: [PATCH] Add type definitions for providers() (#1877) * Add type definitions for providers() * Update test baselines * Update AzNamespaceSymbol.cs Co-authored-by: Bicep Automation --- .../ScenarioTests.cs | 28 ++++++++++ .../Files/Functions/az.json | 27 ++++++++-- .../Assertions/JTokenAssertionsExtensions.cs | 8 +-- .../Semantics/Namespaces/AzNamespaceSymbol.cs | 53 ++++++++++++------- 4 files changed, 90 insertions(+), 26 deletions(-) diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index 6b500aa3299..2fb673ce95a 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -971,5 +971,33 @@ public void Test_Issue1817() }); } } + + [TestMethod] + public void Test_Issue1630() + { + var (template, diags, _) = CompilationHelper.Compile(@" +var singleResource = providers('Microsoft.Insights', 'components') +var allResources = providers('Microsoft.Insights') + +// singleResource is an object! +var firstApiVersion = singleResource.apiVersions[0] + +// allResources is an array of objects! +var firstResourceFirstApiVersion = allResources[0].apiVersions[0] + +output singleResource object = singleResource +output allResources array = allResources +"); + + using (new AssertionScope()) + { + diags.Should().BeEmpty(); + + template.Should().HaveValueAtPath("$.variables['singleResource']", "[providers('Microsoft.Insights', 'components')]"); + template.Should().HaveValueAtPath("$.variables['firstApiVersion']", "[variables('singleResource').apiVersions[0]]"); + template.Should().HaveValueAtPath("$.variables['allResources']", "[providers('Microsoft.Insights')]"); + template.Should().HaveValueAtPath("$.variables['firstResourceFirstApiVersion']", "[variables('allResources')[0].apiVersions[0]]"); + } + } } } \ No newline at end of file diff --git a/src/Bicep.Core.Samples/Files/Functions/az.json b/src/Bicep.Core.Samples/Files/Functions/az.json index 6e077b5135b..f6786510454 100644 --- a/src/Bicep.Core.Samples/Files/Functions/az.json +++ b/src/Bicep.Core.Samples/Files/Functions/az.json @@ -117,6 +117,25 @@ "[offset: int]" ] }, + { + "name": "providers", + "description": "Returns information about a resource provider and its supported resource types. If you don't provide a resource type, the function returns all the supported types for the resource provider.", + "fixedParameters": [ + { + "name": "providerNamespace", + "description": "the namespace of the provider", + "type": "string", + "required": true + } + ], + "minimumArgumentCount": 1, + "maximumArgumentCount": 1, + "flags": "default", + "typeSignature": "(providerNamespace: string): provider[]", + "parameterTypeSignatures": [ + "providerNamespace: string" + ] + }, { "name": "providers", "description": "Returns information about a resource provider and its supported resource types. If you don't provide a resource type, the function returns all the supported types for the resource provider.", @@ -131,16 +150,16 @@ "name": "resourceType", "description": "The type of resource within the specified namespace", "type": "string", - "required": false + "required": true } ], - "minimumArgumentCount": 1, + "minimumArgumentCount": 2, "maximumArgumentCount": 2, "flags": "default", - "typeSignature": "(providerNamespace: string, [resourceType: string]): array", + "typeSignature": "(providerNamespace: string, resourceType: string): provider", "parameterTypeSignatures": [ "providerNamespace: string", - "[resourceType: string]" + "resourceType: string" ] }, { diff --git a/src/Bicep.Core.UnitTests/Assertions/JTokenAssertionsExtensions.cs b/src/Bicep.Core.UnitTests/Assertions/JTokenAssertionsExtensions.cs index 19030581de0..96d4dd72f26 100644 --- a/src/Bicep.Core.UnitTests/Assertions/JTokenAssertionsExtensions.cs +++ b/src/Bicep.Core.UnitTests/Assertions/JTokenAssertionsExtensions.cs @@ -69,12 +69,12 @@ public static AndConstraint HaveValueAtPath(this JTokenAsserti Execute.Assertion .BecauseOf(because, becauseArgs) .ForCondition(valueAtPath is not null) - .FailWith("Expected value at path {0} to be {1} but it was null", jtokenPath, expected.ToString()); + .FailWith("Expected value at path {0} to be {1}{reason} but it was null. Original JSON: {2}", jtokenPath, expected.ToString(), instance.Subject?.ToString()); Execute.Assertion .BecauseOf(because, becauseArgs) .ForCondition(JToken.DeepEquals(valueAtPath, expected)) - .FailWith("Expected value at path {0} to be {1} but it was {2}", jtokenPath, expected.ToString(), valueAtPath?.ToString()); + .FailWith("Expected value at path {0} to be {1}{reason} but it was {2}", jtokenPath, expected.ToString(), valueAtPath?.ToString()); return new AndConstraint(instance); } @@ -86,7 +86,7 @@ public static AndConstraint NotHaveValueAtPath(this JTokenAsse Execute.Assertion .BecauseOf(because, becauseArgs) .ForCondition(valueAtPath is null) - .FailWith("Expected value at path {0} to be null, but it was {1}", jtokenPath, valueAtPath); + .FailWith("Expected value at path {0} to be null{reason}, but it was {1}", jtokenPath, valueAtPath); return new AndConstraint(instance); } @@ -96,7 +96,7 @@ public static AndConstraint NotHaveValue(this JTokenAssertions Execute.Assertion .BecauseOf(because, becauseArgs) .ForCondition(instance.Subject is null) - .FailWith("Expected value to be null, but it was {0}", instance.Subject?.ToString()); + .FailWith("Expected value to be null{reason}, but it was {0}", instance.Subject?.ToString()); return new AndConstraint(instance); } diff --git a/src/Bicep.Core/Semantics/Namespaces/AzNamespaceSymbol.cs b/src/Bicep.Core/Semantics/Namespaces/AzNamespaceSymbol.cs index 80b042a2c0d..b42f2900f96 100644 --- a/src/Bicep.Core/Semantics/Namespaces/AzNamespaceSymbol.cs +++ b/src/Bicep.Core/Semantics/Namespaces/AzNamespaceSymbol.cs @@ -15,19 +15,19 @@ namespace Bicep.Core.Semantics.Namespaces { public class AzNamespaceSymbol : NamespaceSymbol { - private static ObjectType GetRestrictedResourceGroupReturnValue(IEnumerable arguments) + private static ObjectType GetRestrictedResourceGroupReturnType(IEnumerable arguments) => new ResourceGroupScopeType(arguments, Enumerable.Empty()); - private static ObjectType GetRestrictedSubscriptionReturnValue(IEnumerable arguments) + private static ObjectType GetRestrictedSubscriptionReturnType(IEnumerable arguments) => new SubscriptionScopeType(arguments, Enumerable.Empty()); - private static ObjectType GetRestrictedManagementGroupReturnValue(IEnumerable arguments) + private static ObjectType GetRestrictedManagementGroupReturnType(IEnumerable arguments) => new ManagementGroupScopeType(arguments, Enumerable.Empty()); - private static ObjectType GetRestrictedTenantReturnValue(IEnumerable arguments) + private static ObjectType GetRestrictedTenantReturnType(IEnumerable arguments) => new TenantScopeType(arguments, Enumerable.Empty()); - private static ObjectType GetResourceGroupReturnValue(IEnumerable arguments) + private static ObjectType GetResourceGroupReturnType(IEnumerable arguments) { var properties = new NamedObjectType("properties", TypeSymbolValidationFlags.Default, new [] { @@ -46,7 +46,7 @@ private static ObjectType GetResourceGroupReturnValue(IEnumerable arguments) + private static ObjectType GetSubscriptionReturnType(IEnumerable arguments) { return new SubscriptionScopeType(arguments, new [] { @@ -56,6 +56,17 @@ private static ObjectType GetSubscriptionReturnValue(IEnumerable GetAzOverloads(ResourceScope resour .WithVariableParameter("resourceName",LanguageConstants.String, minimumCount: 1, "The extension resource name segment") .Build(); - // TODO: Not sure about return type + var singleProvider = GetSingleProvidersReturnType(); yield return new FunctionOverloadBuilder("providers") - .WithReturnType(LanguageConstants.Array) + .WithReturnType(new TypedArrayType(singleProvider, TypeSymbolValidationFlags.Default)) + .WithDescription("Returns information about a resource provider and its supported resource types. If you don't provide a resource type, the function returns all the supported types for the resource provider.") + .WithRequiredParameter("providerNamespace",LanguageConstants.String, "the namespace of the provider") + .Build(); + + yield return new FunctionOverloadBuilder("providers") + .WithReturnType(singleProvider) .WithDescription("Returns information about a resource provider and its supported resource types. If you don't provide a resource type, the function returns all the supported types for the resource provider.") .WithRequiredParameter("providerNamespace",LanguageConstants.String, "the namespace of the provider") - .WithOptionalParameter("resourceType",LanguageConstants.String, "The type of resource within the specified namespace") + .WithRequiredParameter("resourceType",LanguageConstants.String, "The type of resource within the specified namespace") .Build(); // TODO: return type is string[] @@ -325,4 +342,4 @@ public AzNamespaceSymbol(ResourceScope resourceScope) { } } -} \ No newline at end of file +}