Blame view

node_modules/eslint/lib/rules/no-use-before-define.js 3.59 KB
c39994410   Ryan Glover   wip converting to...
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
  /**
   * @fileoverview Rule to flag use of variables before they are defined
   * @author Ilya Volodin
   * @copyright 2013 Ilya Volodin. All rights reserved.
   */
  
  "use strict";
  
  //------------------------------------------------------------------------------
  // Requirements
  //------------------------------------------------------------------------------
  
  var astUtils = require("../ast-utils");
  
  //------------------------------------------------------------------------------
  // Constants
  //------------------------------------------------------------------------------
  
  var NO_FUNC = "nofunc";
  
  //------------------------------------------------------------------------------
  // Rule Definition
  //------------------------------------------------------------------------------
  
  module.exports = function(context) {
  
      /**
       * Finds and validates all variables in a given scope.
       * @param {Scope} scope The scope object.
       * @returns {void}
       * @private
       */
      function findVariablesInScope(scope) {
          var typeOption = context.options[0];
  
          /**
           * Report the node
           * @param {object} reference reference object
           * @param {ASTNode} declaration node to evaluate
           * @returns {void}
           * @private
           */
          function checkLocationAndReport(reference, declaration) {
              if (typeOption !== NO_FUNC || declaration.defs[0].type !== "FunctionName") {
                  if (declaration.identifiers[0].range[1] > reference.identifier.range[1]) {
                      context.report(reference.identifier, "\"{{a}}\" was used before it was defined", {a: reference.identifier.name});
                  }
              }
          }
  
          scope.references.forEach(function(reference) {
              // if the reference is resolved check for declaration location
              // if not, it could be function invocation, try to find manually
              if (reference.resolved && reference.resolved.identifiers.length > 0) {
                  checkLocationAndReport(reference, reference.resolved);
              } else {
                  var declaration = astUtils.getVariableByName(scope, reference.identifier.name);
                  // if there're no identifiers, this is a global environment variable
                  if (declaration && declaration.identifiers.length !== 0) {
                      checkLocationAndReport(reference, declaration);
                  }
              }
          });
      }
  
  
      /**
       * Validates variables inside of a node's scope.
       * @param {ASTNode} node The node to check.
       * @returns {void}
       * @private
       */
      function findVariables() {
          var scope = context.getScope();
          findVariablesInScope(scope);
      }
  
      var ruleDefinition = {
          "Program": function() {
              var scope = context.getScope();
              findVariablesInScope(scope);
  
              // both Node.js and Modules have an extra scope
              if (context.ecmaFeatures.globalReturn || context.ecmaFeatures.modules) {
                  findVariablesInScope(scope.childScopes[0]);
              }
          }
      };
  
      if (context.ecmaFeatures.blockBindings) {
          ruleDefinition.BlockStatement = ruleDefinition.SwitchStatement = findVariables;
  
          ruleDefinition.ArrowFunctionExpression = function(node) {
              if (node.body.type !== "BlockStatement") {
                  findVariables(node);
              }
          };
      } else {
          ruleDefinition.FunctionExpression = ruleDefinition.FunctionDeclaration = ruleDefinition.ArrowFunctionExpression = findVariables;
      }
  
      return ruleDefinition;
  };
  
  module.exports.schema = [
      {
          "enum": ["nofunc"]
      }
  ];