aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMihai Bazon <mihai@bazon.net>2012-08-29 19:39:19 +0300
committerMihai Bazon <mihai@bazon.net>2012-08-29 19:39:19 +0300
commit52bcca288fe560670584b24cb170f09c250514e6 (patch)
treeb61f91910b94b79cc92d01446f183ef756dff3d6
parent48440dc250d0a8b72a8064fa97760fe9962f7511 (diff)
downloadtracifyjs-52bcca288fe560670584b24cb170f09c250514e6.tar.gz
tracifyjs-52bcca288fe560670584b24cb170f09c250514e6.zip
started support for generating source maps (WIP)
plugged in @fitzgen's source-map library
-rw-r--r--lib/output.js63
-rw-r--r--lib/sourcemap.js77
-rwxr-xr-xtmp/test-maps.js39
-rw-r--r--tools/node.js7
4 files changed, 173 insertions, 13 deletions
diff --git a/lib/output.js b/lib/output.js
index 5f2f46d1..b43d817e 100644
--- a/lib/output.js
+++ b/lib/output.js
@@ -53,7 +53,8 @@ function OutputStream(options) {
width : 80,
max_line_len : 32000,
ie_proof : true,
- beautify : true
+ beautify : true,
+ source_map : null
});
var indentation = 0;
@@ -152,12 +153,12 @@ function OutputStream(options) {
might_need_space = false;
maybe_newline();
}
- var a = str.split(/\r?\n/), n = a.length;
+ var a = str.split(/\r?\n/), n = a.length - 1;
current_line += n;
- if (n == 1) {
- current_col += a[n - 1].length;
+ if (n == 0) {
+ current_col += a[n].length;
} else {
- current_col = a[n - 1].length;
+ current_col = a[n].length;
}
current_pos += str.length;
last = str;
@@ -243,9 +244,22 @@ function OutputStream(options) {
if (options.space_colon) space();
};
+ var add_mapping = options.source_map ? function(token, name) {
+ options.source_map.add(
+ current_line, current_col,
+ token.line, token.col,
+ (!name && token.type == "name") ? token.value : name
+ );
+ } : noop;
+
+ function get() {
+ return OUTPUT;
+ };
+
var stack = [];
return {
- get : function() { return OUTPUT },
+ get : get,
+ toString : get,
indent : indent,
newline : newline,
print : print,
@@ -261,6 +275,7 @@ function OutputStream(options) {
with_block : with_block,
with_parens : with_parens,
with_square : with_square,
+ add_mapping : add_mapping,
option : function(opt) { return options[opt] },
line : function() { return current_line },
col : function() { return current_col },
@@ -287,9 +302,11 @@ function OutputStream(options) {
stream.push_node(self);
if (self.needs_parens(stream)) {
stream.with_parens(function(){
+ self.add_source_map(stream);
generator(self, stream);
});
} else {
+ self.add_source_map(stream);
generator(self, stream);
}
stream.pop_node();
@@ -868,11 +885,7 @@ function OutputStream(options) {
});
DEFPRINT(AST_SymbolRef, function(self, output){
var def = self.symbol;
- if (def) {
- def.print(output);
- } else {
- output.print_name(self.name);
- }
+ output.print_name(def ? def.mangled_name || def.name : self.name);
});
DEFPRINT(AST_This, function(self, output){
output.print("this");
@@ -973,4 +986,32 @@ function OutputStream(options) {
});
};
+ /* -----[ source map generators ]----- */
+
+ function DEFMAP(nodetype, generator) {
+ nodetype.DEFMETHOD("add_source_map", function(stream){
+ generator(this, stream);
+ });
+ };
+
+ // We could easily add info for ALL nodes, but it seems to me that
+ // would be quite wasteful, hence this noop in the base class.
+ DEFMAP(AST_Node, noop);
+
+ function basic_sourcemap_gen(self, output) {
+ output.add_mapping(self.start);
+ };
+
+ // XXX: I'm not exactly sure if we need it for all of these nodes,
+ // or if we should add even more.
+
+ DEFMAP(AST_Directive, basic_sourcemap_gen);
+ DEFMAP(AST_Debugger, basic_sourcemap_gen);
+ DEFMAP(AST_Symbol, basic_sourcemap_gen);
+ DEFMAP(AST_Jump, basic_sourcemap_gen);
+ DEFMAP(AST_PropAccess, basic_sourcemap_gen);
+ DEFMAP(AST_ObjectProperty, function(self, output){
+ output.add_mapping(self.start, self.key);
+ });
+
})();
diff --git a/lib/sourcemap.js b/lib/sourcemap.js
new file mode 100644
index 00000000..6cf63d1b
--- /dev/null
+++ b/lib/sourcemap.js
@@ -0,0 +1,77 @@
+/***********************************************************************
+
+ A JavaScript tokenizer / parser / beautifier / compressor.
+ https://github.com/mishoo/UglifyJS2
+
+ -------------------------------- (C) ---------------------------------
+
+ Author: Mihai Bazon
+ <mihai.bazon@gmail.com>
+ http://mihai.bazon.net/blog
+
+ Distributed under the BSD license:
+
+ Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the following
+ disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ ***********************************************************************/
+
+// a small wrapper around fitzgen's source-map library
+function SourceMap(options) {
+ options = defaults(options, {
+ file : null,
+ root : null
+ });
+ var generator = new MOZ_SourceMap.SourceMapGenerator({
+ file : options.file,
+ sourceRoot : options.root
+ });
+ var current_source = null;
+ function add(gen_line, gen_col, orig_line, orig_col, name) {
+ // AST_Node.warn("Mapping in {file}: {orig_line},{orig_col} → {gen_line},{gen_col} ({name})", {
+ // orig_line : orig_line,
+ // orig_col : orig_col,
+ // gen_line : gen_line,
+ // gen_col : gen_col,
+ // file : current_source,
+ // name : name
+ // });
+ generator.addMapping({
+ generated : { line: gen_line + 1, column: gen_col },
+ original : { line: orig_line + 1, column: orig_col },
+ source : current_source,
+ name : name
+ });
+ };
+ return {
+ add : add,
+ set_source : function(filename) { current_source = filename },
+ get : function() { return generator },
+ toString : function() { return generator.toString() }
+ }
+};
diff --git a/tmp/test-maps.js b/tmp/test-maps.js
new file mode 100755
index 00000000..c89d105e
--- /dev/null
+++ b/tmp/test-maps.js
@@ -0,0 +1,39 @@
+#! /usr/bin/env node
+
+var sys = require("util");
+var fs = require("fs");
+
+var UglifyJS = require("../tools/node");
+
+var files = process.argv.slice(2);
+var map = UglifyJS.SourceMap();
+var output = UglifyJS.OutputStream({
+ beautify : false,
+ source_map : map
+});
+
+function do_file(file) {
+ var code = fs.readFileSync(file, "utf8");
+
+ // parse
+ var ast = UglifyJS.parse(code);
+
+ // mangle
+ ast.figure_out_scope();
+ ast.mangle_names();
+
+ // compress
+ var compressor = UglifyJS.Compressor();
+ ast.squeeze(compressor);
+
+ // generate source into the output stream
+ // first reset the current file name in the source map.
+ map.set_source(file);
+ ast.print(output);
+};
+
+files.forEach(do_file);
+
+fs.writeFileSync("/tmp/source-map.json", map, "utf8");
+
+sys.print(output);
diff --git a/tools/node.js b/tools/node.js
index d61b44a7..be83d171 100644
--- a/tools/node.js
+++ b/tools/node.js
@@ -4,8 +4,10 @@ var sys = require("util");
var path = require("path");
var UglifyJS = vm.createContext({
- sys : sys,
- console : console
+ sys : sys,
+ console : console,
+
+ MOZ_SourceMap : require("source-map")
});
function load_global(file) {
@@ -27,6 +29,7 @@ load_global("../lib/parse.js");
load_global("../lib/scope.js");
load_global("../lib/output.js");
load_global("../lib/compress.js");
+load_global("../lib/sourcemap.js");
UglifyJS.AST_Node.warn_function = function(txt) {
sys.debug(txt);