<commit_before>"use strict";

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;

  var info = this.getInfo();
  this.references = info.references;
  this.declarations = info.declarations;
}

var vars = require("jshint/src/vars");

Scope.defaultDeclarations = _.flatten([
  vars.newEcmaIdentifiers,
  vars.node,
  vars.ecmaIdentifiers,
  vars.reservedVars
].map(_.keys));

Scope.add = function (node, references) {
  if (!node) return;
  _.defaults(references, t.getIds(node, true));
};

/**
 * Description
 *
 * @param {File} file
 * @param {String} [name="temp"]
 */

Scope.prototype.generateTemp = function (file, name) {
  var id = file.generateUidIdentifier(name || "temp", this);
  this.push({
    key: id.name,
    id: id
  });
  return id;
};

/*
 * Description
 *
 * @param {Object} parent
 * @param {File} file
 * @param {Scope} scope
 * @returns {Object}
 */

Scope.prototype.generateUidBasedOnNode = function (parent, file) {
  var node = parent;

  if (t.isAssignmentExpression(parent)) {
    node = parent.left;
  } else if (t.isVariableDeclarator(parent)) {
    node = parent.id;
  } else if (t.isProperty(node)) {
    node = node.key;
  }

  var parts = [];

  var add = function (node) {
    if (t.isMemberExpression(node)) {
      add(node.object);
      add(node.property);
    } else if (t.isIdentifier(node)) {
      parts.push(node.name);
    } else if (t.isLiteral(node)) {
      parts.push(node.value);
    } else if (t.isCallExpression(node)) {
      add(node.callee);
    }
  };

  add(node);

  var id = parts.join("$");
  id = id.replace(/^_/, "") || "ref";

  return file.generateUidIdentifier(id, this);
};

/**
 * Description
 *
 * @param {Object} node
 * @param {File} file
 * @returns {Object}
 */

Scope.prototype.generateTempBasedOnNode = function (node, file) {
  if (t.isIdentifier(node) && this.has(node.name, true)) {
    return null;
  }

  var id = this.generateUidBasedOnNode(node, file);
  this.push({
    key: id.name,
    id: id
  });
  return id;
};

Scope.prototype.getInfo = function () {
  var block = this.block;
  if (block._scopeInfo) return block._scopeInfo;

  var info = block._scopeInfo = {};
  var references = info.references = {};
  var declarations = info.declarations = {};

  var add = function (node, reference) {
    Scope.add(node, references);
    if (!reference) Scope.add(node, declarations);
  };

  // ForStatement - left, init

  if (t.isFor(block)) {
    _.each(FOR_KEYS, function (key) {
      var node = block[key];
      if (t.isBlockScoped(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.isBlockScoped(node)) add(node);
    });
  }

  // CatchClause - param

  if (t.isCatchClause(block)) {
    add(block.param);
  }

  // ComprehensionExpression - blocks

  if (t.isComprehensionExpression(block)) {
    add(block);
  }

  // Program, Function - var variables
<commit_msg>loops should contain their child block let declarations<commit_after>"use strict";

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;

  var info = this.getInfo();
  this.references = info.references;
  this.declarations = info.declarations;
}

var vars = require("jshint/src/vars");

Scope.defaultDeclarations = _.flatten([
  vars.newEcmaIdentifiers,
  vars.node,
  vars.ecmaIdentifiers,
  vars.reservedVars
].map(_.keys));

Scope.add = function (node, references) {
  if (!node) return;
  _.defaults(references, t.getIds(node, true));
};

/**
 * Description
 *
 * @param {File} file
 * @param {String} [name="temp"]
 */

Scope.prototype.generateTemp = function (file, name) {
  var id = file.generateUidIdentifier(name || "temp", this);
  this.push({
    key: id.name,
    id: id
  });
  return id;
};

/*
 * Description
 *
 * @param {Object} parent
 * @param {File} file
 * @param {Scope} scope
 * @returns {Object}
 */

Scope.prototype.generateUidBasedOnNode = function (parent, file) {
  var node = parent;

  if (t.isAssignmentExpression(parent)) {
    node = parent.left;
  } else if (t.isVariableDeclarator(parent)) {
    node = parent.id;
  } else if (t.isProperty(node)) {
    node = node.key;
  }

  var parts = [];

  var add = function (node) {
    if (t.isMemberExpression(node)) {
      add(node.object);
      add(node.property);
    } else if (t.isIdentifier(node)) {
      parts.push(node.name);
    } else if (t.isLiteral(node)) {
      parts.push(node.value);
    } else if (t.isCallExpression(node)) {
      add(node.callee);
    }
  };

  add(node);

  var id = parts.join("$");
  id = id.replace(/^_/, "") || "ref";

  return file.generateUidIdentifier(id, this);
};

/**
 * Description
 *
 * @param {Object} node
 * @param {File} file
 * @returns {Object}
 */

Scope.prototype.generateTempBasedOnNode = function (node, file) {
  if (t.isIdentifier(node) && this.has(node.name, true)) {
    return null;
  }

  var id = this.generateUidBasedOnNode(node, file);
  this.push({
    key: id.name,
    id: id
  });
  return id;
};

Scope.prototype.getInfo = function () {
  var parent = this.parent;
  var block = this.block;
  if (block._scopeInfo) return block._scopeInfo;

  var info = block._scopeInfo = {};
  var references = info.references = {};
  var declarations = info.declarations = {};

  var add = function (node, reference) {
    Scope.add(node, references);
    if (!reference) Scope.add(node, declarations);
  };

  if (parent && t.isBlockStatement(block) && t.isFor(parent.block)) {
    return info;
  }

  // ForStatement - left, init

  if (t.isFor(block)) {
    _.each(FOR_KEYS, function (key) {
      var node = block[key];
      if (t.isBlockScoped(node)) add(node);
    });

    if (t.isBlockStatement(block.body)) {
      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.isBlockScoped(node)) add(node);
    });
  }

  // CatchClause - param

  if (t.isCatchClause(block)) {
    add(block.param);
  }

  // ComprehensionExpression - blocks

  if (t.isComprehensionExpression(block)) {
    add(block);
  }

  // Program, Function - var variables

{'fraction_non_alphanumeric': 0.16211215485340166, 'fraction_numerical': 0.0, 'mean_word_length': 3.1165787932044524, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3277765', 'n_tokens_mistral': 2451, 'n_tokens_neox': 2396, 'n_words': 538}