예제 #1
0
        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}");
            });
        }
예제 #2
0
        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)));
        }
예제 #3
0
        [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");
        }
예제 #4
0
        // 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));
        }
예제 #5
0
        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));
        });
예제 #6
0
 public ResourceType(ResourceTypeReference typeReference, ResourceScope validParentScopes, ITypeReference body)
     : base(typeReference.FormatName())
 {
     TypeReference     = typeReference;
     ValidParentScopes = validParentScopes;
     Body = body;
 }
예제 #7
0
        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));
        }
예제 #8
0
 public ResourceType(ResourceTypeReference typeReference, ITypeReference body, TypeSymbolValidationFlags validationFlags)
     : base(typeReference.FormatName())
 {
     TypeReference   = typeReference;
     Body            = body;
     ValidationFlags = validationFlags;
 }
예제 #9
0
        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));
        }
예제 #10
0
        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));
        }
예제 #11
0
        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));
        });
예제 #12
0
        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);
        }
예제 #14
0
        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
}");
            });
        }
예제 #15
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);
        }
예제 #16
0
        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);
        }
예제 #17
0
        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();
        }
예제 #18
0
        public ResourceType LoadType(ResourceTypeReference reference)
        {
            var typeLocation = availableTypes[reference];

            var serializedResourceType = typeLoader.LoadResourceType(typeLocation);

            return(resourceTypeFactory.GetResourceType(serializedResourceType));
        }
예제 #19
0
        [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();
        }
예제 #20
0
 public ResourceType(NamespaceType declaringNamespace, ResourceTypeReference typeReference, ResourceScope validParentScopes, ITypeReference body)
     : base(typeReference.FormatName())
 {
     DeclaringNamespace = declaringNamespace;
     TypeReference      = typeReference;
     ValidParentScopes  = validParentScopes;
     Body = body;
 }
예제 #21
0
 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),
 };
예제 #22
0
        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));
        }
예제 #23
0
 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);
 }
예제 #24
0
        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)));
        }
예제 #25
0
 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;
 }
예제 #26
0
        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)));
        }
예제 #27
0
        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));
        }
예제 #28
0
        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"));
        }
예제 #29
0
 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);
 }
예제 #30
0
        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));
        }