require("./polyfill");

var sourceMapSupport = require("source-map-support");
var roadrunner       = require('roadrunner');
var util             = require("./util");
var to5              = require("./index");
var fs               = require("fs");
var _                = require("lodash");

sourceMapSupport.install({
  retrieveSourceMap: function (source) {
    var map = maps && maps[source];
    if (map) {
      return {
        url: null,
        map: map
      };
    } else {
      return null;
    }
  }
});

//

var blacklist  = [];

var blacklistTest = function (transformer, code) {
  try {
    if (_.isFunction(code)) {
      code();
    } else {
      new Function(code);
    }
    blacklist.push(transformer);
  } catch (err) {
    if (err.name !== "SyntaxError") throw err;
  }
};

blacklistTest("arrayComprehension", "var foo = [for (foo of bar) foo * foo];");
//blacklistTest("generatorComprehension", "");
blacklistTest("arrowFunctions", "var foo = x => x * x;");
blacklistTest("classes", "class Foo {}");
blacklistTest("computedPropertyNames", "var foo = { [foo]: bar };");
//blacklistTest("constants", "const foo = 0;");
blacklistTest("defaultParamaters", "var foo = function (bar = 0) {};");
blacklistTest("destructuring", "var { x, y } = { x: 0, y: 0 };");
blacklistTest("forOf", "for (var foo of bar) {}");
blacklistTest("generators", "function* foo() {}");
blacklistTest("letScoping", "let foo = 0;");
blacklistTest("modules", 'import foo from "from";');
blacklistTest("propertyMethodAssignment", "{ get foo() {} }");
blacklistTest("propertyNameShorthand", "var foo = { x, y };");
blacklistTest("restParameters", "function foo(...bar) {}");
blacklistTest("spread", "foo(...bar);");
blacklistTest("templateLiterals", "var foo = `foo`;");
blacklistTest("unicodeRegex", function () { new RegExp("foo", "u"); });

//

var transformOpts = {};
var ignoreRegex   = /node_modules/;
var onlyRegex;
var whitelist     = [];
var cache;
var exts          = {};
var maps          = {};
var old           = require.extensions[".js"];

var mtime = function (filename) {
  return +fs.statSync(filename).mtime;
};

var loader = function (m, filename) {
  if ((ignoreRegex && ignoreRegex.test(filename)) || (onlyRegex && !onlyRegex.test(filename))) {
    return old.apply(this, arguments);
  }

  var result;

  if (cache && cache[filename].mtime === mtime(filename)) {
    result = cache[filename];
  }

  result = result || to5.transformFileSync(filename, _.extend({
    whitelist: whitelist,
    blacklist: blacklist,
    sourceMap: true,
    modules:   "commonInterop"
  }, transformOpts));

  if (cache) {
    result.mtime = mtime(filename);
    cache[filename] = result;
  }

  maps[filename] = result.map;

  m._compile(result.code, filename);
};

var hookExtensions = function (_exts) {
  _.each(exts, function (old, ext) {
    require.extensions[ext] = old;
  });

  exts = {};

  _.each(_exts, function (ext) {
    exts[ext] = require.extensions[ext];
    require.extensions[ext] = loader;
  });
};

hookExtensions([".es6", ".js"]);

module.exports = function (opts) {
  // normalise options
  opts = opts || {};
  if (_.isRegExp(opts)) opts = { ignore: opts };
  if (opts.ignoreRegex != null) opts.ignore = opts.ignoreRegex;

  if (opts.only != null) onlyRegex = util.regexify(opts.only);
  if (opts.ignore != null) ignoreRegex = util.regexify(opts.ignore);

  if (opts.extensions) hookExtensions(util.arrayify(opts.extensions));

  if (opts.cache) cache = roadrunner.get('6to5');
  if (opts.cache === false) cache = null;

  _.extend(transformOpts, opts);
};

@@ -2322,27 +2322,70 @@
 ache
- && cache%5Bfilename%5D
+) %7B%0A    var cached = cache%5Bfilename%5D;%0A    if (cached && cached
 .mti
@@ -2410,24 +2410,26 @@
 ame)) %7B%0A    
+  
 result = cac
@@ -2430,27 +2430,24 @@
  = cache
-%5Bfilename%5D;
+d;%0A    %7D
 %0A  %7D%0A%0A  

fix require caching