termi / es6-transpiler

Tomorrow's JavaScript syntax today
Other
216 stars 18 forks source link

Semicolon insertion for generated lines with leading [ ( characters #34

Closed timoxley closed 10 years ago

timoxley commented 10 years ago

The transpiler should probably insert semicolons wherever they would be inserted automatically in the source code, otherwise it can generate invalid JS when semicolons are omitted. See example below.

Maybe it'd be possible to only auto-insert them whenever a generated line will be broken by their omission e.g. any generated line starting with ( or [.

edit: found more minimal test case.

ES6 input:

let a = {
  b: {
    c: () => 0
  }
}

let exec = () => {
  let args = []
  a.b.c(...args)
}

exec()

Generated output:

var a = {
  b: {
    c: function()  {return 0}
  }
}

var exec = function()  {var $D$0;function ITER$0(v,f){var $Symbol_iterator=typeof Symbol!=='undefined'&&Symbol.iterator||'@@iterator';if(v){if(Array.isArray(v))return f?v.slice():v;var i,r;if(typeof v==='object'&&typeof (f=v[$Symbol_iterator])==='function'){i=f.call(v);r=[];while((f=i['next']()),f['done']!==true)r.push(f['value']);return r;}}throw new Error(v+' is not iterable')};
  var args = []
  ($D$0 = a.b).c.apply($D$0, ITER$0(args))
;$D$0 = void 0}

exec()

Error:

  ($D$0 = a.b).c.apply($D$0, ITER$0(args))
  ^
TypeError: object is not a function

Problem is there's no semi between these two lines, so it's interpreted as var args = []($D$0 = a.b), but would be valid es6 without the transpiler.

...
 var args = []
  ($D$0 = a.b).c.apply($D$0, ITER$0(args))
...

Perhaps the most minimal fix would be to just add a semi for the specific case of accessing arrow functions nested in other objects.

timoxley commented 10 years ago

Dug into this a bit, it's this spread handling code causing the problem:

                let tempVar = core.getScopeTempVar(node.callee.object, node.$scope);

                this.alter.wrap(
                    node.callee.object.range[0]
                    , node.callee.object.range[1]
                    , "(" + tempVar + " = "
                    , ")"
                );

                expressionAfter =
                    ".apply(" + tempVar
                    + ", "
                ;

                core.setScopeTempVar(tempVar, node, node.$scope, true);

Source

One can fix this specific issue with:

                this.alter.wrap(
                    node.callee.object.range[0]
                    , node.callee.object.range[1]
                    , ";(" + tempVar + " = " // added leading semi
                    , ")"
                );

But this causes a bunch of other issues if the statement isn't at the start of the line, e.g:

console.log( ;($D$0 = obj$0.obj).test.apply($D$0, [28].concat(ITER$0(arr))) === "THIS|28|6|3" )
 var T$3 = ;($D$0 = obj$0.obj).test.apply($D$0, [27].concat(ITER$0(arr)));

so looks like it requires some probing around the context to detect if there's any leading code… or perhaps some other type of handling, going to have to leave this to you though, sorry!

termi commented 10 years ago

I will fix it soon