Files
memecoin-botV2/.pnpm-store/v10/files/e3/e3fe9fba8df39cdb9d7880e135bd2ce1cf0ef5e8202f333f82119af065eefba38da3b2020a293a80efdc90210ca572cac89f440dc4e84350050b0ee44deed5

378 lines
17 KiB
Plaintext

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("@typescript-eslint/utils");
const tsutils = __importStar(require("ts-api-utils"));
const ts = __importStar(require("typescript"));
const util = __importStar(require("../util"));
exports.default = util.createRule({
name: 'strict-void-return',
meta: {
type: 'problem',
docs: {
description: 'Disallow passing a value-returning function in a position accepting a void function',
requiresTypeChecking: true,
},
messages: {
asyncFunc: 'Async function used in a context where a void function is expected.',
nonVoidFunc: 'Value-returning function used in a context where a void function is expected.',
nonVoidReturn: 'Value returned in a context where a void return is expected.',
},
schema: [
{
type: 'object',
additionalProperties: false,
properties: {
allowReturnAny: {
type: 'boolean',
description: 'Whether to allow functions returning `any` to be used in place expecting a `void` function.',
},
},
},
],
},
defaultOptions: [
{
allowReturnAny: false,
},
],
create(context, [options]) {
const sourceCode = context.sourceCode;
const parserServices = util.getParserServices(context);
const checker = parserServices.program.getTypeChecker();
return {
ArrayExpression: (node) => {
for (const elemNode of node.elements) {
if (elemNode != null &&
elemNode.type !== utils_1.AST_NODE_TYPES.SpreadElement) {
checkExpressionNode(elemNode);
}
}
},
ArrowFunctionExpression: (node) => {
if (node.body.type !== utils_1.AST_NODE_TYPES.BlockStatement) {
checkExpressionNode(node.body);
}
},
AssignmentExpression: (node) => {
checkExpressionNode(node.right); // should ignore operators like `+=` or `-=` automatically
},
'CallExpression, NewExpression': checkFunctionCallNode,
JSXAttribute: (node) => {
if (node.value?.type === utils_1.AST_NODE_TYPES.JSXExpressionContainer &&
node.value.expression.type !== utils_1.AST_NODE_TYPES.JSXEmptyExpression) {
checkExpressionNode(node.value.expression);
}
},
MethodDefinition: checkClassMethodNode,
ObjectExpression: (node) => {
for (const propNode of node.properties) {
if (propNode.type !== utils_1.AST_NODE_TYPES.SpreadElement) {
checkObjectPropertyNode(propNode);
}
}
},
PropertyDefinition: checkClassPropertyNode,
ReturnStatement: (node) => {
if (node.argument != null) {
checkExpressionNode(node.argument);
}
},
VariableDeclarator: (node) => {
if (node.init != null) {
checkExpressionNode(node.init);
}
},
};
function isVoidReturningFunctionType(type) {
const returnTypes = tsutils
.getCallSignaturesOfType(type)
.flatMap(signature => tsutils.unionConstituents(signature.getReturnType()));
return (returnTypes.length > 0 &&
returnTypes.every(type => tsutils.isTypeFlagSet(type, ts.TypeFlags.Void)));
}
/**
* Finds errors in any expression node.
*
* Compares the type of the node against the contextual (expected) type.
*
* @returns `true` if the expected type was void function.
*/
function checkExpressionNode(node) {
const expectedType = parserServices.getContextualType(node);
if (expectedType != null && isVoidReturningFunctionType(expectedType)) {
reportIfNonVoidFunction(node);
return true;
}
return false;
}
/**
* Finds errors in function calls.
*
* When checking arguments, we also manually figure out the argument types
* by iterating over all the function signatures.
* Thanks to this, we can find arguments like `(() => void) | (() => any)`
* and treat them as void too.
* This is done to also support checking functions like `addEventListener`
* which have overloads where one callback returns any.
*
* Implementation mostly based on no-misused-promises,
* which does this to find `(() => void) | (() => NotThenable)`
* and report them too.
*/
function checkFunctionCallNode(callNode) {
if (callNode.arguments.length === 0) {
return;
}
const callTsNode = parserServices.esTreeNodeToTSNodeMap.get(callNode);
const funcType = checker.getTypeAtLocation(callTsNode.expression);
const funcSignatures = tsutils
.unionConstituents(funcType)
.flatMap(type => ts.isCallExpression(callTsNode)
? type.getCallSignatures()
: type.getConstructSignatures());
for (const [argIdx, argNode] of callNode.arguments.entries()) {
if (argNode.type === utils_1.AST_NODE_TYPES.SpreadElement) {
continue;
}
// Collect the types from all of the call signatures
const argExpectedReturnTypes = funcSignatures
.map(s => s.parameters[argIdx])
.filter(Boolean)
.map(param => checker.getTypeOfSymbolAtLocation(param, callTsNode.expression))
.flatMap(paramType => tsutils.unionConstituents(paramType))
.flatMap(paramType => paramType.getCallSignatures())
.map(paramSignature => paramSignature.getReturnType());
const hasSingleSignature = funcSignatures.length === 1;
const allSignaturesReturnVoid = argExpectedReturnTypes.every(type => isVoid(type) ||
// Treat as void even though it might be technically any.
isNullishOrAny(type) ||
// `getTypeOfSymbolAtLocation` returns unresolved type parameters
// (e.g. `T`), even for overloads that match the call.
//
// Since we can't tell whether a generic overload currently matches,
// we treat TypeParameters similar to void.
tsutils.isTypeParameter(type));
// Check against the contextual type first, but only when there is a
// single signature or when all signatures return void, because
// `getContextualType` resolves to the first overload's return type even
// though there may be another one that matches the call.
if ((hasSingleSignature || allSignaturesReturnVoid) &&
checkExpressionNode(argNode)) {
continue;
}
if (
// At least one return type is void
argExpectedReturnTypes.some(isVoid) &&
// The rest are nullish or any
argExpectedReturnTypes.every(isNullishOrAny)) {
// We treat this argument as void even though it might be technically any.
reportIfNonVoidFunction(argNode);
}
}
}
function isNullishOrAny(type) {
return tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike |
ts.TypeFlags.Undefined |
ts.TypeFlags.Null |
ts.TypeFlags.Any |
ts.TypeFlags.Never);
}
function isVoid(type) {
return tsutils.isTypeFlagSet(type, ts.TypeFlags.Void);
}
/**
* Finds errors in an object property.
*
* Object properties require different logic
* when the property is a method shorthand.
*/
function checkObjectPropertyNode(propNode) {
const valueNode = propNode.value;
const propTsNode = parserServices.esTreeNodeToTSNodeMap.get(propNode);
if (propTsNode.kind === ts.SyntaxKind.MethodDeclaration) {
// Object property is a method shorthand.
if (propTsNode.name.kind === ts.SyntaxKind.ComputedPropertyName) {
// Don't check object methods with computed name.
return;
}
const objType = parserServices.getContextualType(propNode.parent);
if (objType == null) {
// Expected object type is unknown.
return;
}
const propSymbol = checker.getPropertyOfType(objType, propTsNode.name.text);
if (propSymbol == null) {
// Expected object type is known, but it doesn't have this method.
return;
}
const propExpectedType = checker.getTypeOfSymbolAtLocation(propSymbol, propTsNode);
if (isVoidReturningFunctionType(propExpectedType)) {
reportIfNonVoidFunction(valueNode);
}
return;
}
// Object property is a regular property.
checkExpressionNode(valueNode);
}
/**
* Finds errors in a class property.
*
* In addition to the regular check against the contextual type,
* we also check against the base class property (when the class extends another class)
* and the implemented interfaces (when the class implements an interface).
*/
function checkClassPropertyNode(propNode) {
if (propNode.value == null) {
return;
}
// Check in comparison to the base types.
for (const { baseMemberType } of util.getBaseTypesOfClassMember(parserServices, propNode)) {
if (isVoidReturningFunctionType(baseMemberType)) {
reportIfNonVoidFunction(propNode.value);
return; // Report at most one error.
}
}
// Check in comparison to the contextual type.
checkExpressionNode(propNode.value);
}
/**
* Finds errors in a class method.
*
* We check against the base class method (when the class extends another class)
* and the implemented interfaces (when the class implements an interface).
*/
function checkClassMethodNode(methodNode) {
if (methodNode.value.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression) {
return;
}
// Check in comparison to the base types.
for (const { baseMemberType } of util.getBaseTypesOfClassMember(parserServices, methodNode)) {
if (isVoidReturningFunctionType(baseMemberType)) {
reportIfNonVoidFunction(methodNode.value);
return; // Report at most one error.
}
}
}
/**
* Reports an error if the provided node is not allowed in a void function context.
*/
function reportIfNonVoidFunction(funcNode) {
const allowedReturnType = ts.TypeFlags.Void |
ts.TypeFlags.Never |
ts.TypeFlags.Undefined |
(options.allowReturnAny ? ts.TypeFlags.Any : 0);
const tsNode = parserServices.esTreeNodeToTSNodeMap.get(funcNode);
const actualType = checker.getApparentType(checker.getTypeAtLocation(tsNode));
if (tsutils
.getCallSignaturesOfType(actualType)
.map(signature => signature.getReturnType())
.flatMap(returnType => tsutils.unionConstituents(returnType))
.every(type => tsutils.isTypeFlagSet(type, allowedReturnType))) {
// The function is already void.
return;
}
if (funcNode.type !== utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
funcNode.type !== utils_1.AST_NODE_TYPES.FunctionExpression) {
// The provided function is not a function literal.
// Report a generic error.
return context.report({
node: funcNode,
messageId: `nonVoidFunc`,
});
}
// The provided function is a function literal.
if (funcNode.generator) {
// The provided function is a generator function.
// Generator functions are not allowed.
return context.report({
loc: util.getFunctionHeadLoc(funcNode, sourceCode),
messageId: `nonVoidFunc`,
});
}
if (funcNode.async) {
// The provided function is an async function.
// Async functions aren't allowed.
return context.report({
loc: util.getFunctionHeadLoc(funcNode, sourceCode),
messageId: `asyncFunc`,
});
}
if (funcNode.body.type !== utils_1.AST_NODE_TYPES.BlockStatement) {
// The provided function is an arrow function shorthand without braces.
return context.report({
node: funcNode.body,
messageId: `nonVoidReturn`,
});
}
// The function is a regular or arrow function with a block body.
// Check return type annotation.
if (funcNode.returnType != null) {
// The provided function has an explicit return type annotation.
const typeAnnotationNode = funcNode.returnType.typeAnnotation;
if (typeAnnotationNode.type !== utils_1.AST_NODE_TYPES.TSVoidKeyword) {
// The explicit return type is not `void`.
return context.report({
node: typeAnnotationNode,
messageId: `nonVoidFunc`,
});
}
}
// Iterate over all function's return statements.
for (const statement of util.walkStatements(funcNode.body.body)) {
if (statement.type !== utils_1.AST_NODE_TYPES.ReturnStatement ||
statement.argument == null) {
// We only care about return statements with a value.
continue;
}
const returnType = checker.getTypeAtLocation(parserServices.esTreeNodeToTSNodeMap.get(statement.argument));
if (tsutils.isTypeFlagSet(returnType, allowedReturnType)) {
// Only visit return statements with invalid type.
continue;
}
// This return statement causes the non-void return type.
const returnKeyword = util.nullThrows(sourceCode.getFirstToken(statement, {
filter: token => token.value === 'return',
}), util.NullThrowsReasons.MissingToken('return keyword', statement.type));
context.report({
node: returnKeyword,
messageId: `nonVoidReturn`,
});
}
// No invalid returns found. The function is allowed.
}
},
});