Code coverage report for 6to5/transformers/block-binding.js

Statements: 100% (74 / 74)      Branches: 100% (40 / 40)      Functions: 100% (13 / 13)      Lines: 100% (66 / 66)      Ignored: none     

All files » 6to5/transformers/ » block-binding.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 1361 1 1 1   1   1 525 36 36 36       1 287   287 498     287     1 113     1 174     15   12   12 12   12 163 1       12 3   3       3 41 3       3       1 2 27 8 1     7         1 1   1 26       26 26 66   41 6 7     6   6 7   6         35 1 1 1         35         26 26   26   26 26 26       26       26          
var traverse = require("../traverse");
var util     = require("../util");
var b        = require("ast-types").builders;
var _        = require("lodash");
 
var blockTypes = traverse.FUNCTION_TYPES.concat(["BlockStatement"]);
 
var isLet = function (node) {
  if (node && node.type === "VariableDeclaration" && node.kind === "let") {
    node.kind = "var";
    node._ignoreBlockBindingHoist = true;
    return true;
  }
};
 
var hasLet = function (nodes) {
  var has = false;
 
  _.each(nodes, function (node) {
    if (isLet(node)) has = true;
  });
 
  return has;
};
 
exports.Program = function (node) {
   if (hasLet(node.body)) node.body = buildNode(node.body).node;
};
 
exports.BlockStatement = function (node, parent, opts, generateUid) {
  if (!hasLet(node.body)) return;
 
  // ignore if we're the body of a closure already
  if (_.contains(traverse.FUNCTION_TYPES, parent.type)) return;
 
  var body = node.body;
 
  var built = buildNode(node.body, true);
  node.body = built.node;
 
  traverse(built.body, function (node) {
    if (node.type === "ContinueStatement") {
      return b.returnStatement(null);
    }
  }, blockTypes);
 
  if (traverse.hasType(body, "BreakStatement", blockTypes)) {
    var id = b.identifier(generateUid("break"));
 
    node.body.unshift(b.variableDeclaration("var", [
      b.variableDeclarator(id, b.literal(false))
    ]));
 
    traverse(built.body, function (node) {
      if (node.type === "BreakStatement") {
        return b.returnStatement(b.assignmentExpression("=", id, b.literal(true)));
      }
    }, blockTypes);
 
    node.body.push(b.ifStatement(id, b.breakStatement()));
  }
};
 
var buildForStatement = function (key) {
  return function (node, parent) {
    if (isLet(node[key])) {
      if (parent.type === "LabeledStatement") {
        throw util.errorWithNode(parent, "Label statements not supported with block binding yet.");
      }
 
      return buildNode(node).node;
    }
  };
};
 
exports.ForOfStatement = exports.ForInStatement = buildForStatement("left");
exports.ForStatement = buildForStatement("init");
 
var buildNode = function (node) {
  var nodes = [];
 
  // hoist normal variable declarations
 
  node = [].concat(node);
  node = node.map(function (node) {
    if (node._ignoreBlockBindingHoist) return node;
 
    if (node.type === "VariableDeclaration" && node.kind === "var") {
      var declars = node.declarations.map(function (declar) {
        return b.variableDeclarator(declar.id, null);
      });
 
      nodes.push(b.variableDeclaration("var", declars));
 
      return _.compact(node.declarations.map(function (declar) {
        if (!declar.init) return;
 
        return util.template("assign", {
          VALUE: declar.init,
          KEY:   declar.id
        }, true);
      }));
    } else if (node.type === "ForInStatement" && node.left.type === "VariableDeclaration" && !node.left._ignoreBlockBindingHoist) {
      var id = node.left.declarations[0].id;
      node.left = id;
      nodes.push(util.template("variable-declare", {
        KEY: id
      }));
    }
 
    return node;
  });
 
  //
 
  var block = b.blockStatement([]);
  block.body = node;
 
  var func = b.functionExpression(null, [], block, false);
 
  var templateName = "function-call";
  if (traverse.hasType(node, "ThisExpression")) templateName += "-this";
  if (traverse.hasType(node, "ReturnStatement", traverse.FUNCTION_TYPES)) templateName += "-return";
 
  //
 
  nodes.push(util.template(templateName, {
    FUNCTION: func
  }, true));
 
  return {
    node: nodes,
    body: block
  };
};