Skip to content

Commit

Permalink
Update: check computed keys in no-prototype-builtins (fixes #13088) (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mdjermanovic committed Oct 19, 2020
1 parent b5e011c commit 67c0605
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 96 deletions.
8 changes: 4 additions & 4 deletions lib/rules/no-prototype-builtins.js
Expand Up @@ -46,15 +46,15 @@ module.exports = {
*/
function disallowBuiltIns(node) {

// TODO: just use `astUtils.getStaticPropertyName(node.callee)`
const callee = astUtils.skipChainExpression(node.callee);

if (callee.type !== "MemberExpression" || callee.computed) {
if (callee.type !== "MemberExpression") {
return;
}
const propName = callee.property.name;

if (DISALLOWED_PROPS.indexOf(propName) > -1) {
const propName = astUtils.getStaticPropertyName(callee);

if (propName !== null && DISALLOWED_PROPS.indexOf(propName) > -1) {
context.report({
messageId: "prototypeBuildIn",
loc: callee.property.loc,
Expand Down
241 changes: 149 additions & 92 deletions tests/lib/rules/no-prototype-builtins.js
Expand Up @@ -17,99 +17,156 @@ const rule = require("../../../lib/rules/no-prototype-builtins"),
//------------------------------------------------------------------------------
const ruleTester = new RuleTester();

const valid = [
{ code: "Object.prototype.hasOwnProperty.call(foo, 'bar')" },
{ code: "Object.prototype.isPrototypeOf.call(foo, 'bar')" },
{ code: "Object.prototype.propertyIsEnumerable.call(foo, 'bar')" },
{ code: "Object.prototype.hasOwnProperty.apply(foo, ['bar'])" },
{ code: "Object.prototype.isPrototypeOf.apply(foo, ['bar'])" },
{ code: "Object.prototype.propertyIsEnumerable.apply(foo, ['bar'])" },
{ code: "hasOwnProperty(foo, 'bar')" },
{ code: "isPrototypeOf(foo, 'bar')" },
{ code: "propertyIsEnumerable(foo, 'bar')" },
{ code: "({}.hasOwnProperty.call(foo, 'bar'))" },
{ code: "({}.isPrototypeOf.call(foo, 'bar'))" },
{ code: "({}.propertyIsEnumerable.call(foo, 'bar'))" },
{ code: "({}.hasOwnProperty.apply(foo, ['bar']))" },
{ code: "({}.isPrototypeOf.apply(foo, ['bar']))" },
{ code: "({}.propertyIsEnumerable.apply(foo, ['bar']))" }
];
ruleTester.run("no-prototype-builtins", rule, {
valid: [
"Object.prototype.hasOwnProperty.call(foo, 'bar')",
"Object.prototype.isPrototypeOf.call(foo, 'bar')",
"Object.prototype.propertyIsEnumerable.call(foo, 'bar')",
"Object.prototype.hasOwnProperty.apply(foo, ['bar'])",
"Object.prototype.isPrototypeOf.apply(foo, ['bar'])",
"Object.prototype.propertyIsEnumerable.apply(foo, ['bar'])",
"foo.hasOwnProperty",
"foo.hasOwnProperty.bar()",
"foo(hasOwnProperty)",
"hasOwnProperty(foo, 'bar')",
"isPrototypeOf(foo, 'bar')",
"propertyIsEnumerable(foo, 'bar')",
"({}.hasOwnProperty.call(foo, 'bar'))",
"({}.isPrototypeOf.call(foo, 'bar'))",
"({}.propertyIsEnumerable.call(foo, 'bar'))",
"({}.hasOwnProperty.apply(foo, ['bar']))",
"({}.isPrototypeOf.apply(foo, ['bar']))",
"({}.propertyIsEnumerable.apply(foo, ['bar']))",
"foo[hasOwnProperty]('bar')",
"foo['HasOwnProperty']('bar')",
{ code: "foo[`isPrototypeOff`]('bar')", parserOptions: { ecmaVersion: 2015 } },
{ code: "foo?.['propertyIsEnumerabl']('bar')", parserOptions: { ecmaVersion: 2020 } },
"foo[1]('bar')",
"foo[null]('bar')",

const invalid = [
{
code: "foo.hasOwnProperty('bar')",
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 19,
messageId: "prototypeBuildIn",
data: { prop: "hasOwnProperty" },
type: "CallExpression"
}]
},
{
code: "foo.isPrototypeOf('bar')",
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 18,
messageId: "prototypeBuildIn",
data: { prop: "isPrototypeOf" },
type: "CallExpression"
}]
},
{
code: "foo.propertyIsEnumerable('bar')",
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 25,
messageId: "prototypeBuildIn",
data: { prop: "propertyIsEnumerable" }
}]
},
{
code: "foo.bar.hasOwnProperty('bar')",
errors: [{
line: 1,
column: 9,
endLine: 1,
endColumn: 23,
messageId: "prototypeBuildIn",
data: { prop: "hasOwnProperty" },
type: "CallExpression"
}]
},
{
code: "foo.bar.baz.isPrototypeOf('bar')",
errors: [{
line: 1,
column: 13,
endLine: 1,
endColumn: 26,
messageId: "prototypeBuildIn",
data: { prop: "isPrototypeOf" },
type: "CallExpression"
}]
},
// out of scope for this rule
"foo['hasOwn' + 'Property']('bar')",
{ code: "foo[`hasOwnProperty${''}`]('bar')", parserOptions: { ecmaVersion: 2015 } }
],

// Optional chaining
{
code: "foo?.hasOwnProperty('bar')",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "prototypeBuildIn", data: { prop: "hasOwnProperty" } }]
},
{
code: "(foo?.hasOwnProperty)('bar')",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "prototypeBuildIn", data: { prop: "hasOwnProperty" } }]
}
];
invalid: [
{
code: "foo.hasOwnProperty('bar')",
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 19,
messageId: "prototypeBuildIn",
data: { prop: "hasOwnProperty" },
type: "CallExpression"
}]
},
{
code: "foo.isPrototypeOf('bar')",
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 18,
messageId: "prototypeBuildIn",
data: { prop: "isPrototypeOf" },
type: "CallExpression"
}]
},
{
code: "foo.propertyIsEnumerable('bar')",
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 25,
messageId: "prototypeBuildIn",
data: { prop: "propertyIsEnumerable" }
}]
},
{
code: "foo.bar.hasOwnProperty('bar')",
errors: [{
line: 1,
column: 9,
endLine: 1,
endColumn: 23,
messageId: "prototypeBuildIn",
data: { prop: "hasOwnProperty" },
type: "CallExpression"
}]
},
{
code: "foo.bar.baz.isPrototypeOf('bar')",
errors: [{
line: 1,
column: 13,
endLine: 1,
endColumn: 26,
messageId: "prototypeBuildIn",
data: { prop: "isPrototypeOf" },
type: "CallExpression"
}]
},
{
code: "foo['hasOwnProperty']('bar')",
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 21,
messageId: "prototypeBuildIn",
data: { prop: "hasOwnProperty" },
type: "CallExpression"
}]
},
{
code: "foo[`isPrototypeOf`]('bar').baz",
parserOptions: { ecmaVersion: 2015 },
errors: [{
line: 1,
column: 5,
endLine: 1,
endColumn: 20,
messageId: "prototypeBuildIn",
data: { prop: "isPrototypeOf" },
type: "CallExpression"
}]
},
{
code: String.raw`foo.bar["propertyIsEnumerable"]('baz')`,
errors: [{
line: 1,
column: 9,
endLine: 1,
endColumn: 31,
messageId: "prototypeBuildIn",
data: { prop: "propertyIsEnumerable" },
type: "CallExpression"
}]
},

ruleTester.run("no-prototype-builtins", rule, {
valid,
invalid
// Optional chaining
{
code: "foo?.hasOwnProperty('bar')",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "prototypeBuildIn", data: { prop: "hasOwnProperty" } }]
},
{
code: "(foo?.hasOwnProperty)('bar')",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "prototypeBuildIn", data: { prop: "hasOwnProperty" } }]
},
{
code: "foo?.['hasOwnProperty']('bar')",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "prototypeBuildIn", data: { prop: "hasOwnProperty" } }]
},
{
code: "(foo?.[`hasOwnProperty`])('bar')",
parserOptions: { ecmaVersion: 2020 },
errors: [{ messageId: "prototypeBuildIn", data: { prop: "hasOwnProperty" } }]
}
]
});

0 comments on commit 67c0605

Please sign in to comment.