diff --git a/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/Amazon.JSII.Runtime.IntegrationTests.csproj b/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/Amazon.JSII.Runtime.IntegrationTests.csproj index e36a80021e..086b0c8af9 100644 --- a/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/Amazon.JSII.Runtime.IntegrationTests.csproj +++ b/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/Amazon.JSII.Runtime.IntegrationTests.csproj @@ -1,7 +1,7 @@  - netcoreapp2.0 + netcoreapp2.1 false diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Deputy/Converters/FrameworkToJsiiConverterTests.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Deputy/Converters/FrameworkToJsiiConverterTests.cs index dfa74c5fa5..eab0a03419 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Deputy/Converters/FrameworkToJsiiConverterTests.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime.UnitTests/Deputy/Converters/FrameworkToJsiiConverterTests.cs @@ -450,6 +450,118 @@ public void RecursivelyConvertsArrayElements() } ); } + + [Fact(DisplayName = _Prefix + nameof(RecursivelyConvertsMapElementsWithMapOfAny))] + public void RecursivelyConvertsMapElementsWithMapOfAny() + { + var instance = new OptionalValue(new TypeReference( + collection: new CollectionTypeReference(CollectionKind.Map, + new TypeReference( + collection: new CollectionTypeReference(CollectionKind.Map, + new TypeReference(primitive: PrimitiveType.Any) + ) + ) + ) + )); + + var frameworkMap = new Dictionary> + { + { "myKey1", new Dictionary { { "mySubKey1", "myValue1" } } }, + { "myKey2", new Dictionary { { "mySubKey2", "myValue2" } } }, + }; + + // This will test the call to FrameworkToJsiiConverter.TryConvertCollectionElement() + // In the case of a of a Map of Map of Any + bool success = _converter.TryConvert(instance, _referenceMap, frameworkMap, out object actual); + + Assert.True(success); + Assert.IsType(actual); + Assert.Collection + ( + ((IEnumerable>)actual).OrderBy(kvp => kvp.Key), + kvp => + { + Assert.Equal("myKey1", kvp.Key); + Assert.IsType(kvp.Value); + Assert.Collection + ( + ((IEnumerable>)kvp.Value), + subKvp => + { + Assert.Equal("mySubKey1", subKvp.Key, ignoreLineEndingDifferences: true); + Assert.Equal("myValue1", subKvp.Value); + } + ); + }, + kvp => + { + Assert.Equal("myKey2", kvp.Key, ignoreLineEndingDifferences: true); + Assert.IsType(kvp.Value); + Assert.Collection + ( + ((IEnumerable>)kvp.Value), + subKvp => + { + Assert.Equal("mySubKey2", subKvp.Key, ignoreLineEndingDifferences: true); + Assert.Equal("myValue2", subKvp.Value); + } + ); + } + ); + } + + [Fact(DisplayName = _Prefix + nameof(RecursivelyConvertsMapElementsWithArrayOfAny))] + public void RecursivelyConvertsMapElementsWithArrayOfAny() + { + var instance = new OptionalValue(new TypeReference + ( + collection: new CollectionTypeReference(CollectionKind.Map, + new TypeReference + ( + collection: new CollectionTypeReference(CollectionKind.Array, + new TypeReference(primitive: PrimitiveType.Any) + ) + ) + ) + )); + + var frameworkArray = new Dictionary() + { + {"key", new [] { "true" }}, + {"key2", new [] { false }}, + }; + + // This will test the call to FrameworkToJsiiConverter.TryConvertCollectionElement() + // In the case of a of a Map of Array of Any + bool success = _converter.TryConvert(instance, _referenceMap, frameworkArray, out object actual); + + Assert.True(success); + Assert.IsType(actual); + Assert.Collection + ( + ((IEnumerable>)actual).OrderBy(kvp => kvp.Key), + kvp => + { + Assert.Equal("key", kvp.Key); + Assert.IsType(kvp.Value); + Assert.Collection + ( + (JArray)kvp.Value, + subValue => Assert.Equal("true", subValue) + ); + }, + kvp => + { + Assert.Equal("key2", kvp.Key, ignoreLineEndingDifferences: true); + Assert.IsType(kvp.Value); + Assert.Collection + ( + (JArray)kvp.Value, + subValue => Assert.Equal(false, subValue) + ); + } + ); + } [Fact(DisplayName = _Prefix + nameof(ConvertsNullMap))] public void ConvertsNullMap() diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/FrameworkToJsiiConverter.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/FrameworkToJsiiConverter.cs index 2f02b6ec52..5912f3f75c 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/FrameworkToJsiiConverter.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/Services/Converters/FrameworkToJsiiConverter.cs @@ -157,7 +157,7 @@ protected override bool TryConvertJson(object value, out object result) return true; } - if (value.GetType().IsAssignableFrom(typeof(JObject))) + if (value.GetType().IsAssignableFrom(typeof(JObject)) || value.GetType().IsAssignableFrom(typeof(JArray))) { result = value; return true; @@ -223,7 +223,7 @@ protected override bool TryConvertArray(IReferenceMap referenceMap, TypeReferenc JArray resultArray = new JArray(); foreach (object element in array) { - if (!TryConvert(elementType, referenceMap, element, out object convertedElement)) + if (!TryConvertCollectionElement(element, referenceMap, elementType, out object convertedElement)) { result = null; return false; @@ -264,15 +264,7 @@ protected override bool TryConvertMap(IReferenceMap referenceMap, TypeReference { object element = indexer.GetValue(value, new object[] {key}); - TypeReference childElementType = InferType(referenceMap, element); - - // We should not pass the parent element type as we are in a map - // A map could be a map etc - // If we pass the parent referenceMap then it will try to convert it as Any - // So by inferring the child element type we are always converting the correct type. - // See https://github.com/aws/aws-cdk/issues/2496 - - if (!TryConvert(childElementType, referenceMap, element, out object convertedElement)) + if (!TryConvertCollectionElement(element, referenceMap, elementType, out object convertedElement)) { result = null; return false; @@ -285,6 +277,47 @@ protected override bool TryConvertMap(IReferenceMap referenceMap, TypeReference return true; } + /// + /// Converts a collection element + /// + /// The element to convert in the collection + /// The known references map + /// The TypeReference of the element, as seen by Jsii + /// out: the converted element + /// True if the conversion was successful, false otherwise + private bool TryConvertCollectionElement(object element, IReferenceMap referenceMap, TypeReference elementType, + out object convertedElement) + { + if (element is IDictionary || element is object[]) + { + var objectType = InferType(referenceMap, element); + var nestedType = elementType.Primitive == PrimitiveType.Any ? elementType : objectType.Collection.ElementType; + switch (objectType.Collection?.Kind) + { + case CollectionKind.Map: + // We should not pass the parent element type as we are + // in a map containing another map. + // If we pass the parent elementType then it will try to convert it as Any + // So we can directly convert to another map here, and forgo the type hierarchy + // induced by elementType + // See https://github.com/aws/aws-cdk/issues/2496 + return TryConvertMap(referenceMap, nestedType, element, + out convertedElement); + case CollectionKind.Array: + // The [object] could be another array. (ie Tags) + // https://github.com/aws/aws-cdk/issues/3244 + return TryConvertArray(referenceMap, nestedType, element, + out convertedElement); + default: + return TryConvert(elementType, referenceMap, element, out convertedElement); + } + } + else + { + return TryConvert(elementType, referenceMap, element, out convertedElement); + } + } + protected override TypeReference InferType(IReferenceMap referenceMap, object value) { value = value ?? throw new ArgumentNullException(nameof(value)); @@ -328,7 +361,7 @@ TypeReference InferType(IReferenceMap referenceMap, Type type) return new TypeReference(primitive: PrimitiveType.Date); } - if (type.IsAssignableFrom(typeof(JObject))) + if (type.IsAssignableFrom(typeof(JObject)) || type.IsAssignableFrom(typeof(JArray))) { return new TypeReference(primitive: PrimitiveType.Json); } diff --git a/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts b/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts index 0b9a291e2c..9fe7e19ca7 100644 --- a/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts +++ b/packages/jsii-pacmak/lib/targets/dotnet/filegenerator.ts @@ -50,8 +50,9 @@ export class FileGenerator { const rootNode = xmlbuilder.create('Project', {encoding: 'UTF-8', headless: true}); rootNode.att("Sdk", "Microsoft.NET.Sdk"); const propertyGroup = rootNode.ele("PropertyGroup"); - propertyGroup.ele("TargetFramework", "netstandard2.0"); + propertyGroup.ele("TargetFramework", "netcoreapp2.1"); propertyGroup.ele("GeneratePackageOnBuild", "true"); + propertyGroup.ele("GenerateDocumentationFile", "true"); propertyGroup.ele("IncludeSymbols", "true"); propertyGroup.ele("IncludeSource", "true"); propertyGroup.ele("PackageVersion", this.getDecoratedVersion(assembly)); @@ -77,7 +78,7 @@ export class FileGenerator { } if (dotnetInfo!.iconUrl != null) { - propertyGroup.ele("IconUrl", dotnetInfo!.iconUrl); + propertyGroup.ele("PackageIconUrl", dotnetInfo!.iconUrl); } const itemGroup1 = rootNode.ele("ItemGroup"); diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId.csproj b/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId.csproj index 89ecd00f8c..085473c5d5 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId.csproj +++ b/packages/jsii-pacmak/test/expected.jsii-calc-base/dotnet/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId/Amazon.JSII.Tests.CalculatorPackageId.BasePackageId.csproj @@ -1,7 +1,8 @@ - netstandard2.0 + netcoreapp2.1 true + true true true 0.16.0 diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId.csproj b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId.csproj index 08dcc3d370..1e38a797c0 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId.csproj +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId.csproj @@ -1,7 +1,8 @@ - netstandard2.0 + netcoreapp2.1 true + true true true 0.16.0-devpreview diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon.JSII.Tests.CalculatorPackageId.csproj b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon.JSII.Tests.CalculatorPackageId.csproj index 937ade62f5..5ae1404dfc 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon.JSII.Tests.CalculatorPackageId.csproj +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon.JSII.Tests.CalculatorPackageId.csproj @@ -1,7 +1,8 @@ - netstandard2.0 + netcoreapp2.1 true + true true true 0.16.0