Skip to content

Commit 22a5582

Browse files
feat: add rule no-object-constructor, deprecate no-new-object (#17576)
* Deprecate `no-new-object` * Add rule `no-object-constructor` * Apply suggestions * mark no-new-object deprecated in v8.50.0 Co-authored-by: Francesco Trotta <github@fasttime.org> --------- Co-authored-by: Milos Djermanovic <milos.djermanovic@gmail.com>
1 parent 48a44a7 commit 22a5582

File tree

12 files changed

+323
-13
lines changed

12 files changed

+323
-13
lines changed

docs/src/_data/rules.json

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -950,13 +950,6 @@
950950
"fixable": false,
951951
"hasSuggestions": false
952952
},
953-
{
954-
"name": "no-new-object",
955-
"description": "Disallow `Object` constructors",
956-
"recommended": false,
957-
"fixable": false,
958-
"hasSuggestions": false
959-
},
960953
{
961954
"name": "no-new-wrappers",
962955
"description": "Disallow `new` operators with the `String`, `Number`, and `Boolean` objects",
@@ -971,6 +964,13 @@
971964
"fixable": false,
972965
"hasSuggestions": true
973966
},
967+
{
968+
"name": "no-object-constructor",
969+
"description": "Disallow calls to the `Object` constructor without an argument",
970+
"recommended": false,
971+
"fixable": false,
972+
"hasSuggestions": true
973+
},
974974
{
975975
"name": "no-octal",
976976
"description": "Disallow octal literals",
@@ -1956,6 +1956,12 @@
19561956
"no-unsafe-negation"
19571957
]
19581958
},
1959+
{
1960+
"name": "no-new-object",
1961+
"replacedBy": [
1962+
"no-object-constructor"
1963+
]
1964+
},
19591965
{
19601966
"name": "no-new-require",
19611967
"replacedBy": []

docs/src/_data/rules_meta.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1364,7 +1364,11 @@
13641364
"description": "Disallow `Object` constructors",
13651365
"recommended": false,
13661366
"url": "https://eslint.org/docs/latest/rules/no-new-object"
1367-
}
1367+
},
1368+
"deprecated": true,
1369+
"replacedBy": [
1370+
"no-object-constructor"
1371+
]
13681372
},
13691373
"no-new-require": {
13701374
"deprecated": true,
@@ -1409,6 +1413,15 @@
14091413
"url": "https://eslint.org/docs/latest/rules/no-obj-calls"
14101414
}
14111415
},
1416+
"no-object-constructor": {
1417+
"type": "suggestion",
1418+
"docs": {
1419+
"description": "Disallow calls to the `Object` constructor without an argument",
1420+
"recommended": false,
1421+
"url": "https://eslint.org/docs/latest/rules/no-object-constructor"
1422+
},
1423+
"hasSuggestions": true
1424+
},
14121425
"no-octal": {
14131426
"type": "suggestion",
14141427
"docs": {

docs/src/rules/no-array-constructor.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
title: no-array-constructor
33
rule_type: suggestion
44
related_rules:
5-
- no-new-object
65
- no-new-wrappers
6+
- no-object-constructor
77
---
88

99

docs/src/rules/no-new-object.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ related_rules:
66
- no-new-wrappers
77
---
88

9+
This rule was **deprecated** in ESLint v8.50.0 and replaced by the [no-object-constructor](no-object-constructor) rule. The new rule flags more situations where object literal syntax can be used, and it does not report a problem when the `Object` constructor is invoked with an argument.
910

1011
The `Object` constructor is used to create new generic objects in JavaScript, such as:
1112

@@ -25,7 +26,7 @@ While there are no performance differences between the two approaches, the byte
2526

2627
## Rule Details
2728

28-
This rule disallows `Object` constructors.
29+
This rule disallows calling the `Object` constructor with `new`.
2930

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

@@ -37,6 +38,8 @@ Examples of **incorrect** code for this rule:
3738
var myObject = new Object();
3839

3940
new Object();
41+
42+
var foo = new Object("foo");
4043
```
4144

4245
:::
@@ -54,10 +57,12 @@ var myObject = {};
5457

5558
var Object = function Object() {};
5659
new Object();
60+
61+
var foo = Object("foo");
5762
```
5863

5964
:::
6065

6166
## When Not To Use It
6267

63-
If you wish to allow the use of the `Object` constructor, you can safely turn this rule off.
68+
If you wish to allow the use of the `Object` constructor with `new`, you can safely turn this rule off.

docs/src/rules/no-new-wrappers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: no-new-wrappers
33
rule_type: suggestion
44
related_rules:
55
- no-array-constructor
6-
- no-new-object
6+
- no-object-constructor
77
further_reading:
88
- https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-3/wrapper-objects
99
---
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
---
2+
title: no-object-constructor
3+
rule_type: suggestion
4+
related_rules:
5+
- no-array-constructor
6+
- no-new-wrappers
7+
---
8+
9+
Use of the `Object` constructor to construct a new empty object is generally discouraged in favor of object literal notation because of conciseness and because the `Object` global may be redefined.
10+
The exception is when the `Object` constructor is used to intentionally wrap a specified value which is passed as an argument.
11+
12+
## Rule Details
13+
14+
This rule disallows calling the `Object` constructor without an argument.
15+
16+
Examples of **incorrect** code for this rule:
17+
18+
:::incorrect
19+
20+
```js
21+
/*eslint no-object-constructor: "error"*/
22+
23+
Object();
24+
25+
new Object();
26+
```
27+
28+
:::
29+
30+
Examples of **correct** code for this rule:
31+
32+
:::correct
33+
34+
```js
35+
/*eslint no-object-constructor: "error"*/
36+
37+
Object("foo");
38+
39+
const obj = { a: 1, b: 2 };
40+
41+
const isObject = value => value === Object(value);
42+
43+
const createObject = Object => new Object();
44+
```
45+
46+
:::
47+
48+
## When Not To Use It
49+
50+
If you wish to allow the use of the `Object` constructor, you can safely turn this rule off.

lib/rules/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
175175
"no-new-wrappers": () => require("./no-new-wrappers"),
176176
"no-nonoctal-decimal-escape": () => require("./no-nonoctal-decimal-escape"),
177177
"no-obj-calls": () => require("./no-obj-calls"),
178+
"no-object-constructor": () => require("./no-object-constructor"),
178179
"no-octal": () => require("./no-octal"),
179180
"no-octal-escape": () => require("./no-octal-escape"),
180181
"no-param-reassign": () => require("./no-param-reassign"),

lib/rules/no-new-object.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* @fileoverview A rule to disallow calls to the Object constructor
33
* @author Matt DuVall <http://www.mattduvall.com/>
4+
* @deprecated in ESLint v8.50.0
45
*/
56

67
"use strict";
@@ -26,6 +27,12 @@ module.exports = {
2627
url: "https://eslint.org/docs/latest/rules/no-new-object"
2728
},
2829

30+
deprecated: true,
31+
32+
replacedBy: [
33+
"no-object-constructor"
34+
],
35+
2936
schema: [],
3037

3138
messages: {

lib/rules/no-object-constructor.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* @fileoverview Rule to disallow calls to the `Object` constructor without an argument
3+
* @author Francesco Trotta
4+
*/
5+
6+
"use strict";
7+
8+
//------------------------------------------------------------------------------
9+
// Requirements
10+
//------------------------------------------------------------------------------
11+
12+
const { getVariableByName, isArrowToken } = require("./utils/ast-utils");
13+
14+
//------------------------------------------------------------------------------
15+
// Helpers
16+
//------------------------------------------------------------------------------
17+
18+
/**
19+
* Tests if a node appears at the beginning of an ancestor ExpressionStatement node.
20+
* @param {ASTNode} node The node to check.
21+
* @returns {boolean} Whether the node appears at the beginning of an ancestor ExpressionStatement node.
22+
*/
23+
function isStartOfExpressionStatement(node) {
24+
const start = node.range[0];
25+
let ancestor = node;
26+
27+
while ((ancestor = ancestor.parent) && ancestor.range[0] === start) {
28+
if (ancestor.type === "ExpressionStatement") {
29+
return true;
30+
}
31+
}
32+
return false;
33+
}
34+
35+
//------------------------------------------------------------------------------
36+
// Rule Definition
37+
//------------------------------------------------------------------------------
38+
39+
/** @type {import('../shared/types').Rule} */
40+
module.exports = {
41+
meta: {
42+
type: "suggestion",
43+
44+
docs: {
45+
description: "Disallow calls to the `Object` constructor without an argument",
46+
recommended: false,
47+
url: "https://eslint.org/docs/latest/rules/no-object-constructor"
48+
},
49+
50+
hasSuggestions: true,
51+
52+
schema: [],
53+
54+
messages: {
55+
preferLiteral: "The object literal notation {} is preferable.",
56+
useLiteral: "Replace with '{{replacement}}'."
57+
}
58+
},
59+
60+
create(context) {
61+
62+
const sourceCode = context.sourceCode;
63+
64+
/**
65+
* Determines whether or not an object literal that replaces a specified node needs to be enclosed in parentheses.
66+
* @param {ASTNode} node The node to be replaced.
67+
* @returns {boolean} Whether or not parentheses around the object literal are required.
68+
*/
69+
function needsParentheses(node) {
70+
if (isStartOfExpressionStatement(node)) {
71+
return true;
72+
}
73+
74+
const prevToken = sourceCode.getTokenBefore(node);
75+
76+
if (prevToken && isArrowToken(prevToken)) {
77+
return true;
78+
}
79+
80+
return false;
81+
}
82+
83+
/**
84+
* Reports on nodes where the `Object` constructor is called without arguments.
85+
* @param {ASTNode} node The node to evaluate.
86+
* @returns {void}
87+
*/
88+
function check(node) {
89+
if (node.callee.type !== "Identifier" || node.callee.name !== "Object" || node.arguments.length) {
90+
return;
91+
}
92+
93+
const variable = getVariableByName(sourceCode.getScope(node), "Object");
94+
95+
if (variable && variable.identifiers.length === 0) {
96+
const replacement = needsParentheses(node) ? "({})" : "{}";
97+
98+
context.report({
99+
node,
100+
messageId: "preferLiteral",
101+
suggest: [
102+
{
103+
messageId: "useLiteral",
104+
data: { replacement },
105+
fix: fixer => fixer.replaceText(node, replacement)
106+
}
107+
]
108+
});
109+
}
110+
}
111+
112+
return {
113+
CallExpression: check,
114+
NewExpression: check
115+
};
116+
117+
}
118+
};

packages/js/src/configs/eslint-all.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,11 @@ module.exports = Object.freeze({
152152
"no-new": "error",
153153
"no-new-func": "error",
154154
"no-new-native-nonconstructor": "error",
155-
"no-new-object": "error",
156155
"no-new-symbol": "error",
157156
"no-new-wrappers": "error",
158157
"no-nonoctal-decimal-escape": "error",
159158
"no-obj-calls": "error",
159+
"no-object-constructor": "error",
160160
"no-octal": "error",
161161
"no-octal-escape": "error",
162162
"no-param-reassign": "error",

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy