|
| 1 | +#include "TSHelpers.h" |
| 2 | +#include <string> |
| 3 | +#include "Helpers.h" |
| 4 | + |
| 5 | +using namespace v8; |
| 6 | + |
| 7 | +namespace tns { |
| 8 | + |
| 9 | +void TSHelpers::Init(Isolate* isolate) { |
| 10 | + // The purpose of this script is to handle the "new" operator when extending native classes: |
| 11 | + // |
| 12 | + // var InheritingClass = (function (_super) { |
| 13 | + // __extends(InheritingClass, _super); |
| 14 | + // function InheritingClass() { |
| 15 | + // return _super !== null && _super.apply(this, arguments) || this; // <---- _super.apply and _super.call methods will invoke the original .extend() method on the derived class |
| 16 | + // } |
| 17 | + // return InheritingClass; |
| 18 | + // }(BaseClass)); |
| 19 | + // var obj = new InheritingClass(); |
| 20 | + |
| 21 | + std::string source = |
| 22 | + "(() => {" |
| 23 | + " var __originalExtends = global.__extends;" |
| 24 | + " var __extends = (Child, Parent) => {" |
| 25 | + " var extendingNativeClass = !!Parent.extend && (Parent.extend.toString().indexOf(\"[native code]\") > -1);" |
| 26 | + " if (!extendingNativeClass) {" |
| 27 | + " __extends_ts(Child, Parent);" |
| 28 | + " return;" |
| 29 | + " }" |
| 30 | + "" |
| 31 | + " if (Parent.__isPrototypeImplementationObject) {" |
| 32 | + " throw new Error(\"Can not extend an already extended native object.\");" |
| 33 | + " }" |
| 34 | + "" |
| 35 | + " function extend(thiz) {" |
| 36 | + " var child = thiz.__proto__.__child;" |
| 37 | + " if (!child.__extended) {" |
| 38 | + " var parent = thiz.__proto__.__parent;" |
| 39 | + " child.__extended = parent.extend(child.prototype, {" |
| 40 | + " name: child.name," |
| 41 | + " protocols: child.ObjCProtocols || []," |
| 42 | + " exposedMethods: child.ObjCExposedMethods || {}" |
| 43 | + " });" |
| 44 | + " child[Symbol.hasInstance] = function (instance) {" |
| 45 | + " return instance instanceof this.__extended;" |
| 46 | + " }" |
| 47 | + " }" |
| 48 | + " return child.__extended;" |
| 49 | + " }" |
| 50 | + "" |
| 51 | + " Parent.call = function (thiz) {" |
| 52 | + " var Extended = extend(thiz);" |
| 53 | + " thiz.__container__ = true;" |
| 54 | + " if (arguments.length > 1) {" |
| 55 | + " thiz.__proto__ = new (Function.prototype.bind.apply(Extended, [null].concat(Array.prototype.slice.call(arguments, 1))));" |
| 56 | + " } else {" |
| 57 | + " thiz.__proto__ = new Extended()" |
| 58 | + " }" |
| 59 | + " return thiz.__proto__;" |
| 60 | + " };" |
| 61 | + "" |
| 62 | + " Parent.apply = function (thiz, args) {" |
| 63 | + " var Extended = extend(thiz);" |
| 64 | + " thiz.__container__ = true;" |
| 65 | + " if (args && args.length > 0) {" |
| 66 | + " thiz.__proto__ = new (Function.prototype.bind.apply(Extended, [null].concat(args)));" |
| 67 | + " } else {" |
| 68 | + " thiz.__proto__ = new Extended();" |
| 69 | + " }" |
| 70 | + " return thiz.__proto__;" |
| 71 | + " };" |
| 72 | + "" |
| 73 | + " __extends_ns(Child, Parent);" |
| 74 | + " Child.__isPrototypeImplementationObject = true;" |
| 75 | + " Child.__proto__ = Parent;" |
| 76 | + " Child.prototype.__parent = Parent;" |
| 77 | + " Child.prototype.__child = Child;" |
| 78 | + "" |
| 79 | + " if (__originalExtends) {" |
| 80 | + " __originalExtends(Child, Parent);" |
| 81 | + " }" |
| 82 | + " };" |
| 83 | + "" |
| 84 | + " var __extends_ts = function (child, parent) {" |
| 85 | + " extendStaticFunctions(child, parent);" |
| 86 | + " assignPrototypeFromParentToChild(parent, child);" |
| 87 | + " };" |
| 88 | + "" |
| 89 | + " var __extends_ns = function (child, parent) {" |
| 90 | + " if (!parent.extend) {" |
| 91 | + " assignPropertiesFromParentToChild(parent, child);" |
| 92 | + " }" |
| 93 | + "" |
| 94 | + " assignPrototypeFromParentToChild(parent, child);" |
| 95 | + " };" |
| 96 | + "" |
| 97 | + " var extendStaticFunctions =" |
| 98 | + " Object.setPrototypeOf" |
| 99 | + " || (hasInternalProtoProperty() && function (child, parent) { child.__proto__ = parent; })" |
| 100 | + " || assignPropertiesFromParentToChild;" |
| 101 | + "" |
| 102 | + " function hasInternalProtoProperty() {" |
| 103 | + " return { __proto__: [] } instanceof Array;" |
| 104 | + " }" |
| 105 | + "" |
| 106 | + " function assignPropertiesFromParentToChild(parent, child) {" |
| 107 | + " for (var property in parent) {" |
| 108 | + " if (parent.hasOwnProperty(property)) {" |
| 109 | + " child[property] = parent[property];" |
| 110 | + " }" |
| 111 | + " }" |
| 112 | + " }" |
| 113 | + "" |
| 114 | + " function assignPrototypeFromParentToChild(parent, child) {" |
| 115 | + " function __() {" |
| 116 | + " this.constructor = child;" |
| 117 | + " }" |
| 118 | + "" |
| 119 | + " if (parent === null) {" |
| 120 | + " child.prototype = Object.create(null);" |
| 121 | + " } else {" |
| 122 | + " __.prototype = parent.prototype;" |
| 123 | + " child.prototype = new __();" |
| 124 | + " }" |
| 125 | + " }" |
| 126 | + "" |
| 127 | + " Object.defineProperty(global, \"__extends\", { value: __extends });" |
| 128 | + "})()"; |
| 129 | + |
| 130 | + Local<Context> context = isolate->GetCurrentContext(); |
| 131 | + Local<Script> script; |
| 132 | + TryCatch tc(isolate); |
| 133 | + if (!Script::Compile(context, tns::ToV8String(isolate, source.c_str())).ToLocal(&script) && tc.HasCaught()) { |
| 134 | + tns::LogError(isolate, tc); |
| 135 | + assert(false); |
| 136 | + } |
| 137 | + assert(!script.IsEmpty()); |
| 138 | + |
| 139 | + Local<Value> result; |
| 140 | + if (!script->Run(context).ToLocal(&result) && tc.HasCaught()) { |
| 141 | + tns::LogError(isolate, tc); |
| 142 | + assert(false); |
| 143 | + } |
| 144 | +} |
| 145 | + |
| 146 | +} |
0 commit comments