diff options
-rwxr-xr-x | bin/uglifyjs | 71 | ||||
-rw-r--r-- | test/input/issue-520/input.js | 3 | ||||
-rw-r--r-- | test/input/issue-520/output.js | 2 | ||||
-rw-r--r-- | test/mocha/cli.js | 48 | ||||
-rw-r--r-- | test/mocha/minify.js | 46 | ||||
-rw-r--r-- | tools/node.js | 31 |
6 files changed, 171 insertions, 30 deletions
diff --git a/bin/uglifyjs b/bin/uglifyjs index 27717fb6..d0c3abb2 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -282,21 +282,29 @@ if (ARGS.self) { var ORIG_MAP = ARGS.in_source_map; -if (ORIG_MAP) { +if (ORIG_MAP && ORIG_MAP != "inline") { ORIG_MAP = JSON.parse(fs.readFileSync(ORIG_MAP)); if (files.length == 0) { print_error("INFO: Using file from the input source map: " + ORIG_MAP.file); files = [ ORIG_MAP.file ]; } - if (ARGS.source_map_root == null) { - ARGS.source_map_root = ORIG_MAP.sourceRoot; - } } if (files.length == 0) { files = [ "-" ]; } +if (ORIG_MAP == "inline") { + if (files.length > 1) { + print_error("ERROR: Inline source map only works with singular input"); + process.exit(1); + } + if (ARGS.acorn || ARGS.spidermonkey) { + print_error("ERROR: Inline source map only works with built-in parser"); + process.exit(1); + } +} + if (files.indexOf("-") >= 0 && ARGS.source_map) { print_error("ERROR: Source map doesn't work with input from STDIN"); process.exit(1); @@ -308,37 +316,19 @@ if (files.filter(function(el){ return el == "-" }).length > 1) { } var STATS = {}; -var OUTPUT_FILE = ARGS.o; var TOPLEVEL = null; var P_RELATIVE = ARGS.p && ARGS.p == "relative"; var SOURCES_CONTENT = {}; -var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({ - file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE, - root: ARGS.source_map_root, - orig: ORIG_MAP, -}) : null; - -OUTPUT_OPTIONS.source_map = SOURCE_MAP; - -try { - var output = UglifyJS.OutputStream(OUTPUT_OPTIONS); - var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS); -} catch(ex) { - if (ex instanceof UglifyJS.DefaultsError) { - print_error(ex.msg); - print_error("Supported options:"); - print_error(sys.inspect(ex.defs)); - process.exit(1); - } -} - async.eachLimit(files, 1, function (file, cb) { read_whole_file(file, function (err, code) { if (err) { print_error("ERROR: can't read file: " + file); process.exit(1); } + if (ORIG_MAP == "inline") { + ORIG_MAP = read_source_map(code); + } if (ARGS.p != null) { if (P_RELATIVE) { file = path.relative(path.dirname(ARGS.source_map), file).replace(/\\/g, '/'); @@ -385,6 +375,28 @@ async.eachLimit(files, 1, function (file, cb) { cb(); }); }, function () { + var OUTPUT_FILE = ARGS.o; + + var SOURCE_MAP = (ARGS.source_map || ARGS.source_map_inline) ? UglifyJS.SourceMap({ + file: P_RELATIVE ? path.relative(path.dirname(ARGS.source_map), OUTPUT_FILE) : OUTPUT_FILE, + root: ARGS.source_map_root || ORIG_MAP && ORIG_MAP.sourceRoot, + orig: ORIG_MAP, + }) : null; + + OUTPUT_OPTIONS.source_map = SOURCE_MAP; + + try { + var output = UglifyJS.OutputStream(OUTPUT_OPTIONS); + var compressor = COMPRESS && UglifyJS.Compressor(COMPRESS); + } catch(ex) { + if (ex instanceof UglifyJS.DefaultsError) { + print_error(ex.msg); + print_error("Supported options:"); + print_error(sys.inspect(ex.defs)); + process.exit(1); + } + } + if (ARGS.acorn || ARGS.spidermonkey) time_it("convert_ast", function(){ TOPLEVEL = UglifyJS.AST_Node.from_mozilla_ast(TOPLEVEL); }); @@ -576,6 +588,15 @@ function read_whole_file(filename, cb) { } } +function read_source_map(code) { + var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code); + if (!match) { + print_error("WARN: inline source map not found"); + return null; + } + return JSON.parse(new Buffer(match[2], "base64")); +} + function time_it(name, cont) { var t1 = new Date().getTime(); var ret = cont(); diff --git a/test/input/issue-520/input.js b/test/input/issue-520/input.js new file mode 100644 index 00000000..62428a52 --- /dev/null +++ b/test/input/issue-520/input.js @@ -0,0 +1,3 @@ +var Foo = function Foo(){console.log(1+2);}; new Foo(); + +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjpudWxsLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLElBQU0sR0FBRyxHQUFDLEFBQUUsWUFBVyxFQUFFLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFBLEFBQUUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDOyJ9 diff --git a/test/input/issue-520/output.js b/test/input/issue-520/output.js new file mode 100644 index 00000000..8d19855b --- /dev/null +++ b/test/input/issue-520/output.js @@ -0,0 +1,2 @@ +new function(){console.log(3)}; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxHQUFyQyxZQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19 diff --git a/test/mocha/cli.js b/test/mocha/cli.js index 450df1fd..52c70935 100644 --- a/test/mocha/cli.js +++ b/test/mocha/cli.js @@ -151,4 +151,52 @@ describe("bin/uglifyjs", function () { done(); }); }); + it("Should process inline source map", function(done) { + var command = uglifyjscmd + ' test/input/issue-520/input.js -cm toplevel --in-source-map inline --source-map-inline'; + + exec(command, function (err, stdout) { + if (err) throw err; + + assert.strictEqual(stdout, readFileSync("test/input/issue-520/output.js", "utf8")); + done(); + }); + }); + it("Should warn for missing inline source map", function(done) { + var command = uglifyjscmd + ' test/input/issue-1323/sample.js --in-source-map inline'; + + exec(command, function (err, stdout, stderr) { + if (err) throw err; + + assert.strictEqual(stdout, "var bar=function(){function foo(bar){return bar}return foo}();\n"); + assert.strictEqual(stderr, "WARN: inline source map not found\n"); + done(); + }); + }); + it("Should fail with multiple input and inline source map", function(done) { + var command = uglifyjscmd + ' test/input/issue-520/input.js test/input/issue-520/output.js --in-source-map inline --source-map-inline'; + + exec(command, function (err, stdout, stderr) { + assert.ok(err); + assert.strictEqual(stderr, "ERROR: Inline source map only works with singular input\n"); + done(); + }); + }); + it("Should fail with acorn and inline source map", function(done) { + var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --acorn'; + + exec(command, function (err, stdout, stderr) { + assert.ok(err); + assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n"); + done(); + }); + }); + it("Should fail with SpiderMonkey and inline source map", function(done) { + var command = uglifyjscmd + ' test/input/issue-520/input.js --in-source-map inline --source-map-inline --spidermonkey'; + + exec(command, function (err, stdout, stderr) { + assert.ok(err); + assert.strictEqual(stderr, "ERROR: Inline source map only works with built-in parser\n"); + done(); + }); + }); }); diff --git a/test/mocha/minify.js b/test/mocha/minify.js index 8fe1565f..1b830cb5 100644 --- a/test/mocha/minify.js +++ b/test/mocha/minify.js @@ -1,5 +1,6 @@ var Uglify = require('../../'); var assert = require("assert"); +var readFileSync = require("fs").readFileSync; describe("minify", function() { it("Should test basic sanity of minify with default options", function() { @@ -75,6 +76,51 @@ describe("minify", function() { assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));'); }); + it("Should process inline source map", function() { + var code = Uglify.minify("./test/input/issue-520/input.js", { + inSourceMap: "inline", + sourceMapInline: true + }).code + "\n"; + assert.strictEqual(code, readFileSync("test/input/issue-520/output.js", "utf8")); + }); + it("Should warn for missing inline source map", function() { + var warn_function = Uglify.AST_Node.warn_function; + var warnings = []; + Uglify.AST_Node.warn_function = function(txt) { + warnings.push(txt); + }; + try { + var result = Uglify.minify("./test/input/issue-1323/sample.js", { + inSourceMap: "inline", + mangle: false, + }); + assert.strictEqual(result.code, "var bar=function(){function foo(bar){return bar}return foo}();"); + assert.strictEqual(warnings.length, 1); + assert.strictEqual(warnings[0], "inline source map not found"); + } finally { + Uglify.AST_Node.warn_function = warn_function; + } + }); + it("Should fail with multiple input and inline source map", function() { + assert.throws(function() { + Uglify.minify([ + "./test/input/issue-520/input.js", + "./test/input/issue-520/output.js" + ], { + inSourceMap: "inline", + sourceMapInline: true + }); + }, "multiple input and inline source map"); + }); + it("Should fail with SpiderMonkey and inline source map", function() { + assert.throws(function() { + Uglify.minify("./test/input/issue-520/input.js", { + inSourceMap: "inline", + sourceMapInline: true, + spidermonkey: true + }); + }, "SpiderMonkey and inline source map"); + }); }); describe("sourceMapInline", function() { diff --git a/tools/node.js b/tools/node.js index 108803e5..c64b4e5c 100644 --- a/tools/node.js +++ b/tools/node.js @@ -37,6 +37,15 @@ UglifyJS.AST_Node.warn_function = function(txt) { console.error("WARN: %s", txt); }; +function read_source_map(code) { + var match = /\n\/\/# sourceMappingURL=data:application\/json(;.*?)?;base64,(.*)/.exec(code); + if (!match) { + UglifyJS.AST_Node.warn("inline source map not found"); + return null; + } + return JSON.parse(new Buffer(match[2], "base64")); +} + exports.minify = function(files, options) { options = UglifyJS.defaults(options, { spidermonkey : false, @@ -57,17 +66,28 @@ exports.minify = function(files, options) { }); UglifyJS.base54.reset(); + var inMap = options.inSourceMap; + if (typeof inMap == "string" && inMap != "inline") { + inMap = JSON.parse(fs.readFileSync(inMap, "utf8")); + } + // 1. parse var toplevel = null, sourcesContent = {}; if (options.spidermonkey) { + if (inMap == "inline") { + throw new Error("inline source map only works with built-in parser"); + } toplevel = UglifyJS.AST_Node.from_mozilla_ast(files); } else { function addFile(file, fileUrl) { var code = options.fromString ? file : fs.readFileSync(file, "utf8"); + if (inMap == "inline") { + inMap = read_source_map(code); + } sourcesContent[fileUrl] = code; toplevel = UglifyJS.parse(code, { filename: fileUrl, @@ -75,7 +95,12 @@ exports.minify = function(files, options) { bare_returns: options.parse ? options.parse.bare_returns : undefined }); } - if (!options.fromString) files = UglifyJS.simple_glob(files); + if (!options.fromString) { + files = UglifyJS.simple_glob(files); + if (inMap == "inline" && files.length > 1) { + throw new Error("inline source map only works with singular input"); + } + } [].concat(files).forEach(function (files, i) { if (typeof files === 'string') { addFile(files, options.fromString ? i : files); @@ -114,11 +139,7 @@ exports.minify = function(files, options) { } // 5. output - var inMap = options.inSourceMap; var output = { max_line_len: 32000 }; - if (typeof options.inSourceMap == "string") { - inMap = JSON.parse(fs.readFileSync(options.inSourceMap, "utf8")); - } if (options.outSourceMap || options.sourceMapInline) { output.source_map = UglifyJS.SourceMap({ // prefer outFileName, otherwise use outSourceMap without .map suffix |