diff --git a/lib/global-this.js b/lib/global-this.js new file mode 100644 index 00000000..2040039d --- /dev/null +++ b/lib/global-this.js @@ -0,0 +1,24 @@ +'use strict'; + +const THIS_BREAK_KEYS = [ 'FunctionExpression', 'FunctionDeclaration', 'ClassProperty', + 'ClassMethod', 'ObjectMethod' ]; + +// Walk the AST looking for 'this' references intended to be references to global +// Replace them with an explicit 'global' reference +module.exports = function (_ref) { + const t = _ref.types; + return { + visitor: { + ThisExpression(path, state) { + if ( + state.opts.allowTopLevelThis !== true + && !path.findParent((path) => !path.is('shadow') + && THIS_BREAK_KEYS.indexOf(path.type) >= 0) + ) { + // TODO: Spit out a warning/deprecation notice? + path.replaceWith(t.identifier('global')); + } + } + } + }; +}; diff --git a/lib/jsanalyze.js b/lib/jsanalyze.js index c81064cf..80742bda 100644 --- a/lib/jsanalyze.js +++ b/lib/jsanalyze.js @@ -76,7 +76,7 @@ function getMemberValue(node) { function getTitaniumExpression(member) { var value = getMemberValue(member), tiNodeRegExp = /^Ti(tanium)?/; - if (value == null) return null; + if (value == null) { return null; } if (tiNodeRegExp.test(value)) { // if value.startsWith('Ti.'), replace with 'Titanium.' if (value.indexOf('Ti.') === 0) { @@ -123,7 +123,7 @@ exports.analyzeJs = function analyzeJs(contents, opts) { contents = contents.split('\n'); if (ex.line && ex.line <= contents.length) { errmsg.push(''); - errmsg.push(' ' + contents[ex.line-1].replace(/\t/g, ' ')); + errmsg.push(' ' + contents[ex.line - 1].replace(/\t/g, ' ')); if (ex.col) { var i = 0, len = ex.col, @@ -142,7 +142,7 @@ exports.analyzeJs = function analyzeJs(contents, opts) { // find all of the titanium symbols traverse(ast, { MemberExpression: { - enter: function(path) { + enter: function (path) { var memberExpr = getTitaniumExpression(path.node); if (memberExpr) { symbols[memberExpr.substring(9)] = 1; // Drop leading 'Titanium.' @@ -170,6 +170,7 @@ exports.analyzeJs = function analyzeJs(contents, opts) { // transpile if (opts.transpile) { + options.plugins.push(require.resolve('./global-this')); options.presets.push([ env, { targets: opts.targets } ]); } @@ -246,7 +247,7 @@ exports.analyzeHtml = function analyzeHtml(contents, relPath) { } try { - var dom = new DOMParser({ errorHandler: function(){} }).parseFromString('\n' + contents + '\n', 'text/html'), + var dom = new DOMParser({ errorHandler: function () {} }).parseFromString('\n' + contents + '\n', 'text/html'), doc = dom && dom.documentElement, scripts = doc && doc.getElementsByTagName('script'), i, len, src, m, p, q, r; diff --git a/package-lock.json b/package-lock.json index b2883b39..5a860954 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "node-titanium-sdk", - "version": "0.4.8", + "version": "0.4.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 50dc3ad9..9a2c356c 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "titanium", "mobile" ], - "version": "0.4.8", + "version": "0.4.9", "author": { "name": "Appcelerator, Inc.", "email": "info@appcelerator.com" @@ -53,6 +53,6 @@ "node": ">=0.6.6" }, "scripts": { - "test": "JUNIT_REPORT_PATH=junit_report.xml mocha --require tests/init --reporter mocha-jenkins-reporter --check-leaks tests/test-tiappxml.js" + "test": "JUNIT_REPORT_PATH=junit_report.xml mocha --require tests/init --reporter mocha-jenkins-reporter --check-leaks tests/*_test.js" } } diff --git a/tests/init.js b/tests/init.js index ed0eeed9..fcaaf2d1 100644 --- a/tests/init.js +++ b/tests/init.js @@ -1,9 +1,10 @@ -global.should = null; -global.should = require('should'); - -var util = require('util'); -global.dump = function () { - for (var i = 0; i < arguments.length; i++) { - console.error(util.inspect(arguments[i], false, null, true)); - } -}; \ No newline at end of file +'use strict'; +global.should = null; +global.should = require('should'); + +var util = require('util'); +global.dump = function () { + for (var i = 0; i < arguments.length; i++) { + console.error(util.inspect(arguments[i], false, null, true)); + } +}; diff --git a/tests/jsanalyze_test.js b/tests/jsanalyze_test.js new file mode 100644 index 00000000..4654a602 --- /dev/null +++ b/tests/jsanalyze_test.js @@ -0,0 +1,10 @@ +'use strict'; + +const jsanalyze = require('../lib/jsanalyze'); + +describe('jsanalyze', function () { + it('#analyzeJs() converts global "this" references into "global" references when transpiling', function () { + const results = jsanalyze.analyzeJs('this.myGlobalMethod = function() {};', { transpile: true }); + results.contents.should.eql('"use strict";global.myGlobalMethod = function () {};'); + }); +}); diff --git a/tests/run.js b/tests/run.js index c3e194e3..9b4dfa04 100644 --- a/tests/run.js +++ b/tests/run.js @@ -1,17 +1,21 @@ -var spawn = require('child_process').spawn, - exitCode = 0, +'use strict'; + +const spawn = require('child_process').spawn, // eslint-disable-line security/detect-child-process tests = [ - 'test-tiappxml.js' + 'jsanalyze_test.js', + 'tiappxml_test.js' ]; +let exitCode = 0; + (function next() { if (tests.length === 0) { process.exit(exitCode); } - + var file = tests.shift(); console.log(file); - + var proc = spawn('node', [ 'tests/' + file ]); proc.stdout.pipe(process.stdout); proc.stderr.pipe(process.stderr); diff --git a/tests/test-tiappxml.js b/tests/tiappxml_test.js similarity index 100% rename from tests/test-tiappxml.js rename to tests/tiappxml_test.js