UNPKG

3.83 kBJavaScriptView Raw
1/**
2 * @fileoverview A rule to disallow `this` keywords outside of classes or class-like objects.
3 * @author Toru Nagashima
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const astUtils = require("./utils/ast-utils");
13
14//------------------------------------------------------------------------------
15// Rule Definition
16//------------------------------------------------------------------------------
17
18module.exports = {
19 meta: {
20 type: "suggestion",
21
22 docs: {
23 description: "disallow `this` keywords outside of classes or class-like objects",
24 category: "Best Practices",
25 recommended: false,
26 url: "https://eslint.org/docs/rules/no-invalid-this"
27 },
28
29 schema: []
30 },
31
32 create(context) {
33 const stack = [],
34 sourceCode = context.getSourceCode();
35
36 /**
37 * Gets the current checking context.
38 *
39 * The return value has a flag that whether or not `this` keyword is valid.
40 * The flag is initialized when got at the first time.
41 *
42 * @returns {{valid: boolean}}
43 * an object which has a flag that whether or not `this` keyword is valid.
44 */
45 stack.getCurrent = function() {
46 const current = this[this.length - 1];
47
48 if (!current.init) {
49 current.init = true;
50 current.valid = !astUtils.isDefaultThisBinding(
51 current.node,
52 sourceCode
53 );
54 }
55 return current;
56 };
57
58 /**
59 * Pushs new checking context into the stack.
60 *
61 * The checking context is not initialized yet.
62 * Because most functions don't have `this` keyword.
63 * When `this` keyword was found, the checking context is initialized.
64 *
65 * @param {ASTNode} node - A function node that was entered.
66 * @returns {void}
67 */
68 function enterFunction(node) {
69
70 // `this` can be invalid only under strict mode.
71 stack.push({
72 init: !context.getScope().isStrict,
73 node,
74 valid: true
75 });
76 }
77
78 /**
79 * Pops the current checking context from the stack.
80 * @returns {void}
81 */
82 function exitFunction() {
83 stack.pop();
84 }
85
86 return {
87
88 /*
89 * `this` is invalid only under strict mode.
90 * Modules is always strict mode.
91 */
92 Program(node) {
93 const scope = context.getScope(),
94 features = context.parserOptions.ecmaFeatures || {};
95
96 stack.push({
97 init: true,
98 node,
99 valid: !(
100 scope.isStrict ||
101 node.sourceType === "module" ||
102 (features.globalReturn && scope.childScopes[0].isStrict)
103 )
104 });
105 },
106
107 "Program:exit"() {
108 stack.pop();
109 },
110
111 FunctionDeclaration: enterFunction,
112 "FunctionDeclaration:exit": exitFunction,
113 FunctionExpression: enterFunction,
114 "FunctionExpression:exit": exitFunction,
115
116 // Reports if `this` of the current context is invalid.
117 ThisExpression(node) {
118 const current = stack.getCurrent();
119
120 if (current && !current.valid) {
121 context.report({ node, message: "Unexpected 'this'." });
122 }
123 }
124 };
125 }
126};