eslint-plugin-unicorn
Version:
More than 100 powerful ESLint rules
113 lines (92 loc) • 2.46 kB
JavaScript
import {getStaticValue} from '@eslint-community/eslint-utils';
import {
isCallExpression,
isNewExpression,
isUndefined,
isNullLiteral,
} from './ast/index.js';
const MESSAGE_ID_ERROR = 'no-invalid-fetch-options';
const messages = {
[MESSAGE_ID_ERROR]: '"body" is not allowed when method is "{{method}}".',
};
const isObjectPropertyWithName = (node, name) =>
node.type === 'Property'
&& !node.computed
&& node.key.type === 'Identifier'
&& node.key.name === name;
function checkFetchOptions(context, node) {
if (node.type !== 'ObjectExpression') {
return;
}
const {properties} = node;
const bodyProperty = properties.findLast(property => isObjectPropertyWithName(property, 'body'));
if (!bodyProperty) {
return;
}
const bodyValue = bodyProperty.value;
if (isUndefined(bodyValue) || isNullLiteral(bodyValue)) {
return;
}
const methodProperty = properties.findLast(property => isObjectPropertyWithName(property, 'method'));
// If `method` is omitted but there is an `SpreadElement`, we just ignore the case
if (!methodProperty) {
if (properties.some(node => node.type === 'SpreadElement')) {
return;
}
return {
node: bodyProperty.key,
messageId: MESSAGE_ID_ERROR,
data: {method: 'GET'},
};
}
const methodValue = methodProperty.value;
const scope = context.sourceCode.getScope(methodValue);
let method = getStaticValue(methodValue, scope)?.value;
if (typeof method !== 'string') {
return;
}
method = method.toUpperCase();
if (method !== 'GET' && method !== 'HEAD') {
return;
}
return {
node: bodyProperty.key,
messageId: MESSAGE_ID_ERROR,
data: {method},
};
}
/** @param {import('eslint').Rule.RuleContext} context */
const create = context => {
context.on('CallExpression', callExpression => {
if (!isCallExpression(callExpression, {
name: 'fetch',
minimumArguments: 2,
optional: false,
})) {
return;
}
return checkFetchOptions(context, callExpression.arguments[1]);
});
context.on('NewExpression', newExpression => {
if (!isNewExpression(newExpression, {
name: 'Request',
minimumArguments: 2,
})) {
return;
}
return checkFetchOptions(context, newExpression.arguments[1]);
});
};
/** @type {import('eslint').Rule.RuleModule} */
const config = {
create,
meta: {
type: 'problem',
docs: {
description: 'Disallow invalid options in `fetch()` and `new Request()`.',
recommended: true,
},
messages,
},
};
export default config;