Skip to content

Commit

Permalink
error-message: Support AggregateError (#1351)
Browse files Browse the repository at this point in the history
  • Loading branch information
fisker authored Jun 15, 2021
1 parent 31a2950 commit e7b4300
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 35 deletions.
8 changes: 4 additions & 4 deletions docs/rules/error-message.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ throw new TypeError();
```

```js
const error = new Error();
const error = new AggregateError(errors);
```


## Pass

```js
throw Error('Foo');
throw Error('Unexpected property.');
```

```js
throw new TypeError('Foo');
throw new TypeError('Array expected.');
```

```js
const error = new Error('Foo');
const error = new AggregateError(errors, 'Promises rejected.');
```
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@
"eslint-plugin/require-meta-schema": "off",
"eslint-plugin/require-meta-has-suggestions": "off",
"eslint-plugin/require-meta-docs-url": "off",
"eslint-plugin/require-meta-has-suggestions": "off",
"eslint-plugin/require-meta-docs-description": [
"error",
{
Expand Down
68 changes: 38 additions & 30 deletions rules/error-message.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,50 @@
const {getStaticValue} = require('eslint-utils');
const {callOrNewExpressionSelector} = require('./selectors/index.js');

const MESSAGE_ID_MISSING_MESSAGE = 'constructorMissingMessage';
const MESSAGE_ID_EMPTY_MESSAGE = 'emptyMessage';
const MESSAGE_ID_MISSING_MESSAGE = 'missing-message';
const MESSAGE_ID_EMPTY_MESSAGE = 'message-is-empty-string';
const MESSAGE_ID_NOT_STRING = 'message-is-not-a-string';
const messages = {
[MESSAGE_ID_MISSING_MESSAGE]: 'Pass a message to the `{{constructor}}` constructor.',
[MESSAGE_ID_MISSING_MESSAGE]: 'Pass a message to the `{{constructorName}}` constructor.',
[MESSAGE_ID_EMPTY_MESSAGE]: 'Error message should not be an empty string.',
[MESSAGE_ID_NOT_STRING]: 'Error message should be a string.'
};

const errorConstructors = [
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
'Error',
'EvalError',
'RangeError',
'ReferenceError',
'SyntaxError',
'TypeError',
'URIError',
'InternalError'
];
const noArgumentsExpressionSelector = callOrNewExpressionSelector({names: errorConstructors, length: 0});
const errorMessageSelector = callOrNewExpressionSelector({names: errorConstructors, min: 1});
const selector = callOrNewExpressionSelector({
names: [
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
'Error',
'EvalError',
'RangeError',
'ReferenceError',
'SyntaxError',
'TypeError',
'URIError',
'InternalError',
'AggregateError'
]
});

const create = context => {
return {
[noArgumentsExpressionSelector](node) {
return {
node,
messageId: MESSAGE_ID_MISSING_MESSAGE,
data: {
constructor: node.callee.name
}
};
},
[errorMessageSelector](expression) {
const [node] = expression.arguments;
[selector](expression) {
const constructorName = expression.callee.name;
const messageArgumentIndex = constructorName === 'AggregateError' ? 1 : 0;
const callArguments = expression.arguments;

// If message is `SpreadElement` or there is `SpreadElement` before message
if (callArguments.some((node, index) => index <= messageArgumentIndex && node.type === 'SpreadElement')) {
return;
}

const node = callArguments[messageArgumentIndex];
if (!node) {
return {
node: expression,
messageId: MESSAGE_ID_MISSING_MESSAGE,
data: {constructorName}
};
}

// These types can't be string, and `getStaticValue` may don't know the value
// Add more types, if issue reported
Expand All @@ -48,14 +56,14 @@ const create = context => {
};
}

const result = getStaticValue(node, context.getScope());
const staticResult = getStaticValue(node, context.getScope());

// We don't know the value of `message`
if (!result) {
if (!staticResult) {
return;
}

const {value} = result;
const {value} = staticResult;
if (typeof value !== 'string') {
return {
node,
Expand Down
32 changes: 32 additions & 0 deletions test/error-message.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,35 @@ test.snapshot({
'const error = new RangeError;'
]
});

// `AggregateError`
test.snapshot({
valid: [
'new AggregateError(errors, "message")',
'new NotAggregateError(errors)',
'new AggregateError(...foo)',
'new AggregateError(...foo, "")',
'new AggregateError(errors, ...foo)',
'new AggregateError(errors, message, "")',
'new AggregateError("", message, "")'
],
invalid: [
'new AggregateError(errors)',
'AggregateError(errors)',
'new AggregateError(errors, "")',
'new AggregateError(errors, ``)',
'new AggregateError(errors, "", extraArgument)',
outdent`
const errorMessage = Object.freeze({errorMessage: 1}).errorMessage;
throw new AggregateError(errors, errorMessage)
`,
'new AggregateError(errors, [])',
'new AggregateError(errors, [foo])',
'new AggregateError(errors, [0][0])',
'new AggregateError(errors, {})',
'new AggregateError(errors, {foo})',
'new AggregateError(errors, {foo: 0}.foo)',
'new AggregateError(errors, lineNumber=2)',
'const error = new AggregateError;'
]
});
142 changes: 142 additions & 0 deletions test/snapshots/error-message.mjs.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,145 @@ Generated by [AVA](https://avajs.dev).
> 1 | const error = new RangeError;␊
| ^^^^^^^^^^^^^^ Pass a message to the \`RangeError\` constructor.␊
`

## Invalid #1
1 | new AggregateError(errors)

> Error 1/1
`␊
> 1 | new AggregateError(errors)␊
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Pass a message to the \`AggregateError\` constructor.␊
`

## Invalid #2
1 | AggregateError(errors)

> Error 1/1
`␊
> 1 | AggregateError(errors)␊
| ^^^^^^^^^^^^^^^^^^^^^^ Pass a message to the \`AggregateError\` constructor.␊
`

## Invalid #3
1 | new AggregateError(errors, "")

> Error 1/1
`␊
> 1 | new AggregateError(errors, "")␊
| ^^ Error message should not be an empty string.␊
`

## Invalid #4
1 | new AggregateError(errors, ``)

> Error 1/1
`␊
> 1 | new AggregateError(errors, \`\`)␊
| ^^ Error message should not be an empty string.␊
`

## Invalid #5
1 | new AggregateError(errors, "", extraArgument)

> Error 1/1
`␊
> 1 | new AggregateError(errors, "", extraArgument)␊
| ^^ Error message should not be an empty string.␊
`

## Invalid #6
1 | const errorMessage = Object.freeze({errorMessage: 1}).errorMessage;
2 | throw new AggregateError(errors, errorMessage)

> Error 1/1
`␊
1 | const errorMessage = Object.freeze({errorMessage: 1}).errorMessage;␊
> 2 | throw new AggregateError(errors, errorMessage)␊
| ^^^^^^^^^^^^ Error message should be a string.␊
`

## Invalid #7
1 | new AggregateError(errors, [])

> Error 1/1
`␊
> 1 | new AggregateError(errors, [])␊
| ^^ Error message should be a string.␊
`

## Invalid #8
1 | new AggregateError(errors, [foo])

> Error 1/1
`␊
> 1 | new AggregateError(errors, [foo])␊
| ^^^^^ Error message should be a string.␊
`

## Invalid #9
1 | new AggregateError(errors, [0][0])

> Error 1/1
`␊
> 1 | new AggregateError(errors, [0][0])␊
| ^^^^^^ Error message should be a string.␊
`

## Invalid #10
1 | new AggregateError(errors, {})

> Error 1/1
`␊
> 1 | new AggregateError(errors, {})␊
| ^^ Error message should be a string.␊
`

## Invalid #11
1 | new AggregateError(errors, {foo})

> Error 1/1
`␊
> 1 | new AggregateError(errors, {foo})␊
| ^^^^^ Error message should be a string.␊
`

## Invalid #12
1 | new AggregateError(errors, {foo: 0}.foo)

> Error 1/1
`␊
> 1 | new AggregateError(errors, {foo: 0}.foo)␊
| ^^^^^^^^^^^^ Error message should be a string.␊
`

## Invalid #13
1 | new AggregateError(errors, lineNumber=2)

> Error 1/1
`␊
> 1 | new AggregateError(errors, lineNumber=2)␊
| ^^^^^^^^^^^^ Error message should be a string.␊
`

## Invalid #14
1 | const error = new AggregateError;

> Error 1/1
`␊
> 1 | const error = new AggregateError;␊
| ^^^^^^^^^^^^^^^^^^ Pass a message to the \`AggregateError\` constructor.␊
`
Binary file modified test/snapshots/error-message.mjs.snap
Binary file not shown.

0 comments on commit e7b4300

Please sign in to comment.