eslint-plugin-unicorn-x
Version:
More than 100 powerful ESLint rules
110 lines (96 loc) • 2.64 kB
JavaScript
import {getStaticValue} from '@eslint-community/eslint-utils';
import {isCallOrNewExpression} from './ast/index.js';
import builtinErrors from './shared/builtin-errors.js';
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 `{{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 messageArgumentIndexes = new Map([
['AggregateError', 1],
['SuppressedError', 2],
]);
/** @param {import('eslint').Rule.RuleContext} context */
const create = (context) => {
context.on(['CallExpression', 'NewExpression'], (expression) => {
if (
!(
isCallOrNewExpression(expression, {
names: builtinErrors,
optional: false,
}) && context.sourceCode.isGlobalReference(expression.callee)
)
) {
return;
}
const constructorName = expression.callee.name;
const messageArgumentIndex = messageArgumentIndexes.has(constructorName)
? messageArgumentIndexes.get(constructorName)
: 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
if (node.type === 'ArrayExpression' || node.type === 'ObjectExpression') {
return {
node,
messageId: MESSAGE_ID_NOT_STRING,
};
}
const staticResult = getStaticValue(
node,
context.sourceCode.getScope(node),
);
// We don't know the value of `message`
if (!staticResult) {
return;
}
const {value} = staticResult;
if (typeof value !== 'string') {
return {
node,
messageId: MESSAGE_ID_NOT_STRING,
};
}
if (value === '') {
return {
node,
messageId: MESSAGE_ID_EMPTY_MESSAGE,
};
}
});
};
/** @type {import('eslint').Rule.RuleModule} */
const config = {
create,
meta: {
type: 'problem',
docs: {
description:
'Enforce passing a `message` value when creating a built-in error.',
recommended: true,
},
messages,
},
};
export default config;