|
|
|
/**
|
|
|
|
* @fileoverview Rule to flag adding properties to native object's prototypes.
|
|
|
|
* @author David Nelson
|
|
|
|
*/
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Requirements
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
var BUILTINS = [
|
|
|
|
"Object", "Function", "Array", "String", "Boolean", "Number", "Date",
|
|
|
|
"RegExp", "Error", "EvalError", "RangeError", "ReferenceError",
|
|
|
|
"SyntaxError", "TypeError", "URIError"
|
|
|
|
];
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Rule Definition
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
module.exports = function(context) {
|
|
|
|
|
|
|
|
var config = context.options[0] || {};
|
|
|
|
var exceptions = config.exceptions || [];
|
|
|
|
var modifiedBuiltins = BUILTINS;
|
|
|
|
|
|
|
|
if (exceptions.length) {
|
|
|
|
modifiedBuiltins = BUILTINS.filter(function(builtIn) {
|
|
|
|
return exceptions.indexOf(builtIn) === -1;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
// handle the Array.prototype.extra style case
|
|
|
|
"AssignmentExpression": function(node) {
|
|
|
|
var lhs = node.left, affectsProto;
|
|
|
|
|
|
|
|
if (lhs.type !== "MemberExpression" || lhs.object.type !== "MemberExpression") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
affectsProto = lhs.object.computed ?
|
|
|
|
lhs.object.property.type === "Literal" && lhs.object.property.value === "prototype" :
|
|
|
|
lhs.object.property.name === "prototype";
|
|
|
|
|
|
|
|
if (!affectsProto) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
modifiedBuiltins.forEach(function(builtin) {
|
|
|
|
if (lhs.object.object.name === builtin) {
|
|
|
|
context.report(node, builtin + " prototype is read only, properties should not be added.");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
// handle the Object.defineProperty(Array.prototype) case
|
|
|
|
"CallExpression": function(node) {
|
|
|
|
|
|
|
|
var callee = node.callee,
|
|
|
|
subject,
|
|
|
|
object;
|
|
|
|
|
|
|
|
// only worry about Object.defineProperty
|
|
|
|
if (callee.type === "MemberExpression" &&
|
|
|
|
callee.object.name === "Object" &&
|
|
|
|
callee.property.name === "defineProperty") {
|
|
|
|
|
|
|
|
// verify the object being added to is a native prototype
|
|
|
|
subject = node.arguments[0];
|
|
|
|
object = subject.object;
|
|
|
|
|
|
|
|
if (object &&
|
|
|
|
object.type === "Identifier" &&
|
|
|
|
(modifiedBuiltins.indexOf(object.name) > -1) &&
|
|
|
|
subject.property.name === "prototype") {
|
|
|
|
|
|
|
|
context.report(node, object.name + " prototype is read only, properties should not be added.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports.schema = [
|
|
|
|
{
|
|
|
|
"type": "object",
|
|
|
|
"properties": {
|
|
|
|
"exceptions": {
|
|
|
|
"type": "array",
|
|
|
|
"items": {
|
|
|
|
"type": "string"
|
|
|
|
},
|
|
|
|
"uniqueItems": true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"additionalProperties": false
|
|
|
|
}
|
|
|
|
];
|