bublejs / buble

https://buble.surge.sh
MIT License
871 stars 67 forks source link

Support for transpiling Array.fill? #64

Closed stffrd closed 6 years ago

stffrd commented 6 years ago

(Search didn't turn up anything useful)

Buble doesn't currently support Array.fill as a feature, I'm curious as to the rationale behind this? I recently ran into an issue where my code broke because of Array.fill not being transpiled into compatible code with my browser environment.

My code looked like this:

// constant to show example
const count = 10; 

const segments = Array(count - 1).fill(0);

Obviously my usage of fill here is to populate a dynamically determined array length with dummy values so I can eventually populate it using map, as sparse arrays are ignored by array methods.

Turns out, this actually worked with buble in its place

const count = 10

const segments = Array(...Array(count - 1)).map(() => 0);

Which is effectively Array.apply(null, Array(count -1)).map(function(){ return 0 });

I understand it's an additional compilation step if you were to transpile it from fill(0) to use the spread operator, so I'm aware that that might be a limitation.

There might be something I'm missing here, but is there a reason we can't statically analyze Array.fill calls to map to an Array.apply call followed by .map() which would pass in the current array being worked on?

e.g. if I have some arbitrary array of values and I want to call fill

[1, 2, true, false, "lol"].fill(2) // -> [2, 2, 2, 2, 2]

couldn't it just transpile into this?

let a = [1, 2, true, false, "lol"]
Array.apply(a, Array(a.length)).map(() => 2);

This is a fill that should work even for sparse arrays.

Note: The longer I write this the more I become aware that yes, fill doesn't always have an arity of one argument, so supporting filling subsections of the array might take more finesse or be more complicated, but I figured it was worth starting a dialog.

stffrd commented 6 years ago

Here's my input/output in the buble REPL, by the way.

// Nope. 
Array(10).fill(0);

// Yep, once we transpile it. 
Array(...Array(10)).map(() => 0);

// Yep, ES5 fill. 
Array.apply(void 0, Array(10)).map(function () { return 0; });

output:

// Nope. 
Array(10).fill(0);

// Yep, once we transpile it. 
Array.apply(void 0, Array(10)).map(function () { return 0; });

// Yep, ES5 fill. 
Array.apply(void 0, Array(10)).map(function () { return 0; });
TrySound commented 6 years ago

@bradstaff Array.fill is a part of standard (or not?) library. Buble handles only special syntaxes which cannot be handled with es5. Just use one of dozens polyfills for that.

Rich-Harris commented 6 years ago

There are two parts of ES2015+ — syntax features and environment features. Syntax features are things like arrow functions and shorthand properties — stuff that's invalid ES5. Environment features are things like 'what methods exist on Array.prototype?' — e.g. fill.

Bublé is only concerned with syntax — taking invalid ES5 and transforming it into valid ES5 — because you can't polyfill syntax.

It can't reliably determine from reading thing.fill(x) in your source code that thing is an array, so it doesn't bother trying to fix the environment. So @TrySound, who beat me to the punch while I was writing this comment, is right — you'll need to add a polyfill.

stffrd commented 6 years ago

Thank you for the clarification y'all!