no-extend-native.js
3.83 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/**
* @fileoverview Rule to flag adding properties to native object's prototypes.
* @author David Nelson
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const globals = require("globals");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: "disallow extending native types",
category: "Best Practices",
recommended: false
},
schema: [
{
type: "object",
properties: {
exceptions: {
type: "array",
items: {
type: "string"
},
uniqueItems: true
}
},
additionalProperties: false
}
]
},
create(context) {
const config = context.options[0] || {};
const exceptions = config.exceptions || [];
let modifiedBuiltins = Object.keys(globals.builtin).filter(builtin => builtin[0].toUpperCase() === builtin[0]);
if (exceptions.length) {
modifiedBuiltins = modifiedBuiltins.filter(builtIn => exceptions.indexOf(builtIn) === -1);
}
return {
// handle the Array.prototype.extra style case
AssignmentExpression(node) {
const lhs = node.left;
if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") {
return;
}
const affectsProto = lhs.object.computed
? lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype"
: lhs.object.property.name === "prototype";
if (!affectsProto) {
return;
}
modifiedBuiltins.forEach(builtin => {
if (lhs.object.object.name === builtin) {
context.report({
node,
message: "{{builtin}} prototype is read only, properties should not be added.",
data: {
builtin
}
});
}
});
},
// handle the Object.definePropert[y|ies](Array.prototype) case
CallExpression(node) {
const callee = node.callee;
// only worry about Object.definePropert[y|ies]
if (callee.type === "MemberExpression" &&
callee.object.name === "Object" &&
(callee.property.name === "defineProperty" || callee.property.name === "defineProperties")) {
// verify the object being added to is a native prototype
const subject = node.arguments[0];
const object = subject && subject.object;
if (object &&
object.type === "Identifier" &&
(modifiedBuiltins.indexOf(object.name) > -1) &&
subject.property.name === "prototype") {
context.report({
node,
message: "{{objectName}} prototype is read only, properties should not be added.",
data: {
objectName: object.name
}
});
}
}
}
};
}
};