Skip to content

Commit

Permalink
New rule no-extra-new
Browse files Browse the repository at this point in the history
  • Loading branch information
fasttime committed Aug 7, 2023
1 parent a012463 commit 59648cb
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 1 deletion.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Then configure the rules defined by this plugin under the `"rules"` section.
"@origin-1/bracket-layout": "error",
"@origin-1/indent": "error",
"@origin-1/nice-space-before-function-paren": "error",
"@origin-1/no-extra-new": "error",
"@origin-1/no-spaces-in-call-expression": "error",
"@origin-1/no-spaces-in-tagged-template": "error",
"@origin-1/property-colon-spacing": "error"
Expand All @@ -44,6 +45,7 @@ Then configure the rules defined by this plugin under the `"rules"` section.
* [`bracket-layout`](rule-docs/bracket-layout.md)
* [`indent`](rule-docs/indent.md)
* [`nice-space-before-function-paren`](rule-docs/nice-space-before-function-paren.md)
* [`no-extra-new`](rule-docs/no-extra-new.md)
* [`no-spaces-in-call-expression`](rule-docs/no-spaces-in-call-expression.md)
* [`no-spaces-in-tagged-template`](rule-docs/no-spaces-in-tagged-template.md)
* [`property-colon-spacing`](rule-docs/property-colon-spacing.md)
Expand Down
61 changes: 61 additions & 0 deletions lib/rules/no-extra-new.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use strict';

const { makeRuleDocsURL } = require('../utils');

const CONSTRUCTOR_NAMES =
[
'AggregateError',
'Array',
'Error',
'EvalError',
'Function',
'Object',
'RangeError',
'ReferenceError',
'RegExp',
'SyntaxError',
'TypeError',
'URIError',
];

const meta =
{
type: 'suggestion',
docs:
{
description: 'Disallow unnecessary usages of the new syntax',
url: makeRuleDocsURL('no-extra-new'),
},
schema: [],
messages: { unexpected: 'Unnecessary usage of the new syntax.' },
};

function create(context)
{
const { sourceCode } = context;
const ruleListeners =
{
'Program:exit':
node =>
{
const globalScope = sourceCode.getScope(node);
for (const constructorName of CONSTRUCTOR_NAMES)
{
const variable = globalScope.set.get(constructorName);
if (variable && variable.defs.length === 0)
{
for (const ref of variable.references)
{
const idNode = ref.identifier;
const { parent } = idNode;
if (parent && parent.type === 'NewExpression' && parent.callee === idNode)
context.report({ node: parent, messageId: 'unexpected' });
}
}
}
},
};
return ruleListeners;
}

module.exports = { meta, create };
2 changes: 1 addition & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function isBracketToken(token)

/**
* Determines whether a specified token is a closing parenthesis token.
* @param {Token} token - The token to check.
* @param {Token} token The token to check.
* @returns {boolean} Whether or not the token is a closing parenthesis token.
*/
function isClosingParenToken(token)
Expand Down
52 changes: 52 additions & 0 deletions rule-docs/no-extra-new.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# `no-extra-new`

The rule `no-extra-new` disallows unnecessary usages of the the `new` syntax.

The following built-in constructors can be called equally with or without `new` syntax:
* `AggregateError`
* `Array`
* `Error`
* `EvalError`
* `Function`
* `Object`
* `RangeError`
* `ReferenceError`
* `RegExp`
* `SyntaxError`
* `TypeError`
* `URIError`

## Examples

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

```js
/* eslint @origin-1/no-extra-new: "error" */

var array = new Array(42);
var fn = new Function;
var obj = new Object('foo');
var regExp = new RegExp('\\d', 'g');
throw new TypeError();
```

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

```js
/* eslint @origin-1/no-extra-new: "error" */

var array = Array(42);
var fn = Function();
var obj = Object('foo');
var regExp = RegExp('\\d', 'g');
throw TypeError();

function throwNew(Error)
{
throw new Error(); // New expressions with a variable as callee are allowed.
}
```

## Superseded core ESLint rules

* [`no-new-object`](https://eslint.org/docs/latest/rules/no-new-object)
122 changes: 122 additions & 0 deletions test/lib/rules/no-extra-new.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
'use strict';

const rule = require('../../../lib/rules/no-extra-new');
const { RuleTester } = require('eslint');

const ruleTester = new RuleTester();
const tests =
{
valid:
[
'var myObject = {};',
'var myObject = new CustomObject();',
'var foo = new foo.Object();',
`
var Object = function Object() {};
new Object();
`,
`
var x = something ? MyClass : Object;
var y = new x();`,
{
code:
`
class Object
{
constructor() { }
}
new Object();
`,
parserOptions: { ecmaVersion: 6 },
},
{
code:
`
import { Object } from './';
new Object();
`,
parserOptions: { ecmaVersion: 6, sourceType: 'module' },
},
`
var Error = CustomError;
function foo()
{
throw new Error();
}
`,
{
code:
`
function foo()
{
throw new Error();
}
const Error = CustomError;
`,
parserOptions: { ecmaVersion: 6 },
},
{
code: 'throw new AggregateError(errors);',
env: { es2020: true },
},
{
code: '(new Function(foo))();',
globals: { Function: 'off' },
},
`
/* global RegExp:off */
new RegExp(pattern, flags);
`,
],
invalid:
[
{
code: 'var foo = new Object();',
errors: [{ messageId: 'unexpected', type: 'NewExpression' }],
},
{
code: 'new Object();',
errors: [{ messageId: 'unexpected', type: 'NewExpression' }],
},
{
code: 'const a = new Object();',
parserOptions: { ecmaVersion: 6 },
errors: [{ messageId: 'unexpected', type: 'NewExpression' }],
},
{
code:
`
new Array;
new Error;
new EvalError;
new Function;
new Object;
new RangeError;
new ReferenceError;
new RegExp;
new SyntaxError;
new TypeError;
new URIError;
`,
errors: Array(11).fill({ messageId: 'unexpected', type: 'NewExpression' }),
},
{
code: 'throw new AggregateError(errors);',
env: { es2021: true },
errors: [{ messageId: 'unexpected', type: 'NewExpression' }],
},
{
code:
`
function foo(Error)
{
throw new Error;
}
throw new Error;
`,
errors: [{ messageId: 'unexpected', type: 'NewExpression' }],
},
],
};

ruleTester.run('no-extra-new', rule, tests);

0 comments on commit 59648cb

Please sign in to comment.