google / traceur-compiler

Traceur is a JavaScript.next-to-JavaScript-of-today compiler
Apache License 2.0
8.18k stars 580 forks source link

--input-source-map command should take a file name argument. #1980

Open d180cf opened 9 years ago

d180cf commented 9 years ago

Let's say there is a es6 js file which was generated from other files and has a corresponding source map. When traceur generates a es5 js file, does the generated source map point to the es6 file or to those files that were used to produce the es6 file?

guybedford commented 9 years ago

You can set options.inputSourceMap to a source map object.

d180cf commented 9 years ago

With this option traceur seems to start parsing the given source map, but fails.

traceur --modules inline --source-maps file 
  --input-source-map es6.js.map --out app.js 
  --script es6.js
{
  "version": 3,
  "file": "es6.js",
  "sourceRoot": "",
  "sources": [ "kb.ts", "xhr.ts", ...]
  "names": [ "testbench", ...]
  "mappings": "AAAA,IAAO,SAAS,CAg..."
}
[ '.../es6.js.map:2:12: Semi-colon expected',
  '.../es6.js.map:2:12: Unexpected token :',
  '.../es6.js.map:2:14: Semi-colon expected',
  '.../es6.js.map:3:9: Semi-colon expected',
  '.../es6.js.map:3:9: Unexpected token :',
  '.../es6.js.map:3:11: Semi-colon expected',
  '.../es6.js.map:4:15: Semi-colon expected',
  '.../es6.js.map:4:15: Unexpected token :',
  '.../es6.js.map:4:17: Semi-colon expected',
  '.../es6.js.map:5:12: Semi-colon expected',
  '.../es6.js.map:5:12: Unexpected token :',
  '.../es6.js.map:6:10: Semi-colon expected',
  '.../es6.js.map:6:10: Unexpected token :',
  '.../es6.js.map:7:13: Semi-colon expected',
  '.../es6.js.map:7:13: Unexpected token :',
  '.../es6.js.map:7:15: Semi-colon expected' ]

Maybe traceur doesn't like the empty sourceRoot value?

UltCombo commented 9 years ago

Quick guess: try --input-source-map=es6.js.map (equal sign instead of space)

d180cf commented 9 years ago

Same result.

UltCombo commented 9 years ago

That's odd. It looks like Traceur is trying to compile your sourcemap as a JavaScript file, you have the same error output as if pasting the sourcemap code into the REPL.

d180cf commented 9 years ago

If traceur tries to eval or require it without wrapping first in (...) then it would fail exactly this way. But I would be odd to use eval when there's JSON.parse.

UltCombo commented 9 years ago

I mean, it looks like Traceur is treating the source map as an input script for compilation instead of using it for source mapping purposes. That's just a guess, though.

d180cf commented 9 years ago

After I wrapped contents of the .map file into (...) traceur produced another source map with files pointing to the original ts files:

{
  "version": 3,
  "file": "app.js", 
  "sourceRoot": "",
  "sources": [ "kb.ts", "xhr.ts", ... ] <-- these are my original files
  "names": [ "testbench", ...]
  "mappings": "AAAA,IAAO,SAAS,CAg..."
}

I wasn't able to check whether the produced source map makes sense because the produced js file didn't. It had a reference to some $traceurRuntime which was undefined:

var $__es6_46_js_46_map__ = (function() {
  "use strict";
  var __moduleName = "es6.js.map";
  ({
    "version": 3,
    "file": "es6.js",
    "sourceRoot": "",
    "sources": ["kb.ts", "xhr.ts", "../src/types.ts", "../src/uti...", ... ]
    "names": ["testbench", "testbench.Subscription", "testbench.S...", ... ]
    "mappings": "AAAA,IAAO,SAAS,CAgCf;AAhCD,WAAO,SAAS,EAAC,CAAC;I..."
  });
  return {};
})();
var $__es6_46_js__ = (function() {
  "use strict";
  var __moduleName = "es6.js";
  var testbench;
  (function(testbench) {
    'use strict';
    var Subscription = function() {
      function Subscription(dispose) {
        this.dispose = dispose;
      }
      return ($traceurRuntime.createClass)(Subscription, {}, {});
    }();
    testbench.Subscription = Subscription;
    ...

As you see, traceur inlined some source map into the file, so I tried to tell it to not do that:

traceur --modules inline --source-maps file --input-source-ap es6.js.map --out app.js es6.js

And got a cryptic error:

TypeError: Cannot use 'in' operator to search for 'version' in true
    at Object.getArg (\bin\traceur.js:24237:20)
    at new SourceMapConsumer (\bin\traceur.js:24893:26)
    at Compiler.getSourceMap (\bin\traceur.js:30326:38)
    at Compiler.NodeCompiler.writeTreeToFile (\src\node\NodeCompiler.js:42:28)
    at \src\node\recursiveModuleCompile.js:56:18
    at lib$rsvp$$internal$$tryCatch (\node_modules\rsvp\dist\rsvp.js:493:16)
    at lib$rsvp$$internal$$invokeCallback (\node_modules\rsvp\dist\rsvp.js:505:17)
    at lib$rsvp$$internal$$publish (\node_modules\rsvp\dist\rsvp.js:476:11)
    at Object.lib$rsvp$asap$$flush [as _onImmediate] (\node_modules\rsvp\dist\rsvp.js:1198:9)
    at processImmediate [as _immediateCallback] (timers.js:345:15)
johnjbarton commented 9 years ago

Please try with an option other than --modules inline. Does that help?

d180cf commented 9 years ago

I've tried all possible --modules: they all yield the same errors.

d180cf commented 9 years ago

It's not working even with a simplest single file source map. I've added a sample in my repository.

guybedford commented 9 years ago

The inputSourceMap option works via the JS options API, that's the only case I've personally tested for this though.

johnjbarton commented 9 years ago

I tried to reproduce your issue, but failed:

tsumego.js (master)]$ git checkout es6generators 
Branch es6generators set up to track remote branch es6generators from origin.
Switched to a new branch 'es6generators'
[tsumego.js (es6generators)]$ npm test

> tsumego.js@ test /work/tsumego.js
> cd tests; npm i; tsc --out es6.js; traceur --modules inline --out es5.js es6.js; node es5

npm WARN package.json @ No repository field.
sh: tsc: command not found
sh: traceur: command not found

module.js:340
    throw err;
          ^
Error: Cannot find module '/work/tsumego.js/tests/es5'
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:280:25)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:935:3
npm ERR! Test failed.  See above for more details.
npm ERR! not ok code 0
[tsumego.js (es6generators)]$ npm install
npm WARN package.json tsumego.js@ No repository field.
d180cf commented 9 years ago

That's because you run npm test in the root folder. Could you run it in /traceur-sample?

johnjbarton commented 9 years ago
traceur-sample (es6generators)]$ npm test

> @ test /work/tsumego.js/traceur-sample
> traceur --input-source-map sample.js.map --source-maps file --out sample.es5.js --inline sample.js

sh: traceur: command not found
npm ERR! Test failed.  See above for more details.
npm ERR! not ok code 0

How do you define your traceur commmand?

johnjbarton commented 9 years ago

The --input-source-map command does not take arguments. Here is a problem I see that I will look into:

[traceur-sample (es6generators)]$ /work/traceur-compiler/traceur  --input-source-map --source-maps=file --out sample.es5.js sample.js
TypeError: Cannot use 'in' operator to search for 'version' in true
    at Object.getArg (/work/traceur-compiler/bin/traceur.js:24091:20)
    at new SourceMapConsumer (/work/traceur-compiler/bin/traceur.js:24747:26)
    at Compiler.getSourceMap (/work/traceur-compiler/bin/traceur.js:30179:38)
    at Compiler.NodeCompiler.writeTreeToFile (/work/traceur-compiler/src/node/NodeCompiler.js:42:28)
    at /work/traceur-compiler/src/node/recursiveModuleCompile.js:56:18
    at $$$internal$$tryCatch (/work/traceur-compiler/node_modules/rsvp/dist/rsvp.js:470:16)
    at $$$internal$$invokeCallback (/work/traceur-compiler/node_modules/rsvp/dist/rsvp.js:482:17)
    at $$$internal$$publish (/work/traceur-compiler/node_modules/rsvp/dist/rsvp.js:453:11)
    at $$rsvp$asap$$flush (/work/traceur-compiler/node_modules/rsvp/dist/rsvp.js:1531:9)
    at process._tickCallback (node.js:448:13)
johnjbarton commented 9 years ago

oh, duh, if we put my claim, that --input-source-map command does not take arguments with Guy's that it the feature works through the API and my output above, it all becomes clear:

The command line does not support --input-source-map. If you supply the option with a file name following it, then traceur compiles the file following it, giving the errors you see. If you don't give a filename, like I did not above, then true gets passed to the SourceMapConsumer and TypeError.

We need to teach src/node/commands.js about file names after --input-source-map.

johnjbarton commented 9 years ago

Or maybe we need to parse the sourcemap fie name from the end of the input source files?

d180cf commented 9 years ago

Thanks, this explains the mystery. I guess I should be able to use the .compile(...) function. It seems to produce a reasonable output, but doesn't generate a new source map. Am I missing somthing in the options list?

var es6src = fs.readFileSync(srcPath, 'utf8');

var es5src = traceur.compile(es6src, {
    inputSourceMap: true,
    sourceMaps: 'file',
    modules: 'inline'
}, path.basename(outPath));
johnjbarton commented 9 years ago

The property inputSourceMap should have a filename value, not true.

d180cf commented 9 years ago

It seems it should have contents of the .map file (otherwise it tries to parse the filename as JSON and throws an exception). However even this code doesn't help me generate the new source map:

var es6src = fs.readFileSync(srcPath, 'utf8');
var es6map = fs.readFileSync(srcPath + '.map', 'utf8');

var es5src = traceur.compile(es6src, {
    inputSourceMap: es6map,
    sourceMaps: 'inline',
    modules: 'inline'
}/*, path.basename(outPath)*/);

fs.writeFileSync(outPath, es5src, 'utf8');

It produces the following es5 code:

var $___60_compile_45_source_62___ = (function() {
  "use strict";
  var __moduleName = "<compile-source>";
  var sample;
  (function(sample) {
    sample.isPositive = function(x) {
      return x > 0;
    };
    sample.isNegative = function(x) {
      return x < 0;
    };
  })(sample || (sample = {}));
  return {};
})();
//# sourceMappingURL=data:application/json;base64,

The way the API looks (the es5 code is returned as a string) makes me think that the corresponding .map file is somehow returned as a string, but I just don't know how to get that string.

johnjbarton commented 9 years ago

In the example output you posted the source map appears to be in the data: URL but chopped off.

d180cf commented 9 years ago

Right, the question is how to make traceur write something meaningful in that data URL.

johnjbarton commented 9 years ago

Can you try sourceMaps: 'file', in the compile options?

d180cf commented 9 years ago

It doesn't work either. The produced .js file makes sense, but the corresponding .map file isn't generated:

var $__sample_45_es5_46_js__ = (function() {
  "use strict";
  var __moduleName = "sample-es5.js";
  var sample;
  (function(sample) {
    sample.isPositive = function(x) {
      return x > 0;
    };
    sample.isNegative = function(x) {
      return x < 0;
    };
  })(sample || (sample = {}));
  return {};
})();
//# sourceMappingURL=sample-es5.js.map

I've added this change to the sample folder.