Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add prefer-object-has-own rule. #15206

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/rules/prefer-object-has-own.md
@@ -0,0 +1,28 @@
# Prefer use of Object.hasOwn over `Object.prototype.hasOwnPrototype` (prefer-object-has-own)

When Object.prototype.hasOwnPrototype.call is used, this rule requires using the `Object.hasOwn` instead. `Object.hasOwn` is a syntactic sugar and makes the code cleaner.
snitin315 marked this conversation as resolved.
Show resolved Hide resolved

## Rule Details

Examples of **incorrect** code for this rule:

```js
/*eslint prefer-object-has-own: "error"*/
Object.prototype.hasOwnProperty.call(obj, "a");

({}).hasOwnProperty(obj,"a");

let a = Object.prototype.hasOwnProperty;
```

Examples of **correct** code for this rule:

```js
/*eslint prefer-object-has-own: "error"*/

Object.hasOwn(obj, "a");
```
Gautam-Arora24 marked this conversation as resolved.
Show resolved Hide resolved

## Related Material

[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn)
1 change: 1 addition & 0 deletions lib/rules/index.js
Expand Up @@ -255,6 +255,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
"prefer-exponentiation-operator": () => require("./prefer-exponentiation-operator"),
"prefer-named-capture-group": () => require("./prefer-named-capture-group"),
"prefer-numeric-literals": () => require("./prefer-numeric-literals"),
"prefer-object-has-own": () => require("./prefer-object-has-own"),
"prefer-object-spread": () => require("./prefer-object-spread"),
"prefer-promise-reject-errors": () => require("./prefer-promise-reject-errors"),
"prefer-reflect": () => require("./prefer-reflect"),
Expand Down
59 changes: 59 additions & 0 deletions lib/rules/prefer-object-has-own.js
@@ -0,0 +1,59 @@
/**
* @fileoverview Prefers Object.hasOwn instead of Object.prototype.hasOwnProperty
* @author Gautam Arora <gautamarora6248@gmail.com>
* See LICENSE file in root directory for full license.
Gautam-Arora24 marked this conversation as resolved.
Show resolved Hide resolved
*/

"use strict";

/**
* Checks to see if a property name object exists in the subtree recursively.
* @param {node} node to evalutate.
* @returns {boolean} `True` if object property exists, false otherwise.
*/
function checkForObject(node) {
if (!node.object) {
return false;
}
if (node.object.name === "Object") {
return true;
}
return checkForObject(node.object);
}


module.exports = {
meta: {
type: "suggestion",
docs: {
description:
"disallow use of Object.prototype.hasOwnProperty and prefer use of Object.hasOwn",
recommended: false,
url: "https://eslint.org/docs/rules/prefer-object-has-own"
},
schema: [],
messages: {
useHasOwn: "Prefer using hasOwn property instead of hasOwnProperty."
}
},
create(context) {
return {
MemberExpression(node) {
const propertyName = node.property.name;
const isObject = checkForObject(node);
const isObjectExpression =
node.object.type === "ObjectExpression";

if (
propertyName === "hasOwnProperty" &&
(isObject || isObjectExpression)
) {
context.report({
node,
messageId: "useHasOwn"
});
}
}
};
}
};
52 changes: 52 additions & 0 deletions tests/lib/rules/prefer-object-has-own.js
@@ -0,0 +1,52 @@
/**
* @fileoverview Prefers Object.hasOwn instead of Object.prototype.hasOwnProperty
* @author Gautam Arora
* See LICENSE file in root directory for full license.
Gautam-Arora24 marked this conversation as resolved.
Show resolved Hide resolved
*/

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const rule = require("../../../lib/rules/prefer-object-has-own");
const { RuleTester } = require("../../../lib/rule-tester");

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const parserOptions = {
ecmaVersion: 2022
};

const ruleTester = new RuleTester({ parserOptions });
const error = { messageId: "useHasOwn" };

ruleTester.run("prefer-object-has-own", rule, {
valid: [
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
`
let obj = {};
Object.hasOwn(obj,"");
`
Gautam-Arora24 marked this conversation as resolved.
Show resolved Hide resolved
],
invalid: [
{
code: "Object.prototype.hasOwnProperty",
snitin315 marked this conversation as resolved.
Show resolved Hide resolved
errors: [error]
},
{
code: "Object.hasOwnProperty.call(obj, 'foo')",
errors: [error]
},
{
code: "Object.prototype.hasOwnProperty.call(obj, 'foo')",
errors: [error]
},
{
code: "({}).hasOwnProperty.call(obj, 'foo')",
errors: [error]
}
]
});
1 change: 1 addition & 0 deletions tools/rule-types.json
Expand Up @@ -242,6 +242,7 @@
"prefer-exponentiation-operator": "suggestion",
"prefer-named-capture-group": "suggestion",
"prefer-numeric-literals": "suggestion",
"prefer-object-has-own":"suggestion",
"prefer-object-spread": "suggestion",
"prefer-promise-reject-errors": "suggestion",
"prefer-reflect": "suggestion",
Expand Down