From 946c6b375dc1d051758f793be61f75a5924d2b9f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Mon, 19 Sep 2016 10:11:20 -0400 Subject: [PATCH 1/2] use estree-walker for faster traversal --- lib/index.js | 20 ++++++++++---------- package.json | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5e4d3c8..c23b26f 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,7 +1,7 @@ 'use strict' var acorn = require('acorn') -var walk = require('walk-ast') +var walk = require('estree-walker').walk var MagicString = require('magic-string') function optimizeJs (jsString, opts) { @@ -9,13 +9,13 @@ function optimizeJs (jsString, opts) { var ast = acorn.parse(jsString) var magicString = new MagicString(jsString) - function walkIt (node) { + function walkIt (node, parentNode) { if (node.type === 'FunctionExpression') { - handleFunctionExpression(node) + handleFunctionExpression(node, parentNode) } } - function handleFunctionExpression (node) { + function handleFunctionExpression (node, parentNode) { var prePreChar = jsString.charAt(node.start - 2) var preChar = jsString.charAt(node.start - 1) var postChar = jsString.charAt(node.end) @@ -24,12 +24,12 @@ function optimizeJs (jsString, opts) { // assuming this node is an argument to a function, return true if it itself // is already padded with parentheses function isPaddedArgument (node) { - var idx = node.parentNode.arguments.indexOf(node) + var idx = parentNode.arguments.indexOf(node) if (idx === 0) { // first arg if (prePreChar === '(' && preChar === '(' && postChar === ')') { // already padded return true } - } else if (idx === node.parentNode.arguments.length - 1) { // last arg + } else if (idx === parentNode.arguments.length - 1) { // last arg if (preChar === '(' && postChar === ')' && postPostChar === ')') { // already padded return true } @@ -41,19 +41,19 @@ function optimizeJs (jsString, opts) { return false } - if (node.parentNode && node.parentNode.type === 'CallExpression') { + if (parentNode && parentNode.type === 'CallExpression') { // this function is getting called itself or // it is getting passed in to another call expression // the else statement is strictly never hit, but I think the code is easier to read this way /* istanbul ignore else */ - if (node.parentNode.arguments.length && node.parentNode.arguments.indexOf(node) !== -1) { + if (parentNode.arguments.length && parentNode.arguments.indexOf(node) !== -1) { // function passed in to another function. these are almost _always_ executed, e.g. // UMD bundles, Browserify bundles, Node-style errbacks, Promise then()s and catch()s, etc. if (!isPaddedArgument(node)) { // don't double-pad magicString = magicString.insertLeft(node.start, '(') .insertRight(node.end, ')') } - } else if (node.parentNode.callee === node) { + } else if (parentNode.callee === node) { // this function is getting immediately invoked, e.g. function(){}() if (preChar !== '(') { magicString.insertLeft(node.start, '(') @@ -63,7 +63,7 @@ function optimizeJs (jsString, opts) { } } - walk(ast, walkIt) + walk(ast, { enter: walkIt }) var out = magicString.toString() if (opts.sourceMap) { out += '\n//# sourceMappingURL=' + magicString.generateMap().toUrl() diff --git a/package.json b/package.json index 413a26c..26636d9 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ "dependencies": { "acorn": "^3.3.0", "concat-stream": "^1.5.1", + "estree-walker": "^0.2.1", "magic-string": "^0.16.0", - "walk-ast": "^0.0.2", "yargs": "^4.8.1" }, "devDependencies": { From d8a142c592a0727f9545e11687c5a8fe00ed62be Mon Sep 17 00:00:00 2001 From: Kris Selden Date: Fri, 30 Sep 2016 15:21:50 -0700 Subject: [PATCH 2/2] Add enough resolution to the source map so it can be traced back to the map output by uglify. Pass through options to generateMap --- lib/index.js | 8 +++++++- test/test.js | 9 +++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/index.js b/lib/index.js index c23b26f..2473039 100644 --- a/lib/index.js +++ b/lib/index.js @@ -10,6 +10,8 @@ function optimizeJs (jsString, opts) { var magicString = new MagicString(jsString) function walkIt (node, parentNode) { + magicString.addSourcemapLocation(node.start) + magicString.addSourcemapLocation(node.end) if (node.type === 'FunctionExpression') { handleFunctionExpression(node, parentNode) } @@ -66,7 +68,11 @@ function optimizeJs (jsString, opts) { walk(ast, { enter: walkIt }) var out = magicString.toString() if (opts.sourceMap) { - out += '\n//# sourceMappingURL=' + magicString.generateMap().toUrl() + out += '\n//# sourceMappingURL=' + magicString.generateMap({ + file: opts.file, + source: opts.source, + includeContent: opts.includeContent + }).toUrl() } return out } diff --git a/test/test.js b/test/test.js index 2a8393f..5e9cfa3 100644 --- a/test/test.js +++ b/test/test.js @@ -14,13 +14,14 @@ var benchmarkLibs = fs.readdirSync('benchmarks').filter(function (script) { describe('main test suite', function () { it('test sourcemaps', function () { var res = optimizeJs('var baz = function () { console.log("foo") }()', { - sourceMap: true + file: 'optimized.js', + source: 'original.js', + sourceMap: true, + includeContent: true }) assert.equal(res, 'var baz = (function () { console.log("foo") })()' + '\n//# sourceMappingURL=data:application/json;charset=utf-8;' + - 'base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbbn' + - 'VsbF0sInNvdXJjZXNDb250ZW50IjpbbnVsbF0sIm5hbWVzIjpbXSwibWFwcGl' + - 'uZ3MiOiJBQUFBLFVBQVUsQ0FBQSxrQ0FBa0MsQ0FBQSJ9') + 'base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW1pemVkLmpzIiwic291cmNlcyI6WyJvcmlnaW5hbC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgYmF6ID0gZnVuY3Rpb24gKCkgeyBjb25zb2xlLmxvZyhcImZvb1wiKSB9KCkiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSSxHQUFHLEdBQUcsQ0FBQSxZQUFZLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFBIn0=') }) testCases.forEach(function (testCase) { it('test ' + testCase, function () {