Skip to content

Commit 3f2e9a6

Browse files
MrHensindresorhus
authored andcommitted
custom-error-definition: Cover exports name (#313)
1 parent 6f10722 commit 3f2e9a6

File tree

2 files changed

+82
-16
lines changed

2 files changed

+82
-16
lines changed

rules/custom-error-definition.js

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
const upperfirst = require('lodash.upperfirst');
33
const getDocsUrl = require('./utils/get-docs-url');
44

5+
const MESSAGE_ID_INVALID_EXPORT = 'invalidExport';
6+
57
const nameRegexp = /^(?:[A-Z][a-z\d]*)*Error$/;
68

79
const getClassName = name => upperfirst(name).replace(/(error|)$/i, 'Error');
@@ -124,10 +126,50 @@ const customErrorDefinition = (context, node) => {
124126
}
125127
};
126128

129+
const customErrorExport = (context, node) => {
130+
if (!node.left.object || node.left.object.name !== 'exports') {
131+
return;
132+
}
133+
134+
if (!node.left.property) {
135+
return;
136+
}
137+
138+
const exportsName = node.left.property.name;
139+
140+
const maybeError = node.right;
141+
142+
if (maybeError.type !== 'ClassExpression') {
143+
return;
144+
}
145+
146+
if (!hasValidSuperClass(maybeError)) {
147+
return;
148+
}
149+
150+
if (!maybeError.id) {
151+
return;
152+
}
153+
154+
// Assume rule has already fixed the error name
155+
const errorName = maybeError.id.name;
156+
157+
if (exportsName === errorName) {
158+
return;
159+
}
160+
161+
context.report({
162+
node: node.left.property,
163+
messageId: MESSAGE_ID_INVALID_EXPORT,
164+
fix: fixer => fixer.replaceText(node.left.property, errorName)
165+
});
166+
};
167+
127168
const create = context => {
128169
return {
129170
ClassDeclaration: node => customErrorDefinition(context, node),
130-
'AssignmentExpression[right.type="ClassExpression"]': node => customErrorDefinition(context, node.right)
171+
'AssignmentExpression[right.type="ClassExpression"]': node => customErrorDefinition(context, node.right),
172+
'AssignmentExpression[left.type="MemberExpression"]': node => customErrorExport(context, node)
131173
};
132174
};
133175

@@ -138,6 +180,9 @@ module.exports = {
138180
docs: {
139181
url: getDocsUrl(__filename)
140182
},
141-
fixable: 'code'
183+
fixable: 'code',
184+
messages: {
185+
[MESSAGE_ID_INVALID_EXPORT]: 'Exported error name should match error class'
186+
}
142187
}
143188
};

test/custom-error-definition.js

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ const noSuperCallError = {ruleId: 'custom-error-definition', message: 'Missing c
1717
const invalidNameError = name => ({ruleId: 'custom-error-definition', message: `The \`name\` property should be set to \`${name}\`.`});
1818
const passMessageToSuperError = {ruleId: 'custom-error-definition', message: 'Pass the error message to `super()`.'};
1919
const invalidMessageAssignmentError = {ruleId: 'custom-error-definition', message: 'Pass the error message to `super()` instead of setting `this.message`.'};
20+
const invalidExportError = {
21+
ruleId: 'custom-error-definition',
22+
messageId: 'invalidExport'
23+
};
2024

2125
ruleTester.run('custom-error-definition', rule, {
2226
valid: [
@@ -110,6 +114,18 @@ ruleTester.run('custom-error-definition', rule, {
110114
this.name = 'fooError';
111115
}
112116
};
117+
`,
118+
`
119+
exports.whatever = class Whatever {};
120+
`,
121+
`
122+
class FooError extends Error {
123+
constructor(error) {
124+
super(error);
125+
this.name = 'FooError';
126+
}
127+
};
128+
exports.fooError = FooError;
113129
`
114130
],
115131
invalid: [
@@ -356,20 +372,25 @@ ruleTester.run('custom-error-definition', rule, {
356372
invalidNameError('FooError')
357373
]
358374
},
359-
// TODO: Uncomment test as part of #190
360-
// {
361-
// code: `
362-
// exports.fooError = class FooError extends Error {
363-
// constructor(error) {
364-
// super(error);
365-
// this.name = 'FooError';
366-
// }
367-
// };
368-
// `,
369-
// errors: [
370-
// invalidNameError('fooError')
371-
// ]
372-
// },
375+
{
376+
code: `
377+
exports.fooError = class FooError extends Error {
378+
constructor(error) {
379+
super(error);
380+
this.name = 'FooError';
381+
}
382+
};
383+
`,
384+
errors: [invalidExportError],
385+
output: `
386+
exports.FooError = class FooError extends Error {
387+
constructor(error) {
388+
super(error);
389+
this.name = 'FooError';
390+
}
391+
};
392+
`
393+
},
373394
{
374395
code: `
375396
exports.FooError = class FooError extends TypeError {

0 commit comments

Comments
 (0)