Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 64 additions & 4 deletions test-app/app/src/main/assets/app/tests/extendedClassesTests.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
describe("Tests extended classes ", function () {

it("Instance_with_no_extension_shouldnt_use_previously_defined_implementation_object", function () {
it("Instance with no extension shouldn't use previously defined implementation object", function () {
var MyButton = com.tns.tests.Button1.extend({
toString: function () {
return "overriden toString method of chronometer instance";
Expand All @@ -21,8 +21,68 @@ describe("Tests extended classes ", function () {
expect(labelToString).not.toBe(labelToString1);
expect(labelgetIMAGE_ID_PROP).not.toBe(labelgetIMAGE_ID_PROP1);
});

it("Having a class with static method named 'extend' and extending it in a child class shouldn't crash the app", function (){

/* JS below the comment is generated from the following TS code

class Base{
static extend(){
return "expectedValue";
}
}
class Child extends Base{
}

class SecondChild extends Child{
}


const superProto = Object.getPrototypeOf(Child.prototype)
const Super = superProto.constructor;
//console.log(Super.extend());

var child = Object.create(Child);
//console.log(child.extend());

//console.log(Child.extend());

*/

var Base = /** @class */ (function () {
function Base() {
}
Base.extend = function () {
return "expectedValue";
};
return Base;
}());
var Child = /** @class */ (function (_super) {
__extends(Child, _super);
function Child() {
return _super !== null && _super.apply(this, arguments) || this;
}
return Child;
}(Base));
var SecondChild = /** @class */ (function (_super) {
__extends(SecondChild, _super);
function SecondChild() {
return _super !== null && _super.apply(this, arguments) || this;
}
return SecondChild;
}(Child));

var superProto = Object.getPrototypeOf(Child.prototype);
var Super = superProto.constructor;
expect(Super.extend()).toBe("expectedValue");

var child = Object.create(Child);
expect(child.extend()).toBe("expectedValue");

expect(Child.extend()).toBe("expectedValue");
});

it("Instance_with_extension_shouldnt_use_previously_defined_implementation_object", function () {
it("Instance with extension shouldn't use previously defined implementation object", function () {

var MyButton = com.tns.tests.Button1.extend({
toString: function () {
Expand Down Expand Up @@ -53,7 +113,7 @@ describe("Tests extended classes ", function () {
expect(labelgetIMAGE_ID_PROP).not.toBe(labelgetIMAGE_ID_PROP1);
});

it("Newly_created_instances_should_behave_the_same_and_not_use_previously_defined_implementation_objects", function () {
it("Newly created instances should behave the same and not use previously defined implementation objects", function () {

var button1 = new com.tns.tests.Button1();
var labelgetIMAGE_ID_PROP1 = button1.getIMAGE_ID_PROP();
Expand All @@ -74,7 +134,7 @@ describe("Tests extended classes ", function () {
expect(labelgetIMAGE_ID_PROP1).toBe(labelgetIMAGE_ID_PROP2);
});

it("should not crash with no exception when incorrectly calling extended class constructor", function () {
it("Should not crash with no exception when incorrectly calling extended class constructor", function () {
let MyObj = java.lang.Object.extend({
toString: () => { return "It's MyObj" }
});
Expand Down
215 changes: 121 additions & 94 deletions test-app/app/src/main/assets/internal/ts_helpers.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
(function() {
var __extends_ts = function (d, b) {
if (!b.extend) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
}

function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
(function () {

var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length;
Expand All @@ -27,102 +18,138 @@
};

// For backward compatibility.
var __native = function(thiz) {
// we are setting the __container__ property to the base class when the super method is called
// if the constructor returns the __native(this) call we will use the old implementation
// copying all the properties to the result
// otherwise if we are using the result from the super() method call we won't need such logic
// as thiz already contains the parent properties
// this way we now support both implementations in typescript generated constructors:
// 1: super(); return __native(this);
// 2: return super() || this;
if(thiz.__container__) {
var result = thiz.__proto__;

for (var prop in thiz)
{
if (thiz.hasOwnProperty(prop))
{
thiz.__proto__[prop] = thiz[prop];
delete thiz[prop];
}
}

thiz.constructor = undefined;
thiz.__proto__ = undefined;
Object.freeze(thiz);
Object.preventExtensions(thiz);
return result;
var __native = function (thiz) {
// we are setting the __container__ property to the base class when the super method is called
// if the constructor returns the __native(this) call we will use the old implementation
// copying all the properties to the result
// otherwise if we are using the result from the super() method call we won't need such logic
// as thiz already contains the parent properties
// this way we now support both implementations in typescript generated constructors:
// 1: super(); return __native(this);
// 2: return super() || this;
if (thiz.__container__) {
var result = thiz.__proto__;

for (var prop in thiz) {
if (thiz.hasOwnProperty(prop)) {
thiz.__proto__[prop] = thiz[prop];
delete thiz[prop];
}
}

thiz.constructor = undefined;
thiz.__proto__ = undefined;
Object.freeze(thiz);
Object.preventExtensions(thiz);
return result;
} else {
return thiz;
return thiz;
}
};

var __extends = function(Child, Parent) {
var __extends = function (Child, Parent) {
const NATIVE_CODE_REGEX = /\{\s*\[native code\]\s*\}/g;
var extendNativeClass = !!Parent.extend && NATIVE_CODE_REGEX.test(Parent.extend.toString());
if (!extendNativeClass) {
__extends_ts(Child, Parent);
return;
}
if (Parent.__isPrototypeImplementationObject) {
throw new Error("Can not extend an already extended native object.");
}

if (Parent.extend) {
if (Parent.__isPrototypeImplementationObject) {
throw new Error("Can not extend an already extended native object.");
function extend(thiz) {
var child = thiz.__proto__.__child;
if (!child.__extended) {
var parent = thiz.__proto__.__parent;
child.__extended = parent.extend(child.name, child.prototype, true);
// This will deal with "i instanceof child"
child[Symbol.hasInstance] = function (instance) {
return instance instanceof this.__extended;
}
}
return child.__extended;
};

function extend(thiz) {
var child = thiz.__proto__.__child;
if (!child.__extended) {
var parent = thiz.__proto__.__parent;
child.__extended = parent.extend(child.name, child.prototype, true);
// This will deal with "i instanceof child"
child[Symbol.hasInstance] = function(instance) {
return instance instanceof this.__extended;
}
}
return child.__extended;
};

Parent.__activityExtend = function(parent, name, implementationObject) {
__log("__activityExtend called");
return parent.extend(name, implementationObject);
};

Parent.call = function(thiz) {
var Extended = extend(thiz);
thiz.__container__ = true;
if (arguments.length > 1)
{
thiz.__proto__ = new (Function.prototype.bind.apply(Extended, [null].concat(Array.prototype.slice.call(arguments, 1))));
}
else
{
thiz.__proto__ = new Extended()
}
return thiz.__proto__;
};

Parent.apply = function(thiz, args) {
var Extended = extend(thiz);
thiz.__container__ = true;
if (args && args.length > 0)
{
thiz.__proto__ = new (Function.prototype.bind.apply(Extended, [null].concat(args)));
}
else
{
thiz.__proto__ = new Extended();
}
return thiz.__proto__;
};
Parent.__activityExtend = function (parent, name, implementationObject) {
__log("__activityExtend called");
return parent.extend(name, implementationObject);
};

Parent.call = function (thiz) {
var Extended = extend(thiz);
thiz.__container__ = true;
if (arguments.length > 1) {
thiz.__proto__ = new (Function.prototype.bind.apply(Extended, [null].concat(Array.prototype.slice.call(arguments, 1))));
}
else {
thiz.__proto__ = new Extended()
}
return thiz.__proto__;
};

Parent.apply = function (thiz, args) {
var Extended = extend(thiz);
thiz.__container__ = true;
if (args && args.length > 0) {
thiz.__proto__ = new (Function.prototype.bind.apply(Extended, [null].concat(args)));
}
else {
thiz.__proto__ = new Extended();
}
return thiz.__proto__;
};
__extends_ns(Child, Parent);
Child.__isPrototypeImplementationObject = true;
Child.__proto__ = Parent;
Child.prototype.__parent = Parent;
Child.prototype.__child = Child;
}

var __extends_ts = function (child, parent) {
extendStaticFunctions(child, parent);
assignPrototypeFromParentToChild(parent, child);
};

var __extends_ns = function (child, parent) {
if (!parent.extend) {
assignPropertiesFromParentToChild(parent, child);
}

__extends_ts(Child, Parent);
assignPrototypeFromParentToChild(parent, child);
};

var extendStaticFunctions =
Object.setPrototypeOf
|| (hasInternalProtoProperty() && function (child, parent) { child.__proto__ = parent; })
|| assignPropertiesFromParentToChild;

if (Parent.extend) {
Child.__isPrototypeImplementationObject = true;
Child.__proto__ = Parent;
Child.prototype.__parent = Parent;
Child.prototype.__child = Child;
function hasInternalProtoProperty() {
return { __proto__: [] } instanceof Array;
}

function assignPropertiesFromParentToChild(parent, child) {
for (var property in parent) {
if (parent.hasOwnProperty(property)) {
child[property] = parent[property];
}
}
}

function assignPrototypeFromParentToChild(parent, child) {
function __() {
this.constructor = child;
}

if (parent === null) {
child.prototype = Object.create(null);
} else {
__.prototype = parent.prototype;
child.prototype = new __();
}
}


function JavaProxy(className) {
return function (target) {
var extended = target.extend(className, target.prototype)
Expand All @@ -133,7 +160,7 @@

function Interfaces(interfacesArr) {
return function (target) {
if(interfacesArr instanceof Array) {
if (interfacesArr instanceof Array) {
// attach interfaces: [] to the object
target.prototype.interfaces = interfacesArr;
}
Expand All @@ -146,4 +173,4 @@

global.JavaProxy = JavaProxy;
global.Interfaces = Interfaces;
})()
})()
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:3.1.4'
classpath 'com.android.tools.build:gradle:3.2.1'
}
}

Expand Down
Loading