Skip to content

Commit 9016e10

Browse files
authored
Add no-legacy-object-prototype-accessor-methods rule (#23)
* Add no-legacy-object-prototype-accessor-methods rule * fix for eslint v7 * fix for eslint v7
1 parent 2bb9cd0 commit 9016e10

File tree

5 files changed

+216
-0
lines changed

5 files changed

+216
-0
lines changed

docs/rules/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ The rules are not included in any preset.
236236
| [es-x/no-function-declarations-in-if-statement-clauses-without-block](./no-function-declarations-in-if-statement-clauses-without-block.md) | disallow function declarations in if statement clauses without using blocks. | 🔧 |
237237
| [es-x/no-initializers-in-for-in](./no-initializers-in-for-in.md) | disallow initializers in for-in heads. | |
238238
| [es-x/no-labelled-function-declarations](./no-labelled-function-declarations.md) | disallow labelled function declarations. | |
239+
| [es-x/no-legacy-object-prototype-accessor-methods](./no-legacy-object-prototype-accessor-methods.md) | disallow legacy `Object.prototype` accessor methods. | |
239240
| [es-x/no-regexp-prototype-compile](./no-regexp-prototype-compile.md) | disallow the `RegExp.prototype.compile` method. | |
240241
| [es-x/no-shadow-catch-param](./no-shadow-catch-param.md) | disallow identifiers from shadowing catch parameter names. | |
241242
| [es-x/no-string-create-html-methods](./no-string-create-html-methods.md) | disallow HTML creation methods of string instances. | |
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# es-x/no-legacy-object-prototype-accessor-methods
2+
> disallow legacy `Object.prototype` accessor methods
3+
4+
This rule reports [the legacy Object.prototype accessor methods](https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.prototype-legacy-accessor-methods) as errors.
5+
6+
## Examples
7+
8+
⛔ Examples of **incorrect** code for this rule:
9+
10+
<eslint-playground type="bad" code="/*eslint es-x/no-legacy-object-prototype-accessor-methods: error */
11+
foo.__defineGetter__(prop, func)
12+
foo.__defineSetter__(prop, val, func)
13+
foo.__lookupGetter__(prop)
14+
foo.__lookupSetter__(prop)
15+
" />
16+
17+
## 📚 References
18+
19+
- [Rule source](https://github.com/ota-meshi/eslint-plugin-es-x/blob/master/lib/rules/no-legacy-object-prototype-accessor-methods.js)
20+
- [Test source](https://github.com/ota-meshi/eslint-plugin-es-x/blob/master/tests/lib/rules/no-legacy-object-prototype-accessor-methods.js)

lib/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ module.exports = {
109109
"no-json-superset": require("./rules/no-json-superset"),
110110
"no-keyword-properties": require("./rules/no-keyword-properties"),
111111
"no-labelled-function-declarations": require("./rules/no-labelled-function-declarations"),
112+
"no-legacy-object-prototype-accessor-methods": require("./rules/no-legacy-object-prototype-accessor-methods"),
112113
"no-logical-assignment-operators": require("./rules/no-logical-assignment-operators"),
113114
"no-malformed-template-literals": require("./rules/no-malformed-template-literals"),
114115
"no-map": require("./rules/no-map"),
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"use strict"
2+
3+
const { getPropertyName, findVariable } = require("eslint-utils")
4+
5+
const LEGACY_ACCESSOR_METHODS = new Set([
6+
"__defineGetter__",
7+
"__defineSetter__",
8+
"__lookupGetter__",
9+
"__lookupSetter__",
10+
])
11+
12+
module.exports = {
13+
meta: {
14+
docs: {
15+
description: "disallow legacy `Object.prototype` accessor methods.",
16+
category: "legacy",
17+
recommended: false,
18+
url: "http://ota-meshi.github.io/eslint-plugin-es-x/rules/no-legacy-object-prototype-accessor-methods.html",
19+
},
20+
fixable: null,
21+
messages: {
22+
forbidden: "LEGACY '{{name}}' method is forbidden.",
23+
},
24+
schema: [],
25+
type: "problem",
26+
},
27+
create(context) {
28+
const reported = new Set()
29+
30+
function report(name, node) {
31+
if (reported.has(node)) {
32+
return
33+
}
34+
reported.add(node)
35+
context.report({
36+
node,
37+
messageId: "forbidden",
38+
data: {
39+
name,
40+
},
41+
})
42+
}
43+
44+
return {
45+
MemberExpression(node) {
46+
const name = getPropertyName(node)
47+
if (!LEGACY_ACCESSOR_METHODS.has(name)) {
48+
return
49+
}
50+
report(name, node.property)
51+
},
52+
Identifier(node) {
53+
const name = node.name
54+
if (!LEGACY_ACCESSOR_METHODS.has(name)) {
55+
return
56+
}
57+
if (
58+
node.parent.type === "MemberExpression" &&
59+
node.parent.property === node
60+
) {
61+
// Already reported.
62+
return
63+
}
64+
if (
65+
node.parent.type === "Property" &&
66+
!node.parent.shorthand &&
67+
node.parent.key === node
68+
) {
69+
return
70+
}
71+
const scopeManager = context.getSourceCode().scopeManager
72+
if (
73+
// Not defined as global variables.
74+
!scopeManager.globalScope.through.some(
75+
({ identifier }) => identifier === node,
76+
)
77+
) {
78+
const variable = findVariable(context.getScope(), node)
79+
if (!variable) {
80+
return
81+
}
82+
// It is defined as global variables.
83+
if (variable.defs.length) {
84+
return
85+
}
86+
}
87+
report(name, node)
88+
},
89+
}
90+
},
91+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"use strict"
2+
3+
const RuleTester = require("../../tester")
4+
const rule = require("../../../lib/rules/no-legacy-object-prototype-accessor-methods.js")
5+
6+
new RuleTester().run("no-legacy-object-prototype-accessor-methods", rule, {
7+
valid: [
8+
"Object.defineProperty(foo, prop, descriptor)",
9+
"Object.getOwnPropertyDescriptor(foo, prop)",
10+
`
11+
const __defineGetter__ = ()=>42;
12+
__defineGetter__()
13+
`,
14+
`
15+
const __defineSetter__ = ()=>42;
16+
__defineSetter__()
17+
`,
18+
`
19+
const __lookupGetter__ = ()=>42;
20+
__lookupGetter__()
21+
`,
22+
`
23+
const __lookupSetter__ = ()=>42;
24+
__lookupSetter__()
25+
`,
26+
`
27+
{
28+
const __defineGetter__ = ()=>42;
29+
__defineGetter__()
30+
}
31+
`,
32+
`
33+
{
34+
var __defineGetter__ = ()=>42;
35+
__defineGetter__()
36+
}
37+
`,
38+
`
39+
const foo = {__defineGetter__:42};
40+
`,
41+
],
42+
invalid: [
43+
{
44+
code: "foo.__defineGetter__(prop, func)",
45+
errors: ["LEGACY '__defineGetter__' method is forbidden."],
46+
},
47+
{
48+
code: "foo.__defineSetter__(prop, val, func)",
49+
errors: ["LEGACY '__defineSetter__' method is forbidden."],
50+
},
51+
{
52+
code: "foo.__lookupGetter__(prop)",
53+
errors: ["LEGACY '__lookupGetter__' method is forbidden."],
54+
},
55+
{
56+
code: "foo.__lookupSetter__(prop)",
57+
errors: ["LEGACY '__lookupSetter__' method is forbidden."],
58+
},
59+
{
60+
code: "__defineGetter__(prop, func)",
61+
errors: ["LEGACY '__defineGetter__' method is forbidden."],
62+
},
63+
{
64+
code: "__defineSetter__(prop, val, func)",
65+
errors: ["LEGACY '__defineSetter__' method is forbidden."],
66+
},
67+
{
68+
code: "__lookupGetter__(prop)",
69+
errors: ["LEGACY '__lookupGetter__' method is forbidden."],
70+
},
71+
{
72+
code: "__lookupSetter__(prop)",
73+
errors: ["LEGACY '__lookupSetter__' method is forbidden."],
74+
},
75+
{
76+
code: `
77+
__defineGetter__(prop, func)
78+
__defineSetter__(prop, val, func)
79+
__lookupGetter__(prop)
80+
__lookupSetter__(prop)`,
81+
globals: {
82+
__defineGetter__: false,
83+
__defineSetter__: false,
84+
__lookupGetter__: false,
85+
__lookupSetter__: false,
86+
},
87+
errors: [
88+
"LEGACY '__defineGetter__' method is forbidden.",
89+
"LEGACY '__defineSetter__' method is forbidden.",
90+
"LEGACY '__lookupGetter__' method is forbidden.",
91+
"LEGACY '__lookupSetter__' method is forbidden.",
92+
],
93+
},
94+
{
95+
code: "__defineGetter__.call",
96+
errors: ["LEGACY '__defineGetter__' method is forbidden."],
97+
},
98+
{
99+
code: "const foo = {__defineGetter__}",
100+
errors: ["LEGACY '__defineGetter__' method is forbidden."],
101+
},
102+
],
103+
})

0 commit comments

Comments
 (0)