diff --git a/packages/jsii-calc/lib/erasures.ts b/packages/jsii-calc/lib/erasures.ts new file mode 100644 index 0000000000..dd6459d1ed --- /dev/null +++ b/packages/jsii-calc/lib/erasures.ts @@ -0,0 +1,25 @@ +// +// Un-exported base classes are erased +// https://github.com/awslabs/jsii/issues/417 +// +class JSII417PrivateRoot { + public readonly hasRoot = true; +} +export class JSII417PublicBaseOfBase extends JSII417PrivateRoot { + public static makeInstance(): JSII417PublicBaseOfBase { + return new JSII417PrivateBase("TEST"); + } + public foo() { return; } +} +class JSII417PrivateBase extends JSII417PublicBaseOfBase { + constructor(protected readonly property: string) { + super(); + } + public bar() { return; } +} +export class JSII417Derived extends JSII417PrivateBase { + public bar() { + return super.bar(); + } + public baz() { return; } +} diff --git a/packages/jsii-calc/lib/index.ts b/packages/jsii-calc/lib/index.ts index def34613d1..ff61744495 100644 --- a/packages/jsii-calc/lib/index.ts +++ b/packages/jsii-calc/lib/index.ts @@ -1,3 +1,4 @@ export * from './calculator'; export * from './compliance'; export * from './documented'; +export * from './erasures'; diff --git a/packages/jsii-calc/test/assembly.jsii b/packages/jsii-calc/test/assembly.jsii index bca6e36ff5..29460bee26 100644 --- a/packages/jsii-calc/test/assembly.jsii +++ b/packages/jsii-calc/test/assembly.jsii @@ -2558,6 +2558,74 @@ } ] }, + "jsii-calc.JSII417Derived": { + "assembly": "jsii-calc", + "base": { + "fqn": "jsii-calc.JSII417PublicBaseOfBase" + }, + "fqn": "jsii-calc.JSII417Derived", + "initializer": { + "initializer": true, + "parameters": [ + { + "name": "property", + "type": { + "primitive": "string" + } + } + ] + }, + "kind": "class", + "methods": [ + { + "name": "bar" + }, + { + "name": "baz" + } + ], + "name": "JSII417Derived", + "properties": [ + { + "immutable": true, + "name": "property", + "protected": true, + "type": { + "primitive": "string" + } + } + ] + }, + "jsii-calc.JSII417PublicBaseOfBase": { + "assembly": "jsii-calc", + "fqn": "jsii-calc.JSII417PublicBaseOfBase", + "initializer": { + "initializer": true + }, + "kind": "class", + "methods": [ + { + "name": "makeInstance", + "returns": { + "fqn": "jsii-calc.JSII417PublicBaseOfBase" + }, + "static": true + }, + { + "name": "foo" + } + ], + "name": "JSII417PublicBaseOfBase", + "properties": [ + { + "immutable": true, + "name": "hasRoot", + "type": { + "primitive": "boolean" + } + } + ] + }, "jsii-calc.JSObjectLiteralForInterface": { "assembly": "jsii-calc", "fqn": "jsii-calc.JSObjectLiteralForInterface", @@ -4732,5 +4800,5 @@ } }, "version": "0.8.2", - "fingerprint": "RIbNFrgvpaT1nTpWaVDxO0fWs/kZcVmMscsDGU/GXwE=" + "fingerprint": "5kMI3UzT9N2sovIndhAmSefEqtrUStnpb0hmWwfLjOs=" } diff --git a/packages/jsii-kernel/test/test.kernel.ts b/packages/jsii-kernel/test/test.kernel.ts index 8bd6b59c5b..74e5298eb8 100644 --- a/packages/jsii-kernel/test/test.kernel.ts +++ b/packages/jsii-kernel/test/test.kernel.ts @@ -1126,6 +1126,11 @@ defineTest('struct: non-empty object deserializes properly', async (test, sandbo test.equal('foo', field.value); }); +defineTest('erased base: can receive an instance of private type', async (test, sandbox) => { + const objref = sandbox.sinvoke({ fqn: 'jsii-calc.JSII417PublicBaseOfBase', method: 'makeInstance' }); + test.deepEqual(objref.result, { [api.TOKEN_REF]: 'jsii-calc.JSII417PublicBaseOfBase@10000' }); +}); + // ================================================================================================= const testNames: { [name: string]: boolean } = { }; 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 bca6e36ff5..29460bee26 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 @@ -2558,6 +2558,74 @@ } ] }, + "jsii-calc.JSII417Derived": { + "assembly": "jsii-calc", + "base": { + "fqn": "jsii-calc.JSII417PublicBaseOfBase" + }, + "fqn": "jsii-calc.JSII417Derived", + "initializer": { + "initializer": true, + "parameters": [ + { + "name": "property", + "type": { + "primitive": "string" + } + } + ] + }, + "kind": "class", + "methods": [ + { + "name": "bar" + }, + { + "name": "baz" + } + ], + "name": "JSII417Derived", + "properties": [ + { + "immutable": true, + "name": "property", + "protected": true, + "type": { + "primitive": "string" + } + } + ] + }, + "jsii-calc.JSII417PublicBaseOfBase": { + "assembly": "jsii-calc", + "fqn": "jsii-calc.JSII417PublicBaseOfBase", + "initializer": { + "initializer": true + }, + "kind": "class", + "methods": [ + { + "name": "makeInstance", + "returns": { + "fqn": "jsii-calc.JSII417PublicBaseOfBase" + }, + "static": true + }, + { + "name": "foo" + } + ], + "name": "JSII417PublicBaseOfBase", + "properties": [ + { + "immutable": true, + "name": "hasRoot", + "type": { + "primitive": "boolean" + } + } + ] + }, "jsii-calc.JSObjectLiteralForInterface": { "assembly": "jsii-calc", "fqn": "jsii-calc.JSObjectLiteralForInterface", @@ -4732,5 +4800,5 @@ } }, "version": "0.8.2", - "fingerprint": "RIbNFrgvpaT1nTpWaVDxO0fWs/kZcVmMscsDGU/GXwE=" + "fingerprint": "5kMI3UzT9N2sovIndhAmSefEqtrUStnpb0hmWwfLjOs=" } diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JSII417Derived.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JSII417Derived.cs new file mode 100644 index 0000000000..f17487efe6 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JSII417Derived.cs @@ -0,0 +1,38 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + [JsiiClass(typeof(JSII417Derived), "jsii-calc.JSII417Derived", "[{\"name\":\"property\",\"type\":{\"primitive\":\"string\"}}]")] + public class JSII417Derived : JSII417PublicBaseOfBase + { + public JSII417Derived(string property): base(new DeputyProps(new object[]{property})) + { + } + + protected JSII417Derived(ByRefValue reference): base(reference) + { + } + + protected JSII417Derived(DeputyProps props): base(props) + { + } + + [JsiiProperty("property", "{\"primitive\":\"string\"}")] + protected virtual string Property + { + get => GetInstanceProperty(); + } + + [JsiiMethod("bar", null, "[]")] + public virtual void Bar() + { + InvokeInstanceVoidMethod(new object[]{}); + } + + [JsiiMethod("baz", null, "[]")] + public virtual void Baz() + { + InvokeInstanceVoidMethod(new object[]{}); + } + } +} \ 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/JSII417PublicBaseOfBase.cs b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JSII417PublicBaseOfBase.cs new file mode 100644 index 0000000000..258b186702 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/JSII417PublicBaseOfBase.cs @@ -0,0 +1,38 @@ +using Amazon.JSII.Runtime.Deputy; + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + [JsiiClass(typeof(JSII417PublicBaseOfBase), "jsii-calc.JSII417PublicBaseOfBase", "[]")] + public class JSII417PublicBaseOfBase : DeputyBase + { + public JSII417PublicBaseOfBase(): base(new DeputyProps(new object[]{})) + { + } + + protected JSII417PublicBaseOfBase(ByRefValue reference): base(reference) + { + } + + protected JSII417PublicBaseOfBase(DeputyProps props): base(props) + { + } + + [JsiiProperty("hasRoot", "{\"primitive\":\"boolean\"}")] + public virtual bool HasRoot + { + get => GetInstanceProperty(); + } + + [JsiiMethod("makeInstance", "{\"fqn\":\"jsii-calc.JSII417PublicBaseOfBase\"}", "[]")] + public static JSII417PublicBaseOfBase MakeInstance() + { + return InvokeStaticMethod(typeof(JSII417PublicBaseOfBase), new object[]{}); + } + + [JsiiMethod("foo", null, "[]")] + public virtual void Foo() + { + InvokeInstanceVoidMethod(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/$Module.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java index e74511530b..93243b9b76 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/$Module.java @@ -80,6 +80,8 @@ protected Class resolveClass(final String fqn) throws ClassNotFoundException case "jsii-calc.InterfaceInNamespaceIncludesClasses.Foo": return software.amazon.jsii.tests.calculator.InterfaceInNamespaceIncludesClasses.Foo.class; case "jsii-calc.InterfaceInNamespaceIncludesClasses.Hello": return software.amazon.jsii.tests.calculator.InterfaceInNamespaceIncludesClasses.Hello.class; case "jsii-calc.InterfaceInNamespaceOnlyInterface.Hello": return software.amazon.jsii.tests.calculator.InterfaceInNamespaceOnlyInterface.Hello.class; + case "jsii-calc.JSII417Derived": return software.amazon.jsii.tests.calculator.JSII417Derived.class; + case "jsii-calc.JSII417PublicBaseOfBase": return software.amazon.jsii.tests.calculator.JSII417PublicBaseOfBase.class; case "jsii-calc.JSObjectLiteralForInterface": return software.amazon.jsii.tests.calculator.JSObjectLiteralForInterface.class; case "jsii-calc.JSObjectLiteralToNative": return software.amazon.jsii.tests.calculator.JSObjectLiteralToNative.class; case "jsii-calc.JSObjectLiteralToNativeClass": return software.amazon.jsii.tests.calculator.JSObjectLiteralToNativeClass.class; diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/JSII417Derived.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/JSII417Derived.java new file mode 100644 index 0000000000..e187620d45 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/JSII417Derived.java @@ -0,0 +1,25 @@ +package software.amazon.jsii.tests.calculator; + +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.JSII417Derived") +public class JSII417Derived extends software.amazon.jsii.tests.calculator.JSII417PublicBaseOfBase { + protected JSII417Derived(final software.amazon.jsii.JsiiObject.InitializationMode mode) { + super(mode); + } + public JSII417Derived(final java.lang.String property) { + super(software.amazon.jsii.JsiiObject.InitializationMode.Jsii); + software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this, java.util.stream.Stream.of(java.util.Objects.requireNonNull(property, "property is required")).toArray()); + } + + public void bar() { + this.jsiiCall("bar", Void.class); + } + + public void baz() { + this.jsiiCall("baz", Void.class); + } + + protected java.lang.String getProperty() { + return this.jsiiGet("property", java.lang.String.class); + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/JSII417PublicBaseOfBase.java b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/JSII417PublicBaseOfBase.java new file mode 100644 index 0000000000..1cf5446ee8 --- /dev/null +++ b/packages/jsii-pacmak/test/expected.jsii-calc/java/src/main/java/software/amazon/jsii/tests/calculator/JSII417PublicBaseOfBase.java @@ -0,0 +1,25 @@ +package software.amazon.jsii.tests.calculator; + +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.JSII417PublicBaseOfBase") +public class JSII417PublicBaseOfBase extends software.amazon.jsii.JsiiObject { + protected JSII417PublicBaseOfBase(final software.amazon.jsii.JsiiObject.InitializationMode mode) { + super(mode); + } + public JSII417PublicBaseOfBase() { + super(software.amazon.jsii.JsiiObject.InitializationMode.Jsii); + software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this); + } + + public static software.amazon.jsii.tests.calculator.JSII417PublicBaseOfBase makeInstance() { + return software.amazon.jsii.JsiiObject.jsiiStaticCall(software.amazon.jsii.tests.calculator.JSII417PublicBaseOfBase.class, "makeInstance", software.amazon.jsii.tests.calculator.JSII417PublicBaseOfBase.class); + } + + public void foo() { + this.jsiiCall("foo", Void.class); + } + + public java.lang.Boolean getHasRoot() { + return this.jsiiGet("hasRoot", java.lang.Boolean.class); + } +} diff --git a/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py b/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py index 3799aeeb42..a3a5377f51 100644 --- a/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py +++ b/packages/jsii-pacmak/test/expected.jsii-calc/python/src/jsii_calc/__init__.py @@ -1257,6 +1257,43 @@ class Hello(jsii.compat.TypedDict): foo: jsii.Number +class JSII417PublicBaseOfBase(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.JSII417PublicBaseOfBase"): + def __init__(self) -> None: + jsii.create(JSII417PublicBaseOfBase, self, []) + + @jsii.member(jsii_name="makeInstance") + @classmethod + def make_instance(cls) -> "JSII417PublicBaseOfBase": + return jsii.sinvoke(cls, "makeInstance", []) + + @jsii.member(jsii_name="foo") + def foo(self) -> None: + return jsii.invoke(self, "foo", []) + + @property + @jsii.member(jsii_name="hasRoot") + def has_root(self) -> bool: + return jsii.get(self, "hasRoot") + + +class JSII417Derived(JSII417PublicBaseOfBase, metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.JSII417Derived"): + def __init__(self, property: str) -> None: + jsii.create(JSII417Derived, self, [property]) + + @jsii.member(jsii_name="bar") + def bar(self) -> None: + return jsii.invoke(self, "bar", []) + + @jsii.member(jsii_name="baz") + def baz(self) -> None: + return jsii.invoke(self, "baz", []) + + @property + @jsii.member(jsii_name="property") + def _property(self) -> str: + return jsii.get(self, "property") + + class JSObjectLiteralForInterface(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.JSObjectLiteralForInterface"): def __init__(self) -> None: jsii.create(JSObjectLiteralForInterface, self, []) @@ -2454,6 +2491,6 @@ def parts(self, value: typing.List[scope.jsii_calc_lib.Value]): return jsii.set(self, "parts", value) -__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AsyncVirtualMethods", "AugmentableClass", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumersOfThisCrazyTypeSystem", "DefaultedConstructorArgument", "DerivedClassHasNoProperties", "DerivedStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExportedBaseClass", "ExtendsInternalInterface", "ExtendsPrivateInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnotherPublicInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "ImplementInternalInterface", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RuntimeTypeChecking", "SingleInstanceTwoTypes", "Statics", "StringEnum", "StripInternal", "Sum", "SyncVirtualMethods", "Thrower", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicMethod", "VirtualMethodPlayground", "__jsii_assembly__", "composition"] +__all__ = ["AbstractClass", "AbstractClassBase", "AbstractClassReturner", "Add", "AllTypes", "AllTypesEnum", "AllowedMethodNames", "AsyncVirtualMethods", "AugmentableClass", "BinaryOperation", "Calculator", "CalculatorProps", "ClassThatImplementsTheInternalInterface", "ClassThatImplementsThePrivateInterface", "ClassWithMutableObjectLiteralProperty", "ClassWithPrivateConstructorAndAutomaticProperties", "ConstructorPassesThisOut", "Constructors", "ConsumersOfThisCrazyTypeSystem", "DefaultedConstructorArgument", "DerivedClassHasNoProperties", "DerivedStruct", "DoNotOverridePrivates", "DoNotRecognizeAnyAsOptional", "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", "ExportedBaseClass", "ExtendsInternalInterface", "ExtendsPrivateInterface", "GiveMeStructs", "Greetee", "GreetingAugmenter", "IAnotherPublicInterface", "IFriendlier", "IFriendlyRandomGenerator", "IInterfaceImplementedByAbstractClass", "IInterfaceThatShouldNotBeADataType", "IInterfaceWithInternal", "IInterfaceWithMethods", "IInterfaceWithOptionalMethodArguments", "IInterfaceWithProperties", "IInterfaceWithPropertiesExtension", "IMutableObjectLiteral", "INonInternalInterface", "IPrivatelyImplemented", "IPublicInterface", "IPublicInterface2", "IRandomNumberGenerator", "IReturnsNumber", "ImplementInternalInterface", "ImplementsInterfaceWithInternal", "ImplementsInterfaceWithInternalSubclass", "ImplementsPrivateInterface", "ImplictBaseOfBase", "InbetweenClass", "InterfaceInNamespaceIncludesClasses", "InterfaceInNamespaceOnlyInterface", "JSII417Derived", "JSII417PublicBaseOfBase", "JSObjectLiteralForInterface", "JSObjectLiteralToNative", "JSObjectLiteralToNativeClass", "JavaReservedWords", "JsiiAgent", "LoadBalancedFargateServiceProps", "Multiply", "Negate", "NodeStandardLibrary", "NullShouldBeTreatedAsUndefined", "NullShouldBeTreatedAsUndefinedData", "NumberGenerator", "ObjectRefsInCollections", "Old", "OptionalConstructorArgument", "OptionalStruct", "OptionalStructConsumer", "OverrideReturnsObject", "PartiallyInitializedThisConsumer", "Polymorphism", "Power", "PublicClass", "PythonReservedWords", "ReferenceEnumFromScopedPackage", "ReturnsPrivateImplementationOfInterface", "RuntimeTypeChecking", "SingleInstanceTwoTypes", "Statics", "StringEnum", "StripInternal", "Sum", "SyncVirtualMethods", "Thrower", "UnaryOperation", "UnionProperties", "UseBundledDependency", "UseCalcBase", "UsesInterfaceWithProperties", "VariadicMethod", "VirtualMethodPlayground", "__jsii_assembly__", "composition"] publication.publish() 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 0eb087ee74..2654e12ce3 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 @@ -3279,6 +3279,107 @@ Hello (interface) .. py:currentmodule:: jsii-calc +JSII417Derived +^^^^^^^^^^^^^^ + +.. py:class:: JSII417Derived(property) + + **Language-specific names:** + + .. tabs:: + + .. code-tab:: c# + + using Amazon.JSII.Tests.CalculatorNamespace; + + .. code-tab:: java + + import software.amazon.jsii.tests.calculator.JSII417Derived; + + .. code-tab:: javascript + + const { JSII417Derived } = require('jsii-calc'); + + .. code-tab:: typescript + + import { JSII417Derived } from 'jsii-calc'; + + + + :extends: :py:class:`~jsii-calc.JSII417PublicBaseOfBase`\ + :param property: + :type property: string + + .. py:method:: bar() + + + + .. py:method:: baz() + + + + .. py:attribute:: property + + *Protected property* + + :type: string *(readonly)* + + + .. py:method:: foo() + + *Inherited from* :py:meth:`jsii-calc.JSII417PublicBaseOfBase ` + + + + .. py:attribute:: hasRoot + + *Inherited from* :py:attr:`jsii-calc.JSII417PublicBaseOfBase ` + + :type: boolean *(readonly)* + + +JSII417PublicBaseOfBase +^^^^^^^^^^^^^^^^^^^^^^^ + +.. py:class:: JSII417PublicBaseOfBase() + + **Language-specific names:** + + .. tabs:: + + .. code-tab:: c# + + using Amazon.JSII.Tests.CalculatorNamespace; + + .. code-tab:: java + + import software.amazon.jsii.tests.calculator.JSII417PublicBaseOfBase; + + .. code-tab:: javascript + + const { JSII417PublicBaseOfBase } = require('jsii-calc'); + + .. code-tab:: typescript + + import { JSII417PublicBaseOfBase } from 'jsii-calc'; + + + + + .. py:staticmethod:: makeInstance() -> jsii-calc.JSII417PublicBaseOfBase + + :rtype: :py:class:`~jsii-calc.JSII417PublicBaseOfBase`\ + + + .. py:method:: foo() + + + + .. py:attribute:: hasRoot + + :type: boolean *(readonly)* + + JSObjectLiteralForInterface ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/packages/jsii-reflect/test/classes.expected.txt b/packages/jsii-reflect/test/classes.expected.txt index 7fd29ad13d..cb4fb67e59 100644 --- a/packages/jsii-reflect/test/classes.expected.txt +++ b/packages/jsii-reflect/test/classes.expected.txt @@ -35,6 +35,8 @@ ImplementsInterfaceWithInternal ImplementsInterfaceWithInternalSubclass ImplementsPrivateInterface InbetweenClass +JSII417Derived +JSII417PublicBaseOfBase JSObjectLiteralForInterface JSObjectLiteralToNative JSObjectLiteralToNativeClass diff --git a/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt index 7583982279..af0f6df45d 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.all.expected.txt @@ -512,6 +512,34 @@ assemblies │ │ │ └── returns: void │ │ └─┬ bar property │ │ └── type: string? + │ ├─┬ class JSII417Derived + │ │ ├── base: JSII417PublicBaseOfBase + │ │ └─┬ members + │ │ ├─┬ (property) method + │ │ │ ├─┬ parameters + │ │ │ │ └─┬ property + │ │ │ │ └── type: string + │ │ │ └── returns: void + │ │ ├─┬ bar() method + │ │ │ └── returns: void + │ │ ├─┬ baz() method + │ │ │ └── returns: void + │ │ └─┬ property property + │ │ ├── immutable + │ │ ├── protected + │ │ └── type: string + │ ├─┬ class JSII417PublicBaseOfBase + │ │ └─┬ members + │ │ ├─┬ () method + │ │ │ └── returns: void + │ │ ├─┬ makeInstance() method + │ │ │ ├── static + │ │ │ └── returns: jsii-calc.JSII417PublicBaseOfBase + │ │ ├─┬ foo() method + │ │ │ └── returns: void + │ │ └─┬ hasRoot property + │ │ ├── immutable + │ │ └── type: boolean │ ├─┬ class JSObjectLiteralForInterface │ │ └─┬ members │ │ ├─┬ () method diff --git a/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt index d7b4958c78..7314fd81f9 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.inheritance.expected.txt @@ -51,6 +51,9 @@ assemblies │ │ ├── base: PublicClass │ │ └── interfaces: IPublicInterface2 │ ├── class Foo + │ ├─┬ class JSII417Derived + │ │ └── base: JSII417PublicBaseOfBase + │ ├── class JSII417PublicBaseOfBase │ ├── class JSObjectLiteralForInterface │ ├── class JSObjectLiteralToNative │ ├── class JSObjectLiteralToNativeClass diff --git a/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt index 651e46efbe..760adca226 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.members.expected.txt @@ -210,6 +210,18 @@ assemblies │ │ └─┬ members │ │ ├── () method │ │ └── bar property + │ ├─┬ class JSII417Derived + │ │ └─┬ members + │ │ ├── (property) method + │ │ ├── bar() method + │ │ ├── baz() method + │ │ └── property property + │ ├─┬ class JSII417PublicBaseOfBase + │ │ └─┬ members + │ │ ├── () method + │ │ ├── makeInstance() method + │ │ ├── foo() method + │ │ └── hasRoot property │ ├─┬ class JSObjectLiteralForInterface │ │ └─┬ members │ │ ├── () method diff --git a/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt b/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt index ea44cf1652..6c70eb5d4e 100644 --- a/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt +++ b/packages/jsii-reflect/test/jsii-tree.test.types.expected.txt @@ -36,6 +36,8 @@ assemblies │ ├── class ImplementsPrivateInterface │ ├── class InbetweenClass │ ├── class Foo + │ ├── class JSII417Derived + │ ├── class JSII417PublicBaseOfBase │ ├── class JSObjectLiteralForInterface │ ├── class JSObjectLiteralToNative │ ├── class JSObjectLiteralToNativeClass diff --git a/packages/jsii/lib/assembler.ts b/packages/jsii/lib/assembler.ts index 2dd6e5bef2..ed951f5a80 100644 --- a/packages/jsii/lib/assembler.ts +++ b/packages/jsii/lib/assembler.ts @@ -420,12 +420,29 @@ export class Assembler implements Emitter { if (_isAbstract(type.symbol, jsiiType)) { jsiiType.abstract = true; } - for (const base of (type.getBaseTypes() || [])) { + + const erasedBases = new Array(); + for (let base of (type.getBaseTypes() || [])) { if (jsiiType.base) { this._diagnostic(base.symbol.valueDeclaration, ts.DiagnosticCategory.Error, `Found multiple base types for ${jsiiType.fqn}`); continue; } + /* + * Crawl up the inheritance tree if the current base type is not exported, so we identify the type(s) to be + * erased, and identify the closest exported base class, should there be one. + */ + // tslint:disable-next-line: no-bitwise + while (base && this._isPrivateOrInternal(base.symbol)) { + LOG.debug(`Base class of ${colors.green(jsiiType.fqn)} named ${colors.green(base.symbol.name)} is not exported, erasing it...`); + erasedBases.push(base); + base = (base.getBaseTypes() || [])[0]; + } + if (!base) { + // There is no exported base class to be found, pretend this class has no base class. + continue; + } + const ref = await this._typeReference(base, type.symbol.valueDeclaration); if (!spec.isNamedTypeReference(ref)) { @@ -470,14 +487,21 @@ export class Assembler implements Emitter { throw new Error('Oh no'); } - for (const decl of type.symbol.declarations) { + const allDeclarations: Array<{ decl: ts.Declaration, type: ts.InterfaceType | ts.BaseType }> + = type.symbol.declarations.map(decl => ({ decl, type })); + // Considering erased bases' declarations, too, so they are "blended in" + for (const base of erasedBases) { + allDeclarations.push(...base.symbol.declarations.map(decl => ({ decl, type: base }))); + } + + for (const { decl, type: declaringType } of allDeclarations) { const classDecl = (decl as ts.ClassDeclaration | ts.InterfaceDeclaration); if (!classDecl.members) { continue; } for (const memberDecl of classDecl.members) { const member: ts.Symbol = (memberDecl as any).symbol; - if (!(type.symbol.getDeclarations() || []).find(d => d === memberDecl.parent)) { + if (!(declaringType.symbol.getDeclarations() || []).find(d => d === memberDecl.parent)) { continue; } @@ -504,7 +528,8 @@ export class Assembler implements Emitter { } } - const constructor = type.symbol.members && type.symbol.members.get(ts.InternalSymbolName.Constructor); + // Find the first defined constructor in this class, or it's erased bases + const constructor = [type, ...erasedBases].map(getConstructor).find(ctor => ctor != null); const ctorDeclaration = constructor && (constructor.declarations[0] as ts.ConstructorDeclaration); if (constructor && ctorDeclaration) { const signature = this._typeChecker.getSignatureFromDeclaration(ctorDeclaration); @@ -557,7 +582,7 @@ export class Assembler implements Emitter { const hasUnderscorePrefix = symbol.name !== '__constructor' && symbol.name.startsWith('_'); if (_isPrivate(symbol)) { - LOG.trace(`${symbol.name} is marked "private"`); + LOG.trace(`${colors.cyan(symbol.name)} is marked "private", or is an unexported type declaration`); return true; } @@ -569,12 +594,12 @@ export class Assembler implements Emitter { if (validateDeclaration) { if (!hasUnderscorePrefix) { this._diagnostic(validateDeclaration, ts.DiagnosticCategory.Error, - `${symbol.name}: the name of members marked as @internal must begin with an underscore`); + `${colors.cyan(symbol.name)}: the name of members marked as @internal must begin with an underscore`); } if (!hasInternalJsDocTag) { this._diagnostic(validateDeclaration, ts.DiagnosticCategory.Error, - `${symbol.name}: members with names that begin with an underscore must be marked as @internal via a JSDoc tag`); + `${colors.cyan(symbol.name)}: members with names that begin with an underscore must be marked as @internal via a JSDoc tag`); } } @@ -817,6 +842,10 @@ export class Assembler implements Emitter { } type.methods = type.methods || []; + if (type.methods.find(m => m.name === method.name && m.static === method.static) != null) { + LOG.trace(`Dropping re-declaration of ${colors.green(type.fqn)}#${colors.cyan(method.name!)}`); + return; + } type.methods.push(method); } @@ -865,6 +894,10 @@ export class Assembler implements Emitter { property.docs = this._visitDocumentation(symbol); type.properties = type.properties || []; + if (type.properties.find(prop => prop.name === property.name && prop.static === property.static) != null) { + LOG.trace(`Dropping re-declaration of ${colors.green(type.fqn)}#${colors.cyan(property.name)}`); + return; + } type.properties.push(property); } @@ -1167,10 +1200,14 @@ function _isExported(node: ts.Declaration): boolean { * @return `true` if the symbol should be hidden */ function _isPrivate(symbol: ts.Symbol): boolean { - + const TYPE_DECLARATION_KINDS = new Set([ + ts.SyntaxKind.ClassDeclaration, + ts.SyntaxKind.InterfaceDeclaration, + ts.SyntaxKind.EnumDeclaration, + ]); // if the symbol doesn't have a value declaration, we are assuming it's a type (enum/interface/class) // and check that it has an "export" modifier - if (!symbol.valueDeclaration) { + if (!symbol.valueDeclaration || TYPE_DECLARATION_KINDS.has(symbol.valueDeclaration.kind)) { let hasExport = false; for (const decl of symbol.declarations) { // tslint:disable-next-line:no-bitwise @@ -1346,3 +1383,8 @@ function interfaceMemberNames(jsiiType: spec.InterfaceType): string[] { function isInterfaceName(name: string) { return name.length >= 2 && name.charAt(0) === 'I' && name.charAt(1).toUpperCase() === name.charAt(1); } + +function getConstructor(type: ts.Type): ts.Symbol | undefined { + return type.symbol.members + && type.symbol.members.get(ts.InternalSymbolName.Constructor); +} diff --git a/packages/jsii/test/negatives/neg.deref-error.ts b/packages/jsii/test/negatives/neg.deref-error.ts deleted file mode 100644 index f0179642bd..0000000000 --- a/packages/jsii/test/negatives/neg.deref-error.ts +++ /dev/null @@ -1,9 +0,0 @@ -///!MATCH_ERROR: Unable to resolve referenced type 'Base'. Type may be @internal or unexported - -class Base { - -} - -export class Derived extends Base { - -} \ No newline at end of file diff --git a/packages/jsii/test/negatives/neg.internal-base-class.ts b/packages/jsii/test/negatives/neg.internal-base-class.ts deleted file mode 100644 index 3ff0231c92..0000000000 --- a/packages/jsii/test/negatives/neg.internal-base-class.ts +++ /dev/null @@ -1,10 +0,0 @@ -///!MATCH_ERROR: Unable to resolve referenced type 'jsii.InternalBaseClass'. Type may be @internal or unexported - -/** @internal */ -export class InternalBaseClass { - -} - -export class MyClass extends InternalBaseClass { - -}