diff --git a/test-app/app/build.gradle b/test-app/app/build.gradle index 45a14c1b..3b12bcc6 100644 --- a/test-app/app/build.gradle +++ b/test-app/app/build.gradle @@ -516,6 +516,10 @@ task runSbg(type: BuildToolTask) { paramz.add("-show-deprecation-warnings") } + if (ns_engine == "PRIMJS") { + paramz.add("-line-column-primjs") + } + setOutputs outLogger args paramz diff --git a/test-app/app/src/main/assets/internal/ts_helpers.js b/test-app/app/src/main/assets/internal/ts_helpers.js index 86d3d429..85038088 100644 --- a/test-app/app/src/main/assets/internal/ts_helpers.js +++ b/test-app/app/src/main/assets/internal/ts_helpers.js @@ -63,12 +63,12 @@ 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); + child.__extended = parent.extend(child.name, child.prototype, true, error); // This will deal with "i instanceof child" child[Symbol.hasInstance] = function (instance) { return instance instanceof this.__extended; diff --git a/test-app/build-tools/buildMetadata.log b/test-app/build-tools/buildMetadata.log index 3e7477fc..bde0244d 100644 --- a/test-app/build-tools/buildMetadata.log +++ b/test-app/build-tools/buildMetadata.log @@ -2,5 +2,5 @@ Added Properties 54 Ignored Properties 2 duplicates. Added Methods 81320 Ignored Methods 3300 duplicates. -Added Fields 54583 -Ignored Fields 16676 duplicates. +Added Fields 54602 +Ignored Fields 16678 duplicates. diff --git a/test-app/build-tools/jsparser/js_parser.js b/test-app/build-tools/jsparser/js_parser.js index 3b65fa3c..5d5839fe 100644 --- a/test-app/build-tools/jsparser/js_parser.js +++ b/test-app/build-tools/jsparser/js_parser.js @@ -17,6 +17,8 @@ const showErrorsAndWarnings = process.argv && process.argv.includes("enableErrorLogging")); +const lineColumnPrimJS = process.argv.includes("-line-column-primjs"); + const loggingSettings = { logPath: require("path").join(__dirname, "logs", "i.txt"), strategy: "console", @@ -279,6 +281,7 @@ const visitAst = function (path, data, err) { .substring(inputDir.length + 1) .replace(/[\\]/g, "/"), interfaceNames: interfaceNames, + isPrimJS: lineColumnPrimJS }; es5_visitors.es5Visitor(path, decoratorConfig); }, diff --git a/test-app/build-tools/jsparser/package-lock.json b/test-app/build-tools/jsparser/package-lock.json index 90b92add..d6e1c3be 100644 --- a/test-app/build-tools/jsparser/package-lock.json +++ b/test-app/build-tools/jsparser/package-lock.json @@ -16,6 +16,9 @@ "split": "1.0.1" }, "devDependencies": { + "@types/babel__traverse": "^7.20.6", + "@types/split": "^1.0.5", + "ts-loader": "^9.5.2", "webpack": "5.70.0", "webpack-cli": "4.9.2" } @@ -749,17 +752,19 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -992,6 +997,30 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@types/babel__traverse": { + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/babel__traverse/node_modules/@babel/types": { + "version": "7.26.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", + "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@types/eslint": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", @@ -1033,6 +1062,27 @@ "undici-types": "~6.19.2" } }, + "node_modules/@types/split": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/split/-/split-1.0.5.tgz", + "integrity": "sha512-gMiDr4vA6YofTpAkPQtP+5pvStIf3CMYphf32YAG/3RwogNL8ii1CQKDc+sxN62KuxPoRaJXcf2zDCDkEBH4FA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/through": "*" + } + }, + "node_modules/@types/through": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", + "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", @@ -1284,6 +1334,19 @@ "node": ">=4" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", @@ -1593,6 +1656,19 @@ "node": ">= 4.9.1" } }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -1737,6 +1813,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -1899,6 +1985,20 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2037,6 +2137,19 @@ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", @@ -2347,6 +2460,154 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-loader": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.2.tgz", + "integrity": "sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 8" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/undici-types": { "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", diff --git a/test-app/build-tools/jsparser/package.json b/test-app/build-tools/jsparser/package.json index 25b49dbf..b39c625b 100644 --- a/test-app/build-tools/jsparser/package.json +++ b/test-app/build-tools/jsparser/package.json @@ -18,6 +18,8 @@ }, "repository": "https://github.com/NativeScript/android-runtime", "devDependencies": { + "@types/babel__traverse": "^7.20.6", + "@types/split": "^1.0.5", "webpack": "5.70.0", "webpack-cli": "4.9.2" } diff --git a/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/app/myCustomActivity.android.ts b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/app/myCustomActivity.android.ts new file mode 100644 index 00000000..b577da7d --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/app/myCustomActivity.android.ts @@ -0,0 +1,10 @@ +import Bundle = android.os.Bundle; + +@JavaProxy('org.nativescript.MyCustomActivity') +export class TestActivity extends android.app.Activity { + static readonly TEST1: string = "my_test"; + public onCreate(savedInstanceState?: Bundle): void { + super.onCreate(savedInstanceState); + console.log(TestActivity.TEST1); + } +} diff --git a/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/app/myCustomActivity_ts.android.js b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/app/myCustomActivity_ts.android.js new file mode 100644 index 00000000..003b9e62 --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/app/myCustomActivity_ts.android.js @@ -0,0 +1,58 @@ +"use strict"; +var __swc_crazy_long_line_swc_inherit_polyfill = { + _: () => {} +} +var _Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__ = { + _: () => {} +} + +var _swc_helpers_possible_constructor_return__WEBPACK_IMPORTED_MODULE_4__ = { + _: () => {} +} + +var _swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__ = { + _: () => {} +} + +var _swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__ = { + _: () => {} +} + +var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__ = { + __decorate: () => {} +} + +var _swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_9__ = { + _: () => {} +} +var _swc_helpers_get__WEBPACK_IMPORTED_MODULE_7__ = { + _: () => {} +} + +var _swc_helpers_get_prototype_of__WEBPACK_IMPORTED_MODULE_8__ = { + _: () => {} +} + +var _android_app_Activity; +var TestActivity = /*#__PURE__*/ function(_superClass) { + "use strict"; + (0,__swc_crazy_long_line_swc_inherit_polyfill._)(TestActivity, _superClass); + function TestActivity() { + (0,_swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__._)(this, TestActivity); + return (0,_Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__._)(this, TestActivity, arguments); + } + (0,_swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__._)(TestActivity, [ + { + key: "onCreate", + value: function onCreate(savedInstanceState) { + (0,_swc_helpers_get__WEBPACK_IMPORTED_MODULE_7__._)((0,_swc_helpers_get_prototype_of__WEBPACK_IMPORTED_MODULE_8__._)(TestActivity.prototype), "onCreate", this).call(this, savedInstanceState); + console.log(TestActivity.TEST1); + } + } + ]); + return TestActivity; +}(_android_app_Activity = android.app.Activity); +(0,_swc_helpers_define_property__WEBPACK_IMPORTED_MODULE_9__._)(TestActivity, "TEST1", "my_test"); +TestActivity = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__decorate)([ + JavaProxy('org.nativescript.MyCustomActivity') +], TestActivity); \ No newline at end of file diff --git a/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/internal/ts_helpers.js b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/internal/ts_helpers.js new file mode 100644 index 00000000..1a0625f4 --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/decorated_double_assignment_ts_swc/internal/ts_helpers.js @@ -0,0 +1,175 @@ +(function () { + + var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length; + var r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + + if (typeof global.Reflect === "object" && typeof global.Reflect.decorate === "function") { + r = global.Reflect.decorate(decorators, target, key, desc); + } + else { + for (var i = decorators.length - 1; i >= 0; i--) { + if (d = decorators[i]) { + r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + } + } + } + return c > 3 && r && Object.defineProperty(target, key, r), r; + }; + + // 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; + } else { + return thiz; + } + }; + + var __extends = function (Child, Parent) { + var extendNativeClass = !!Parent.extend && (Parent.extend.toString().indexOf("[native code]") > -1); + if (!extendNativeClass) { + __extends_ts(Child, Parent); + return; + } + 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; + }; + + 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); + } + + assignPrototypeFromParentToChild(parent, child); + }; + + var extendStaticFunctions = + Object.setPrototypeOf + || (hasInternalProtoProperty() && function (child, parent) { child.__proto__ = parent; }) + || assignPropertiesFromParentToChild; + + 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) + extended.name = className; + return extended; + }; + } + + function Interfaces(interfacesArr) { + return function (target) { + if (interfacesArr instanceof Array) { + // attach interfaces: [] to the object + target.prototype.interfaces = interfacesArr; + } + } + } + + Object.defineProperty(global, "__native", { value: __native }); + Object.defineProperty(global, "__extends", { value: __extends }); + Object.defineProperty(global, "__decorate", { value: __decorate }); + + global.JavaProxy = JavaProxy; + global.Interfaces = Interfaces; +})() \ No newline at end of file diff --git a/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc/app/normal_ts_extends.js b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc/app/normal_ts_extends.js new file mode 100644 index 00000000..3f08b182 --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc/app/normal_ts_extends.js @@ -0,0 +1,60 @@ +var __swc_crazy_long_line_swc_inherit_polyfill = { + _: () => {} +} +var _Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__ = { + _: () => {} +} + +var _swc_helpers_possible_constructor_return__WEBPACK_IMPORTED_MODULE_4__ = { + _: () => {} +} + +var _swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__ = { + _: () => {} +} + +var _swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__ = { + _: () => {} +} + +var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__ = { + __decorate: () => {} +} + +var ClickListener = /*#__PURE__*/ function(_java_lang_Object) { + "use strict"; + (0, __swc_crazy_long_line_swc_inherit_polyfill._)(ClickListener, _java_lang_Object); + function ClickListener() { + (0,_swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__._)(this, ClickListener); + var _this; + _this = (0,_Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__._)(this, + ClickListener); + // necessary when extending TypeScript constructors + return (0,_swc_helpers_possible_constructor_return__WEBPACK_IMPORTED_MODULE_4__._)(_this, global.__native(_this)); + } + (0,_swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__._)(ClickListener, [ + { + key: "onClick", + value: function onClick(view) { + console.log("Button clicked!"); + } + }, + { + key: "onDone", + value: function onClick(view) { + console.log("Button clicked!"); + } + } + ]); + return ClickListener; +}(java.lang.Object); + +ClickListener = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__decorate)([ + NativeClass, + Interfaces([ + android.view.View.OnClickListener + ]), + (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__metadata)("design:type", Function), + (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__metadata)("design:paramtypes", []) +], ClickListener); +var myObj = new MyObject("world"); diff --git a/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc/internal/ts_helpers.js b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc/internal/ts_helpers.js new file mode 100644 index 00000000..1a0625f4 --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc/internal/ts_helpers.js @@ -0,0 +1,175 @@ +(function () { + + var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length; + var r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + + if (typeof global.Reflect === "object" && typeof global.Reflect.decorate === "function") { + r = global.Reflect.decorate(decorators, target, key, desc); + } + else { + for (var i = decorators.length - 1; i >= 0; i--) { + if (d = decorators[i]) { + r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + } + } + } + return c > 3 && r && Object.defineProperty(target, key, r), r; + }; + + // 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; + } else { + return thiz; + } + }; + + var __extends = function (Child, Parent) { + var extendNativeClass = !!Parent.extend && (Parent.extend.toString().indexOf("[native code]") > -1); + if (!extendNativeClass) { + __extends_ts(Child, Parent); + return; + } + 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; + }; + + 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); + } + + assignPrototypeFromParentToChild(parent, child); + }; + + var extendStaticFunctions = + Object.setPrototypeOf + || (hasInternalProtoProperty() && function (child, parent) { child.__proto__ = parent; }) + || assignPropertiesFromParentToChild; + + 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) + extended.name = className; + return extended; + }; + } + + function Interfaces(interfacesArr) { + return function (target) { + if (interfacesArr instanceof Array) { + // attach interfaces: [] to the object + target.prototype.interfaces = interfacesArr; + } + } + } + + Object.defineProperty(global, "__native", { value: __native }); + Object.defineProperty(global, "__extends", { value: __extends }); + Object.defineProperty(global, "__decorate", { value: __decorate }); + + global.JavaProxy = JavaProxy; + global.Interfaces = Interfaces; +})() \ No newline at end of file diff --git a/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case2/app/normal_ts_extends.js b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case2/app/normal_ts_extends.js new file mode 100644 index 00000000..c9f2009a --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case2/app/normal_ts_extends.js @@ -0,0 +1,59 @@ +var __swc_crazy_long_line_swc_inherit_polyfill = { + _: () => {} +} +var _Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__ = { + _: () => {} +} + +var _swc_helpers_possible_constructor_return__WEBPACK_IMPORTED_MODULE_4__ = { + _: () => {} +} + +var _swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__ = { + _: () => {} +} + +var _swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__ = { + _: () => {} +} + +var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__ = { + __decorate: () => {} +} + +var ClickListener = /*#__PURE__*/ function(_java_lang_Object) { + "use strict"; + __swc_crazy_long_line_swc_inherit_polyfill._(ClickListener, _java_lang_Object); + function ClickListener() { + (0,_swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__._)(this, ClickListener); + var _this; + _this = (0,_Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__._)(this, ClickListener); + // necessary when extending TypeScript constructors + return (0,_swc_helpers_possible_constructor_return__WEBPACK_IMPORTED_MODULE_4__._)(_this, global.__native(_this)); + } + (0,_swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__._)(ClickListener, [ + { + key: "onClick", + value: function onClick(view) { + console.log("Button clicked!"); + } + }, + { + key: "onDone", + value: function onClick(view) { + console.log("Button clicked!"); + } + } + ]); + return ClickListener; +}(java.lang.Object); + +ClickListener = (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__decorate)([ + NativeClass, + Interfaces([ + android.view.View.OnClickListener + ]), + (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__metadata)("design:type", Function), + (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__metadata)("design:paramtypes", []) +], ClickListener); +var myObj = new MyObject("world"); diff --git a/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case2/internal/ts_helpers.js b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case2/internal/ts_helpers.js new file mode 100644 index 00000000..1a0625f4 --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case2/internal/ts_helpers.js @@ -0,0 +1,175 @@ +(function () { + + var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length; + var r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + + if (typeof global.Reflect === "object" && typeof global.Reflect.decorate === "function") { + r = global.Reflect.decorate(decorators, target, key, desc); + } + else { + for (var i = decorators.length - 1; i >= 0; i--) { + if (d = decorators[i]) { + r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + } + } + } + return c > 3 && r && Object.defineProperty(target, key, r), r; + }; + + // 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; + } else { + return thiz; + } + }; + + var __extends = function (Child, Parent) { + var extendNativeClass = !!Parent.extend && (Parent.extend.toString().indexOf("[native code]") > -1); + if (!extendNativeClass) { + __extends_ts(Child, Parent); + return; + } + 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; + }; + + 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); + } + + assignPrototypeFromParentToChild(parent, child); + }; + + var extendStaticFunctions = + Object.setPrototypeOf + || (hasInternalProtoProperty() && function (child, parent) { child.__proto__ = parent; }) + || assignPropertiesFromParentToChild; + + 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) + extended.name = className; + return extended; + }; + } + + function Interfaces(interfacesArr) { + return function (target) { + if (interfacesArr instanceof Array) { + // attach interfaces: [] to the object + target.prototype.interfaces = interfacesArr; + } + } + } + + Object.defineProperty(global, "__native", { value: __native }); + Object.defineProperty(global, "__extends", { value: __extends }); + Object.defineProperty(global, "__decorate", { value: __decorate }); + + global.JavaProxy = JavaProxy; + global.Interfaces = Interfaces; +})() \ No newline at end of file diff --git a/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case3/app/normal_ts_extends.js b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case3/app/normal_ts_extends.js new file mode 100644 index 00000000..421251e1 --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case3/app/normal_ts_extends.js @@ -0,0 +1,56 @@ +var __swc_crazy_long_line_swc_inherit_polyfill = () => {} + +var _Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__ = { + _: () => {} +} + +var _swc_helpers_possible_constructor_return__WEBPACK_IMPORTED_MODULE_4__ = { + _: () => {} +} + +var _swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__ = { + _: () => {} +} + +var _swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__ = { + _: () => {} +} + +var _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__ = () => {} + +var ClickListener = /*#__PURE__*/ function(_java_lang_Object) { + "use strict"; + __swc_crazy_long_line_swc_inherit_polyfill(ClickListener, _java_lang_Object); + function ClickListener() { + (0,_swc_helpers_class_call_check__WEBPACK_IMPORTED_MODULE_2__._)(this, ClickListener); + var _this; + _this = (0,_Users_ammarahmed_Downloads_ns_vue_rspack_nativescript_rspack_dist_helpers_swc_call_super_polyfill_js__WEBPACK_IMPORTED_MODULE_0__._)(this, ClickListener); + // necessary when extending TypeScript constructors + return (0,_swc_helpers_possible_constructor_return__WEBPACK_IMPORTED_MODULE_4__._)(_this, global.__native(_this)); + } + (0,_swc_helpers_create_class__WEBPACK_IMPORTED_MODULE_5__._)(ClickListener, [ + { + key: "onClick", + value: function onClick(view) { + console.log("Button clicked!"); + } + }, + { + key: "onDone", + value: function onClick(view) { + console.log("Button clicked!"); + } + } + ]); + return ClickListener; +}(java.lang.Object); + +ClickListener = _swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__([ + NativeClass, + Interfaces([ + android.view.View.OnClickListener + ]), + (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__metadata)("design:type", Function), + (0,_swc_helpers_ts_decorate__WEBPACK_IMPORTED_MODULE_6__.__metadata)("design:paramtypes", []) +], ClickListener); +var myObj = new MyObject("world"); diff --git a/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case3/internal/ts_helpers.js b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case3/internal/ts_helpers.js new file mode 100644 index 00000000..1a0625f4 --- /dev/null +++ b/test-app/build-tools/jsparser/tests/cases/extends_with_interfaces_ts_swc_case3/internal/ts_helpers.js @@ -0,0 +1,175 @@ +(function () { + + var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length; + var r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + + if (typeof global.Reflect === "object" && typeof global.Reflect.decorate === "function") { + r = global.Reflect.decorate(decorators, target, key, desc); + } + else { + for (var i = decorators.length - 1; i >= 0; i--) { + if (d = decorators[i]) { + r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + } + } + } + return c > 3 && r && Object.defineProperty(target, key, r), r; + }; + + // 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; + } else { + return thiz; + } + }; + + var __extends = function (Child, Parent) { + var extendNativeClass = !!Parent.extend && (Parent.extend.toString().indexOf("[native code]") > -1); + if (!extendNativeClass) { + __extends_ts(Child, Parent); + return; + } + 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; + }; + + 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); + } + + assignPrototypeFromParentToChild(parent, child); + }; + + var extendStaticFunctions = + Object.setPrototypeOf + || (hasInternalProtoProperty() && function (child, parent) { child.__proto__ = parent; }) + || assignPropertiesFromParentToChild; + + 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) + extended.name = className; + return extended; + }; + } + + function Interfaces(interfacesArr) { + return function (target) { + if (interfacesArr instanceof Array) { + // attach interfaces: [] to the object + target.prototype.interfaces = interfacesArr; + } + } + } + + Object.defineProperty(global, "__native", { value: __native }); + Object.defineProperty(global, "__extends", { value: __extends }); + Object.defineProperty(global, "__decorate", { value: __decorate }); + + global.JavaProxy = JavaProxy; + global.Interfaces = Interfaces; +})() \ No newline at end of file diff --git a/test-app/build-tools/jsparser/tests/run-tests.js b/test-app/build-tools/jsparser/tests/run-tests.js index 91147959..668390a8 100644 --- a/test-app/build-tools/jsparser/tests/run-tests.js +++ b/test-app/build-tools/jsparser/tests/run-tests.js @@ -1,11 +1,19 @@ +let fs; +try { + fs = require('fs'); +} catch (e) { + +} (function () { let { spawnSync, execSync } = require('child_process'); - console.log("Installing JavaScript parser test dependencies."); + if (!fs.existsSync('node_modules')) { + console.log("Installing JavaScript parser test dependencies."); - let npmInstallResult = execSync('npm install'); + let npmInstallResult = execSync('npm install'); - console.log(npmInstallResult.toString()); + console.log(npmInstallResult.toString()); + } console.log("Executing JavaScript parser tests using Jasmine."); diff --git a/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js b/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js index b8030989..24471d1a 100644 --- a/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js +++ b/test-app/build-tools/jsparser/tests/specs/ast-parser-tests.spec.js @@ -15,7 +15,6 @@ function execGradle(inputPath, generatedJavaClassesRoot, callback) { } function logExecResult(stdout, stderr) { - // console.log(`stdout: ${stdout}`); if (stderr) { console.log(`stderr: ${stderr}`); } @@ -206,6 +205,116 @@ describe("parser/js_parser tests", function () { }); }); + it("SWC: Generate valid metadata for bindings from a transpiled typescript file where multiple interfaces are implemented using a decorator", function (done) { + let input = path.normalize(path.join(prefix, "extends_with_interfaces_ts_swc", "app")), + generatedJavaClassesRoot = path.normalize(path.join(prefix, "extends_with_interfaces_ts_swc", "src", "main", "java")); + + clearOutput(); + + execGradle(input, generatedJavaClassesRoot, function (error, stdout, stderr) { + if (error) { + console.error(`exec error: ${error}`); + return done.fail(error); + } + + logExecResult(stdout, stderr) + + let bindingsContent = fs.readFileSync(sbgBindingOutoutFile, "utf-8").toString().trim().split('\n'); + + let bindings = bindingsContent[0].split('*'); + let implInterfacesStr = bindings[bindings.length - 1]; + + expect(implInterfacesStr).toBeDefined(); + expect(implInterfacesStr.length).toBeGreaterThan(0); + + let implInterfaces = implInterfacesStr.split(','); + + let expectedInterfaces = [ + "android.view.View.OnClickListener" + ]; + + for (let i in expectedInterfaces) { + expect(implInterfaces.indexOf(expectedInterfaces[i])).toBeGreaterThan(-1); + } + + done(); + }); + }); + + it("SWC: Generate valid metadata for bindings from a transpiled typescript file where multiple interfaces are implemented using a decorator", function (done) { + let input = path.normalize(path.join(prefix, "extends_with_interfaces_ts_swc_case2", "app")), + generatedJavaClassesRoot = path.normalize(path.join(prefix, "extends_with_interfaces_ts_swc_case2", "src", "main", "java")); + + clearOutput(); + + execGradle(input, generatedJavaClassesRoot, function (error, stdout, stderr) { + if (error) { + console.error(`exec error: ${error}`); + return done.fail(error); + } + + logExecResult(stdout, stderr) + + let bindingsContent = fs.readFileSync(sbgBindingOutoutFile, "utf-8").toString().trim().split('\n'); + + let bindings = bindingsContent[0].split('*'); + let implInterfacesStr = bindings[bindings.length - 1]; + + + expect(implInterfacesStr).toBeDefined(); + expect(implInterfacesStr.length).toBeGreaterThan(0); + + let implInterfaces = implInterfacesStr.split(','); + + let expectedInterfaces = [ + "android.view.View.OnClickListener" + ]; + + for (let i in expectedInterfaces) { + expect(implInterfaces.indexOf(expectedInterfaces[i])).toBeGreaterThan(-1); + } + + done(); + }); + }); + + it("SWC: Generate valid metadata for bindings from a transpiled typescript file where multiple interfaces are implemented using a decorator", function (done) { + let input = path.normalize(path.join(prefix, "extends_with_interfaces_ts_swc_case3", "app")), + generatedJavaClassesRoot = path.normalize(path.join(prefix, "extends_with_interfaces_ts_swc_case3", "src", "main", "java")); + + clearOutput(); + + execGradle(input, generatedJavaClassesRoot, function (error, stdout, stderr) { + if (error) { + console.error(`exec error: ${error}`); + return done.fail(error); + } + + logExecResult(stdout, stderr) + + let bindingsContent = fs.readFileSync(sbgBindingOutoutFile, "utf-8").toString().trim().split('\n'); + + let bindings = bindingsContent[0].split('*'); + let implInterfacesStr = bindings[bindings.length - 1]; + + + expect(implInterfacesStr).toBeDefined(); + expect(implInterfacesStr.length).toBeGreaterThan(0); + + let implInterfaces = implInterfacesStr.split(','); + + let expectedInterfaces = [ + "android.view.View.OnClickListener", + ]; + + for (let i in expectedInterfaces) { + expect(implInterfaces.indexOf(expectedInterfaces[i])).toBeGreaterThan(-1); + } + + done(); + }); + }); + it("Generated metadata for bindings should return proper JavaClass name despite emitted TS ES5 code", function (done) { let input = path.normalize(path.join(prefix, "decorated_extends_ts", "app")), generatedJavaClassesRoot = path.normalize(path.join(prefix, "decorated_extends_ts", "src", "main", "java")); @@ -266,6 +375,44 @@ describe("parser/js_parser tests", function () { expect(bindingsContent.length).toBe(1); + + for (let line of bindingsContent) { + var lineParts = line.split("*"); + var tsExtendsPart = lineParts[1]; + expect(tsExtendsPart).toBeFalsy(); + + var newClassNamePart = lineParts[6]; + expect(newClassNames).toContain(newClassNamePart); + } + + done(); + }); + }); + + it("SWC: Generated metadata for bindings should return proper JavaClass name when there is a static property and double assignment", function (done) { + let input = path.normalize(path.join(prefix, "decorated_double_assignment_ts_swc", "app")), + generatedJavaClassesRoot = path.normalize(path.join(prefix, "decorated_double_assignment_ts_swc", "src", "main", "java")); + + const newClassNames = [ + "org.nativescript.MyCustomActivity", + ]; + + clearOutput(); + + execGradle(input, generatedJavaClassesRoot, function (error, stdout, stderr) { + if (error) { + console.error(`exec error: ${error}`); + return done.fail(error); + } + + logExecResult(stdout, stderr) + + let bindingsContent = fs.readFileSync(sbgBindingOutoutFile, "utf-8").toString().trim().split('\n'); + + expect(bindingsContent.length).toBe(1); + + + for (let line of bindingsContent) { var lineParts = line.split("*"); var tsExtendsPart = lineParts[1]; diff --git a/test-app/build-tools/jsparser/visitors/es5-visitors.js b/test-app/build-tools/jsparser/visitors/es5-visitors.js index f78d1d9a..2648eac8 100644 --- a/test-app/build-tools/jsparser/visitors/es5-visitors.js +++ b/test-app/build-tools/jsparser/visitors/es5-visitors.js @@ -1,558 +1,888 @@ -var es5_visitors = (function() { - - var types = require("@babel/types"), - - defaultExtendDecoratorName = "JavaProxy", - columnOffset = 1, - ASTERISK_SEPARATOR = "*", - customExtendsArr = [], - normalExtendsArr = [], - interfacesArr = [], - UNSUPPORTED_TYPESCRIPT_EXTEND_FORMAT_MESSAGE = "[WARN] TypeScript-extended class has a super() call in an unsupported format.", - - customExtendsArrGlobal = []; - - /* ENTRY POINT! - * Traverses each passed node with several visitors. - * Result from visit can be got from static methods. - * - * Input parameters: - * path - node to visit - * config - filename, decorator name ... - */ - function es5Visitor(path, config) { - - if (!config.filePath) { - config.filePath = "No file path provided"; - } - - if (path.node.skipMeOnVisit) { - return; - } - - // ES5 Syntax - // anchor is extend (normal extend pattern + custom extend pattern) - if (types.isMemberExpression(path) && path.node.property.name === "extend") { - traverseEs5Extend(path, config); - } - - //anchor is new keyword (interface pattern) - if (types.isNewExpression(path)) { - traverseInterface(path, config); - } - - // // Parsed Typescript to ES5 Syntax (normal extend pattern + custom extend pattern) - // // anchor is __extends - if (types.isIdentifier(path) && path.node.name === "__extends") { - traverseTsExtend(path, config); - } - // Maybe it's not a good idea to expose this scenario because it can be explicitly covered - // //anchor is JavaProxy (optional) - // var customDecoratorName = config.extendDecoratorName === undefined ? defaultExtendDecoratorName : config.extendDecoratorName; - // if(t.isIdentifier(path) && path.node.name === customDecoratorName) { - // if(path.node.skipMeOnVisit) { - // return; - // } - // console.log("enters because there is a java proxy down the way") - // traverseJavaProxyExtend(path, config, customDecoratorName); - // } - +var es5_visitors = (function () { + var types = require("@babel/types"), + defaultExtendDecoratorName = "JavaProxy", + columnOffset = 1, + ASTERISK_SEPARATOR = "*", + customExtendsArr = [], + normalExtendsArr = [], + interfacesArr = [], + UNSUPPORTED_TYPESCRIPT_EXTEND_FORMAT_MESSAGE = + "[WARN] TypeScript-extended class has a super() call in an unsupported format.", + customExtendsArrGlobal = []; + + /* ENTRY POINT! + * Traverses each passed node with several visitors. + * Result from visit can be got from static methods. + * + * Input parameters: + * path - node to visit + * config - filename, decorator name ... + */ + function es5Visitor(path, config) { + if (!config.filePath) { + config.filePath = "No file path provided"; } - /* - * Returns the custom extends array generated from visitor - */ - es5Visitor.getProxyExtendInfo = function() { - var res = customExtendsArr.slice(); - customExtendsArr = []; - return res; + if (path.node.skipMeOnVisit) { + return; } - /* - * Returns the common extends array generated from visitor - */ - es5Visitor.getCommonExtendInfo = function() { - var res = []; - for (var index in normalExtendsArr) { - if (normalExtendsArr[index][0] !== "*") { - res.push(normalExtendsArr[index]); - } - } - - normalExtendsArr = []; - return res; + // ES5 Syntax + // anchor is extend (normal extend pattern + custom extend pattern) + if ( + types.isMemberExpression(path) && + path.node.property.name === "extend" + ) { + traverseEs5Extend(path, config); } - /* - * Returns the extended interfaces array generated from visitor - */ - es5Visitor.getInterfaceInfo = function() { - var res = interfacesArr.slice(); - interfacesArr = []; - return res; + //anchor is new keyword (interface pattern) + if (types.isNewExpression(path)) { + traverseInterface(path, config); } - /* - * Traverses the typescript extend case (__extends()) - * Write results in "normalExtendsArr" or "customExtendsArr". - */ - function traverseTsExtend(path, config) { - // information for normal extend (unnamed) - var extendClass; - try { - extendClass = _getArgumentFromNodeAsString(path, 5, config) - } catch (e) { - config.logger.warn(e.message) - return; - } - - var overriddenMethodNames = _getOverriddenMethodsTypescript(path, 3); + // // Parsed Typescript to ES5 Syntax (normal extend pattern + custom extend pattern) + // // anchor is __extends + if (types.isIdentifier(path) && path.node.name === "__extends") { + traverseTsExtend(path, config); + } - var extendPath = _getParent(path, 3, config); - var declaredClassName = ""; + if ( + types.isIdentifier(path) && + path.node.name.includes("swc_inherit_polyfill") && + (types.isMemberExpression(path.container) || + types.isCallExpression(path.container)) + ) { + traverseTsInherit(path, config); + } - var typescriptClassExtendSuperCallLocation = getTypeScriptExtendSuperCallLocation(extendPath, config); - var extendParent = _getParent(path, 1, config); + // Maybe it's not a good idea to expose this scenario because it can be explicitly covered + // //anchor is JavaProxy (optional) + // var customDecoratorName = config.extendDecoratorName === undefined ? defaultExtendDecoratorName : config.extendDecoratorName; + // if(t.isIdentifier(path) && path.node.name === customDecoratorName) { + // if(path.node.skipMeOnVisit) { + // return; + // } + // console.log("enters because there is a java proxy down the way") + // traverseJavaProxyExtend(path, config, customDecoratorName); + // } + } + + /* + * Returns the custom extends array generated from visitor + */ + es5Visitor.getProxyExtendInfo = function () { + var res = customExtendsArr.slice(); + customExtendsArr = []; + return res; + }; + + /* + * Returns the common extends array generated from visitor + */ + es5Visitor.getCommonExtendInfo = function () { + var res = []; + for (var index in normalExtendsArr) { + if (normalExtendsArr[index][0] !== "*") { + res.push(normalExtendsArr[index]); + } + } - if (types.isCallExpression(extendParent)) { - declaredClassName = extendParent.node.arguments[0].name; - } + normalExtendsArr = []; + return res; + }; + + /* + * Returns the extended interfaces array generated from visitor + */ + es5Visitor.getInterfaceInfo = function () { + var res = interfacesArr.slice(); + interfacesArr = []; + return res; + }; + + /* + * Traverses the typescript extend case (__extends()) + * Write results in "normalExtendsArr" or "customExtendsArr". + */ + function traverseTsExtend(path, config) { + // information for normal extend (unnamed) + var extendClass; + try { + extendClass = _getArgumentFromNodeAsString(path, 5, config); + } catch (e) { + config.logger.warn(e.message); + return; + } - var decorateNodes = traverseForDecorate(path, config, 3); + var overriddenMethodNames = _getOverriddenMethodsTypescript(path, 3); - var isDecoratedWithExtend = false, - customExtendDecoratorName, - customExtendDecoratorValue, - implementedInterfaces = []; + var declaredClassName = ""; + var extendPath = _getParent(path, 3, config); + const location = getTypeScriptExtendSuperCallLocation(extendPath, config); + const line = location.line; + const column = location.column; - if (!decorateNodes) { - // 7 -> Takes 7 levels up to get to the scope where the class is declared - decorateNodes = traverseForDecorateSpecial(path, config, 7); - } + var extendParent = _getParent(path, 1, config); - if (decorateNodes) { - for (var i in decorateNodes) { - var currentDecorator = decorateNodes[i]; - if (types.isCallExpression(currentDecorator)) { - // Interfaces/Implements - if (currentDecorator.callee.name === config.interfacesDecoratorName) { - currentDecorator.callee.skipMeOnVisit = true; - - var interfaces = currentDecorator.arguments[0].elements; + if (types.isCallExpression(extendParent)) { + declaredClassName = extendParent.node.arguments[0].name; + } - for (var i in interfaces) { - var interfaceName = _getWholeInterfaceNameFromInterfacesNode(interfaces[i]); - implementedInterfaces.push(interfaceName); - } - } + var decorateNodes = traverseForDecorate(path, config, 3); - // JavaProxy - if (currentDecorator.callee.name === config.extendDecoratorName) { - currentDecorator.callee.skipMeOnVisit = true; + var isDecoratedWithExtend = false, + customExtendDecoratorName, + customExtendDecoratorValue, + implementedInterfaces = []; - isDecoratedWithExtend = true; + if (!decorateNodes) { + // 7 -> Takes 7 levels up to get to the scope where the class is declared + decorateNodes = traverseForDecorateSpecial(path, config, 7); + } - customExtendDecoratorName = config.extendDecoratorName === undefined ? defaultExtendDecoratorName : config.extendDecoratorName; - customExtendDecoratorValue = currentDecorator.arguments[0].value; - } - } + if (decorateNodes) { + for (var i in decorateNodes) { + var currentDecorator = decorateNodes[i]; + if (types.isCallExpression(currentDecorator)) { + // Interfaces/Implements + if (currentDecorator.callee.name === config.interfacesDecoratorName) { + currentDecorator.callee.skipMeOnVisit = true; + + var interfaces = currentDecorator.arguments[0].elements; + + for (var i in interfaces) { + var interfaceName = _getWholeInterfaceNameFromInterfacesNode( + interfaces[i] + ); + implementedInterfaces.push(interfaceName); } - } + } - if (isDecoratedWithExtend) { - traverseJavaProxyExtend(customExtendDecoratorValue, config, customExtendDecoratorName, extendClass, overriddenMethodNames, implementedInterfaces); - } else { - var lineToWrite; + // JavaProxy + if (currentDecorator.callee.name === config.extendDecoratorName) { + currentDecorator.callee.skipMeOnVisit = true; - lineToWrite = _generateLineToWrite("", extendClass, overriddenMethodNames, { file: config.filePath, line: typescriptClassExtendSuperCallLocation.line, column: typescriptClassExtendSuperCallLocation.column, className: declaredClassName }, "", implementedInterfaces); + isDecoratedWithExtend = true; - if (config.logger) { - config.logger.info(lineToWrite) - } - - normalExtendsArr.push(lineToWrite); + customExtendDecoratorName = + config.extendDecoratorName === undefined + ? defaultExtendDecoratorName + : config.extendDecoratorName; + customExtendDecoratorValue = currentDecorator.arguments[0].value; + } } + } } - function getTypeScriptExtendSuperCallLocation(extendPath, config) { - var constructorFunctionName; - var returnIdentifierName; - var superCalleeStartColumn; - var superCalleeLine; - var locationAssigned = false; - - // checks if constructor function and return identifiers match in a transpiled typescript class extend - if (extendPath.node.body && extendPath.node.body.length >= 3) { - if (types.isFunctionDeclaration(extendPath.node.body[1]) && extendPath.node.body[1].id) - constructorFunctionName = extendPath.node.body[1].id.name; - if (types.isReturnStatement(extendPath.node.body[extendPath.node.body.length - 1])) - returnIdentifierName = extendPath.node.body[extendPath.node.body.length - 1].argument.name; + if (isDecoratedWithExtend) { + traverseJavaProxyExtend( + customExtendDecoratorValue, + config, + customExtendDecoratorName, + extendClass, + overriddenMethodNames, + implementedInterfaces + ); + } else { + var lineToWrite; + + lineToWrite = _generateLineToWrite( + "", + extendClass, + overriddenMethodNames, + { + file: config.filePath, + line: line, + column: column + 1, + className: declaredClassName, + }, + "", + implementedInterfaces + ); + + if (config.logger) { + config.logger.info(lineToWrite); + } + + normalExtendsArr.push(lineToWrite); + } + } + + function traverseTsInherit(path, config) { + // information for normal extend (unnamed) + let defaultDepth = 5; + var extendClass; + try { + // externalHelpers = false; + // _inherits() + extendClass = _getArgumentFromNodeAsString(path, defaultDepth, config); + } catch (e) { + defaultDepth += 1; + try { + // externalHelpers = true; + // swc_inherit_polyfill._() + extendClass = _getArgumentFromNodeAsString(path, defaultDepth, config); + } catch (e) { + defaultDepth += 1; + try { + // externalHelpers = true case 2 + // (0,swc_inherit_polyfill._)() + extendClass = _getArgumentFromNodeAsString( + path, + defaultDepth, + config + ); + } catch (e) { + config.logger.warn(e.message); + return; } + } + } - // checks the typescript-extended class for a strict format, and a super call/apply inside - /** - * function MyBtn() { - var _this = _super.call(this) || this; - return global.__native(_this); - } + var extendPath = _getParent(path, defaultDepth - 2, config); + const location = getTypeScriptExtendSuperCallLocation(extendPath, config); + const line = location.line; + const column = location.column; + + var overriddenMethodNames = []; + + try { + const parentPath = _getParent(path, defaultDepth - 2, config); + const create_class_properties = + parentPath.node.body[2].expression.arguments[1].elements; + for (const element of create_class_properties) { + overriddenMethodNames.push(element.properties[0].value.value); + } + } catch (e) { + config.logger.warn(e.message); + return; + } - **UGLIFIED extended class** + var declaredClassName = ""; + var extendParent = _getParent(path, defaultDepth - 4, config); - function t(t) { - var r = e.call(this) || this; - r.textBase = t; - return global.__native(r); - } - */ - if (constructorFunctionName === returnIdentifierName && !!constructorFunctionName) { - var constructorFunctionScope = extendPath.node.body[1]; - // the 'super' variable will always be passed as the second argument to the __extends call - // try to find the 'super' identifier which may be uglified - var superVariableIdentifier = getSuperVariableIdentifier(extendPath.node.body[0]); - - //// helper functions to find the correct super.call(this) node - function getSuperVariableIdentifier(__extendsNode) { - if (types.isExpressionStatement(__extendsNode) && types.isCallExpression(__extendsNode.expression)) { - var __extendsCallArguments = __extendsNode.expression.arguments; - if (__extendsCallArguments.length == 2) { - return __extendsCallArguments[1].name; - } - } - } + if (types.isCallExpression(extendParent)) { + declaredClassName = extendParent.node.arguments[0].name; + } - /** Getting the super.call node from assignment - if expressionStatement => check possibleExpressionStatements[0] - if possibleExpressionStatements[0].expression is assignment expression - if possibleExpressionStatements[0].expression.right is logical expression - if possibleExpressionStatements[0].expression.right.left is Call expression - if possibleExpressionStatements[0].expression.right.left.callee.object.name === superVariableIdentifier - if the above is valid, then variableRHS = possibleVariableDeclarations[0].expression.right.left - */ - function getThisAssignmentSuperCallLineNode(nodes, superIdentifier) { - var matchingNodes = nodes.filter( - (node) => { - return types.isAssignmentExpression(node.expression) && - types.isLogicalExpression(node.expression.right) && - types.isCallExpression(node.expression.right.left) && - node.expression.right.left.callee.object.name === superIdentifier; - }); - - return matchingNodes.length > 0 ? matchingNodes[0].expression.right.left : null; + const extendParentScope = _getParent(path, defaultDepth + 2, config); + + var isDecoratedWithExtend = false, + customExtendDecoratorName, + customExtendDecoratorValue, + implementedInterfaces = []; + + try { + for (let define of extendParentScope.container) { + if ( + types.isExpressionStatement(define) && + types.isAssignmentExpression(define.expression) && + define.expression.left.name === declaredClassName && + types.isCallExpression(define.expression.right) + ) { + const decoratedNodes = define.expression.right.arguments[0]; + for (let i = 0; i < decoratedNodes.elements.length; i++) { + const current = decoratedNodes.elements[i]; + if ( + types.isCallExpression(current) && + current.callee.name === config.interfacesDecoratorName + ) { + const interfaces = current.arguments[0].elements; + for (let i = 0; i < interfaces.length; i++) { + implementedInterfaces.push( + _getWholeInterfaceNameFromInterfacesNode(interfaces[i]) + ); + } } - /** Getting the super.call node from declaration - if variableDeclaration => check possibleVariableDeclarations[0].declarations[0].init isn't null - if possibleNodesForSuperCall[0].declarations[0].init is logical expression - if possibleNodesForSuperCall[0].declarations[0].init.left is Call Expression - if possibleNodesForSuperCall[0].declarations[0].init.left.callee.object.name === superVariableIdentifier - if the above is valid, then variableRHS = possibleVariableDeclarations[0].declarations[0].init.left - */ - function getThisDeclarationSuperCallLineNode(nodes, superIdentifier) { - var matchingNodes = nodes.filter( - (node) => { - return types.isLogicalExpression(node.declarations[0].init) && - types.isCallExpression(node.declarations[0].init.left) && - node.declarations[0].init.left.callee.object.name === superIdentifier; - }); - - return matchingNodes.length > 0 ? matchingNodes[0].declarations[0].init.left : null; - } - //// - - if (superVariableIdentifier) { - var possibleVariableDeclarations = []; - var possibleExpressionStatements = []; - - constructorFunctionScope.body.body.forEach(node => { - if (types.isVariableDeclaration(node)) { - possibleVariableDeclarations.push(node); - } else if (types.isExpressionStatement(node)) { - possibleExpressionStatements.push(node); - } - }); - - if (possibleVariableDeclarations.length > 0 || possibleExpressionStatements.length > 0) { - var superCallRHS = getThisDeclarationSuperCallLineNode(possibleVariableDeclarations, superVariableIdentifier) || - getThisAssignmentSuperCallLineNode(possibleExpressionStatements, superVariableIdentifier); - - if (superCallRHS) { - var superCallee = superCallRHS.callee.property; - superCalleeStartColumn = superCallee.loc.start.column + 1; - superCalleeLine = superCallee.loc.start.line; - - locationAssigned = true; - } - } + if ( + types.isCallExpression(current) && + current.callee.name === config.extendDecoratorName + ) { + isDecoratedWithExtend = true; + customExtendDecoratorName = + config.extendDecoratorName === undefined + ? defaultExtendDecoratorName + : config.extendDecoratorName; + customExtendDecoratorValue = current.arguments[0].value; } + } } - - if (!locationAssigned) { - config.logger.info(UNSUPPORTED_TYPESCRIPT_EXTEND_FORMAT_MESSAGE + " ctor function name: " + constructorFunctionName); - } - - return { - line: superCalleeLine, - column: superCalleeStartColumn - }; + } + } catch (e) { + config.logger.warn(e.message); + return; } - function traverseForDecorate(path, config, depth) { - var iifeRoot = _getParent(path, depth) - var body = iifeRoot.node.body; - for (var index in body) { - var ci = body[index]; - if (isDecorateStatement(ci)) { - // returns the node of the decorate (node.expression.right.callee) - // __decorate([..]) - return getRightExpression(ci.expression).arguments[0].elements; - } - } - - return null; + if (isDecoratedWithExtend) { + traverseJavaProxyExtend( + customExtendDecoratorValue, + config, + customExtendDecoratorName, + extendClass, + overriddenMethodNames, + implementedInterfaces + ); + } else { + var lineToWrite; + + lineToWrite = _generateLineToWrite( + "", + extendClass, + overriddenMethodNames, + { + file: config.filePath, + line: line, + column: column + 1, + className: declaredClassName, + }, + "", + implementedInterfaces + ); + + if (config.logger) { + config.logger.info(lineToWrite); + } + + normalExtendsArr.push(lineToWrite); + console.log(lineToWrite); + } + } + + function traverseForDecorate(path, config, depth) { + var iifeRoot = _getParent(path, depth); + var body = iifeRoot.node.body; + for (var index in body) { + var ci = body[index]; + if (isDecorateStatement(ci)) { + // returns the node of the decorate (node.expression.right.callee) + // __decorate([..]) + return getRightExpression(ci.expression).arguments[0].elements; + } } - function traverseForDecorateSpecial(path, config, depth) { - var iifeRoot = _getParent(path, depth); + return null; + } - var sibling = iifeRoot.getSibling(iifeRoot.key + 1).node; - if (sibling) { - if (isDecorateStatement(sibling)) { - // returns the node of the decorate (node.expression.right.callee) - // __decorate([..]) - return getRightExpression(sibling.expression).arguments[0].elements; - } - } + function traverseForDecorateSpecial(path, config, depth) { + var iifeRoot = _getParent(path, depth); - return null; + var sibling = iifeRoot.getSibling(iifeRoot.key + 1).node; + if (sibling) { + if (isDecorateStatement(sibling)) { + // returns the node of the decorate (node.expression.right.callee) + // __decorate([..]) + return getRightExpression(sibling.expression).arguments[0].elements; + } } - function getRightExpression(expression) { - if(!expression) { - return null; - } - var rightExpression = expression.right; - // if the right expression is a new assignment, get the right expression from that assignment - while (types.isAssignmentExpression(rightExpression)) { - rightExpression = rightExpression.right; - } - return rightExpression; + return null; + } + + function getRightExpression(expression) { + if (!expression) { + return null; + } + var rightExpression = expression.right; + // if the right expression is a new assignment, get the right expression from that assignment + while (types.isAssignmentExpression(rightExpression)) { + rightExpression = rightExpression.right; + } + return rightExpression; + } + + function isDecorateStatement(node) { + var rightExpression = getRightExpression(node.expression); + return ( + types.isExpressionStatement(node) && + types.isAssignmentExpression(node.expression) && + rightExpression.callee && + rightExpression.callee.name === "__decorate" && + rightExpression.arguments && + types.isArrayExpression(rightExpression.arguments[0]) + ); + } + + /* + * Traverses the node, which is a "new" expression and find if it's a native interface or not. + * Write results in "interfacesArr". + */ + function traverseInterface(path, config) { + if (!config.interfaceNames) { + throw "JSParser Error: No interface names are provided! You can pass them in config.interfaceNames as an array!"; } - function isDecorateStatement(node) { - var rightExpression = getRightExpression(node.expression); - return types.isExpressionStatement(node) && - types.isAssignmentExpression(node.expression) && - rightExpression.callee && - rightExpression.callee.name === "__decorate" && - rightExpression.arguments && - types.isArrayExpression(rightExpression.arguments[0]) + var o = path.node.callee, + interfaceArr = _getWholeName(o), + foundInterface = false, + interfaceNames = config.interfaceNames; + + var currentInterface = interfaceArr.reverse().join("."); + for (var i in interfaceNames) { + var interfaceName = interfaceNames[i].trim(); + if (interfaceName === currentInterface) { + currentInterface = interfaceName; + foundInterface = true; + break; + } } - /* - * Traverses the node, which is a "new" expression and find if it's a native interface or not. - * Write results in "interfacesArr". - */ - function traverseInterface(path, config) { - if (!config.interfaceNames) { - throw "JSParser Error: No interface names are provided! You can pass them in config.interfaceNames as an array!" - } + if (foundInterface) { + var arg0 = "", + arg1; + if (path.node.arguments.length === 1) { + arg1 = path.node.arguments[0]; + } else if (path.node.arguments.length === 2) { + arg0 = path.node.arguments[0]; + arg1 = path.node.arguments[1]; + } else { + throw { + message: + "JSParser Error: Not enough or too many arguments passed(" + + path.node.arguments.length + + ") when trying to extend interface: " + + interfaceName + + " in file: " + + config.fullPathName, + errCode: 1, + }; + } + + var isCorrectInterfaceName = _testClassName(arg0.value); + var overriddenInterfaceMethods = _getOverriddenMethods(arg1, config); + var extendInfo = { + file: config.filePath, + line: path.node.loc.start.line, + column: path.node.loc.start.column + columnOffset, + className: isCorrectInterfaceName ? arg0.value : "", + }; + var lineToWrite = _generateLineToWrite( + "", + currentInterface, + overriddenInterfaceMethods.join(","), + extendInfo, + "" + ); + if (config.logger) { + config.logger.info(lineToWrite); + } + + interfacesArr.push(lineToWrite); + } + } + + /* + * Finds the java proxy name from custom class decorator. + * Write results in "customExtendsArr" + */ + function traverseJavaProxyExtend( + path, + config, + customDecoratorName, + extendClass, + overriddenMethodNames, + implementedInterfaces + ) { + if (config.logger) { + config.logger.info("\t+in " + customDecoratorName + " anchor"); + } - var o = path.node.callee, - interfaceArr = _getWholeName(o), - foundInterface = false, - interfaceNames = config.interfaceNames - - var currentInterface = interfaceArr.reverse().join("."); - for (var i in interfaceNames) { - var interfaceName = interfaceNames[i].trim(); - if (interfaceName === currentInterface) { - currentInterface = interfaceName; - foundInterface = true; - break; - } + var classNameFromDecorator = path; //_getDecoratorArgument(path, config, customDecoratorName); + + var lineToWrite = _generateLineToWrite( + classNameFromDecorator, + extendClass, + overriddenMethodNames, + "", + config.fullPathName, + implementedInterfaces + ); + if (config.logger) { + config.logger.info(lineToWrite); + } + addCustomExtend(classNameFromDecorator, config.fullPathName, lineToWrite); + } + + /* + * Finds the normal extend name, overridden methods and possibly java proxy name from passed node. + * Writes to "customExtendsArr" or "normalExtendsArr". + * Left whole for readability. + */ + function traverseEs5Extend(path, config) { + var callee = path.parent.callee; + + if (callee) { + var o = callee.object; + extendClass = _getWholeName(o); + + var extendArguments = path.parent.arguments; + var arg0, arg1; + if (extendArguments.length === 1 && types.isObjectExpression(arg0)) { + arg0 = extendArguments[0]; + } else if (types.isStringLiteral(arg0)) { + } + + var arg0 = "", + arg1; + if (extendArguments.length) { + // Get implementation object when there is only 1 argument + if ( + extendArguments.length === 1 && + types.isObjectExpression(extendArguments[0]) + ) { + arg1 = extendArguments[0]; } - - if (foundInterface) { - var arg0 = "", - arg1; - if (path.node.arguments.length === 1) { - arg1 = path.node.arguments[0]; - } else if (path.node.arguments.length === 2) { - arg0 = path.node.arguments[0]; - arg1 = path.node.arguments[1]; - } else { - throw { - message: "JSParser Error: Not enough or too many arguments passed(" + path.node.arguments.length + ") when trying to extend interface: " + interfaceName + " in file: " + config.fullPathName, - errCode: 1 - } - } - - var isCorrectInterfaceName = _testClassName(arg0.value); - var overriddenInterfaceMethods = _getOverriddenMethods(arg1, config); - var extendInfo = { - file: config.filePath, - line: path.node.loc.start.line, - column: path.node.loc.start.column + columnOffset, - className: (isCorrectInterfaceName ? arg0.value : "") - } - var lineToWrite = _generateLineToWrite("", currentInterface, overriddenInterfaceMethods.join(","), extendInfo, ""); - if (config.logger) { - config.logger.info(lineToWrite) - } - - interfacesArr.push(lineToWrite) + // Get the name of the extended class and the implementation object when both arguments are present + else if (extendArguments.length === 2) { + if ( + types.isStringLiteral(extendArguments[0]) && + types.isObjectExpression(extendArguments[1]) + ) { + arg0 = extendArguments[0]; + arg1 = extendArguments[1]; + } + } else { + // don't throw here, because there can be a valid js extend that has nothing to do with NS + return; + throw { + message: + "JSParser Error: Not enough or too many arguments passed(" + + extendArguments.length + + ") when trying to extend class: " + + extendClass + + " in file: " + + config.fullPathName, + errCode: 1, + }; } - } + } else { + // don't throw here, because there can be a valid js extend that has nothing to do with NS + return; + throw { + message: + "JSParser Error: You need to call the extend with parameters. Example: '...extend(\"a.b.C\", {...overrides...})') for class: " + + extendClass + + " in file: " + + config.fullPathName, + errCode: 1, + }; + } + + className = arg0.value ? arg0.value : ""; + + // Get all methods from the implementation object + var methodsAndInterfaces = _getOverridenMethodsAndImplementedInterfaces( + arg1, + config + ); + var overriddenMethodNames = methodsAndInterfaces[0]; + var implementedInterfaces = methodsAndInterfaces[1]; + + var isCorrectExtendClassName = _testJavaProxyName(className); + var isCorrectClassName = _testClassName(className); + if (className && !isCorrectClassName && !isCorrectExtendClassName) { + throw { + message: + "JSParser Error: The 'extend' you are trying to make has an invalid name. Example: '...extend(\"a.b.C\", {...overrides...})'), for class: " + + extendClass + + " file: " + + config.fullPathName, + errCode: 1, + }; + } - /* - * Finds the java proxy name from custom class decorator. - * Write results in "customExtendsArr" - */ - function traverseJavaProxyExtend(path, config, customDecoratorName, extendClass, overriddenMethodNames, implementedInterfaces) { + var lineToWrite = ""; + if (isCorrectExtendClassName) { if (config.logger) { - config.logger.info("\t+in " + customDecoratorName + " anchor"); + config.logger.info(lineToWrite); } - var classNameFromDecorator = path; //_getDecoratorArgument(path, config, customDecoratorName); - - var lineToWrite = _generateLineToWrite(classNameFromDecorator, extendClass, overriddenMethodNames, "", config.fullPathName, implementedInterfaces); - if (config.logger) { - config.logger.info(lineToWrite) - } - addCustomExtend(classNameFromDecorator, config.fullPathName, lineToWrite) + var classNameFromDecorator = isCorrectExtendClassName ? className : ""; + lineToWrite = _generateLineToWrite( + classNameFromDecorator, + extendClass.reverse().join("."), + overriddenMethodNames, + "", + config.fullPathName, + implementedInterfaces + ); + addCustomExtend( + classNameFromDecorator, + config.fullPathName, + lineToWrite + ); + + return; + } + + if (config.logger) { + config.logger.info(lineToWrite); + } + + var extendInfo = { + file: config.filePath, + line: config.isPrimJS + ? path.container.loc.end.line + : path.node.property.loc.start.line, + column: config.isPrimJS + ? path.container.loc.end.column + columnOffset + : path.node.property.loc.start.column + columnOffset, + className: className, + }; + lineToWrite = _generateLineToWrite( + isCorrectExtendClassName ? className : "", + extendClass.reverse().join("."), + overriddenMethodNames, + extendInfo, + "", + implementedInterfaces + ); + normalExtendsArr.push(lineToWrite); + } else { + // don't throw here, because there can be a valid js extend that has nothing to do with NS + return; + throw { + message: + "JSParser Error: You need to call the extend '...extend(\"extend_name\", {...overrides...})'), for class: " + + extendClass + + " file: " + + config.fullPathName, + errCode: 1, + }; + } + } + + /* + * HELPER METHODS + */ + + function getTypeScriptExtendSuperCallLocation(extendPath, config) { + var constructorFunctionName; + var returnIdentifierName; + var superCalleeStartColumn; + var superCalleeLine; + var locationAssigned = false; + + // checks if constructor function and return identifiers match in a transpiled typescript class extend + if (extendPath.node.body && extendPath.node.body.length >= 3) { + if ( + types.isFunctionDeclaration(extendPath.node.body[1]) && + extendPath.node.body[1].id + ) + constructorFunctionName = extendPath.node.body[1].id.name; + if ( + types.isReturnStatement( + extendPath.node.body[extendPath.node.body.length - 1] + ) + ) + returnIdentifierName = + extendPath.node.body[extendPath.node.body.length - 1].argument.name; } - /* - * Finds the normal extend name, overridden methods and possibly java proxy name from passed node. - * Writes to "customExtendsArr" or "normalExtendsArr". - * Left whole for readability. - */ - function traverseEs5Extend(path, config) { - var callee = path.parent.callee; - - if (callee) { - var o = callee.object - extendClass = _getWholeName(o); - - var extendArguments = path.parent.arguments; - var arg0, - arg1; - if (extendArguments.length === 1 && types.isObjectExpression(arg0)) { - arg0 = extendArguments[0]; - } else if (types.isStringLiteral(arg0)) { - - } - - var arg0 = "", - arg1; - if (extendArguments.length) { - // Get implementation object when there is only 1 argument - if (extendArguments.length === 1 && types.isObjectExpression(extendArguments[0])) { - arg1 = extendArguments[0]; - } - // Get the name of the extended class and the implementation object when both arguments are present - else if (extendArguments.length === 2) { - if (types.isStringLiteral(extendArguments[0]) && types.isObjectExpression(extendArguments[1])) { - arg0 = extendArguments[0]; - arg1 = extendArguments[1]; - } - } else { - // don't throw here, because there can be a valid js extend that has nothing to do with NS - return; - throw { - message: "JSParser Error: Not enough or too many arguments passed(" + extendArguments.length + ") when trying to extend class: " + extendClass + " in file: " + config.fullPathName, - errCode: 1 - } - } - } else { - // don't throw here, because there can be a valid js extend that has nothing to do with NS - return; - throw { - message: "JSParser Error: You need to call the extend with parameters. Example: '...extend(\"a.b.C\", {...overrides...})') for class: " + extendClass + " in file: " + config.fullPathName, - errCode: 1 - } - } - - className = arg0.value ? arg0.value : ""; - - // Get all methods from the implementation object - var methodsAndInterfaces = _getOverridenMethodsAndImplementedInterfaces(arg1, config); - var overriddenMethodNames = methodsAndInterfaces[0]; - var implementedInterfaces = methodsAndInterfaces[1]; - - var isCorrectExtendClassName = _testJavaProxyName(className); - var isCorrectClassName = _testClassName(className); - if (className && !isCorrectClassName && !isCorrectExtendClassName) { - throw { - message: "JSParser Error: The 'extend' you are trying to make has an invalid name. Example: '...extend(\"a.b.C\", {...overrides...})'), for class: " + extendClass + " file: " + config.fullPathName, - errCode: 1 - } + // checks the typescript-extended class for a strict format, and a super call/apply inside + /** + * function MyBtn() { + var _this = _super.call(this) || this; + return global.__native(_this); } - var lineToWrite = ""; - if (isCorrectExtendClassName) { - if (config.logger) { - config.logger.info(lineToWrite) - } + **UGLIFIED extended class** - var classNameFromDecorator = isCorrectExtendClassName ? className : ""; - lineToWrite = _generateLineToWrite(classNameFromDecorator, extendClass.reverse().join("."), overriddenMethodNames, "", config.fullPathName, implementedInterfaces); - addCustomExtend(classNameFromDecorator, config.fullPathName, lineToWrite); - - return; + function t(t) { + var r = e.call(this) || this; + r.textBase = t; + return global.__native(r); } + */ + if ( + constructorFunctionName === returnIdentifierName && + !!constructorFunctionName + ) { + var constructorFunctionScope = extendPath.node.body[1]; + // the 'super' variable will always be passed as the second argument to the __extends call + // try to find the 'super' identifier which may be uglified + var superVariableIdentifier = getSuperVariableIdentifier( + extendPath.node.body[0] + ); + + //// helper functions to find the correct super.call(this) node + function getSuperVariableIdentifier(__extendsNode) { + if ( + types.isExpressionStatement(__extendsNode) && + types.isCallExpression(__extendsNode.expression) + ) { + var __extendsCallArguments = __extendsNode.expression.arguments; + if (__extendsCallArguments.length == 2) { + return __extendsCallArguments[1].name; + } + } + } + + /** Getting the super.call node from assignment + if expressionStatement => check possibleExpressionStatements[0] + if possibleExpressionStatements[0].expression is assignment expression + if possibleExpressionStatements[0].expression.right is logical expression + if possibleExpressionStatements[0].expression.right.left is Call expression + if possibleExpressionStatements[0].expression.right.left.callee.object.name === superVariableIdentifier + if the above is valid, then variableRHS = possibleVariableDeclarations[0].expression.right.left + */ + function getThisAssignmentSuperCallLineNode(nodes, superIdentifier) { + var matchingNodes = nodes.filter((node) => { + if ( + types.isMemberExpression( + node.expression?.right?.callee?.expressions[1] + ) && + node.expression?.right?.callee?.expressions[1].object.name.includes( + "call_super" + ) + ) + return true; + + return ( + types.isAssignmentExpression(node.expression) && + types.isLogicalExpression(node.expression.right) && + types.isCallExpression(node.expression.right.left) && + (node.expression.right.left.callee.object.name === + superIdentifier || + node.expression.right.left.callee.object.name.includes( + "call_super" + )) + ); + }); + + if ( + matchingNodes.length > 0 && + types.isMemberExpression( + matchingNodes[0].expression?.right?.callee?.expressions[1] + ) && + matchingNodes[0].expression?.right?.callee?.expressions[1].object.name.includes( + "call_super" + ) + ) { + return config.isPrimJS + ? matchingNodes[0].expression?.right + : matchingNodes[0].expression?.right?.callee?.expressions[1]; + } - if (config.logger) { - config.logger.info(lineToWrite) - } - var extendInfo = { - file: config.filePath, - line: path.node.property.loc.start.line, - column: path.node.property.loc.start.column + columnOffset, - className: className - }; - lineToWrite = _generateLineToWrite(isCorrectExtendClassName ? className : "", extendClass.reverse().join("."), overriddenMethodNames, extendInfo, "", implementedInterfaces); - normalExtendsArr.push(lineToWrite) - } else { - // don't throw here, because there can be a valid js extend that has nothing to do with NS - return; - throw { - message: "JSParser Error: You need to call the extend '...extend(\"extend_name\", {...overrides...})'), for class: " + extendClass + " file: " + config.fullPathName, - errCode: 1 - } + return matchingNodes.length > 0 + ? config.isPrimJS + ? matchingNodes[0].expression?.right + : matchingNodes[0].expression?.right?.left + : null; + } + + /** Getting the super.call node from declaration + if variableDeclaration => check possibleVariableDeclarations[0].declarations[0].init isn't null + if possibleNodesForSuperCall[0].declarations[0].init is logical expression + if possibleNodesForSuperCall[0].declarations[0].init.left is Call Expression + if possibleNodesForSuperCall[0].declarations[0].init.left.callee.object.name === superVariableIdentifier + if the above is valid, then variableRHS = possibleVariableDeclarations[0].declarations[0].init.left + */ + function getThisDeclarationSuperCallLineNode(nodes, superIdentifier) { + var matchingNodes = nodes.filter((node) => { + return ( + types.isLogicalExpression(node.declarations[0].init) && + types.isCallExpression(node.declarations[0].init.left) && + node.declarations[0].init.left.callee.object.name === + superIdentifier + ); + }); + + return matchingNodes.length > 0 + ? matchingNodes[0].declarations[0].init.left + : null; + } + //// + + if (superVariableIdentifier) { + var possibleVariableDeclarations = []; + var possibleExpressionStatements = []; + + constructorFunctionScope.body.body.forEach((node) => { + if (types.isVariableDeclaration(node)) { + possibleVariableDeclarations.push(node); + } else if (types.isExpressionStatement(node)) { + possibleExpressionStatements.push(node); + } + }); + + if ( + possibleVariableDeclarations.length > 0 || + possibleExpressionStatements.length > 0 + ) { + var superCallRHS = + getThisDeclarationSuperCallLineNode( + possibleVariableDeclarations, + superVariableIdentifier + ) || + getThisAssignmentSuperCallLineNode( + possibleExpressionStatements, + superVariableIdentifier + ); + + if (types.isCallExpression(superCallRHS)) { + superCalleeStartColumn = superCallRHS.loc.end.column; + superCalleeLine = superCallRHS.loc.end.line; + locationAssigned = true; + } else if (types.isMemberExpression(superCallRHS)) { + console.log(superCallRHS); + var superCallee = superCallRHS.property; + superCalleeStartColumn = superCallee.loc.start.column + 2; + superCalleeLine = superCallee.loc.start.line; + locationAssigned = true; + } else if (superCallRHS) { + var superCallee = superCallRHS.callee.property; + superCalleeStartColumn = superCallee.loc.start.column + 1; + superCalleeLine = superCallee.loc.start.line; + + locationAssigned = true; + } } + } } - /* - * HELPER METHODS - */ - function _getOverriddenMethods(node, config) { - var overriddenMethodNames = []; - if (types.isObjectExpression(node)) { - var objectProperties = node.properties; - - for (var index in objectProperties) { - overriddenMethodNames.push(objectProperties[index].key.name); - } - } + if (!locationAssigned) { + config.logger.info( + UNSUPPORTED_TYPESCRIPT_EXTEND_FORMAT_MESSAGE + + " ctor function name: " + + constructorFunctionName + ); + } - return overriddenMethodNames; + return { + line: superCalleeLine, + column: superCalleeStartColumn, + }; + } + + function _getOverriddenMethods(node, config) { + var overriddenMethodNames = []; + if (types.isObjectExpression(node)) { + var objectProperties = node.properties; + + for (var index in objectProperties) { + overriddenMethodNames.push(objectProperties[index].key.name); + } } - // NOTE: It's a near-identical method to _getOverridenMethods for optimisation reasons - // we do not want to check for interfaces while creating an interface - // and likewise, we do not want to iterate twice through the impl. object's properties to read the interfaces - function _getOverridenMethodsAndImplementedInterfaces(node, config) { - var result = []; - var overriddenMethodNames = []; - var implementedInterfaces = []; + return overriddenMethodNames; + } + + // NOTE: It's a near-identical method to _getOverridenMethods for optimisation reasons + // we do not want to check for interfaces while creating an interface + // and likewise, we do not want to iterate twice through the impl. object's properties to read the interfaces + function _getOverridenMethodsAndImplementedInterfaces(node, config) { + var result = []; + var overriddenMethodNames = []; + var implementedInterfaces = []; - var interfacesFound = false; + var interfacesFound = false; - if (types.isObjectExpression(node)) { - var objectProperties = node.properties; + if (types.isObjectExpression(node)) { + var objectProperties = node.properties; - /* + /* Iterates through all properties of the implementation object, e.g. { @@ -566,213 +896,261 @@ var es5_visitors = (function() { will get 'method1' and 'method3' */ - for (var index in objectProperties) { - // if the user has declared interfaces that he is implementing - if (!interfacesFound && - objectProperties[index].key.name.toLowerCase() === "interfaces" && - types.isArrayExpression(objectProperties[index].value)) { - interfacesFound = true; - var interfaces = objectProperties[index].value.elements; - - for (var i in interfaces) { - var interfaceName = _getWholeInterfaceNameFromInterfacesNode(interfaces[i]); - implementedInterfaces.push(interfaceName); - } - } else { - overriddenMethodNames.push(objectProperties[index].key.name) - } - } + for (var index in objectProperties) { + // if the user has declared interfaces that he is implementing + if ( + !interfacesFound && + objectProperties[index].key.name.toLowerCase() === "interfaces" && + types.isArrayExpression(objectProperties[index].value) + ) { + interfacesFound = true; + var interfaces = objectProperties[index].value.elements; + + for (var i in interfaces) { + var interfaceName = _getWholeInterfaceNameFromInterfacesNode( + interfaces[i] + ); + implementedInterfaces.push(interfaceName); + } + } else { + overriddenMethodNames.push(objectProperties[index].key.name); } - - result.push(overriddenMethodNames); - result.push(implementedInterfaces); - - return result; + } } - function _getWholeInterfaceNameFromInterfacesNode(node) { - var interfaceName = ""; - - if (types.isMemberExpression(node)) { - interfaceName += _resolveInterfacePath(node.object); - interfaceName += node.property.name; - } - - return interfaceName; - } + result.push(overriddenMethodNames); + result.push(implementedInterfaces); - function _resolveInterfacePath(node) { - var subNode = ""; + return result; + } - if (types.isMemberExpression(node)) { - if (types.isMemberExpression(node.object)) { - subNode += _resolveInterfacePath(node.object); - subNode += node.property.name + "."; - } else { - subNode += node.object.name + "."; - subNode += node.property.name + "."; - } - } + function _getWholeInterfaceNameFromInterfacesNode(node) { + var interfaceName = ""; - return subNode; + if (types.isMemberExpression(node)) { + interfaceName += _resolveInterfacePath(node.object); + interfaceName += node.property.name; } - function _getWholeName(node) { - var arr = [], - isAndroidInterface = false; + return interfaceName; + } - while (node !== undefined) { - if (!types.isMemberExpression(node)) { - if (isAndroidInterface) { - arr.push(node.name) - } - break; - } + function _resolveInterfacePath(node) { + var subNode = ""; - isAndroidInterface = true; - arr.push(node.property.name) - node = node.object - } - - return arr; + if (types.isMemberExpression(node)) { + if (types.isMemberExpression(node.object)) { + subNode += _resolveInterfacePath(node.object); + subNode += node.property.name + "."; + } else { + subNode += node.object.name + "."; + subNode += node.property.name + "."; + } } - function _getArgumentFromNodeAsString(path, count, config) { + return subNode; + } - var extClassArr = []; - var extendedClass = _getParent(path, count, config); + function _getWholeName(node) { + var arr = [], + isAndroidInterface = false; - if (extendedClass) { - if (types.isCallExpression(extendedClass.node)) { - var o = extendedClass.node.arguments[0]; - } else { - throw { - message: "JSParser Error: Node type is not a call expression. File=" + config.fullPathName + " line=" + path.node.loc.start.line, - errCode: 1 - } - } + while (node !== undefined) { + if (!types.isMemberExpression(node)) { + if (isAndroidInterface) { + arr.push(node.name); } + break; + } - extClassArr = _getWholeName(o); - - return extClassArr.reverse().join("."); + isAndroidInterface = true; + arr.push(node.property.name); + node = node.object; } - function _getDecoratorArgument(path, config, customDecoratorName) { - if (path.parent && types.isCallExpression(path.parent)) { - - if (path.parent.arguments && path.parent.arguments.length > 0) { - - var classNameFromDecorator = path.parent.arguments[0].value - var isCorrectExtendClassName = _testJavaProxyName(classNameFromDecorator); - if (isCorrectExtendClassName) { - return path.parent.arguments[0].value; - } else { - throw { - message: "JSParser Error: The first argument '" + classNameFromDecorator + "' of the " + customDecoratorName + " decorator is not following the right pattern which is: '[namespace.]ClassName'. Example: '" + customDecoratorName + "(\"a.b.ClassName\", {overrides...})', file: " + config.fullPathName, - errCode: 1 - } - } - } else { - throw { - message: "JSParser Error: No arguments passed to " + customDecoratorName + " decorator. Example: '" + customDecoratorName + "(\"a.b.ClassName\", {overrides...})', file: " + config.fullPathName, - errCode: 1 - } - } - } else { - throw { - message: "JSParser Error: Decorator " + customDecoratorName + " must be called with parameters: Example: '" + customDecoratorName + "(\"a.b.ClassName\", {overrides...})', file: " + config.fullPathName, - errCode: 1 - } + return arr; + } + + function _getArgumentFromNodeAsString(path, count, config) { + var extClassArr = []; + var extendedClass = _getParent(path, count, config); + var o; + if (extendedClass) { + if (types.isCallExpression(extendedClass.node)) { + o = extendedClass.node.arguments[0]; + if (types.isAssignmentExpression(o)) { + o = o.right; } - return undefined; + } else { + throw { + message: + "JSParser Error: Node type is not a call expression. File=" + + config.fullPathName + + " line=" + + path.node.loc.start.line, + errCode: 1, + }; + } } - function _getOverriddenMethodsTypescript(path, count) { - var overriddenMethods = []; + extClassArr = _getWholeName(o); - var cn = _getParent(path, count) + return extClassArr.reverse().join("."); + } - // this pattern follows typescript generated syntax - for (var item in cn.node.body) { - var ci = cn.node.body[item]; - if (types.isExpressionStatement(ci)) { - if (types.isAssignmentExpression(ci.expression)) { - if (ci.expression.left.property) { - overriddenMethods.push(ci.expression.left.property.name) - } - } - } + function _getDecoratorArgument(path, config, customDecoratorName) { + if (path.parent && types.isCallExpression(path.parent)) { + if (path.parent.arguments && path.parent.arguments.length > 0) { + var classNameFromDecorator = path.parent.arguments[0].value; + var isCorrectExtendClassName = _testJavaProxyName( + classNameFromDecorator + ); + if (isCorrectExtendClassName) { + return path.parent.arguments[0].value; + } else { + throw { + message: + "JSParser Error: The first argument '" + + classNameFromDecorator + + "' of the " + + customDecoratorName + + " decorator is not following the right pattern which is: '[namespace.]ClassName'. Example: '" + + customDecoratorName + + '("a.b.ClassName", {overrides...})\', file: ' + + config.fullPathName, + errCode: 1, + }; } - - return overriddenMethods; + } else { + throw { + message: + "JSParser Error: No arguments passed to " + + customDecoratorName + + " decorator. Example: '" + + customDecoratorName + + '("a.b.ClassName", {overrides...})\', file: ' + + config.fullPathName, + errCode: 1, + }; + } + } else { + throw { + message: + "JSParser Error: Decorator " + + customDecoratorName + + " must be called with parameters: Example: '" + + customDecoratorName + + '("a.b.ClassName", {overrides...})\', file: ' + + config.fullPathName, + errCode: 1, + }; } - - function _getParent(node, numberOfParents, config) { - if (!node) { - throw { - message: "JSParser Error: No parent found for node in file: " + config.fullPathName, - errCode: 1 - } - } - if (numberOfParents === 0) { - return node; + return undefined; + } + + function _getOverriddenMethodsTypescript(path, count) { + var overriddenMethods = []; + + var cn = _getParent(path, count); + + // this pattern follows typescript generated syntax + for (var item in cn.node.body) { + var ci = cn.node.body[item]; + if (types.isExpressionStatement(ci)) { + if (types.isAssignmentExpression(ci.expression)) { + if (ci.expression.left.property) { + overriddenMethods.push(ci.expression.left.property.name); + } } - - return _getParent(node.parentPath, --numberOfParents) + } } - function _testJavaProxyName(name) { - if (name) { - return /^((\w+\.)+\w+)$/.test(name) - } - return false; + return overriddenMethods; + } + + function _getParent(node, numberOfParents, config) { + if (!node) { + throw { + message: + "JSParser Error: No parent found for node in file: " + + config.fullPathName, + errCode: 1, + }; } - - function _testClassName(name) { - if (name && name != "") { - return /^(\w+)$/.test(name) - } - return false; + if (numberOfParents === 0) { + return node; } - function _generateLineToWrite(classNameFromDecorator, extendClass, overriddenMethodNames, extendInfo, filePath, implementedInterfaces = "") { - const extendInfoFile = extendInfo.file ? extendInfo.file.replace(/[-\\/\\. ]/g, "_") : ""; - const extendInfoLine = extendInfo.line ? extendInfo.line : ""; - const extendInfoColumn = extendInfo.column ? extendInfo.column : ""; - const extendInfoNewClassName = extendInfo.className ? extendInfo.className : ""; - - var lineToWrite = `${extendClass}${ASTERISK_SEPARATOR}` + - `${extendInfoFile}${ASTERISK_SEPARATOR}` + - `${extendInfoLine}${ASTERISK_SEPARATOR}` + - `${extendInfoColumn}${ASTERISK_SEPARATOR}` + - `${extendInfoNewClassName}${ASTERISK_SEPARATOR}` + - `${overriddenMethodNames}${ASTERISK_SEPARATOR}` + - `${classNameFromDecorator}${ASTERISK_SEPARATOR}` + - `${filePath}${ASTERISK_SEPARATOR}` + - `${implementedInterfaces}` + return _getParent(node.parentPath, --numberOfParents); + } - return lineToWrite; + function _testJavaProxyName(name) { + if (name) { + return /^((\w+\.)+\w+)$/.test(name); } + return false; + } - function addCustomExtend(param, extendPath, lineToWrite) { - if (customExtendsArrGlobal.indexOf(param) === -1) { - customExtendsArr.push(lineToWrite) - customExtendsArrGlobal.push(param) - } else { - console.log("Warning: there already is an extend called " + param + ".") - if (extendPath.indexOf("tns_modules") === -1) { - // app folder will take precedence over tns_modules - console.log("Warning: The static binding generator will generate extend from:" + extendPath + " implementation") - customExtendsArr.push(lineToWrite) - customExtendsArrGlobal.push(param) - } - } + function _testClassName(name) { + if (name && name != "") { + return /^(\w+)$/.test(name); } - - return { - es5Visitor: es5Visitor + return false; + } + + function _generateLineToWrite( + classNameFromDecorator, + extendClass, + overriddenMethodNames, + extendInfo, + filePath, + implementedInterfaces = "" + ) { + const extendInfoFile = extendInfo.file + ? extendInfo.file.replace(/[-\\/\\. ]/g, "_") + : ""; + const extendInfoLine = extendInfo.line ? extendInfo.line : ""; + const extendInfoColumn = extendInfo.column ? extendInfo.column : ""; + const extendInfoNewClassName = extendInfo.className + ? extendInfo.className + : ""; + + var lineToWrite = + `${extendClass}${ASTERISK_SEPARATOR}` + + `${extendInfoFile}${ASTERISK_SEPARATOR}` + + `${extendInfoLine}${ASTERISK_SEPARATOR}` + + `${extendInfoColumn}${ASTERISK_SEPARATOR}` + + `${extendInfoNewClassName}${ASTERISK_SEPARATOR}` + + `${overriddenMethodNames}${ASTERISK_SEPARATOR}` + + `${classNameFromDecorator}${ASTERISK_SEPARATOR}` + + `${filePath}${ASTERISK_SEPARATOR}` + + `${implementedInterfaces}`; + + return lineToWrite; + } + + function addCustomExtend(param, extendPath, lineToWrite) { + if (customExtendsArrGlobal.indexOf(param) === -1) { + customExtendsArr.push(lineToWrite); + customExtendsArrGlobal.push(param); + } else { + console.log("Warning: there already is an extend called " + param + "."); + if (extendPath.indexOf("tns_modules") === -1) { + // app folder will take precedence over tns_modules + console.log( + "Warning: The static binding generator will generate extend from:" + + extendPath + + " implementation" + ); + customExtendsArr.push(lineToWrite); + customExtendsArrGlobal.push(param); + } } + } + + return { + es5Visitor: es5Visitor, + }; })(); -module.exports = es5_visitors; \ No newline at end of file +module.exports = es5_visitors; diff --git a/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/InputParameters.java b/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/InputParameters.java index 816f5e15..1408df4b 100644 --- a/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/InputParameters.java +++ b/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/InputParameters.java @@ -6,15 +6,18 @@ public class InputParameters { private static final String SHOW_DEPRECATION_WARNINGS = "-show-deprecation-warnings"; // if the flag is passed the generation will exit on error private static final String THROW_ON_ERROR = "-throw-on-error"; + private static final String LINE_COL_PRIMJS = "-line-column-primjs"; private static InputParameters current = new InputParameters(); private boolean showDeprecationWarnings; private boolean throwOnError; + private boolean lineColumnPrimjs; public InputParameters() { this.showDeprecationWarnings = false; this.throwOnError = false; + this.lineColumnPrimjs = false; } public void setShowDeprecationWarnings(boolean value) { @@ -33,6 +36,14 @@ public boolean getThrowOnError() { return throwOnError; } + public void setLineColumnPrimjs(boolean value) { + this.lineColumnPrimjs = value; + } + + public boolean getLineColumnPrimjs() { + return lineColumnPrimjs; + } + public static void parseCommand(String[] args) { InputParameters inputParameters = new InputParameters(); @@ -47,6 +58,10 @@ public static void parseCommand(String[] args) { if (commandArg.equals(THROW_ON_ERROR)) { inputParameters.setThrowOnError(true); } + + if (commandArg.equals(LINE_COL_PRIMJS)) { + inputParameters.setLineColumnPrimjs(true); + } } } diff --git a/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/nodejs/impl/NodeJSProcessImpl.java b/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/nodejs/impl/NodeJSProcessImpl.java index 57174bdd..3373513d 100644 --- a/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/nodejs/impl/NodeJSProcessImpl.java +++ b/test-app/build-tools/static-binding-generator/src/main/java/org/nativescript/staticbindinggenerator/nodejs/impl/NodeJSProcessImpl.java @@ -3,6 +3,7 @@ import org.nativescript.staticbindinggenerator.nodejs.NodeJSProcess; import org.nativescript.staticbindinggenerator.system.environment.EnvironmentVariablesReader; import org.nativescript.staticbindinggenerator.system.process.ProcessExecutor; +import org.nativescript.staticbindinggenerator.InputParameters; import java.util.ArrayList; import java.util.List; @@ -27,6 +28,7 @@ public NodeJSProcessImpl(ProcessExecutor processExecutor, EnvironmentVariablesRe @Override public int runScript(String scriptPath) { List<String> parameters = createNodeJSParameters(scriptPath); + return processExecutor.executeProcess(NODE_PROCESS_NAME, parameters); } @@ -40,6 +42,10 @@ private List<String> createNodeJSParameters(String scriptPath) { parameters.add(scriptPath); + if (InputParameters.getCurrent().getLineColumnPrimjs()) { + parameters.add("-line-column-primjs"); + } + return parameters; } diff --git a/test-app/runtime/src/main/cpp/runtime/global/GlobalHelpers.cpp b/test-app/runtime/src/main/cpp/runtime/global/GlobalHelpers.cpp index e2d83afe..6d384ca5 100644 --- a/test-app/runtime/src/main/cpp/runtime/global/GlobalHelpers.cpp +++ b/test-app/runtime/src/main/cpp/runtime/global/GlobalHelpers.cpp @@ -168,11 +168,11 @@ std::vector<tns::JsStacktraceFrame> tns::BuildStacktraceFrames(napi_env env, nap if (error == nullptr && count < 3) continue; #endif -#ifdef __JSC__ +//#ifdef __JSC__ regex frameRegex(R"((.*):(\d+):(\d+))"); -#else - regex frameRegex(R"(\((.*):(\d+):(\d+)\))"); -#endif +//#else +// regex frameRegex(R"(\((.*):(\d+):(\d+)\))"); +//#endif smatch match; if (regex_search(frame, match, frameRegex)) { current++; diff --git a/test-app/runtime/src/main/cpp/runtime/metadata/MetadataNode.cpp b/test-app/runtime/src/main/cpp/runtime/metadata/MetadataNode.cpp index d727afdc..efe5398e 100644 --- a/test-app/runtime/src/main/cpp/runtime/metadata/MetadataNode.cpp +++ b/test-app/runtime/src/main/cpp/runtime/metadata/MetadataNode.cpp @@ -507,10 +507,14 @@ bool MetadataNode::GetExtendLocation(napi_env env, string &extendLocation, bool isTypeScriptExtend) { stringstream extendLocationStream; - auto frames = tns::BuildStacktraceFrames(env, nullptr, 3); + auto frames = tns::BuildStacktraceFrames(env, nullptr, 4); tns::JsStacktraceFrame *frame; if (isTypeScriptExtend) { - frame = &frames[2]; // the _super.apply call to ts_helpers will always be the third call frame + if (Util::Contains(frames[2].text, "call_super")) { + frame = &frames[3]; + } else { + frame = &frames[2]; // the _super.apply call to ts_helpers will always be the third call frame + } } else { frame = &frames[0]; } diff --git a/test-app/runtime/src/main/cpp/runtime/util/Util.cpp b/test-app/runtime/src/main/cpp/runtime/util/Util.cpp index bdf2b2d1..f6490453 100644 --- a/test-app/runtime/src/main/cpp/runtime/util/Util.cpp +++ b/test-app/runtime/src/main/cpp/runtime/util/Util.cpp @@ -79,6 +79,10 @@ namespace tns { return res; } + bool Util::Contains(const string &str, const string &sequence) { + return str.find(sequence) != string::npos; + } + string Util::ConvertFromJniToCanonicalName(const string &name) { string converted = name; replace(converted.begin(), converted.end(), '/', '.'); diff --git a/test-app/runtime/src/main/cpp/runtime/util/Util.h b/test-app/runtime/src/main/cpp/runtime/util/Util.h index c16e9588..71227083 100644 --- a/test-app/runtime/src/main/cpp/runtime/util/Util.h +++ b/test-app/runtime/src/main/cpp/runtime/util/Util.h @@ -17,6 +17,7 @@ class Util { static void JoinString(const std::vector<std::string>& list, const std::string& delimiter, std::string& out); static bool EndsWith(const std::string& str, const std::string& suffix); + static bool Contains(const std::string &str, const std::string &sequence); static std::string ConvertFromJniToCanonicalName(const std::string& name);