Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
throw-new-error: Check MemberExpression customError (#716)
  • Loading branch information
fisker committed May 4, 2020
1 parent 05f5ccb commit a28aad5
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 17 deletions.
14 changes: 13 additions & 1 deletion docs/rules/throw-new-error.md
Expand Up @@ -4,18 +4,30 @@ While it's possible to create a new error without using the `new` keyword, it's

This rule is fixable.


## Fail

```js
throw Error();
```

```js
throw TypeError('unicorn');
```

```js
throw lib.TypeError();
```

## Pass

```js
throw new Error();
```

```js
throw new TypeError('unicorn');
```

```js
throw new lib.TypeError();
```
39 changes: 28 additions & 11 deletions rules/throw-new-error.js
@@ -1,24 +1,38 @@
'use strict';
const getDocumentationUrl = require('./utils/get-documentation-url');

const messageId = 'throw-new-error';
const customError = /^(?:[A-Z][\da-z]*)*Error$/;

const selector = [
'ThrowStatement',
'>',
'CallExpression',
'[callee.type="Identifier"]'
'CallExpression.argument',
`:matches(${
[
// `throw FooError()`
[
'[callee.type="Identifier"]',
`[callee.name=/${customError.source}/]`
],
// `throw lib.FooError()`
[
'[callee.type="MemberExpression"]',
'[callee.computed=false]',
'[callee.property.type="Identifier"]',
`[callee.property.name=/${customError.source}/]`
]
].map(selector => selector.join('')).join(', ')
})`
].join('');
const customError = /^(?:[A-Z][\da-z]*)*Error$/;
const message = 'Use `new` when throwing an error.';

const create = context => ({
[selector]: node => {
if (customError.test(node.callee.name)) {
context.report({
node,
message,
fix: fixer => fixer.insertTextBefore(node, 'new ')
});
}
context.report({
node,
messageId,
fix: fixer => fixer.insertTextBefore(node, 'new ')
});
}
});

Expand All @@ -29,6 +43,9 @@ module.exports = {
docs: {
url: getDocumentationUrl(__filename)
},
messages: {
[messageId]: 'Use `new` when throwing an error.'
},
fixable: 'code'
}
};
43 changes: 38 additions & 5 deletions test/throw-new-error.js
Expand Up @@ -2,13 +2,15 @@ import test from 'ava';
import avaRuleTester from 'eslint-ava-rule-tester';
import rule from '../rules/throw-new-error';

const messageId = 'throw-new-error';

const ruleTester = avaRuleTester(test, {
env: {
es6: true
parserOptions: {
ecmaVersion: 2020
}
});

const errors = [{ruleId: 'throw-new-error'}];
const errors = [{messageId}];

ruleTester.run('new-error', rule, {
valid: [
Expand All @@ -28,15 +30,46 @@ ruleTester.run('new-error', rule, {
'throw getError()',
// Not `CallExpression`
'throw CustomError',
// Not `Identifier`
'throw lib.Error()'
// Not `Identifier` / `MemberExpression`
'throw getErrorConstructor()()',
// `MemberExpression.computed`
'throw lib[Error]()',
// `MemberExpression.property` not `Identifier`
'throw lib["Error"]()',
// Not `FooError` like
'throw lib.getError()'
],
invalid: [
{
code: 'throw Error()',
output: 'throw new Error()',
errors
},
{
code: 'throw (Error)()',
output: 'throw new (Error)()',
errors
},
{
code: 'throw lib.Error()',
output: 'throw new lib.Error()',
errors
},
{
code: 'throw lib.mod.Error()',
output: 'throw new lib.mod.Error()',
errors
},
{
code: 'throw lib[mod].Error()',
output: 'throw new lib[mod].Error()',
errors
},
{
code: 'throw (lib.mod).Error()',
output: 'throw new (lib.mod).Error()',
errors
},
{
code: 'throw Error(\'foo\')',
output: 'throw new Error(\'foo\')',
Expand Down

0 comments on commit a28aad5

Please sign in to comment.