Blame view

node_modules/eslint/lib/rules/no-invalid-this.js 3.62 KB
f7563de62   Palak Handa   first commit
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
  /**
   * @fileoverview A rule to disallow `this` keywords outside of classes or class-like objects.
   * @author Toru Nagashima
   */
  
  "use strict";
  
  //------------------------------------------------------------------------------
  // Requirements
  //------------------------------------------------------------------------------
  
  const astUtils = require("../ast-utils");
  
  //------------------------------------------------------------------------------
  // Rule Definition
  //------------------------------------------------------------------------------
  
  module.exports = {
      meta: {
          docs: {
              description: "disallow `this` keywords outside of classes or class-like objects",
              category: "Best Practices",
              recommended: false
          },
  
          schema: []
      },
  
      create(context) {
          const stack = [],
              sourceCode = context.getSourceCode();
  
          /**
           * Gets the current checking context.
           *
           * The return value has a flag that whether or not `this` keyword is valid.
           * The flag is initialized when got at the first time.
           *
           * @returns {{valid: boolean}}
           *   an object which has a flag that whether or not `this` keyword is valid.
           */
          stack.getCurrent = function() {
              const current = this[this.length - 1];
  
              if (!current.init) {
                  current.init = true;
                  current.valid = !astUtils.isDefaultThisBinding(
                      current.node,
                      sourceCode);
              }
              return current;
          };
  
          /**
           * Pushs new checking context into the stack.
           *
           * The checking context is not initialized yet.
           * Because most functions don't have `this` keyword.
           * When `this` keyword was found, the checking context is initialized.
           *
           * @param {ASTNode} node - A function node that was entered.
           * @returns {void}
           */
          function enterFunction(node) {
  
              // `this` can be invalid only under strict mode.
              stack.push({
                  init: !context.getScope().isStrict,
                  node,
                  valid: true
              });
          }
  
          /**
           * Pops the current checking context from the stack.
           * @returns {void}
           */
          function exitFunction() {
              stack.pop();
          }
  
          return {
  
              /*
               * `this` is invalid only under strict mode.
               * Modules is always strict mode.
               */
              Program(node) {
                  const scope = context.getScope(),
                      features = context.parserOptions.ecmaFeatures || {};
  
                  stack.push({
                      init: true,
                      node,
                      valid: !(
                          scope.isStrict ||
                          node.sourceType === "module" ||
                          (features.globalReturn && scope.childScopes[0].isStrict)
                      )
                  });
              },
  
              "Program:exit"() {
                  stack.pop();
              },
  
              FunctionDeclaration: enterFunction,
              "FunctionDeclaration:exit": exitFunction,
              FunctionExpression: enterFunction,
              "FunctionExpression:exit": exitFunction,
  
              // Reports if `this` of the current context is invalid.
              ThisExpression(node) {
                  const current = stack.getCurrent();
  
                  if (current && !current.valid) {
                      context.report({ node, message: "Unexpected 'this'." });
                  }
              }
          };
      }
  };