Files
UglifyJS/test/mocha/sourcemaps.js

389 lines
15 KiB
JavaScript

var assert = require("assert");
var fs = require("fs");
var UglifyJS = require("../node");
function read(path) {
return fs.readFileSync(path, "utf8");
}
function source_map(code) {
var result = UglifyJS.minify(code, {
compress: false,
mangle: false,
sourceMap: true,
});
if (result.error) throw result.error;
return JSON.parse(result.map);
}
function get_map() {
return {
"version": 3,
"sources": ["index.js"],
"names": [],
"mappings": ";;AAAA,IAAI,MAAM,SAAN,GAAM;AAAA,SAAK,SAAS,CAAd;AAAA,CAAV;AACA,QAAQ,GAAR,CAAY,IAAI,KAAJ,CAAZ",
"file": "bundle.js",
"sourcesContent": ["let foo = x => \"foo \" + x;\nconsole.log(foo(\"bar\"));"]
};
}
function prepare_map(sourceMap) {
var code = [
'"use strict";',
"",
"var foo = function foo(x) {",
' return "foo " + x;',
"};",
'console.log(foo("bar"));',
"",
"//# sourceMappingURL=bundle.js.map",
].join("\n");
var result = UglifyJS.minify(code, {
sourceMap: {
content: sourceMap,
includeSources: true,
}
});
if (result.error) throw result.error;
return JSON.parse(result.map);
}
describe("sourcemaps", function() {
it("Should give correct version", function() {
var map = source_map("var x = 1 + 1;");
assert.strictEqual(map.version, 3);
assert.deepEqual(map.names, [ "x" ]);
});
it("Should give correct names", function() {
var map = source_map([
"({",
" get enabled() {",
" return 3;",
" },",
" set enabled(x) {",
" ;",
" }",
"});",
].join("\n"));
assert.deepEqual(map.names, [ "enabled", "x" ]);
});
it("Should work with sourceMap.names=true", function() {
var result = UglifyJS.minify([
"var obj = {",
" p: a,",
" q: b",
"};",
].join("\n"), {
compress: false,
mangle: false,
sourceMap: {
names: true,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.deepEqual(map.names, [ "obj", "p", "a", "q", "b" ]);
});
it("Should work with sourceMap.names=false", function() {
var result = UglifyJS.minify([
"var obj = {",
" p: a,",
" q: b",
"};",
].join("\n"), {
compress: false,
mangle: false,
sourceMap: {
names: false,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.deepEqual(map.names, []);
});
it("Should mark array/object literals", function() {
var result = UglifyJS.minify([
"var obj = {};",
"obj.wat([]);",
].join("\n"), {
sourceMap: true,
toplevel: true,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, "({}).wat([]);");
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["wat"],"mappings":"CAAU,IACNA,IAAI"}');
});
it("Should give correct sourceRoot", function() {
var code = "console.log(42);";
var result = UglifyJS.minify(code, {
sourceMap: {
root: "//foo.bar/",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, code);
assert.strictEqual(result.map, '{"version":3,"sourceRoot":"//foo.bar/","sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI"}');
});
it("Should produce same source map with DOS or UNIX line endings", function() {
var code = [
'console.log("\\',
'hello",',
'"world");',
];
var dos = UglifyJS.minify(code.join("\r\n"), {
sourceMap: true,
});
if (dos.error) throw dos.error;
var unix = UglifyJS.minify(code.join("\n"), {
sourceMap: true,
});
if (unix.error) throw unix.error;
assert.strictEqual(dos.map, unix.map);
});
describe("inSourceMap", function() {
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled", function() {
var result = UglifyJS.minify(read("test/input/issue-1236/simple.js"), {
sourceMap: {
content: read("test/input/issue-1236/simple.js.map"),
filename: "simple.min.js",
includeSources: true
}
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.equal(map.file, "simple.min.js");
assert.equal(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
});
it("Should process inline source map", function() {
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
includeSources: true,
url: "inline"
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", read("test/input/issue-520/output.js"));
});
it("Should warn for missing inline source map", function() {
var result = UglifyJS.minify(read("test/input/issue-1323/sample.js"), {
mangle: false,
sourceMap: {
content: "inline"
},
warnings: true,
});
assert.strictEqual(result.code, "var bar=function(bar){return bar};");
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 0" ]);
});
it("Should handle multiple input and inline source map", function() {
var result = UglifyJS.minify([
read("test/input/issue-520/input.js"),
read("test/input/issue-1323/sample.js"),
], {
sourceMap: {
content: "inline",
url: "inline",
},
warnings: true,
});
if (result.error) throw result.error;
assert.strictEqual(result.code, [
"var Foo=function(){console.log(3)};new Foo;var bar=function(o){return o};",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwiMSJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFdBQWdCQyxRQUFRQyxJQUFJLElBQVMsSUFBSUYsSUNBbkQsSUFBSUcsSUFDQSxTQUFjQSxHQUNWLE9BQU9BIn0=",
].join("\n"));
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
});
it("Should drop source contents for includeSources=false", function() {
var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
compress: false,
mangle: false,
sourceMap: {
content: "inline",
includeSources: true,
},
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.strictEqual(map.sourcesContent.length, 1);
result = UglifyJS.minify(result.code, {
compress: false,
mangle: false,
sourceMap: {
content: result.map,
},
});
if (result.error) throw result.error;
map = JSON.parse(result.map);
assert.ok(!("sourcesContent" in map));
});
it("Should parse the correct sourceMappingURL", function() {
var result = UglifyJS.minify(read("test/input/issue-3294/input.js"), {
compress: { toplevel: true },
sourceMap: {
content: "inline",
includeSources: true,
url: "inline"
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
});
it("Should work in presence of unrecognised annotations", function() {
var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
compress: false,
mangle: false,
sourceMap: {
content: "inline",
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '(function(){console.log("hello")}).call(this);');
assert.strictEqual(result.map, '{"version":3,"sources":["main.coffee"],"names":["console","log"],"mappings":"CAAA,WAAAA,QAAQC,IAAI"}');
});
it("Should not overwrite existing sourcesContent", function() {
var result = UglifyJS.minify({
"in.js": [
'"use strict";',
"",
"var _window$foo = window.foo,",
" a = _window$foo[0],",
" b = _window$foo[1];",
].join("\n"),
}, {
compress: false,
mangle: false,
sourceMap: {
content: {
version: 3,
sources: [ "in.js" ],
names: [
"window",
"foo",
"a",
"b",
],
mappings: ";;kBAAaA,MAAM,CAACC,G;IAAfC,C;IAAGC,C",
file: "in.js",
sourcesContent: [ "let [a, b] = window.foo;\n" ],
},
includeSources: true,
},
});
if (result.error) throw result.error;
assert.strictEqual(result.code, '"use strict";var _window$foo=window.foo,a=_window$foo[0],b=_window$foo[1];');
assert.strictEqual(result.map, '{"version":3,"sources":["in.js"],"sourcesContent":["let [a, b] = window.foo;\\n"],"names":["window","foo","a","b"],"mappings":"6BAAaA,OAAOC,IAAfC,E,eAAGC,E"}');
});
});
describe("sourceMapInline", function() {
it("Should append source map to output js when sourceMapInline is enabled", function() {
var result = UglifyJS.minify('var a = function(foo) { return foo; };', {
sourceMap: {
url: "inline"
}
});
if (result.error) throw result.error;
var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};\n" +
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjAiXSwibmFtZXMiOlsiYSIsImZvbyJdLCJtYXBwaW5ncyI6IkFBQUEsSUFBSUEsRUFBSSxTQUFTQyxHQUFPLE9BQU9BIn0=");
});
it("Should not append source map to output js when sourceMapInline is not enabled", function() {
var result = UglifyJS.minify('var a = function(foo) { return foo; };');
if (result.error) throw result.error;
var code = result.code;
assert.strictEqual(code, "var a=function(n){return n};");
});
it("Should work with max_line_len", function() {
var result = UglifyJS.minify(read("test/input/issue-505/input.js"), {
compress: {
directives: false,
},
output: {
max_line_len: 20
},
sourceMap: {
url: "inline"
}
});
if (result.error) throw result.error;
assert.strictEqual(result.code, read("test/input/issue-505/output.js"));
});
it("Should work with unicode characters", function() {
var code = [
"var tëst = '→unicøde←';",
"alert(tëst);",
].join("\n");
var result = UglifyJS.minify(code, {
sourceMap: {
includeSources: true,
url: "inline",
}
});
if (result.error) throw result.error;
var map = JSON.parse(result.map);
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
var encoded = result.code.slice(result.code.lastIndexOf(",") + 1);
map = JSON.parse(UglifyJS.to_ascii(encoded));
assert.strictEqual(map.sourcesContent.length, 1);
assert.strictEqual(map.sourcesContent[0], code);
result = UglifyJS.minify(result.code, {
sourceMap: {
content: "inline",
includeSources: true,
}
});
if (result.error) throw result.error;
map = JSON.parse(result.map);
assert.strictEqual(map.names.length, 2);
assert.strictEqual(map.names[0], "tëst");
assert.strictEqual(map.names[1], "alert");
});
});
describe("input sourcemaps", function() {
it("Should not modify input source map", function() {
var orig = get_map();
var original = JSON.stringify(orig);
var map = prepare_map(orig);
assert.strictEqual(JSON.stringify(orig), original);
});
it("Should copy over original sourcesContent", function() {
var orig = get_map();
var map = prepare_map(orig);
assert.strictEqual(map.sources.length, 1);
assert.strictEqual(map.sources[0], "index.js");
assert.strictEqual(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0], orig.sourcesContent[0]);
});
it("Should copy sourcesContent if sources are relative", function() {
var relativeMap = get_map();
relativeMap.sources = ['./index.js'];
var map = prepare_map(relativeMap);
assert.strictEqual(map.sources.length, 1);
assert.strictEqual(map.sources[0], "./index.js");
assert.strictEqual(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0], relativeMap.sourcesContent[0]);
});
it("Should not have invalid mappings from inputSourceMap", function() {
var map = prepare_map(get_map());
// The original source has only 2 lines, check that mappings don't have more lines
var msg = "Mapping should not have higher line number than the original file had";
var lines = map.mappings.split(/;/);
assert.ok(lines.length <= 2, msg);
var indices = [ 0, 0, 1, 0, 0];
lines.forEach(function(segments) {
indices[0] = 0;
segments.split(/,/).forEach(function(segment) {
UglifyJS.vlq_decode(indices, segment);
assert.ok(indices[2] <= 2, msg);
});
});
});
});
});