bublejs/buble

Incorrectly converted spread operator on string

Opened this issue · 1 comments

I see there are a number of other issues related to the spread operator which have been reported, but I think this one dealing with strings is a separate case.

I had a function in my code that was meant to transform a base64-encoded string into a Uint8Array:

base64 => new Uint8Array([...atob(base64)].map(char => char.charCodeAt(0)));

Buble unfortunately converts the above code into this:

function (base64) { return new Uint8Array([].concat( atob(base64) ).map(function (char) { return char.charCodeAt(0); })); };

Instead of splitting the string value atob(base64) up into an array of individual characters, all that was produced was an array of length one, with the entire unbroken string inside the array as the single element. The result was that no matter how long the base64 input was, only a single-byte array would be produced.

I was able to work around the problem by changing the original code to this:

base64 => new Uint8Array(atob(base64).split('').map(char => char.charCodeAt(0)));

Even though I have a workaround for now, I thought you might want to know about this bug.

Looking at how babel does this, getting it right is actually pretty complicated:

"use strict";

function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }

function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); }

function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); }

function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }

(function (base64) {
  return new Uint8Array(_toConsumableArray(atob(base64)).map(function (_char) {
    return _char.charCodeAt(0);
  }));
});