Code coverage report for 6to5/traverse/scope.js

Statements: 100% (63 / 63)      Branches: 98.04% (50 / 51)      Functions: 100% (15 / 15)      Lines: 100% (57 / 57)      Ignored: none     

All files » 6to5/traverse/ » scope.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 1281   1 1 1   1                   1 41069 41069   41069     1 41069 41069   2406 2406   2406 6316         2406 117 234 234     117         2406 1679   2762           2406 40         2406 1118 23319 98 196 196           23319   22834 4258         22834 757             2406 672 672 403       2406     1 6316 5655     1 156     1 14858     1 213     1 14682     1 14702     1 14111    
module.exports = Scope;
 
var traverse = require("./index");
var t        = require("../types");
var _        = require("lodash");
 
var FOR_KEYS = ["left", "init"];
 
/**
 * This searches the current "scope" and collects all references/declarations
 * within.
 *
 * @param {Node} block
 * @param {Scope} [parent]
 */
 
function Scope(block, parent) {
  this.parent = parent;
  this.block  = block;
 
  this.references = this.getReferences();
}
 
Scope.prototype.getReferences = function () {
  var block = this.block;
  if (block._scopeReferences) return block._scopeReferences;
 
  var self       = this;
  var references = block._scopeReferences = {};
 
  var add = function (node) {
    self.add(node, references);
  };
 
  // ForStatement - left, init
 
  if (t.isFor(block)) {
    _.each(FOR_KEYS, function (key) {
      var node = block[key];
      if (t.isLet(node)) add(node);
    });
 
    block = block.body;
  }
 
  // Program, BlockStatement - let variables
 
  if (t.isBlockStatement(block) || t.isProgram(block)) {
    _.each(block.body, function (node) {
      // check for non-var `VariableDeclaration`s
      if (t.isLet(node)) add(node);
    });
  }
 
  // CatchClause - param
 
  if (t.isCatchClause(block)) {
    add(block.param);
  }
 
  // Program, Function - var variables
 
  if (t.isProgram(block) || t.isFunction(block)) {
    traverse(block, function (node, parent, scope) {
      if (t.isFor(node)) {
        _.each(FOR_KEYS, function (key) {
          var declar = node[key];
          if (t.isVar(declar)) add(declar);
        });
      }
 
      // this block is a function so we'll stop since none of the variables
      // declared within are accessible
      if (t.isFunction(node)) return false;
 
      if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
        add(node);
      }
 
      // we've ran into a declaration!
      // we'll let the BlockStatement scope deal with `let` declarations
      if (t.isDeclaration(node) && !t.isLet(node)) {
        add(node);
      }
    }, { scope: this });
  }
 
  // Function - params, rest
 
  if (t.isFunction(block)) {
    add(block.rest);
    _.each(block.params, function (param) {
      add(param);
    });
  }
 
  return references;
};
 
Scope.prototype.add = function (node, references) {
  if (!node) return;
  _.merge(references || this.references, t.getIds(node, true));
};
 
Scope.prototype.get = function (id) {
  return id && (this.getOwn(id) || this.parentGet(id));
};
 
Scope.prototype.getOwn = function (id) {
  return _.has(this.references, id) && this.references[id];
};
 
Scope.prototype.parentGet = function (id) {
  return this.parent && this.parent.get(id);
};
 
Scope.prototype.has = function (id) {
  return id && (this.hasOwn(id) || this.parentHas(id));
};
 
Scope.prototype.hasOwn = function (id) {
  return !!this.getOwn(id);
};
 
Scope.prototype.parentHas = function (id) {
  return this.parent && this.parent.has(id);
};