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

Statements: 98.65% (73 / 74)      Branches: 97.62% (41 / 42)      Functions: 100% (13 / 13)      Lines: 98.48% (65 / 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 462 30 30 30       1 261   261 437     261     1 105     1 156     15   12   12 12   12 163 1       12 3   3       3 41 3       3       1 2 25 7       7         1 1   1 24       24 24 59   39 6 7     6   6 7   6         33 1 1 1         33         24 24   24   24 24 24       24       24          
var traverse = require("../traverse");
var util     = require("../util");
var b        = require("ast-types").builders;
var _        = require("lodash");
 
var blockTypes = ["FunctionDeclaration", "FunctionExpression", "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 (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") 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])) {
      Iif (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", ["FunctionDeclaration", "FunctionExpression"])) templateName += "-return";
 
  //
 
  nodes.push(util.template(templateName, {
    FUNCTION: func
  }, true));
 
  return {
    node: nodes,
    body: block
  };
};