Skip to content

Commit

Permalink
Update: Add never option for new-parens (fixes eslint#10034)
Browse files Browse the repository at this point in the history
  • Loading branch information
pfgithub committed Feb 12, 2019
1 parent 82a58ce commit d768240
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 14 deletions.
38 changes: 34 additions & 4 deletions docs/rules/new-parens.md
@@ -1,4 +1,4 @@
# require parentheses when invoking a constructor with no arguments (new-parens)
# Require parentheses when invoking a constructor with no arguments (new-parens)

JavaScript allows the omission of parentheses when invoking a function via the `new` keyword and the constructor has no arguments. However, some coders believe that omitting the parentheses is inconsistent with the rest of the language and thus makes code less clear.

Expand All @@ -8,9 +8,18 @@ var person = new Person;

## Rule Details

This rule requires parentheses when invoking a constructor with no arguments using the `new` keyword in order to increase code clarity.
This rule can enforce or disallow parentheses when invoking a constructor with no arguments using the `new` keyword.

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

This rule takes one option.

- `"always"` enforces parenthesis after a new constructor with no arguments (default)
- `"never"` enforces no parenthesis after a new constructor with no arguments

### always

Examples of **incorrect** code for this rule with the `"always"` option:

```js
/*eslint new-parens: "error"*/
Expand All @@ -19,11 +28,32 @@ var person = new Person;
var person = new (Person);
```

Examples of **correct** code for this rule:
Examples of **correct** code for this rule with the `"always"` option:

```js
/*eslint new-parens: "error"*/

var person = new Person();
var person = new (Person)();
```

### never

Examples of **incorrect** code for this rule with the `"never"` option:

```js
/*eslint new-parens: "error"*/

var person = new Person();
var person = new (Person)();
```

Examples of **correct** code for this rule with the `"never"` option:

```js
/*eslint new-parens: "error"*/

var person = new Person;
var person = (new Person);
var person = new Person("Name");
```
50 changes: 41 additions & 9 deletions lib/rules/new-parens.js
Expand Up @@ -31,31 +31,63 @@ module.exports = {
},

fixable: "code",
schema: [],
schema: {
anyOf: [
{
type: "array",
items: [
{
enum: ["always", "never"]
}
],
minItems: 0,
maxItems: 1
}
]
},
messages: {
missing: "Missing '()' invoking a constructor."
missing: "Missing '()' invoking a constructor.",
using: "'()' included invoking a constructor with no arguments."
}
},

create(context) {
const options = context.options;
const always = options[0] !== "never"; // Default is never

const sourceCode = context.getSourceCode();

return {
NewExpression(node) {
if (node.arguments.length !== 0) {
return; // shortcut: if there are arguments, there have to be parens
return; // if there are arguments, there have to be parens
}

const lastToken = sourceCode.getLastToken(node);
const hasLastParen = lastToken && astUtils.isClosingParenToken(lastToken);
const hasParens = hasLastParen && astUtils.isOpeningParenToken(sourceCode.getTokenBefore(lastToken));

if (!hasParens) {
context.report({
node,
messageId: "missing",
fix: fixer => fixer.insertTextAfter(node, "()")
});
if (always) {
if (!hasParens) {
context.report({
node,
messageId: "missing",
fix: fixer => fixer.insertTextAfter(node, "()")
});
}
} else {
if (hasParens) {
context.report({
node,
messageId: "using",
fix: fixer => [
fixer.remove(sourceCode.getTokenBefore(lastToken)),
fixer.remove(lastToken),
fixer.insertTextBefore(node, "("),
fixer.insertTextAfter(node, ")")
]
});
}
}
}
};
Expand Down
62 changes: 61 additions & 1 deletion tests/lib/rules/new-parens.js
Expand Up @@ -17,6 +17,7 @@ const parser = require("../../fixtures/fixture-parser"),
// Tests
//------------------------------------------------------------------------------
const error = { messageId: "missing", type: "NewExpression" };
const neverError = { messageId: "using", type: "NewExpression" };

const ruleTester = new RuleTester();

Expand All @@ -29,7 +30,16 @@ ruleTester.run("new-parens", rule, {
"var a = (new Date());",
"var a = new foo.Bar();",
"var a = (new Foo()).bar;",
{ code: "new Storage<RootState>('state');", parser: parser("typescript-parsers/new-parens") }
{ code: "new Storage<RootState>('state');", parser: parser("typescript-parsers/new-parens") },

// Never
{ code: "var a = new Date;", options: ["never"] },
{ code: "var a = new Date(function() {});", options: ["never"] },
{ code: "var a = new (Date);", options: ["never"] },
{ code: "var a = new ((Date));", options: ["never"] },
{ code: "var a = (new Date);", options: ["never"] },
{ code: "var a = new foo.Bar;", options: ["never"] },
{ code: "var a = (new Foo).bar;", options: ["never"] }
],
invalid: [
{
Expand Down Expand Up @@ -73,6 +83,56 @@ ruleTester.run("new-parens", rule, {
code: "var a = (new Foo).bar;",
output: "var a = (new Foo()).bar;",
errors: [error]
},

// Never
{
code: "var a = new Date();",
output: "var a = (new Date);",
options: ["never"],
errors: [neverError]
},
{
code: "var a = new Date()",
output: "var a = (new Date)",
options: ["never"],
errors: [neverError]
},
{
code: "var a = new (Date)();",
output: "var a = (new (Date));",
options: ["never"],
errors: [neverError]
},
{
code: "var a = new (Date)()",
output: "var a = (new (Date))",
options: ["never"],
errors: [neverError]
},
{
code: "var a = (new Date())",
output: "var a = ((new Date))",
options: ["never"],
errors: [neverError]
},
{
code: "var a = (new Date())()",
output: "var a = ((new Date))()",
options: ["never"],
errors: [neverError]
},
{
code: "var a = new foo.Bar();",
output: "var a = (new foo.Bar);",
options: ["never"],
errors: [neverError]
},
{
code: "var a = (new Foo()).bar;",
output: "var a = ((new Foo)).bar;",
options: ["never"],
errors: [neverError]
}
]
});

0 comments on commit d768240

Please sign in to comment.