public void GetResourceBodyCompletionSnippets_WithDiscriminatedObjectTypeAndNoRequiredProperties_ShouldReturnEmptySnippet() { SnippetsProvider snippetsProvider = new SnippetsProvider(); var objectTypeA = new ObjectType("objA", TypeSymbolValidationFlags.Default, new[] { new TypeProperty("discKey", new StringLiteralType("keyA")), new TypeProperty("keyAProp", LanguageConstants.String), }, null); var objectTypeB = new ObjectType("objB", TypeSymbolValidationFlags.Default, new[] { new TypeProperty("discKey", new StringLiteralType("keyB")), new TypeProperty("keyBProp", LanguageConstants.String), }, null); var discriminatedObjectType = new DiscriminatedObjectType("discObj", TypeSymbolValidationFlags.Default, "discKey", new[] { objectTypeA, objectTypeB }); TypeSymbol typeSymbol = new ResourceType( ResourceTypeReference.Parse("microsoft.aadiam/azureADMetrics@2020-07-01-preview"), ResourceScope.ResourceGroup, discriminatedObjectType); IEnumerable <Snippet> snippets = snippetsProvider.GetResourceBodyCompletionSnippets(typeSymbol, false); snippets.Should().SatisfyRespectively( x => { x.Prefix.Should().Be("{}"); x.Detail.Should().Be("{}"); x.CompletionPriority.Should().Be(CompletionPriority.Medium); x.Text.Should().Be("{\n\t$0\n}"); }); }
private static ResourceTypeComponents DiscriminatedPropertiesTestsType() { var resourceType = ResourceTypeReference.Parse("Test.Rp/discriminatedPropertiesTests@2020-01-01"); var propsA = new ObjectType( "PropertiesA", TypeSymbolValidationFlags.WarnOnTypeMismatch, new[] { new TypeProperty("propType", new StringLiteralType("PropertiesA"), TypePropertyFlags.None, "..."), new TypeProperty("propA", LanguageConstants.String, TypePropertyFlags.None, "This is the description for propA!"), }, null); var propsB = new ObjectType( "PropertiesB", TypeSymbolValidationFlags.WarnOnTypeMismatch, new[] { new TypeProperty("propType", new StringLiteralType("PropertiesB"), TypePropertyFlags.None, "..."), new TypeProperty("propB", LanguageConstants.String, TypePropertyFlags.None, "This is the description for propB!"), }, null); var propertiesType = new DiscriminatedObjectType( "properties", TypeSymbolValidationFlags.Default, "propType", new[] { propsA, propsB }); return(new ResourceTypeComponents(resourceType, ResourceScope.ResourceGroup, new ObjectType(resourceType.FormatName(), TypeSymbolValidationFlags.Default, GetCommonResourceProperties(resourceType).Concat(new[] { new TypeProperty("properties", propertiesType, TypePropertyFlags.Required, "properties property"), }), null))); }
[DataRow("Microsoft.Compute/virtualMachines/extensions@2019-06-01", "Microsoft.COMPUTE/virtualMachines/etxensions@2019-06-01")] // different child type public void ResourceTypeReferenceComparer_should_determine_equality_correctly_for_inequal_types(string first, string second) { var firstReference = ResourceTypeReference.Parse(first); var secondReference = ResourceTypeReference.Parse(second); ResourceTypeReferenceComparer.Instance.Equals(firstReference, secondReference).Should().BeFalse($"'{firstReference.FormatName()}' and '{secondReference.FormatName()}' should not be considered equal"); }
// TODO: This does not recognize non-resource named objects yet public TypeSymbol?GetTypeByName(string?typeName) { /* * Obtaining the type by name currently does not involve processing outgoing edges in the expression graph (function or variable refs) * This means that we do not need to check for cycles. However, if that ever changes, ensure that proper cycle detection is added here. */ if (typeName == null) { return(null); } if (LanguageConstants.DeclarationTypes.TryGetValue(typeName, out TypeSymbol primitiveType)) { return(primitiveType); } // TODO: This needs proper namespace, type, and version resolution logic in the future ResourceTypeReference?typeReference = ResourceTypeReference.TryParse(typeName); if (typeReference == null) { return(null); } // TODO: Construct/lookup type information based on JSON schema or swagger // for now assuming very basic resource schema return(new ResourceType(typeName, LanguageConstants.TopLevelResourceProperties, additionalPropertiesType: null, typeReference)); }
public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax) => AssignTypeWithDiagnostics(syntax, diagnostics => { var stringSyntax = syntax.TryGetType(); if (stringSyntax != null && stringSyntax.IsInterpolated()) { // TODO: in the future, we can relax this check to allow interpolation with compile-time constants. // right now, codegen will still generate a format string however, which will cause problems for the type. return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).ResourceTypeInterpolationUnsupported())); } var stringContent = stringSyntax?.TryGetLiteralValue(); if (stringContent == null) { return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType())); } // TODO: This needs proper namespace, type, and version resolution logic in the future var typeReference = ResourceTypeReference.TryParse(stringContent); if (typeReference == null) { return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType())); } var declaredType = resourceTypeRegistrar.GetType(typeReference); return(TypeValidator.NarrowTypeAndCollectDiagnostics(typeManager, syntax.Body, declaredType, diagnostics)); });
public ResourceType(ResourceTypeReference typeReference, ResourceScope validParentScopes, ITypeReference body) : base(typeReference.FormatName()) { TypeReference = typeReference; ValidParentScopes = validParentScopes; Body = body; }
public ResourceType GetType(ResourceTypeReference reference, ResourceTypeGenerationFlags flags) { var bodyType = new ObjectType(reference.FormatName(), TypeSymbolValidationFlags.Default, LanguageConstants.CreateResourceProperties(reference), null); var resourceType = new ResourceType(reference, ResourceScope.Tenant | ResourceScope.ManagementGroup | ResourceScope.Subscription | ResourceScope.ResourceGroup | ResourceScope.Resource, bodyType); return(AzResourceTypeProvider.SetBicepResourceProperties(resourceType, flags)); }
public ResourceType(ResourceTypeReference typeReference, ITypeReference body, TypeSymbolValidationFlags validationFlags) : base(typeReference.FormatName()) { TypeReference = typeReference; Body = body; ValidationFlags = validationFlags; }
public ResourceTypeComponents GetResourceType(Azure.Bicep.Types.Concrete.ResourceType resourceType) { var resourceTypeReference = ResourceTypeReference.Parse(resourceType.Name); var bodyType = GetTypeSymbol(resourceType.Body.Type, true); return(new ResourceTypeComponents(resourceTypeReference, ToResourceScope(resourceType.ScopeType), bodyType)); }
public TypeSymbol GetDeclaredType(ResourceScope targetScope, IResourceTypeProvider resourceTypeProvider) { var stringSyntax = this.TypeString; if (stringSyntax != null && stringSyntax.IsInterpolated()) { // TODO: in the future, we can relax this check to allow interpolation with compile-time constants. // right now, codegen will still generate a format string however, which will cause problems for the type. return(ErrorType.Create(DiagnosticBuilder.ForPosition(this.Type).ResourceTypeInterpolationUnsupported())); } var stringContent = stringSyntax?.TryGetLiteralValue(); if (stringContent == null) { return(ErrorType.Create(DiagnosticBuilder.ForPosition(this.Type).InvalidResourceType())); } var typeReference = ResourceTypeReference.TryParse(stringContent); if (typeReference == null) { return(ErrorType.Create(DiagnosticBuilder.ForPosition(this.Type).InvalidResourceType())); } return(resourceTypeProvider.GetType(targetScope, typeReference)); }
public override void VisitResourceDeclarationSyntax(ResourceDeclarationSyntax syntax) => AssignTypeWithCaching(syntax, () => { var stringSyntax = syntax.TryGetType(); if (stringSyntax != null && stringSyntax.IsInterpolated()) { // TODO: in the future, we can relax this check to allow interpolation with compile-time constants. // right now, codegen will still generate a format string however, which will cause problems for the type. return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).ResourceTypeInterpolationUnsupported())); } var stringContent = stringSyntax?.GetLiteralValue(); if (stringContent == null) { return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType())); } // TODO: This needs proper namespace, type, and version resolution logic in the future var typeReference = ResourceTypeReference.TryParse(stringContent); if (typeReference == null) { return(new ErrorTypeSymbol(DiagnosticBuilder.ForPosition(syntax.Type).InvalidResourceType())); } // TODO: Construct/lookup type information based on JSON schema or swagger // for now assuming very basic resource schema return(new ResourceType(stringContent, LanguageConstants.CreateResourceProperties(typeReference), additionalProperties: null, typeReference)); });
public void ValidType_FullyQualitifedTypeShouldBeCorrect(string value, string expectedFullyQualifiedType) { var actual = ResourceTypeReference.TryParse(value); actual.Should().NotBeNull(); actual !.FullyQualifiedType.Should().Be(expectedFullyQualifiedType); }
public void Parse_permits_types_with_single_type_segment_and_optional_version(string value, string expectedType, string?expectedVersion) { var result = ResourceTypeReference.Parse(value); result.FormatType().Should().BeEquivalentTo(expectedType); result.ApiVersion.Should().BeEquivalentTo(expectedVersion); }
public void GetResourceBodyCompletionSnippets_WithDiscriminatedObjectTypeAndRequiredProperties_ShouldReturnRequiredPropertiesSnippet() { SnippetsProvider snippetsProvider = new SnippetsProvider(); var objectTypeA = new ObjectType("objA", TypeSymbolValidationFlags.Default, new[] { new TypeProperty("discKey", new StringLiteralType("keyA")), new TypeProperty("name", new StringLiteralType("keyA"), TypePropertyFlags.Required), new TypeProperty("location", LanguageConstants.String, TypePropertyFlags.Required), new TypeProperty("id", LanguageConstants.String) }, null); var objectTypeB = new ObjectType("objB", TypeSymbolValidationFlags.Default, new[] { new TypeProperty("discKey", new StringLiteralType("keyB")), new TypeProperty("name", LanguageConstants.String, TypePropertyFlags.Required), new TypeProperty("kind", new StringLiteralType("discKey"), TypePropertyFlags.ReadOnly), new TypeProperty("hostPoolType", LanguageConstants.String) }, null); var discriminatedObjectType = new DiscriminatedObjectType("discObj", TypeSymbolValidationFlags.Default, "discKey", new[] { objectTypeA, objectTypeB }); TypeSymbol typeSymbol = new ResourceType( ResourceTypeReference.Parse("microsoft.aadiam/azureADMetrics@2020-07-01-preview"), ResourceScope.ResourceGroup, discriminatedObjectType); IEnumerable <Snippet> snippets = snippetsProvider.GetResourceBodyCompletionSnippets(typeSymbol, false); snippets.Should().SatisfyRespectively( x => { x.Prefix.Should().Be("{}"); x.Detail.Should().Be("{}"); x.CompletionPriority.Should().Be(CompletionPriority.Medium); x.Text.Should().Be("{\n\t$0\n}"); }, x => { x.Prefix.Should().Be("required-properties-keyA"); x.Detail.Should().Be("Required properties"); x.CompletionPriority.Should().Be(CompletionPriority.Medium); x.Text.Should().BeEquivalentToIgnoringNewlines(@"{ name: 'keyA' location: $1 $0 }"); }, x => { x.Prefix.Should().Be("required-properties-keyB"); x.Detail.Should().Be("Required properties"); x.CompletionPriority.Should().Be(CompletionPriority.Medium); x.Text.Should().BeEquivalentToIgnoringNewlines(@"{ name: $1 $0 }"); }); }
public void TryCombine_CombinesValidTypeSegments(string baseTypeText, string[] typeSegments, string expected) { var baseType = ResourceTypeReference.Parse(baseTypeText); var actual = ResourceTypeReference.TryCombine(baseType, typeSegments); actual.Should().NotBeNull(); actual !.FormatName().Should().BeEquivalentTo(expected); }
public void TryParseSingleTypeSegment_TypeSegmentIsParsed(string value, string expectedType, string expectedVersion) { var success = ResourceTypeReference.TryParseSingleTypeSegment(value, out var type, out var version); success.Should().BeTrue($"For input '{value}': type was '{type}', version was '{version}'"); type.Should().BeEquivalentTo(expectedType); version.Should().BeEquivalentTo(expectedVersion); }
public void TryCombine_RejectsInvalidTypeSegment() { var baseType = ResourceTypeReference.Parse("My.RP/someType@2020-01-01"); var typeSegments = new [] { "childType@2019-06-01", "childType/grandChildType", }; var actual = ResourceTypeReference.TryCombine(baseType, typeSegments); actual.Should().BeNull(); }
public ResourceType LoadType(ResourceTypeReference reference) { var typeLocation = availableTypes[reference]; var serializedResourceType = typeLoader.LoadResourceType(typeLocation); return(resourceTypeFactory.GetResourceType(serializedResourceType)); }
[DataRow("artifacts@2018-11-012222-preview")] // invalid version public void TryParseSingleTypeSegment_InvalidTypeSegmentIsRejected(string value) { var success = ResourceTypeReference.TryParseSingleTypeSegment(value, out var type, out var version); success.Should().BeFalse($"For input '{value}': type was '{type}', version was '{version}'"); type.Should().BeNull(); version.Should().BeNull(); }
public ResourceType(NamespaceType declaringNamespace, ResourceTypeReference typeReference, ResourceScope validParentScopes, ITypeReference body) : base(typeReference.FormatName()) { DeclaringNamespace = declaringNamespace; TypeReference = typeReference; ValidParentScopes = validParentScopes; Body = body; }
private static IEnumerable <TypeProperty> GetCommonResourceProperties(ResourceTypeReference reference) => new [] { new TypeProperty("id", LanguageConstants.String, TypePropertyFlags.ReadOnly | TypePropertyFlags.SkipInlining), new TypeProperty("name", LanguageConstants.String, TypePropertyFlags.Required | TypePropertyFlags.SkipInlining), new TypeProperty("type", new StringLiteralType(reference.FullyQualifiedType), TypePropertyFlags.ReadOnly | TypePropertyFlags.SkipInlining), new TypeProperty("apiVersion", new StringLiteralType(reference.ApiVersion), TypePropertyFlags.ReadOnly | TypePropertyFlags.SkipInlining), };
private static IReadOnlyDictionary <ResourceTypeReference, TypeLocation> GetAvailableResourceTypes(ITypeLoader typeLoader) { var indexedTypes = typeLoader.GetIndexedTypes(); return(indexedTypes.Types.ToDictionary( kvp => ResourceTypeReference.Parse(kvp.Key), kvp => kvp.Value, ResourceTypeReferenceComparer.Instance)); }
public AzResourceTypeLoader() { this.typeLoader = new TypeLoader(); this.resourceTypeFactory = new AzResourceTypeFactory(); this.availableTypes = typeLoader.GetIndexedTypes().Types.ToImmutableDictionary( kvp => ResourceTypeReference.Parse(kvp.Key), kvp => kvp.Value, ResourceTypeReferenceComparer.Instance); }
public static ResourceType CreateCustomResourceType(string fullyQualifiedType, string apiVersion, TypeSymbolValidationFlags validationFlags, params TypeProperty[] customProperties) { var reference = ResourceTypeReference.Parse($"{fullyQualifiedType}@{apiVersion}"); var resourceProperties = LanguageConstants.GetCommonResourceProperties(reference) .Concat(new TypeProperty("properties", new NamedObjectType("properties", validationFlags, customProperties, null), TypePropertyFlags.Required)); return(new ResourceType(reference, new NamedObjectType(reference.FormatName(), validationFlags, resourceProperties, null))); }
public ResourceType(NamespaceType declaringNamespace, ResourceTypeReference typeReference, ResourceScope validParentScopes, ITypeReference body, ImmutableHashSet <string> uniqueIdentifierProperties) : base(typeReference.FormatName()) { DeclaringNamespace = declaringNamespace; TypeReference = typeReference; ValidParentScopes = validParentScopes; Body = body; UniqueIdentifierProperties = uniqueIdentifierProperties; }
private static ResourceTypeComponents BasicTestsType() { var resourceType = ResourceTypeReference.Parse("Test.Rp/basicTests@2020-01-01"); return(new ResourceTypeComponents(resourceType, ResourceScope.ResourceGroup, new ObjectType(resourceType.FormatName(), TypeSymbolValidationFlags.Default, GetCommonResourceProperties(resourceType).Concat(new[] { new TypeProperty("kind", LanguageConstants.String, TypePropertyFlags.ReadOnly, "kind property"), }), null))); }
public static IEnumerable <TypeProperty> GetCommonResourceProperties(ResourceTypeReference reference) { yield return(new TypeProperty(ResourceIdPropertyName, String, TypePropertyFlags.ReadOnly | TypePropertyFlags.DeployTimeConstant)); yield return(new TypeProperty(ResourceNamePropertyName, String, TypePropertyFlags.Required | TypePropertyFlags.DeployTimeConstant)); yield return(new TypeProperty(ResourceTypePropertyName, new StringLiteralType(reference.FullyQualifiedType), TypePropertyFlags.ReadOnly | TypePropertyFlags.DeployTimeConstant)); yield return(new TypeProperty(ResourceApiVersionPropertyName, new StringLiteralType(reference.ApiVersion), TypePropertyFlags.ReadOnly | TypePropertyFlags.DeployTimeConstant)); }
private static IEnumerable <TypeProperty> GetCommonResourceProperties(ResourceTypeReference reference) { yield return(new TypeProperty(LanguageConstants.ResourceIdPropertyName, LanguageConstants.String, TypePropertyFlags.ReadOnly | TypePropertyFlags.DeployTimeConstant, "id property")); yield return(new TypeProperty(LanguageConstants.ResourceNamePropertyName, LanguageConstants.String, TypePropertyFlags.Required | TypePropertyFlags.DeployTimeConstant | TypePropertyFlags.LoopVariant, "name property")); yield return(new TypeProperty(LanguageConstants.ResourceTypePropertyName, new StringLiteralType(reference.FullyQualifiedType), TypePropertyFlags.ReadOnly | TypePropertyFlags.DeployTimeConstant, "type property")); yield return(new TypeProperty(LanguageConstants.ResourceApiVersionPropertyName, new StringLiteralType(reference.ApiVersion), TypePropertyFlags.ReadOnly | TypePropertyFlags.DeployTimeConstant, "apiVersion property")); }
public AzResourceTypeProvider(ITypeLoader typeLoader) { this.typeLoader = typeLoader; this.resourceTypeFactory = new AzResourceTypeFactory(); this.availableResourceTypes = typeLoader.ListAllAvailableTypes().ToDictionary( kvp => ResourceTypeReference.Parse(kvp.Key), kvp => kvp.Value, ResourceTypeReferenceComparer.Instance); this.loadedTypeCache = new Dictionary <ResourceTypeReference, ResourceType>(ResourceTypeReferenceComparer.Instance); }
public static IEnumerable <TypeProperty> GetCommonResourceProperties(ResourceTypeReference reference) { yield return(new TypeProperty("id", String, TypePropertyFlags.ReadOnly | TypePropertyFlags.SkipInlining)); yield return(new TypeProperty("name", String, TypePropertyFlags.Required | TypePropertyFlags.SkipInlining)); yield return(new TypeProperty("type", new StringLiteralType(reference.FullyQualifiedType), TypePropertyFlags.ReadOnly | TypePropertyFlags.SkipInlining)); yield return(new TypeProperty("apiVersion", new StringLiteralType(reference.ApiVersion), TypePropertyFlags.ReadOnly | TypePropertyFlags.SkipInlining)); }