UNPKG

2.47 kBJavaScriptView Raw
1'use strict';
2const getDocumentationUrl = require('./utils/get-documentation-url');
3
4const errorConstructors = new Set([
5 'Error',
6 'EvalError',
7 'InternalError',
8 'RangeError',
9 'ReferenceError',
10 'SyntaxError',
11 'TypeError',
12 'URIError'
13]);
14
15const isReferenceAssigned = expression => {
16 if (expression.type === 'AssignmentExpression') {
17 const assignedVariable = expression.left;
18 return assignedVariable.type === 'Identifier' && assignedVariable.name;
19 }
20
21 return false;
22};
23
24const findIdentifierValues = (identifierNode, context) => {
25 const scope = context.getScope(identifierNode);
26 const declarations = scope.set.get(identifierNode.name);
27 if (declarations === undefined) {
28 return [];
29 }
30
31 const expressions = declarations.references.map(reference => reference.identifier.parent);
32 const referenceValues = [];
33 for (const expression of expressions) {
34 if (isReferenceAssigned(expression)) {
35 referenceValues.push(expression.right);
36 } else if (expression.type === 'VariableDeclarator') {
37 referenceValues.push(expression.init);
38 }
39 }
40
41 return referenceValues;
42};
43
44const isEmptyMessageString = node => {
45 return (
46 node.arguments.length > 0 &&
47 node.arguments[0].type === 'Literal' &&
48 !node.arguments[0].value
49 );
50};
51
52const reportError = (expressionNode, context) => {
53 const error = expressionNode.callee;
54 if (errorConstructors.has(error.name)) {
55 if (expressionNode.arguments.length === 0) {
56 context.report({
57 node: expressionNode.parent,
58 message: 'Pass a message to the error constructor.'
59 });
60 }
61
62 if (isEmptyMessageString(expressionNode)) {
63 context.report({
64 node: expressionNode.parent,
65 message: 'Error message should not be an empty string.'
66 });
67 }
68 }
69};
70
71const checkErrorMessage = (node, context) => {
72 if (node.type === 'Identifier') {
73 const identifierValues = findIdentifierValues(node, context);
74 for (const node of identifierValues) {
75 checkErrorMessage(node, context);
76 }
77 } else if (node.type === 'NewExpression' || node.type === 'CallExpression') {
78 reportError(node, context);
79 }
80};
81
82const create = context => {
83 const throwStatements = [];
84 return {
85 'ThrowStatement'(throwStatement) {
86 throwStatements.push(throwStatement);
87 },
88 'Program:exit'() {
89 for (const throwStatement of throwStatements) {
90 checkErrorMessage(throwStatement.argument, context);
91 }
92 }
93 };
94};
95
96module.exports = {
97 create,
98 meta: {
99 type: 'problem',
100 docs: {
101 url: getDocumentationUrl(__filename)
102 }
103 }
104};