Instead of a templates file, let's give the runtime lib a try and see where this takes us.

I'm envisioning something like the following (super rough sketch of what's in my head at least):

es6-spread-operator-visitors.js
```
var RUNTIME = '____JSTRANSFORM_SPREAD_RUNTIME____';

function visitProgram(traverse, node, path, state) {
  if (state.g.opts.includeSpreadRuntime) {
    utils.append(fs.readFileSync('./es6-spread-operator-runtime.js'), state);
  }
}
visitProgram.test = function(node) {
  return node.type === Syntax.Program;
};

[a, ...b, c];
Array.prototype.concat.apply([],[a],RUNTIME.expandSpreadElement(b),[c])

[...a];

function visitArrayExpressionWithSpread(traverse, node, path, state) {

  // I didn't test this exact logic, just winging it for example's sake

  utils.append('Array.prototype.concat.apply([],[', state);
  node.elements.forEach(function(element) {
    if (element.type === Syntax.SpreadElement) {
      utils.move(element.range[0] + 3, state); // jump past '...'
      utils.append('],', state);
      utils.append(RUNTIME + '.assertSpreadElement(', state);
      utils.catchup(element.range[1], state);
      utils.append('),[', state);
    } else {
      utils.move(element.range[0], state);
      utils.catchup(element.range[1], state);
    }
  });
  utils.catchup(node.range[1], state);
}

// ...etc...
```

es6-spread-operator-runtime.js
```
(function(global) {
  function assertSpreadElement(element) {
    if (!Array.isArray(element)) {
      throw new TypeError('Attempted to spread a non-array!');
    }
    return element;
  }

  global.____JSTRANSFORM_SPREAD_RUNTIME____ = {
    assertSpreadElement: assertSpreadElement
  };
})(this);
```