From 67c06059dd1ddcee6f369c650ce71220da1510c3 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Mon, 19 Oct 2020 12:48:17 +0200 Subject: [PATCH] Update: check computed keys in no-prototype-builtins (fixes #13088) (#13755) --- lib/rules/no-prototype-builtins.js | 8 +- tests/lib/rules/no-prototype-builtins.js | 241 ++++++++++++++--------- 2 files changed, 153 insertions(+), 96 deletions(-) diff --git a/lib/rules/no-prototype-builtins.js b/lib/rules/no-prototype-builtins.js index ccec86c30da..c5e4d49259b 100644 --- a/lib/rules/no-prototype-builtins.js +++ b/lib/rules/no-prototype-builtins.js @@ -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, diff --git a/tests/lib/rules/no-prototype-builtins.js b/tests/lib/rules/no-prototype-builtins.js index 8f57545bef9..a65b54d4d63 100644 --- a/tests/lib/rules/no-prototype-builtins.js +++ b/tests/lib/rules/no-prototype-builtins.js @@ -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" } }] + } + ] });