handle source-map operations internally (#3754)

This commit is contained in:
Alex Lam S.L
2020-03-28 14:18:56 +00:00
committed by GitHub
parent d105ab9722
commit 827bcec186
11 changed files with 173 additions and 89 deletions

View File

@@ -203,6 +203,7 @@ function minify(files, options) {
if (!HOP(options.output, "code") || options.output.code) { if (!HOP(options.output, "code") || options.output.code) {
if (options.sourceMap) { if (options.sourceMap) {
options.output.source_map = SourceMap({ options.output.source_map = SourceMap({
content: options.sourceMap.includeSources,
file: options.sourceMap.filename, file: options.sourceMap.filename,
orig: source_maps, orig: source_maps,
root: options.sourceMap.root root: options.sourceMap.root
@@ -211,10 +212,8 @@ function minify(files, options) {
if (files instanceof AST_Toplevel) { if (files instanceof AST_Toplevel) {
throw new Error("original source content unavailable"); throw new Error("original source content unavailable");
} else for (var name in files) if (HOP(files, name)) { } else for (var name in files) if (HOP(files, name)) {
options.output.source_map.get().setSourceContent(name, files[name]); options.output.source_map.setSourceContent(name, files[name]);
} }
} else {
options.output.source_map.get()._sourcesContents = null;
} }
} }
delete options.output.ast; delete options.output.ast;

View File

@@ -43,62 +43,144 @@
"use strict"; "use strict";
// a small wrapper around fitzgen's source-map library var vlq_char = characters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
var vlq_bits = vlq_char.reduce(function(map, ch, bits) {
map[ch] = bits;
return map;
}, Object.create(null));
function vlq_decode(indices, str) {
var value = 0;
var shift = 0;
for (var i = 0, j = 0; i < str.length; i++) {
var bits = vlq_bits[str[i]];
value += (bits & 31) << shift;
if (bits & 32) {
shift += 5;
} else {
indices[j++] += value & 1 ? 0x80000000 | -(value >> 1) : value >> 1;
value = shift = 0;
}
}
return j;
}
function vlq_encode(num) {
var result = "";
num = Math.abs(num) << 1 | num >>> 31;
do {
var bits = num & 31;
if (num >>>= 5) bits |= 32;
result += vlq_char[bits];
} while (num);
return result;
}
function create_array_map() {
var map = Object.create(null);
var array = [];
array.index = function(name) {
if (!HOP(map, name)) {
map[name] = array.length;
array.push(name);
}
return map[name];
};
return array;
}
function SourceMap(options) { function SourceMap(options) {
options = defaults(options, { options = defaults(options, {
content: false,
file: null, file: null,
root: null, root: null,
orig: null, orig: null,
orig_line_diff: 0,
dest_line_diff: 0,
}, true); }, true);
var generator = new MOZ_SourceMap.SourceMapGenerator({ var sources = create_array_map();
file: options.file, var sources_content = options.content && Object.create(null);
sourceRoot: options.root var names = create_array_map();
var mappings = "";
if (options.orig) Object.keys(options.orig).forEach(function(name) {
var map = options.orig[name];
var indices = [ 0, 0, 1, 0, 0 ];
map.mappings = map.mappings.split(/;/).map(function(line) {
indices[0] = 0;
return line.split(/,/).map(function(segment) {
return indices.slice(0, vlq_decode(indices, segment));
}); });
var maps = options.orig && Object.create(null);
if (maps) for (var source in options.orig) {
var map = new MOZ_SourceMap.SourceMapConsumer(options.orig[source]);
if (Array.isArray(options.orig[source].sources)) {
map._sources.toArray().forEach(function(source) {
var sourceContent = map.sourceContentFor(source, true);
if (sourceContent) generator.setSourceContent(source, sourceContent);
}); });
if (!sources_content || !map.sourcesContent) return;
for (var i = 0; i < map.sources.length; i++) {
var content = map.sourcesContent[i];
if (content) sources_content[map.sources[i]] = content;
} }
maps[source] = map; });
} var generated_line = 1;
var generated_column = 0;
var source_index = 0;
var original_line = 1;
var original_column = 0;
var name_index = 0;
return { return {
add: function(source, gen_line, gen_col, orig_line, orig_col, name) { add: options.orig ? function(source, gen_line, gen_col, orig_line, orig_col, name) {
var map = maps && maps[source]; var map = options.orig[source];
if (map) { if (map) {
var info = map.originalPositionFor({ var segments = map.mappings[orig_line - 1];
line: orig_line, if (!segments) return;
column: orig_col var indices;
}); for (var i = 0; i < segments.length; i++) {
if (info.source === null) return; var col = segments[i][0];
source = info.source; if (orig_col >= col) indices = segments[i];
orig_line = info.line; if (orig_col <= col) break;
orig_col = info.column;
name = info.name || name;
} }
generator.addMapping({ if (!indices) return;
name: name, source = map.sources[indices[1]];
source: source, orig_line = indices[2];
generated: { orig_col = indices[3];
line: gen_line + options.dest_line_diff, if (indices.length > 4) name = map.names[indices[4]];
column: gen_col
},
original: {
line: orig_line + options.orig_line_diff,
column: orig_col
} }
}); add(source, gen_line, gen_col, orig_line, orig_col, name);
}, } : add,
get: function() { setSourceContent: sources_content ? function(source, content) {
return generator; sources_content[source] = content;
}, } : noop,
toString: function() { toString: function() {
return JSON.stringify(generator.toJSON()); return JSON.stringify({
version: 3,
file: options.file || undefined,
sourceRoot: options.root || undefined,
sources: sources,
sourcesContent: sources_content ? sources.map(function(source) {
return sources_content[source] || null;
}) : undefined,
names: names,
mappings: mappings,
});
} }
}; };
function add(source, gen_line, gen_col, orig_line, orig_col, name) {
if (generated_line < gen_line) {
generated_column = 0;
do {
mappings += ";";
} while (++generated_line < gen_line);
} else if (mappings) {
mappings += ",";
}
mappings += vlq_encode(gen_col - generated_column);
generated_column = gen_col;
var src_idx = sources.index(source);
mappings += vlq_encode(src_idx - source_index);
source_index = src_idx;
mappings += vlq_encode(orig_line - original_line);
original_line = orig_line;
mappings += vlq_encode(orig_col - original_column);
original_column = orig_col;
if (name != null) {
var name_idx = names.index(name);
mappings += vlq_encode(name_idx - name_index);
name_index = name_idx;
}
}
} }

View File

@@ -23,8 +23,7 @@
"LICENSE" "LICENSE"
], ],
"dependencies": { "dependencies": {
"commander": "~2.20.3", "commander": "~2.20.3"
"source-map": "~0.6.1"
}, },
"devDependencies": { "devDependencies": {
"acorn": "~7.1.0", "acorn": "~7.1.0",

View File

@@ -13,3 +13,4 @@ exports["to_ascii"] = to_ascii;
exports["tokenizer"] = tokenizer; exports["tokenizer"] = tokenizer;
exports["TreeTransformer"] = TreeTransformer; exports["TreeTransformer"] = TreeTransformer;
exports["TreeWalker"] = TreeWalker; exports["TreeWalker"] = TreeWalker;
exports["vlq_decode"] = vlq_decode;

View File

@@ -1,2 +1,2 @@
function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var _require=require("bar"),foo=_require.foo;var _require2=require("world"),hello=_require2.hello;foo.x.apply(foo,_toConsumableArray(foo.y(hello.z))); function _toConsumableArray(arr){if(Array.isArray(arr)){for(var i=0,arr2=Array(arr.length);i<arr.length;i++){arr2[i]=arr[i]}return arr2}else{return Array.from(arr)}}var _require=require("bar"),foo=_require.foo;var _require2=require("world"),hello=_require2.hello;foo.x.apply(foo,_toConsumableArray(foo.y(hello.z)));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJuYW1lcyI6WyJyZXF1aXJlIiwiYXJyIl0sIm1hcHBpbmdzIjoiMEpBQWNBLEtBQVFDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3Qge2Zvb30gPSByZXF1aXJlKFwiYmFyXCIpO1xuY29uc3Qge2hlbGxvfSA9IHJlcXVpcmUoXCJ3b3JsZFwiKTtcblxuZm9vLngoLi4uZm9vLnkoaGVsbG8ueikpO1xuIl19 //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImlucHV0Mi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCB7Zm9vfSA9IHJlcXVpcmUoXCJiYXJcIik7XG5jb25zdCB7aGVsbG99ID0gcmVxdWlyZShcIndvcmxkXCIpO1xuXG5mb28ueCguLi5mb28ueShoZWxsby56KSk7XG4iXSwibmFtZXMiOlsicmVxdWlyZSIsImFyciJdLCJtYXBwaW5ncyI6IjBKQUFjQSxLQUFRQyJ9

View File

@@ -1,2 +1,2 @@
new function(){console.log(3)}; new function(){console.log(3)};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19 //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9

View File

@@ -1,2 +1,2 @@
new function(){console.log(3)}; new function(){console.log(3)};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSIsInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl19 //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIl0sInNvdXJjZXNDb250ZW50IjpbImNsYXNzIEZvbyB7IGNvbnN0cnVjdG9yKCl7Y29uc29sZS5sb2coMSsyKTt9IH0gbmV3IEZvbygpO1xuIl0sIm5hbWVzIjpbImNvbnNvbGUiLCJsb2ciXSwibWFwcGluZ3MiOiJBQUErQyxJQUFyQyxXQUFnQkEsUUFBUUMsSUFBSSJ9

View File

@@ -245,7 +245,7 @@ describe("bin/uglifyjs", function() {
if (err) throw err; if (err) throw err;
assert.strictEqual(stdout, [ assert.strictEqual(stdout, [
"var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();", "var Foo=function Foo(){console.log(1+2)};new Foo;var bar=function(){function foo(bar){return bar}return foo}();",
"//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUFBLE1BQWdCQyxRQUFRQyxJQUFJLEVBQUUsSUFBTyxJQUFJRixJQ0FuRCxJQUFJRyxJQUFNLFdBQ04sU0FBU0MsSUFBS0QsS0FDVixPQUFPQSxJQUdYLE9BQU9DLElBTEQifQ==", "//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0ZGluIiwidGVzdC9pbnB1dC9pc3N1ZS0xMzIzL3NhbXBsZS5qcyJdLCJuYW1lcyI6WyJGb28iLCJjb25zb2xlIiwibG9nIiwiYmFyIiwiZm9vIl0sIm1hcHBpbmdzIjoiQUFBQSxJQUFNQSxJQUFJLFNBQUVBLE1BQWNDLFFBQVFDLElBQUksRUFBRSxJQUFPLElBQUlGLElDQW5ELElBQUlHLElBQU0sV0FDTixTQUFTQyxJQUFLRCxLQUNWLE9BQU9BLElBR1gsT0FBT0MsSUFMRCJ9",
"", "",
].join("\n")); ].join("\n"));
var stderrLines = stderr.split("\n"); var stderrLines = stderr.split("\n");
@@ -587,7 +587,7 @@ describe("bin/uglifyjs", function() {
}); });
function read_map() { function read_map() {
var map = JSON.parse(read("./test/input/issue-1236/simple.js.map")); var map = JSON.parse(read("test/input/issue-1236/simple.js.map"));
delete map.sourcesContent; delete map.sourcesContent;
return JSON.stringify(map).replace(/"/g, '\\"'); return JSON.stringify(map).replace(/"/g, '\\"');
} }

View File

@@ -1,10 +1,9 @@
var assert = require("assert"); var assert = require("assert");
var readFileSync = require("fs").readFileSync; var fs = require("fs");
var SourceMapConsumer = require("source-map").SourceMapConsumer;
var UglifyJS = require("../node"); var UglifyJS = require("../node");
function read(path) { function read(path) {
return readFileSync(path, "utf8"); return fs.readFileSync(path, "utf8");
} }
function source_map(code) { function source_map(code) {
@@ -44,7 +43,7 @@ function prepare_map(sourceMap) {
} }
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
return new SourceMapConsumer(result.map); return JSON.parse(result.map);
} }
describe("sourcemaps", function() { describe("sourcemaps", function() {
@@ -87,7 +86,7 @@ describe("sourcemaps", function() {
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code, code); assert.strictEqual(result.code, code);
assert.strictEqual(result.map, '{"version":3,"sources":["0"],"names":["console","log"],"mappings":"AAAAA,QAAQC,IAAI","sourceRoot":"//foo.bar/"}'); 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() { it("Should produce same source map with DOS or UNIX line endings", function() {
var code = [ var code = [
@@ -108,9 +107,9 @@ describe("sourcemaps", function() {
describe("inSourceMap", function() { describe("inSourceMap", function() {
it("Should read the given string filename correctly when sourceMapIncludeSources is enabled", 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"), { var result = UglifyJS.minify(read("test/input/issue-1236/simple.js"), {
sourceMap: { sourceMap: {
content: read("./test/input/issue-1236/simple.js.map"), content: read("test/input/issue-1236/simple.js.map"),
filename: "simple.min.js", filename: "simple.min.js",
includeSources: true includeSources: true
} }
@@ -122,7 +121,7 @@ describe("sourcemaps", function() {
assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));'); assert.equal(map.sourcesContent[0], 'let foo = x => "foo " + x;\nconsole.log(foo("bar"));');
}); });
it("Should process inline source map", function() { it("Should process inline source map", function() {
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), { var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
compress: { toplevel: true }, compress: { toplevel: true },
sourceMap: { sourceMap: {
content: "inline", content: "inline",
@@ -131,10 +130,10 @@ describe("sourcemaps", function() {
} }
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-520/output.js", "utf8")); assert.strictEqual(result.code + "\n", read("test/input/issue-520/output.js"));
}); });
it("Should warn for missing inline source map", function() { it("Should warn for missing inline source map", function() {
var result = UglifyJS.minify(read("./test/input/issue-1323/sample.js"), { var result = UglifyJS.minify(read("test/input/issue-1323/sample.js"), {
mangle: false, mangle: false,
sourceMap: { sourceMap: {
content: "inline" content: "inline"
@@ -146,8 +145,8 @@ describe("sourcemaps", function() {
}); });
it("Should handle multiple input and inline source map", function() { it("Should handle multiple input and inline source map", function() {
var result = UglifyJS.minify([ var result = UglifyJS.minify([
read("./test/input/issue-520/input.js"), read("test/input/issue-520/input.js"),
read("./test/input/issue-1323/sample.js"), read("test/input/issue-1323/sample.js"),
], { ], {
sourceMap: { sourceMap: {
content: "inline", content: "inline",
@@ -163,7 +162,7 @@ describe("sourcemaps", function() {
assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]); assert.deepEqual(result.warnings, [ "WARN: inline source map not found: 1" ]);
}); });
it("Should drop source contents for includeSources=false", function() { it("Should drop source contents for includeSources=false", function() {
var result = UglifyJS.minify(read("./test/input/issue-520/input.js"), { var result = UglifyJS.minify(read("test/input/issue-520/input.js"), {
compress: false, compress: false,
mangle: false, mangle: false,
sourceMap: { sourceMap: {
@@ -186,7 +185,7 @@ describe("sourcemaps", function() {
assert.ok(!("sourcesContent" in map)); assert.ok(!("sourcesContent" in map));
}); });
it("Should parse the correct sourceMappingURL", function() { it("Should parse the correct sourceMappingURL", function() {
var result = UglifyJS.minify(read("./test/input/issue-3294/input.js"), { var result = UglifyJS.minify(read("test/input/issue-3294/input.js"), {
compress: { toplevel: true }, compress: { toplevel: true },
sourceMap: { sourceMap: {
content: "inline", content: "inline",
@@ -195,10 +194,10 @@ describe("sourcemaps", function() {
} }
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code + "\n", readFileSync("test/input/issue-3294/output.js", "utf8")); assert.strictEqual(result.code + "\n", read("test/input/issue-3294/output.js"));
}); });
it("Should work in presence of unrecognised annotations", function() { it("Should work in presence of unrecognised annotations", function() {
var result = UglifyJS.minify(read("./test/input/issue-3441/input.js"), { var result = UglifyJS.minify(read("test/input/issue-3441/input.js"), {
compress: false, compress: false,
mangle: false, mangle: false,
sourceMap: { sourceMap: {
@@ -230,7 +229,7 @@ describe("sourcemaps", function() {
assert.strictEqual(code, "var a=function(n){return n};"); assert.strictEqual(code, "var a=function(n){return n};");
}); });
it("Should work with max_line_len", function() { it("Should work with max_line_len", function() {
var result = UglifyJS.minify(read("./test/input/issue-505/input.js"), { var result = UglifyJS.minify(read("test/input/issue-505/input.js"), {
compress: { compress: {
directives: false, directives: false,
}, },
@@ -242,7 +241,7 @@ describe("sourcemaps", function() {
} }
}); });
if (result.error) throw result.error; if (result.error) throw result.error;
assert.strictEqual(result.code, read("./test/input/issue-505/output.js")); assert.strictEqual(result.code, read("test/input/issue-505/output.js"));
}); });
it("Should work with unicode characters", function() { it("Should work with unicode characters", function() {
var code = [ var code = [
@@ -281,29 +280,33 @@ describe("sourcemaps", function() {
it("Should copy over original sourcesContent", function() { it("Should copy over original sourcesContent", function() {
var orig = get_map(); var orig = get_map();
var map = prepare_map(orig); var map = prepare_map(orig);
assert.equal(map.sourceContentFor("index.js"), orig.sourcesContent[0]); 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() { it("Should copy sourcesContent if sources are relative", function() {
var relativeMap = get_map(); var relativeMap = get_map();
relativeMap.sources = ['./index.js']; relativeMap.sources = ['./index.js'];
var map = prepare_map(relativeMap); var map = prepare_map(relativeMap);
assert.notEqual(map.sourcesContent, null); assert.strictEqual(map.sources.length, 1);
assert.equal(map.sourcesContent.length, 1); assert.strictEqual(map.sources[0], "./index.js");
assert.equal(map.sourceContentFor("index.js"), relativeMap.sourcesContent[0]); assert.strictEqual(map.sourcesContent.length, 1);
assert.equal(map.sourcesContent[0], relativeMap.sourcesContent[0]);
}); });
it("Should not have invalid mappings from inputSourceMap", function() { it("Should not have invalid mappings from inputSourceMap", function() {
var map = prepare_map(get_map()); var map = prepare_map(get_map());
// The original source has only 2 lines, check that mappings don't have more lines // 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 msg = "Mapping should not have higher line number than the original file had";
map.eachMapping(function(mapping) { var lines = map.mappings.split(/;/);
assert.ok(mapping.originalLine <= 2, msg); 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);
}); });
map.allGeneratedPositionsFor({
source: "index.js",
line: 1,
column: 1
}).forEach(function(pos) {
assert.ok(pos.line <= 2, msg);
}); });
}); });
}); });

View File

@@ -1,6 +1,6 @@
var fs = require("fs"); var fs = require("fs");
new Function("MOZ_SourceMap", "exports", require("../tools/node").FILES.map(function(file) { new Function("exports", require("../tools/node").FILES.map(function(file) {
if (/exports\.js$/.test(file)) file = require.resolve("./exports"); if (/exports\.js$/.test(file)) file = require.resolve("./exports");
return fs.readFileSync(file, "utf8"); return fs.readFileSync(file, "utf8");
}).join("\n\n"))(require("source-map"), exports); }).join("\n\n"))(exports);

View File

@@ -15,13 +15,13 @@ exports.FILES = [
require.resolve("./exports.js"), require.resolve("./exports.js"),
]; ];
new Function("MOZ_SourceMap", "exports", function() { new Function("exports", function() {
var code = exports.FILES.map(function(file) { var code = exports.FILES.map(function(file) {
return fs.readFileSync(file, "utf8"); return fs.readFileSync(file, "utf8");
}); });
code.push("exports.describe_ast = " + describe_ast.toString()); code.push("exports.describe_ast = " + describe_ast.toString());
return code.join("\n\n"); return code.join("\n\n");
}())(require("source-map"), exports); }())(exports);
function describe_ast() { function describe_ast() {
var out = OutputStream({ beautify: true }); var out = OutputStream({ beautify: true });