lib/js/scope.js
function process(ast, scope){
  ast.scope = scope;
  ast.names = [];
  ast.scopes = [];

  var varWalker = function(token, scope){
    scope.declarations.push({
      type: 'var',
      name: token.id.name,
      parent: this.top(1),
      loc: token.loc.start
    });

    scope.put(token.id.name, {
      type: 'var',
      token: token.init,
      loc: token.loc.start
    });
  };

  return walker.walk(ast, {
    VariableDeclarator: varWalker,
    FunctionDeclaration: fnWalker,
    FunctionExpression: fnWalker,
    ArrowFunctionExpression: fnWalker,
    ExpressionStatement: function(token){
      if (token.directive && token.directive.toLowerCase() === 'use strict')
        scope.strict = true;
    },

    CatchClause: function(token, scope){
      var newScope = new Scope('catch', scope);

      scope.put(token.param.name, {
        type: 'catch',
        token: null
      });
      token.body.scope = newScope;

      this.scopes.push(scope);
    },

    Identifier: function(token, scope){
      var parent = this.top(1);

      // let insane begin!
      // todo implement more efficient solution in a future version
      var isLabel = parent.type === 'LabeledStatement' || parent.type === 'ContinueStatement' || parent.type === 'BreakStatement';
      var isFunctionName = parent.type === 'FunctionDeclaration' || parent.type === 'FunctionExpression' || parent.type === 'ClassDeclaration' || parent.type === 'ClassExpression';
      var isProperty = parent.type === 'Property';
      var isMemberExpression = parent.type === 'MemberExpression';
      var isAssignmentExpression = parent.type === 'AssignmentExpression';
      var isVariableDeclarator = parent.type === 'VariableDeclarator';

      if (isLabel || isFunctionName || isProperty || isMemberExpression || isAssignmentExpression || isVariableDeclarator)
      {
        var isObjectKey = isProperty && parent.key === token && parent.computed;
        var isObjectValue = isProperty && parent.value === token;
        var isMemberExpressionProperty = isMemberExpression && parent.property === token && parent.computed;
        var isMemberExpressionObject = isMemberExpression&& parent.object === token;
        var isVariableInit = isVariableDeclarator && parent.init === token;
        var isLeftOfAssignment = isAssignmentExpression && parent.left === token && parent.operator !== '=';
        var isRightOfAssignment = isAssignmentExpression && parent.right === token;
        // is it for..in variable? (mark its name as used)
        var isVarInForIn = false;
        if (isVariableDeclarator)
        {
          var declarationParent = this.top(3);
          isVarInForIn = declarationParent && declarationParent.type === 'ForInStatement';
        }

        if (isFunctionName || isLabel ||
          !isObjectKey && !isObjectValue &&
          !isMemberExpressionProperty && !isMemberExpressionObject &&
          !isLeftOfAssignment && !isRightOfAssignment &&
          !isVariableInit && !isVarInForIn)
          return;
      }

      this.names.push({
        scope: scope,
        token: token
      });
    }
  }, {
    names: ast.names,
    scopes: ast.scopes
  });
}
function process(ast, scope){
  ast.scope = scope;
  ast.names = [];
  ast.scopes = [];

  var varWalker = function(token, scope){
    scope.declarations.push({
      type: 'var',
      name: token.id.name,
      parent: this.top(1),
      loc: token.loc.start
    });

    scope.put(token.id.name, {
      type: 'var',
      token: token.init,
      loc: token.loc.start
    });
  };

  return walker.walk(ast, {
    VariableDeclarator: varWalker,
    FunctionDeclaration: fnWalker,
    FunctionExpression: fnWalker,
    ArrowFunctionExpression: fnWalker,
    ExpressionStatement: function(token){
      if (token.directive && token.directive.toLowerCase() === 'use strict')
        scope.strict = true;
    },

    CatchClause: function(token, scope){
      var newScope = new Scope('catch', scope);

      scope.put(token.param.name, {
        type: 'catch',
        token: null
      });
      token.body.scope = newScope;

      this.scopes.push(scope);
    },

    Identifier: function(token, scope){
      var parent = this.top(1);

      // let insane begin!
      // todo implement more efficient solution in a future version
      var isLabel = parent.type === 'LabeledStatement' || parent.type === 'ContinueStatement' || parent.type === 'BreakStatement';
      var isFunctionName = parent.type === 'FunctionDeclaration' || parent.type === 'FunctionExpression' || parent.type === 'ClassDeclaration' || parent.type === 'ClassExpression';
      var isProperty = parent.type === 'Property';
      var isMemberExpression = parent.type === 'MemberExpression';
      var isAssignmentExpression = parent.type === 'AssignmentExpression';
      var isVariableDeclarator = parent.type === 'VariableDeclarator';

      if (isLabel || isFunctionName || isProperty || isMemberExpression || isAssignmentExpression || isVariableDeclarator)
      {
        var isObjectKey = isProperty && parent.key === token && parent.computed;
        var isObjectValue = isProperty && parent.value === token;
        var isMemberExpressionProperty = isMemberExpression && parent.property === token && parent.computed;
        var isMemberExpressionObject = isMemberExpression&& parent.object === token;
        var isVariableInit = isVariableDeclarator && parent.init === token;
        var isLeftOfAssignment = isAssignmentExpression && parent.left === token && parent.operator !== '=';
        var isRightOfAssignment = isAssignmentExpression && parent.right === token;
        // is it for..in variable? (mark its name as used)
        var isVarInForIn = false;
        if (isVariableDeclarator)
        {
          var declarationParent = this.top(3);
          isVarInForIn = declarationParent && declarationParent.type === 'ForInStatement';
        }

        if (isFunctionName || isLabel ||
          !isObjectKey && !isObjectValue &&
          !isMemberExpressionProperty && !isMemberExpressionObject &&
          !isLeftOfAssignment && !isRightOfAssignment &&
          !isVariableInit && !isVarInForIn)
          return;
      }

      this.names.push({
        scope: scope,
        token: token
      });
    }
  }, {
    names: ast.names,
    scopes: ast.scopes
  });
}
function process ( ast , scope ) { ast . scope = scope ; ast . names = [ ] ; ast . scopes = [ ] ; var varWalker = function ( token , scope ) { scope . declarations . push ( { type : 'var' , name : token . id . name , parent : this . top ( 1 ) , loc : token . loc . start } ) ; scope . put ( token . id . name , { type : 'var' , token : token . init , loc : token . loc . start } ) ; } ; return walker . walk ( ast , { VariableDeclarator : varWalker , FunctionDeclaration : fnWalker , FunctionExpression : fnWalker , ArrowFunctionExpression : fnWalker , ExpressionStatement : function ( token ) { if ( token . directive && token . directive . toLowerCase ( ) === 'use strict' ) scope . strict = true ; } , CatchClause : function ( token , scope ) { var newScope = new Scope ( 'catch' , scope ) ; scope . put ( token . param . name , { type : 'catch' , token : null } ) ; token . body . scope = newScope ; this . scopes . push ( scope ) ; } , Identifier : function ( token , scope ) { var parent = this . top ( 1 ) ; // let insane begin! // todo implement more efficient solution in a future version var isLabel = parent . type === 'LabeledStatement' || parent . type === 'ContinueStatement' || parent . type === 'BreakStatement' ; var isFunctionName = parent . type === 'FunctionDeclaration' || parent . type === 'FunctionExpression' || parent . type === 'ClassDeclaration' || parent . type === 'ClassExpression' ; var isProperty = parent . type === 'Property' ; var isMemberExpression = parent . type === 'MemberExpression' ; var isAssignmentExpression = parent . type === 'AssignmentExpression' ; var isVariableDeclarator = parent . type === 'VariableDeclarator' ; if ( isLabel || isFunctionName || isProperty || isMemberExpression || isAssignmentExpression || isVariableDeclarator ) { var isObjectKey = isProperty && parent . key === token && parent . computed ; var isObjectValue = isProperty && parent . value === token ; var isMemberExpressionProperty = isMemberExpression && parent . property === token && parent . computed ; var isMemberExpressionObject = isMemberExpression && parent . object === token ; var isVariableInit = isVariableDeclarator && parent . init === token ; var isLeftOfAssignment = isAssignmentExpression && parent . left === token && parent . operator !== '=' ; var isRightOfAssignment = isAssignmentExpression && parent . right === token ; // is it for..in variable? (mark its name as used) var isVarInForIn = false ; if ( isVariableDeclarator ) { var declarationParent = this . top ( 3 ) ; isVarInForIn = declarationParent && declarationParent . type === 'ForInStatement' ; } if ( isFunctionName || isLabel || ! isObjectKey && ! isObjectValue && ! isMemberExpressionProperty && ! isMemberExpressionObject && ! isLeftOfAssignment && ! isRightOfAssignment && ! isVariableInit && ! isVarInForIn ) return ; } this . names . push ( { scope : scope , token : token } ) ; } } , { names : ast . names , scopes : ast . scopes } ) ; }
main function
main function