UNPKG

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