diff --git a/README.md b/README.md index 6a50cf50..60631840 100644 --- a/README.md +++ b/README.md @@ -387,7 +387,7 @@ Streamline also provides _stream wrappers_ that simplify stream programming. The You can seamlessly debug streamline code thanks to [JavaScript source maps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/). See [this video](https://www.youtube.com/watch?v=duC1Sqy66IE) for a quick demo. -To activate this feature, pass the `--source-map` options to `_node` or `_coffee`, or set the `sourcemap` option if you register via a loader. +To activate this feature, pass the `--source-map` options to `_node` or `_coffee`, or set the `sourceMap` option if you register via a loader. # Monitoring performance with flame graphs @@ -460,7 +460,7 @@ For support and discussion, please join the [streamline.js mailing list](http:// See the [AUTHORS](https://github.com/Sage/streamlinejs/blob/master/AUTHORS) file. -Special thanks to Marcel Laverdet who contributed the _fibers_ implementation and to Geoffry Song who contributed sourcemap support. +Special thanks to Marcel Laverdet who contributed the _fibers_ implementation and to Geoffry Song who contributed source map support. # License diff --git a/lib/callbacks/transform.js b/lib/callbacks/transform.js index fff3fb47..b4eb0dd5 100644 --- a/lib/callbacks/transform.js +++ b/lib/callbacks/transform.js @@ -276,6 +276,7 @@ if (typeof exports !== 'undefined') { return child; }, true); node = _flatten(node); + node.loc = node.loc || loc; return node; } } @@ -1881,6 +1882,7 @@ if (typeof exports !== 'undefined') { var node = esprima.parse(source, { loc: true, range: true, + source: options.sourceName || '', }); node = node.body[0].body; if (node.type !== 'BlockStatement') throw new Error("source wrapper error: " + node.type); @@ -1904,22 +1906,38 @@ if (typeof exports !== 'undefined') { var used = {}; node = _simplify(node, options, used); //fixRanges(node); - addNewlines(node); - var result = escodegen.generate(node, { + if (options.lines === "preserve") addNewlines(node); + + // transform top node into Program to avoid extra curly braces + if (node.type === "BlockStatement") node.type = "Program"; + + var ecopts = options.sourceMap ? { + sourceMap: true, + sourceMapWithCode: true, + } : options.lines === "preserve" ? { comment: true, - }); - // remove curly braces around generated source - result = result[0] === '{' ? result.substring(1, result.length - 1) : result; - // turn comments into newlines - //result = result.replace(/\n\s*/g, ' ').replace(/\/\*undefined\*\//g, '\n'); - result = result.split(/\/\*undefined\*\/\n/).map(function(s) { - return s.replace(/\n\s*/g, ' '); - }).join('\n'); + } : {}; + var result = escodegen.generate(node, ecopts); + if (options.sourceMap) { + // convert result into a SourceNode. + // would be much easier (and faster) if escodegen had an option to return SourceNode directly + var SourceNode = require('source-map').SourceNode; + var SourceMapConsumer = require('source-map').SourceMapConsumer; + result = SourceNode.fromStringWithSourceMap(result.code, new SourceMapConsumer(result.map.toString())); + } + + if (options.lines === "preserve") { + // turn comments into newlines + //result = result.replace(/\n\s*/g, ' ').replace(/\/\*undefined\*\//g, '\n'); + result = result.split(/\/\*undefined\*\/\n/).map(function(s) { + return s.replace(/\n\s*/g, ' '); + }).join('\n'); + }; // add helpers at beginning so that __g is initialized before any other code if (!options.noHelpers) { var s = exports.helpersSource(options, used, strict); - if (options.lines == "sourcemap") { + if (options.sourceMap) { result.prepend(s); } else { result = s + result; diff --git a/lib/compiler/compile._js b/lib/compiler/compile._js index 0153eb30..69b4de4f 100644 --- a/lib/compiler/compile._js +++ b/lib/compiler/compile._js @@ -113,12 +113,13 @@ function outputFile(_, inFile, options) { } function fixSourceMap(sourceMap) { - var keys = {}; + var prev; sourceMap._mappings._array = sourceMap._mappings._array.filter(function(mapping) { if (!mapping.originalLine) return false; - var key = mapping.originalLine + '/' + mapping.originalColumn; - if (keys[key]) return false; - keys[key] = true; + if (prev && mapping.source === prev.source // + && mapping.originalLine === prev.originalLine // + && mapping.originalColumn === prev.originalColumn) return false; + prev = mapping; return true; }); } @@ -315,7 +316,7 @@ function cachedTransform(_, content, path, transform, banner, options) { } // no luck in cache if (options.verbose) console.log("streamline: transforming: " + path); - options.lines = options.lines || "sourcemap"; + options.lines = options.lines || (options.sourceMap ? "sourcemap" : "preserve"); transformed = banner + _transform(transform, content, options); if (options.cache && path.indexOf('/tmp--') < 0) fs.writeFile(f, transformed, "utf8", ~_); return transformed; diff --git a/lib/compiler/compileSync.js b/lib/compiler/compileSync.js index e25bf779..750e2981 100644 --- a/lib/compiler/compileSync.js +++ b/lib/compiler/compileSync.js @@ -154,7 +154,7 @@ function cachedTransformSync(content, path, transform, banner, options, testOnly r[k] = options[k]; return r; }, {}); - opts.lines = opts.lines || "sourcemap"; + opts.lines = opts.lines || (opts.sourceMap ? "sourcemap" : "preserve"); transformed = banner + _transform(transform, content, opts); if (options.cache && path.indexOf('/tmp--') < 0) fs.writeFileSync(f, transformed, "utf8"); return transformed;