Skip to content

Commit e7b4300

Browse files
authored
error-message: Support AggregateError (#1351)
1 parent 31a2950 commit e7b4300

File tree

6 files changed

+216
-35
lines changed

6 files changed

+216
-35
lines changed

docs/rules/error-message.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,20 @@ throw new TypeError();
1818
```
1919

2020
```js
21-
const error = new Error();
21+
const error = new AggregateError(errors);
2222
```
2323

2424

2525
## Pass
2626

2727
```js
28-
throw Error('Foo');
28+
throw Error('Unexpected property.');
2929
```
3030

3131
```js
32-
throw new TypeError('Foo');
32+
throw new TypeError('Array expected.');
3333
```
3434

3535
```js
36-
const error = new Error('Foo');
36+
const error = new AggregateError(errors, 'Promises rejected.');
3737
```

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@
134134
"eslint-plugin/require-meta-schema": "off",
135135
"eslint-plugin/require-meta-has-suggestions": "off",
136136
"eslint-plugin/require-meta-docs-url": "off",
137-
"eslint-plugin/require-meta-has-suggestions": "off",
138137
"eslint-plugin/require-meta-docs-description": [
139138
"error",
140139
{

rules/error-message.js

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,50 @@
22
const {getStaticValue} = require('eslint-utils');
33
const {callOrNewExpressionSelector} = require('./selectors/index.js');
44

5-
const MESSAGE_ID_MISSING_MESSAGE = 'constructorMissingMessage';
6-
const MESSAGE_ID_EMPTY_MESSAGE = 'emptyMessage';
5+
const MESSAGE_ID_MISSING_MESSAGE = 'missing-message';
6+
const MESSAGE_ID_EMPTY_MESSAGE = 'message-is-empty-string';
77
const MESSAGE_ID_NOT_STRING = 'message-is-not-a-string';
88
const messages = {
9-
[MESSAGE_ID_MISSING_MESSAGE]: 'Pass a message to the `{{constructor}}` constructor.',
9+
[MESSAGE_ID_MISSING_MESSAGE]: 'Pass a message to the `{{constructorName}}` constructor.',
1010
[MESSAGE_ID_EMPTY_MESSAGE]: 'Error message should not be an empty string.',
1111
[MESSAGE_ID_NOT_STRING]: 'Error message should be a string.'
1212
};
1313

14-
const errorConstructors = [
15-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
16-
'Error',
17-
'EvalError',
18-
'RangeError',
19-
'ReferenceError',
20-
'SyntaxError',
21-
'TypeError',
22-
'URIError',
23-
'InternalError'
24-
];
25-
const noArgumentsExpressionSelector = callOrNewExpressionSelector({names: errorConstructors, length: 0});
26-
const errorMessageSelector = callOrNewExpressionSelector({names: errorConstructors, min: 1});
14+
const selector = callOrNewExpressionSelector({
15+
names: [
16+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error
17+
'Error',
18+
'EvalError',
19+
'RangeError',
20+
'ReferenceError',
21+
'SyntaxError',
22+
'TypeError',
23+
'URIError',
24+
'InternalError',
25+
'AggregateError'
26+
]
27+
});
2728

2829
const create = context => {
2930
return {
30-
[noArgumentsExpressionSelector](node) {
31-
return {
32-
node,
33-
messageId: MESSAGE_ID_MISSING_MESSAGE,
34-
data: {
35-
constructor: node.callee.name
36-
}
37-
};
38-
},
39-
[errorMessageSelector](expression) {
40-
const [node] = expression.arguments;
31+
[selector](expression) {
32+
const constructorName = expression.callee.name;
33+
const messageArgumentIndex = constructorName === 'AggregateError' ? 1 : 0;
34+
const callArguments = expression.arguments;
35+
36+
// If message is `SpreadElement` or there is `SpreadElement` before message
37+
if (callArguments.some((node, index) => index <= messageArgumentIndex && node.type === 'SpreadElement')) {
38+
return;
39+
}
40+
41+
const node = callArguments[messageArgumentIndex];
42+
if (!node) {
43+
return {
44+
node: expression,
45+
messageId: MESSAGE_ID_MISSING_MESSAGE,
46+
data: {constructorName}
47+
};
48+
}
4149

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

51-
const result = getStaticValue(node, context.getScope());
59+
const staticResult = getStaticValue(node, context.getScope());
5260

5361
// We don't know the value of `message`
54-
if (!result) {
62+
if (!staticResult) {
5563
return;
5664
}
5765

58-
const {value} = result;
66+
const {value} = staticResult;
5967
if (typeof value !== 'string') {
6068
return {
6169
node,

test/error-message.mjs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,35 @@ test.snapshot({
6464
'const error = new RangeError;'
6565
]
6666
});
67+
68+
// `AggregateError`
69+
test.snapshot({
70+
valid: [
71+
'new AggregateError(errors, "message")',
72+
'new NotAggregateError(errors)',
73+
'new AggregateError(...foo)',
74+
'new AggregateError(...foo, "")',
75+
'new AggregateError(errors, ...foo)',
76+
'new AggregateError(errors, message, "")',
77+
'new AggregateError("", message, "")'
78+
],
79+
invalid: [
80+
'new AggregateError(errors)',
81+
'AggregateError(errors)',
82+
'new AggregateError(errors, "")',
83+
'new AggregateError(errors, ``)',
84+
'new AggregateError(errors, "", extraArgument)',
85+
outdent`
86+
const errorMessage = Object.freeze({errorMessage: 1}).errorMessage;
87+
throw new AggregateError(errors, errorMessage)
88+
`,
89+
'new AggregateError(errors, [])',
90+
'new AggregateError(errors, [foo])',
91+
'new AggregateError(errors, [0][0])',
92+
'new AggregateError(errors, {})',
93+
'new AggregateError(errors, {foo})',
94+
'new AggregateError(errors, {foo: 0}.foo)',
95+
'new AggregateError(errors, lineNumber=2)',
96+
'const error = new AggregateError;'
97+
]
98+
});

test/snapshots/error-message.mjs.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,145 @@ Generated by [AVA](https://avajs.dev).
195195
> 1 | const error = new RangeError;␊
196196
| ^^^^^^^^^^^^^^ Pass a message to the \`RangeError\` constructor.␊
197197
`
198+
199+
## Invalid #1
200+
1 | new AggregateError(errors)
201+
202+
> Error 1/1
203+
204+
`␊
205+
> 1 | new AggregateError(errors)␊
206+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ Pass a message to the \`AggregateError\` constructor.␊
207+
`
208+
209+
## Invalid #2
210+
1 | AggregateError(errors)
211+
212+
> Error 1/1
213+
214+
`␊
215+
> 1 | AggregateError(errors)␊
216+
| ^^^^^^^^^^^^^^^^^^^^^^ Pass a message to the \`AggregateError\` constructor.␊
217+
`
218+
219+
## Invalid #3
220+
1 | new AggregateError(errors, "")
221+
222+
> Error 1/1
223+
224+
`␊
225+
> 1 | new AggregateError(errors, "")␊
226+
| ^^ Error message should not be an empty string.␊
227+
`
228+
229+
## Invalid #4
230+
1 | new AggregateError(errors, ``)
231+
232+
> Error 1/1
233+
234+
`␊
235+
> 1 | new AggregateError(errors, \`\`)␊
236+
| ^^ Error message should not be an empty string.␊
237+
`
238+
239+
## Invalid #5
240+
1 | new AggregateError(errors, "", extraArgument)
241+
242+
> Error 1/1
243+
244+
`␊
245+
> 1 | new AggregateError(errors, "", extraArgument)␊
246+
| ^^ Error message should not be an empty string.␊
247+
`
248+
249+
## Invalid #6
250+
1 | const errorMessage = Object.freeze({errorMessage: 1}).errorMessage;
251+
2 | throw new AggregateError(errors, errorMessage)
252+
253+
> Error 1/1
254+
255+
`␊
256+
1 | const errorMessage = Object.freeze({errorMessage: 1}).errorMessage;␊
257+
> 2 | throw new AggregateError(errors, errorMessage)␊
258+
| ^^^^^^^^^^^^ Error message should be a string.␊
259+
`
260+
261+
## Invalid #7
262+
1 | new AggregateError(errors, [])
263+
264+
> Error 1/1
265+
266+
`␊
267+
> 1 | new AggregateError(errors, [])␊
268+
| ^^ Error message should be a string.␊
269+
`
270+
271+
## Invalid #8
272+
1 | new AggregateError(errors, [foo])
273+
274+
> Error 1/1
275+
276+
`␊
277+
> 1 | new AggregateError(errors, [foo])␊
278+
| ^^^^^ Error message should be a string.␊
279+
`
280+
281+
## Invalid #9
282+
1 | new AggregateError(errors, [0][0])
283+
284+
> Error 1/1
285+
286+
`␊
287+
> 1 | new AggregateError(errors, [0][0])␊
288+
| ^^^^^^ Error message should be a string.␊
289+
`
290+
291+
## Invalid #10
292+
1 | new AggregateError(errors, {})
293+
294+
> Error 1/1
295+
296+
`␊
297+
> 1 | new AggregateError(errors, {})␊
298+
| ^^ Error message should be a string.␊
299+
`
300+
301+
## Invalid #11
302+
1 | new AggregateError(errors, {foo})
303+
304+
> Error 1/1
305+
306+
`␊
307+
> 1 | new AggregateError(errors, {foo})␊
308+
| ^^^^^ Error message should be a string.␊
309+
`
310+
311+
## Invalid #12
312+
1 | new AggregateError(errors, {foo: 0}.foo)
313+
314+
> Error 1/1
315+
316+
`␊
317+
> 1 | new AggregateError(errors, {foo: 0}.foo)␊
318+
| ^^^^^^^^^^^^ Error message should be a string.␊
319+
`
320+
321+
## Invalid #13
322+
1 | new AggregateError(errors, lineNumber=2)
323+
324+
> Error 1/1
325+
326+
`␊
327+
> 1 | new AggregateError(errors, lineNumber=2)␊
328+
| ^^^^^^^^^^^^ Error message should be a string.␊
329+
`
330+
331+
## Invalid #14
332+
1 | const error = new AggregateError;
333+
334+
> Error 1/1
335+
336+
`␊
337+
> 1 | const error = new AggregateError;␊
338+
| ^^^^^^^^^^^^^^^^^^ Pass a message to the \`AggregateError\` constructor.␊
339+
`
506 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)