UNPKG

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