diff --git a/packages/jsii-calc-lib/lib/index.ts b/packages/jsii-calc-lib/lib/index.ts index e7d0a1a801..fc05371a8f 100644 --- a/packages/jsii-calc-lib/lib/index.ts +++ b/packages/jsii-calc-lib/lib/index.ts @@ -7,20 +7,27 @@ export abstract class Value extends base.Base { /** * The value. */ - abstract readonly value: number + public abstract readonly value: number; /** * String representation of the value. */ - toString() { + public toString() { return this.value.toString(); } } +/** + * The general contract for a concrete number. + */ +export interface IDoublable { + readonly doubleValue: number; +} + /** * Represents a concrete number. */ -export class Number extends Value { +export class Number extends Value implements IDoublable { /** * Creates a Number object. * @param value The number. @@ -41,7 +48,7 @@ export class Number extends Value { * Represents an operation on values. */ export abstract class Operation extends Value { - abstract toString(): string + public abstract toString(): string; } /** diff --git a/packages/jsii-calc-lib/test/assembly.jsii b/packages/jsii-calc-lib/test/assembly.jsii index e351e0ce08..dc6ac23805 100644 --- a/packages/jsii-calc-lib/test/assembly.jsii +++ b/packages/jsii-calc-lib/test/assembly.jsii @@ -92,6 +92,25 @@ ], "name": "EnumFromScopedModule" }, + "@scope/jsii-calc-lib.IDoublable": { + "assembly": "@scope/jsii-calc-lib", + "docs": { + "comment": "The general contract for a concrete number." + }, + "fqn": "@scope/jsii-calc-lib.IDoublable", + "kind": "interface", + "name": "IDoublable", + "properties": [ + { + "abstract": true, + "immutable": true, + "name": "doubleValue", + "type": { + "primitive": "number" + } + } + ] + }, "@scope/jsii-calc-lib.IFriendly": { "assembly": "@scope/jsii-calc-lib", "docs": { @@ -184,6 +203,11 @@ } ] }, + "interfaces": [ + { + "fqn": "@scope/jsii-calc-lib.IDoublable" + } + ], "kind": "class", "name": "Number", "properties": [ @@ -193,6 +217,9 @@ }, "immutable": true, "name": "doubleValue", + "overrides": { + "fqn": "@scope/jsii-calc-lib.IDoublable" + }, "type": { "primitive": "number" } @@ -324,5 +351,5 @@ } }, "version": "0.7.8", - "fingerprint": "16sTfW7oHGAWfPOj50gWvXsI1REjbNbpk7VUpG1JVVI=" + "fingerprint": "HzcyHys0b9gFmP4dogeIJmGE6GVtrSo/P0S54Vd/X8U=" } diff --git a/packages/jsii-calc/lib/compliance.ts b/packages/jsii-calc/lib/compliance.ts index c8ab84a415..783a5a94cf 100644 --- a/packages/jsii-calc/lib/compliance.ts +++ b/packages/jsii-calc/lib/compliance.ts @@ -1,5 +1,5 @@ // tslint:disable -import { Value, Number, IFriendly, MyFirstStruct, StructWithOnlyOptionals, EnumFromScopedModule } from '@scope/jsii-calc-lib'; +import { Value, Number, IFriendly, IDoublable, MyFirstStruct, StructWithOnlyOptionals, EnumFromScopedModule } from '@scope/jsii-calc-lib'; import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; @@ -574,7 +574,7 @@ export class AllowedMethodNames { } export interface IReturnsNumber { - obtainNumber(): Number; + obtainNumber(): IDoublable; readonly numberProp: Number; } @@ -938,4 +938,4 @@ export interface IInterfaceWithMethods { */ export interface IInterfaceThatShouldNotBeADataType extends IInterfaceWithMethods { readonly otherValue: string; -} \ No newline at end of file +} diff --git a/packages/jsii-calc/test/assembly.jsii b/packages/jsii-calc/test/assembly.jsii index 2aa5115a4b..c6ffb76b77 100644 --- a/packages/jsii-calc/test/assembly.jsii +++ b/packages/jsii-calc/test/assembly.jsii @@ -436,7 +436,7 @@ "type": { "collection": { "elementtype": { - "primitive": "number" + "fqn": "@scope/jsii-calc-lib.Number" }, "kind": "map" } @@ -486,6 +486,9 @@ }, { "primitive": "number" + }, + { + "fqn": "@scope/jsii-calc-lib.Number" } ] } @@ -507,6 +510,9 @@ }, { "fqn": "jsii-calc.Multiply" + }, + { + "fqn": "@scope/jsii-calc-lib.Number" } ] } @@ -1559,7 +1565,7 @@ "abstract": true, "name": "obtainNumber", "returns": { - "primitive": "number" + "fqn": "@scope/jsii-calc-lib.IDoublable" } } ], @@ -1570,7 +1576,7 @@ "immutable": true, "name": "numberProp", "type": { - "primitive": "number" + "fqn": "@scope/jsii-calc-lib.Number" } } ] @@ -3401,5 +3407,5 @@ } }, "version": "0.7.8", - "fingerprint": "fhzPkiQLwsWAnEdA5+YEotaWom2Av1au0q2FzpexXaQ=" + "fingerprint": "jHSXTzCSZbwYMvLKpeZB6SE8hNgYgt9/2JF1ihM41SI=" } diff --git a/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs b/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs index 9b287e9483..ff6747a7be 100644 --- a/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs +++ b/packages/jsii-dotnet-runtime-test/test/Amazon.JSII.Runtime.IntegrationTests/ComplianceTests.cs @@ -83,10 +83,10 @@ public void CollectionTypes() Assert.Equal("World", types.ArrayProperty[1]); // map - IDictionary map = new Dictionary(); - map["Foo"] = 123; + IDictionary map = new Dictionary(); + map["Foo"] = new Number(123); types.MapProperty = map; - Assert.Equal((double) 123, types.MapProperty["Foo"]); + Assert.Equal((double) 123, types.MapProperty["Foo"].Value); } [Fact(DisplayName = Prefix + nameof(DynamicTypes))] @@ -818,6 +818,43 @@ public void TestClassWithPrivateConstructorAndAutomaticProperties() Assert.Equal("Hello", obj.ReadOnlyString); } + [Fact(DisplayName = Prefix + nameof(TestReturnInterfaceFromOverride))] + public void TestReturnInterfaceFromOverride() + { + var n = 1337; + var obj = new OverrideReturnsObject(); + var arg = new NumberReturner(n); + Assert.Equal(4 * n, obj.Test(arg)); + } + + class NumberReturner : DeputyBase, IIReturnsNumber + { + public NumberReturner(double number) + { + NumberProp = new Number(number); + } + + [JsiiProperty("numberProp", "{\"fqn\":\"@scope/jsii-calc-lib.Number\"}", true)] + public Number NumberProp { get; } + + [JsiiMethod("obtainNumber", "{\"fqn\":\"@scope/jsii-calc-lib.IDoublable\"}", "[]",true)] + public IIDoublable ObtainNumber() + { + return new Doublable(this.NumberProp); + } + + class Doublable : DeputyBase, IIDoublable + { + public Doublable(Number number) + { + this.DoubleValue = number.DoubleValue; + } + + [JsiiProperty("doubleValue","{\"primitive\":\"number\"}",true)] + public Double DoubleValue { get; } + } + } + class MulTen : Multiply { public MulTen(int value) diff --git a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/CallbackExtensions.cs b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/CallbackExtensions.cs index ca1c259831..8fe9067aae 100644 --- a/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/CallbackExtensions.cs +++ b/packages/jsii-dotnet-runtime/src/Amazon.JSII.Runtime/CallbackExtensions.cs @@ -15,12 +15,12 @@ public static object InvokeCallback(this Callback callback, IReferenceMap refere { try { - object frameworkResult = callback.InvokeCallbackCore(referenceMap); + CallbackResult frameworkResult = callback.InvokeCallbackCore(referenceMap); converter.TryConvert( - new TypeReference(primitive: PrimitiveType.Any), + frameworkResult?.Type ?? new TypeReference(primitive: PrimitiveType.Any), referenceMap, - frameworkResult, + frameworkResult?.Value, out object result ); @@ -41,7 +41,7 @@ public static object InvokeCallback(this Callback callback, IReferenceMap refere } } - static object InvokeCallbackCore(this Callback callback, IReferenceMap referenceMap) + static CallbackResult InvokeCallbackCore(this Callback callback, IReferenceMap referenceMap) { if (callback.Invoke != null) { @@ -62,7 +62,7 @@ static object InvokeCallbackCore(this Callback callback, IReferenceMap reference throw new ArgumentException("Callback does not specificy a method, getter, or setter to invoke"); } - static object InvokeMethod(InvokeRequest request, IReferenceMap referenceMap) + static CallbackResult InvokeMethod(InvokeRequest request, IReferenceMap referenceMap) { request = request ?? throw new ArgumentNullException(nameof(request)); DeputyBase deputy = referenceMap.GetOrCreateNativeReference(request.ObjectReference); @@ -74,10 +74,11 @@ static object InvokeMethod(InvokeRequest request, IReferenceMap referenceMap) throw new InvalidOperationException($"Received callback for {deputy.GetType().Name}.{request.Method} getter, but this method does not exist"); } - return methodInfo.Invoke(deputy, request.Arguments); + JsiiMethodAttribute attribute = methodInfo.GetCustomAttribute(); + return new CallbackResult(attribute?.Returns, methodInfo.Invoke(deputy, request.Arguments)); } - static object InvokeGetter(GetRequest request, IReferenceMap referenceMap) + static CallbackResult InvokeGetter(GetRequest request, IReferenceMap referenceMap) { request = request ?? throw new ArgumentNullException(nameof(request)); DeputyBase deputy = referenceMap.GetOrCreateNativeReference(request.ObjectReference); @@ -88,13 +89,15 @@ static object InvokeGetter(GetRequest request, IReferenceMap referenceMap) throw new InvalidOperationException($"Received callback for {deputy.GetType().Name}.{request.Property} getter, but this property does not exist"); } + JsiiPropertyAttribute attribute = propertyInfo.GetCustomAttribute(); + MethodInfo methodInfo = propertyInfo.GetGetMethod(); if (methodInfo == null) { throw new InvalidOperationException($"Received callback for {deputy.GetType().Name}.{request.Property} getter, but this property does not have a getter"); } - return methodInfo.Invoke(deputy, new object[] { }); + return new CallbackResult(attribute?.Type, methodInfo.Invoke(deputy, new object[] { })); } static void InvokeSetter(SetRequest request, IReferenceMap referenceMap) @@ -117,4 +120,16 @@ static void InvokeSetter(SetRequest request, IReferenceMap referenceMap) methodInfo.Invoke(deputy, new object[] { request.Value }); } } + + internal class CallbackResult + { + public CallbackResult(TypeReference type, object value) + { + Type = type; + Value = value; + } + + public TypeReference Type { get; } + public object Value { get; } + } } 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 9dabadcb95..f4cdbc674e 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 @@ -251,6 +251,10 @@ protected override bool TryConvertMap(IReferenceMap referenceMap, TypeReference return false; } + if (convertedElement != null && !(convertedElement is String) && !convertedElement.GetType().IsPrimitive) + { + convertedElement = JObject.FromObject(convertedElement); + } resultObject.Add(new JProperty(key, convertedElement)); } diff --git a/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java b/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java index 43aef436d1..f2c437819b 100644 --- a/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java +++ b/packages/jsii-java-runtime-test/project/src/test/java/software/amazon/jsii/testing/ComplianceTest.java @@ -109,8 +109,8 @@ public void collectionTypes() { assertEquals("World", types.getArrayProperty().get(1)); // map - Map map = new HashMap<>(); - map.put("Foo", 123); + Map map = new HashMap<>(); + map.put("Foo", new Number(123)); types.setMapProperty(map); } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii index e351e0ce08..dc6ac23805 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/.jsii @@ -92,6 +92,25 @@ ], "name": "EnumFromScopedModule" }, + "@scope/jsii-calc-lib.IDoublable": { + "assembly": "@scope/jsii-calc-lib", + "docs": { + "comment": "The general contract for a concrete number." + }, + "fqn": "@scope/jsii-calc-lib.IDoublable", + "kind": "interface", + "name": "IDoublable", + "properties": [ + { + "abstract": true, + "immutable": true, + "name": "doubleValue", + "type": { + "primitive": "number" + } + } + ] + }, "@scope/jsii-calc-lib.IFriendly": { "assembly": "@scope/jsii-calc-lib", "docs": { @@ -184,6 +203,11 @@ } ] }, + "interfaces": [ + { + "fqn": "@scope/jsii-calc-lib.IDoublable" + } + ], "kind": "class", "name": "Number", "properties": [ @@ -193,6 +217,9 @@ }, "immutable": true, "name": "doubleValue", + "overrides": { + "fqn": "@scope/jsii-calc-lib.IDoublable" + }, "type": { "primitive": "number" } @@ -324,5 +351,5 @@ } }, "version": "0.7.8", - "fingerprint": "16sTfW7oHGAWfPOj50gWvXsI1REjbNbpk7VUpG1JVVI=" + "fingerprint": "HzcyHys0b9gFmP4dogeIJmGE6GVtrSo/P0S54Vd/X8U=" } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/IDoublableProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/IDoublableProxy.cs new file mode 100644 index 0000000000..2d5c772875 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/IDoublableProxy.cs @@ -0,0 +1,19 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace.LibNamespace +{ + /// The general contract for a concrete number. + [JsiiTypeProxy(typeof(IIDoublable), "@scope/jsii-calc-lib.IDoublable")] + internal sealed class IDoublableProxy : DeputyBase, IIDoublable + { + private IDoublableProxy(ByRefValue reference): base(reference) + { + } + + [JsiiProperty("doubleValue", "{\"primitive\":\"number\"}")] + public double DoubleValue + { + get => GetInstanceProperty(); + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/IIDoublable.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/IIDoublable.cs new file mode 100644 index 0000000000..d7260984a8 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/IIDoublable.cs @@ -0,0 +1,15 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace.LibNamespace +{ + /// The general contract for a concrete number. + [JsiiInterface(typeof(IIDoublable), "@scope/jsii-calc-lib.IDoublable")] + public interface IIDoublable + { + [JsiiProperty("doubleValue", "{\"primitive\":\"number\"}")] + double DoubleValue + { + get; + } + } +} \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/Number.cs b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/Number.cs index f86323d0cc..e19ce0ad51 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/Number.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/dotnet/Amazon.JSII.Tests.CalculatorPackageId.LibPackageId/Amazon/JSII/Tests/CalculatorNamespace/LibNamespace/Number.cs @@ -4,7 +4,7 @@ namespace Amazon.JSII.Tests.CalculatorNamespace.LibNamespace { /// Represents a concrete number. [JsiiClass(typeof(Number), "@scope/jsii-calc-lib.Number", "[{\"name\":\"value\",\"type\":{\"primitive\":\"number\"}}]")] - public class Number : Value_ + public class Number : Value_, IIDoublable { public Number(double value): base(new DeputyProps(new object[]{value})) { diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/$Module.java b/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/$Module.java index 5b1453d5d0..52c6de750a 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/$Module.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/$Module.java @@ -19,6 +19,7 @@ public List> getDependencies() { protected Class resolveClass(final String fqn) throws ClassNotFoundException { switch (fqn) { case "@scope/jsii-calc-lib.EnumFromScopedModule": return software.amazon.jsii.tests.calculator.lib.EnumFromScopedModule.class; + case "@scope/jsii-calc-lib.IDoublable": return software.amazon.jsii.tests.calculator.lib.IDoublable.class; case "@scope/jsii-calc-lib.IFriendly": return software.amazon.jsii.tests.calculator.lib.IFriendly.class; case "@scope/jsii-calc-lib.MyFirstStruct": return software.amazon.jsii.tests.calculator.lib.MyFirstStruct.class; case "@scope/jsii-calc-lib.Number": return software.amazon.jsii.tests.calculator.lib.Number.class; diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/IDoublable.java b/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/IDoublable.java new file mode 100644 index 0000000000..a7cf2325fe --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/IDoublable.java @@ -0,0 +1,23 @@ +package software.amazon.jsii.tests.calculator.lib; + +/** + * The general contract for a concrete number. + */ +@javax.annotation.Generated(value = "jsii-pacmak") +public interface IDoublable extends software.amazon.jsii.JsiiSerializable { + java.lang.Number getDoubleValue(); + + /** + * A proxy class which represents a concrete javascript instance of this type. + */ + final static class Jsii$Proxy extends software.amazon.jsii.JsiiObject implements software.amazon.jsii.tests.calculator.lib.IDoublable { + protected Jsii$Proxy(final software.amazon.jsii.JsiiObject.InitializationMode mode) { + super(mode); + } + + @Override + public java.lang.Number getDoubleValue() { + return this.jsiiGet("doubleValue", java.lang.Number.class); + } + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/Number.java b/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/Number.java index a14b6fe024..0f023695d2 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/Number.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/java/src/main/java/software/amazon/jsii/tests/calculator/lib/Number.java @@ -5,7 +5,7 @@ */ @javax.annotation.Generated(value = "jsii-pacmak") @software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.lib.$Module.class, fqn = "@scope/jsii-calc-lib.Number") -public class Number extends software.amazon.jsii.tests.calculator.lib.Value { +public class Number extends software.amazon.jsii.tests.calculator.lib.Value implements software.amazon.jsii.tests.calculator.lib.IDoublable { protected Number(final software.amazon.jsii.JsiiObject.InitializationMode mode) { super(mode); } @@ -21,6 +21,7 @@ public Number(final java.lang.Number value) { /** * The number multiplied by 2. */ + @Override public java.lang.Number getDoubleValue() { return this.jsiiGet("doubleValue", java.lang.Number.class); } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc-lib/sphinx/_scope_jsii-calc-lib.rst b/packages/jsii-pacmak/test/expected.jsii-calc-lib/sphinx/_scope_jsii-calc-lib.rst index 9cac7a500a..0121d0e144 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc-lib/sphinx/_scope_jsii-calc-lib.rst +++ b/packages/jsii-pacmak/test/expected.jsii-calc-lib/sphinx/_scope_jsii-calc-lib.rst @@ -158,6 +158,43 @@ EnumFromScopedModule (enum) .. py:data:: Value2 +IDoublable (interface) +^^^^^^^^^^^^^^^^^^^^^^ + +.. py:class:: IDoublable + + **Language-specific names:** + + .. tabs:: + + .. code-tab:: c# + + using Amazon.JSII.Tests.CalculatorNamespace.LibNamespace; + + .. code-tab:: java + + import software.amazon.jsii.tests.calculator.lib.IDoublable; + + .. code-tab:: javascript + + // IDoublable is an interface + + .. code-tab:: typescript + + import { IDoublable } from '@scope/jsii-calc-lib'; + + + + The general contract for a concrete number. + + + + + .. py:attribute:: doubleValue + + :type: number *(readonly)* *(abstract)* + + IFriendly (interface) ^^^^^^^^^^^^^^^^^^^^^ @@ -283,11 +320,14 @@ Number :extends: :py:class:`~@scope/jsii-calc-lib.Value`\ + :implements: :py:class:`~@scope/jsii-calc-lib.IDoublable`\ :param value: The number. :type value: number .. py:attribute:: doubleValue + *Implements* :py:meth:`@scope/jsii-calc-lib.IDoublable.doubleValue` + The number multiplied by 2. diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii index 2aa5115a4b..c6ffb76b77 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/.jsii @@ -436,7 +436,7 @@ "type": { "collection": { "elementtype": { - "primitive": "number" + "fqn": "@scope/jsii-calc-lib.Number" }, "kind": "map" } @@ -486,6 +486,9 @@ }, { "primitive": "number" + }, + { + "fqn": "@scope/jsii-calc-lib.Number" } ] } @@ -507,6 +510,9 @@ }, { "fqn": "jsii-calc.Multiply" + }, + { + "fqn": "@scope/jsii-calc-lib.Number" } ] } @@ -1559,7 +1565,7 @@ "abstract": true, "name": "obtainNumber", "returns": { - "primitive": "number" + "fqn": "@scope/jsii-calc-lib.IDoublable" } } ], @@ -1570,7 +1576,7 @@ "immutable": true, "name": "numberProp", "type": { - "primitive": "number" + "fqn": "@scope/jsii-calc-lib.Number" } } ] @@ -3401,5 +3407,5 @@ } }, "version": "0.7.8", - "fingerprint": "fhzPkiQLwsWAnEdA5+YEotaWom2Av1au0q2FzpexXaQ=" + "fingerprint": "jHSXTzCSZbwYMvLKpeZB6SE8hNgYgt9/2JF1ihM41SI=" } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs index b4a4896b31..489e96e84c 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/AllTypes.cs @@ -1,5 +1,6 @@ using Amazon.JSII.Runtime.Deputy; using Amazon.JSII.Tests.CalculatorNamespace.composition; +using Amazon.JSII.Tests.CalculatorNamespace.LibNamespace; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; @@ -80,10 +81,10 @@ public virtual JObject JsonProperty set => SetInstanceProperty(value); } - [JsiiProperty("mapProperty", "{\"collection\":{\"kind\":\"map\",\"elementtype\":{\"primitive\":\"number\"}}}")] - public virtual IDictionary MapProperty + [JsiiProperty("mapProperty", "{\"collection\":{\"kind\":\"map\",\"elementtype\":{\"fqn\":\"@scope/jsii-calc-lib.Number\"}}}")] + public virtual IDictionary MapProperty { - get => GetInstanceProperty>(); + get => GetInstanceProperty>(); set => SetInstanceProperty(value); } @@ -108,14 +109,14 @@ public virtual object[] UnionArrayProperty set => SetInstanceProperty(value); } - [JsiiProperty("unionMapProperty", "{\"collection\":{\"kind\":\"map\",\"elementtype\":{\"union\":{\"types\":[{\"primitive\":\"string\"},{\"primitive\":\"number\"}]}}}}")] + [JsiiProperty("unionMapProperty", "{\"collection\":{\"kind\":\"map\",\"elementtype\":{\"union\":{\"types\":[{\"primitive\":\"string\"},{\"primitive\":\"number\"},{\"fqn\":\"@scope/jsii-calc-lib.Number\"}]}}}}")] public virtual IDictionary UnionMapProperty { get => GetInstanceProperty>(); set => SetInstanceProperty(value); } - [JsiiProperty("unionProperty", "{\"union\":{\"types\":[{\"primitive\":\"string\"},{\"primitive\":\"number\"},{\"fqn\":\"jsii-calc.Multiply\"}]}}")] + [JsiiProperty("unionProperty", "{\"union\":{\"types\":[{\"primitive\":\"string\"},{\"primitive\":\"number\"},{\"fqn\":\"jsii-calc.Multiply\"},{\"fqn\":\"@scope/jsii-calc-lib.Number\"}]}}")] public virtual object UnionProperty { get => GetInstanceProperty(); diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IIReturnsNumber.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IIReturnsNumber.cs index 4c3ab80cc1..e62565eb16 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IIReturnsNumber.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IIReturnsNumber.cs @@ -1,17 +1,18 @@ using Amazon.JSII.Runtime.Deputy; +using Amazon.JSII.Tests.CalculatorNamespace.LibNamespace; namespace Amazon.JSII.Tests.CalculatorNamespace { [JsiiInterface(typeof(IIReturnsNumber), "jsii-calc.IReturnsNumber")] public interface IIReturnsNumber { - [JsiiProperty("numberProp", "{\"primitive\":\"number\"}")] - double NumberProp + [JsiiProperty("numberProp", "{\"fqn\":\"@scope/jsii-calc-lib.Number\"}")] + Number NumberProp { get; } - [JsiiMethod("obtainNumber", "{\"primitive\":\"number\"}", "[]")] - double ObtainNumber(); + [JsiiMethod("obtainNumber", "{\"fqn\":\"@scope/jsii-calc-lib.IDoublable\"}", "[]")] + IIDoublable ObtainNumber(); } } \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IReturnsNumberProxy.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IReturnsNumberProxy.cs index e77ef70356..bc689a1bc8 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IReturnsNumberProxy.cs +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/IReturnsNumberProxy.cs @@ -1,4 +1,5 @@ using Amazon.JSII.Runtime.Deputy; +using Amazon.JSII.Tests.CalculatorNamespace.LibNamespace; namespace Amazon.JSII.Tests.CalculatorNamespace { @@ -9,16 +10,16 @@ private IReturnsNumberProxy(ByRefValue reference): base(reference) { } - [JsiiProperty("numberProp", "{\"primitive\":\"number\"}")] - public double NumberProp + [JsiiProperty("numberProp", "{\"fqn\":\"@scope/jsii-calc-lib.Number\"}")] + public Number NumberProp { - get => GetInstanceProperty(); + get => GetInstanceProperty(); } - [JsiiMethod("obtainNumber", "{\"primitive\":\"number\"}", "[]")] - public double ObtainNumber() + [JsiiMethod("obtainNumber", "{\"fqn\":\"@scope/jsii-calc-lib.IDoublable\"}", "[]")] + public IIDoublable ObtainNumber() { - return InvokeInstanceMethod(new object[]{}); + return InvokeInstanceMethod(new object[]{}); } } } \ No newline at end of file diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/AllTypes.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/AllTypes.java index b57eb209d9..c6e710a699 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/AllTypes.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/AllTypes.java @@ -79,11 +79,11 @@ public void setJsonProperty(final com.fasterxml.jackson.databind.node.ObjectNode this.jsiiSet("jsonProperty", java.util.Objects.requireNonNull(value, "jsonProperty is required")); } - public java.util.Map getMapProperty() { + public java.util.Map getMapProperty() { return this.jsiiGet("mapProperty", java.util.Map.class); } - public void setMapProperty(final java.util.Map value) { + public void setMapProperty(final java.util.Map value) { this.jsiiSet("mapProperty", java.util.Objects.requireNonNull(value, "mapProperty is required")); } @@ -135,6 +135,10 @@ public void setUnionProperty(final software.amazon.jsii.tests.calculator.Multipl this.jsiiSet("unionProperty", java.util.Objects.requireNonNull(value, "unionProperty is required")); } + public void setUnionProperty(final software.amazon.jsii.tests.calculator.lib.Number value) { + this.jsiiSet("unionProperty", java.util.Objects.requireNonNull(value, "unionProperty is required")); + } + public java.util.List getUnknownArrayProperty() { return this.jsiiGet("unknownArrayProperty", java.util.List.class); } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/IReturnsNumber.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/IReturnsNumber.java index 352f2ef930..1b81b6f07b 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/IReturnsNumber.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/IReturnsNumber.java @@ -2,8 +2,8 @@ @javax.annotation.Generated(value = "jsii-pacmak") public interface IReturnsNumber extends software.amazon.jsii.JsiiSerializable { - java.lang.Number getNumberProp(); - java.lang.Number obtainNumber(); + software.amazon.jsii.tests.calculator.lib.Number getNumberProp(); + software.amazon.jsii.tests.calculator.lib.IDoublable obtainNumber(); /** * A proxy class which represents a concrete javascript instance of this type. @@ -14,13 +14,13 @@ final static class Jsii$Proxy extends software.amazon.jsii.JsiiObject implements } @Override - public java.lang.Number getNumberProp() { - return this.jsiiGet("numberProp", java.lang.Number.class); + public software.amazon.jsii.tests.calculator.lib.Number getNumberProp() { + return this.jsiiGet("numberProp", software.amazon.jsii.tests.calculator.lib.Number.class); } @Override - public java.lang.Number obtainNumber() { - return this.jsiiCall("obtainNumber", java.lang.Number.class); + public software.amazon.jsii.tests.calculator.lib.IDoublable obtainNumber() { + return this.jsiiCall("obtainNumber", software.amazon.jsii.tests.calculator.lib.IDoublable.class); } } } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst b/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst index cbc903a8c6..f7aa575961 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst +++ b/packages/jsii-pacmak/test/expected.jsii-calc/sphinx/jsii-calc.rst @@ -434,7 +434,7 @@ AllTypes .. py:attribute:: mapProperty - :type: string => number + :type: string => :py:class:`@scope/jsii-calc-lib.Number`\ .. py:attribute:: numberProperty @@ -454,12 +454,12 @@ AllTypes .. py:attribute:: unionMapProperty - :type: string => (string or number) + :type: string => (string or number or :py:class:`@scope/jsii-calc-lib.Number`\ ) .. py:attribute:: unionProperty - :type: string or number or :py:class:`~jsii-calc.Multiply`\ + :type: string or number or :py:class:`~jsii-calc.Multiply`\ or :py:class:`@scope/jsii-calc-lib.Number`\ .. py:attribute:: unknownArrayProperty @@ -1761,12 +1761,12 @@ IReturnsNumber (interface) .. py:attribute:: numberProp - :type: number *(readonly)* *(abstract)* + :type: :py:class:`@scope/jsii-calc-lib.Number`\ *(readonly)* *(abstract)* - .. py:method:: obtainNumber() -> number + .. py:method:: obtainNumber() -> @scope/jsii-calc-lib.IDoublable - :rtype: number + :rtype: :py:class:`@scope/jsii-calc-lib.IDoublable`\ :abstract: Yes diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index d46dc342ac..4d2ae4ea06 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -11,7 +11,6 @@ import literate = require('./literate'); import { ProjectInfo } from './project-info'; import utils = require('./utils'); import { Validator } from './validator'; -import { NamedTypeReference, isInterfaceType } from 'jsii-spec'; // tslint:disable:no-var-requires Modules without TypeScript definitions const sortJson = require('sort-json'); @@ -30,9 +29,11 @@ export class Assembler implements Emitter { /** * @param projectInfo information about the package being assembled * @param program the TypeScript program to be assembled from + * @param stdlib the directory where the TypeScript stdlib is rooted */ public constructor(public readonly projectInfo: ProjectInfo, - public readonly program: ts.Program) {} + public readonly program: ts.Program, + public readonly stdlib: string) {} private get _typeChecker(): ts.TypeChecker { return this.program.getTypeChecker(); @@ -152,7 +153,7 @@ export class Assembler implements Emitter { * that case anyway. */ // tslint:disable-next-line:max-line-length - private _deferUntilTypesAvailable(fqn: string, baseTypes: NamedTypeReference[], referencingNode: ts.Node, cb: (...xs: spec.Type[]) => void) { + private _deferUntilTypesAvailable(fqn: string, baseTypes: spec.NamedTypeReference[], referencingNode: ts.Node, cb: (...xs: spec.Type[]) => void) { // We can do this one eagerly if (baseTypes.length === 0) { cb(); @@ -581,7 +582,7 @@ export class Assembler implements Emitter { jsiiType.datatype = true; } for (const base of bases) { - if (isInterfaceType(base) && !base.datatype) { + if (spec.isInterfaceType(base) && !base.datatype) { jsiiType.datatype = undefined; } } @@ -731,7 +732,7 @@ export class Assembler implements Emitter { type = this._typeChecker.getApparentType(type); } - const primitiveType = _tryMakePrimitiveType(); + const primitiveType = _tryMakePrimitiveType.call(this); if (primitiveType) { return primitiveType; } if (type.isUnion() && !_isEnumLike(type)) { @@ -809,7 +810,7 @@ export class Assembler implements Emitter { }; } - function _tryMakePrimitiveType(): spec.PrimitiveTypeReference | undefined { + function _tryMakePrimitiveType(this: Assembler): spec.PrimitiveTypeReference | undefined { if (!type.symbol) { // tslint:disable-next-line:no-bitwise if (type.flags & ts.TypeFlags.Object) { @@ -819,7 +820,7 @@ export class Assembler implements Emitter { if (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { return { primitive: spec.PrimitiveType.Any, optional: true }; } - } else { + } else if (type.symbol.valueDeclaration && isUnder(type.symbol.valueDeclaration.getSourceFile().fileName, this.stdlib)) { switch (type.symbol.name) { case 'Boolean': return { primitive: spec.PrimitiveType.Boolean }; @@ -833,6 +834,11 @@ export class Assembler implements Emitter { } // Not a primitive type! return undefined; + + function isUnder(file: string, dir: string): boolean { + const relative = path.relative(dir, file); + return !relative.startsWith(path.sep) && !relative.startsWith('..'); + } } async function _unionType(this: Assembler): Promise { diff --git a/packages/jsii/lib/compiler.ts b/packages/jsii/lib/compiler.ts index 7fc7528745..1c8e4b780c 100644 --- a/packages/jsii/lib/compiler.ts +++ b/packages/jsii/lib/compiler.ts @@ -67,13 +67,16 @@ export class Compiler implements Emitter { private async _buildOnce(files: string[]): Promise { await this._writeTypeScriptConfig(); const host = ts.createCompilerHost(COMPILER_OPTIONS); + if (!host.getDefaultLibLocation) { + throw new Error('No default library location was found on the TypeScript compiler host!'); + } host.getCurrentDirectory = () => this.options.projectInfo.projectRoot; const prog = ts.createProgram( files.concat(_pathOfLibraries(host)), COMPILER_OPTIONS, host ); - return await this._consumeProgram(prog); + return await this._consumeProgram(prog, host.getDefaultLibLocation()); } private async _startWatch(): Promise { @@ -84,9 +87,12 @@ export class Compiler implements Emitter { { ...COMPILER_OPTIONS, noEmitOnError: false }, { ...ts.sys, getCurrentDirectory() { return projectRoot; } } ); + if (!host.getDefaultLibLocation) { + throw new Error('No default library location was found on the TypeScript compiler host!'); + } const orig = host.afterProgramCreate; host.afterProgramCreate = async builderProgram => { - await this._consumeProgram(builderProgram.getProgram()); + await this._consumeProgram(builderProgram.getProgram(), host.getDefaultLibLocation!()); if (orig) { orig.call(host, builderProgram); } }; ts.createWatchProgram(host); @@ -94,13 +100,13 @@ export class Compiler implements Emitter { }); } - private async _consumeProgram(program: ts.Program): Promise { + private async _consumeProgram(program: ts.Program, stdlib: string): Promise { const emit = program.emit(); if (emit.emitSkipped) { LOG.error('Compilation errors prevented the JSII assembly from being created'); return emit; } - const assembler = new Assembler(this.options.projectInfo, program); + const assembler = new Assembler(this.options.projectInfo, program, stdlib); const assmEmit = await assembler.emit(); if (assmEmit.emitSkipped) { LOG.error('Type model errors prevented the JSII assembly from being created');