-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
Copy pathno-static-this.js
95 lines (90 loc) · 2.54 KB
/
no-static-this.js
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
/**
* Copyright 2020 The AMP HTML Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
// Forbids use of `this` inside static class methods
//
// Good:
// ```
// class Foo {
// static s() {
// Foo.prop;
// }
//
// i() {
// this.prop;
// Foo.prop;
// }
// }
//
// Foo.prop = 1;
// ```
//
// Bad:
// ```
// class Foo {
// static s() {
// this.prop;
// }
// }
//
// Foo.prop = 1;
// ```
module.exports = {
meta: {
type: 'problem',
docs: {
description:
"Disallow using `this` within static functions, since Closure Compiler's Advanced Compilation breaks it",
context: 'https://github.com/google/closure-compiler/issues/2397',
},
},
create(context) {
return {
'MethodDefinition[static=true] ThisExpression': function (node) {
const ancestry = context.getAncestors().slice().reverse();
let i = 0;
for (; i < ancestry.length; i++) {
const ancestor = ancestry[i];
const {type} = ancestor;
// Arrow functions inherit `this` from their lexical scope, so we need
// to continue searching if it's an arrow.
if (
!type.includes('Function') ||
type === 'ArrowFunctionExpression'
) {
continue;
}
// If the direct parent of this function is a static method definition,
// then we've found our root method. If it's non-static, then it's a
// nested class expression's instance method, which is safe.
if (i < ancestry.length - 2) {
const parent = ancestry[i + 1];
if (parent.type === 'MethodDefinition' && parent.static) {
break;
}
}
// Found a function with it's own `this`, so it's safe.
return;
}
context.report({
node,
message:
'`this` in static methods is broken by Advanced Closure Compiler optimizations. Please use the class name directly.',
});
},
};
},
};