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

Statements: 98.57% (69 / 70)      Branches: 97.22% (35 / 36)      Functions: 100% (13 / 13)      Lines: 98.44% (63 / 64)      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 1331 1 1 1   1   1 369 24 24 24       1 210   210 347     210     1 93     1 117     12   11   11 11   11 150 1       11 3   3       3 41 3       3       1 2 22 7       7         1 1   1 22       22 22 41   25 2 3     2   2 3         23 1 1 1         23         22 22   22   22 22       22       22          
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") return;
 
  var body = node.body;
 
  var built = buildNode(node.body, true);
  node.body = built.node;
 
  traverse.replace(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.replace(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 node.declarations.map(function (declar) {
        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";
 
  //
 
  nodes.push(util.template(templateName, {
    FUNCTION: func
  }, true));
 
  return {
    node: nodes,
    body: block
  };
};